@gitkraken/core-gitlens 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +21 -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/git-cli/exec/git.js +1 -1
  5. package/dist/git-cli/providers/config.js +2 -2
  6. package/dist/git-cli/providers/pausedOperations.js +2 -2
  7. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  8. package/dist/git-cli/providers/staging.js +1 -1
  9. package/dist/ipc/discovery.js +1 -1
  10. package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
  11. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  12. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
  13. package/dist/plus/integrations/authentication/configuredIntegrationService.js +9 -2
  14. package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -1
  15. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +1 -1
  16. package/dist/plus/integrations/index.d.ts +2 -2
  17. package/dist/plus/integrations/index.js.map +1 -1
  18. package/dist/plus/integrations/integrationService.d.ts +34 -0
  19. package/dist/plus/integrations/integrationService.js +90 -43
  20. package/dist/plus/integrations/integrationService.js.map +1 -1
  21. package/dist/plus/integrations/lite.js +5 -4
  22. package/dist/plus/integrations/lite.js.map +1 -1
  23. package/dist/plus/integrations/manager.d.ts +68 -23
  24. package/dist/plus/integrations/models/gitHostIntegration.d.ts +30 -14
  25. package/dist/plus/integrations/models/gitHostIntegration.js +59 -21
  26. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  27. package/dist/plus/integrations/models/integration.d.ts +3 -3
  28. package/dist/plus/integrations/models/integration.js +1 -1
  29. package/dist/plus/integrations/models/integration.js.map +1 -1
  30. package/dist/plus/integrations/models/issueReads.d.ts +17 -0
  31. package/dist/plus/integrations/models/pullRequestReads.d.ts +26 -0
  32. package/dist/plus/integrations/providers/azure/azure.d.ts +66 -1
  33. package/dist/plus/integrations/providers/azure/azure.js +192 -12
  34. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  35. package/dist/plus/integrations/providers/azure/search.d.ts +144 -0
  36. package/dist/plus/integrations/providers/azure/search.js +250 -0
  37. package/dist/plus/integrations/providers/azure/search.js.map +1 -0
  38. package/dist/plus/integrations/providers/azureDevOps.d.ts +54 -35
  39. package/dist/plus/integrations/providers/azureDevOps.js +154 -121
  40. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  41. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +176 -0
  42. package/dist/plus/integrations/providers/azureDevOpsServer.js +560 -0
  43. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -0
  44. package/dist/plus/integrations/providers/bitbucket-server/discovery.d.ts +12 -0
  45. package/dist/plus/integrations/providers/bitbucket-server/discovery.js +128 -0
  46. package/dist/plus/integrations/providers/bitbucket-server/discovery.js.map +1 -0
  47. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +10 -1
  48. package/dist/plus/integrations/providers/bitbucket-server/models.js +3 -2
  49. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
  50. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +58 -0
  51. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +485 -0
  52. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -0
  53. package/dist/plus/integrations/providers/bitbucket-server.d.ts +52 -3
  54. package/dist/plus/integrations/providers/bitbucket-server.js +96 -20
  55. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  56. package/dist/plus/integrations/providers/bitbucket.js +1 -1
  57. package/dist/plus/integrations/providers/github.d.ts +5 -5
  58. package/dist/plus/integrations/providers/github.js +34 -33
  59. package/dist/plus/integrations/providers/github.js.map +1 -1
  60. package/dist/plus/integrations/providers/gitlab.d.ts +5 -3
  61. package/dist/plus/integrations/providers/gitlab.js +31 -27
  62. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  63. package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
  64. package/dist/plus/integrations/providers/jira-server.d.ts +9 -0
  65. package/dist/plus/integrations/providers/jira-server.js +13 -2
  66. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  67. package/dist/plus/integrations/providers/jira.js +1 -1
  68. package/dist/plus/integrations/providers/linear.js +1 -1
  69. package/dist/plus/integrations/providers/models.d.ts +9 -0
  70. package/dist/plus/integrations/providers/models.js +86 -0
  71. package/dist/plus/integrations/providers/models.js.map +1 -1
  72. package/dist/plus/integrations/providers/providersApi.d.ts +10 -0
  73. package/dist/plus/integrations/providers/providersApi.js +16 -1
  74. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  75. package/dist/plus/integrations/providers/utils.d.ts +12 -1
  76. package/dist/plus/integrations/providers/utils.js +36 -6
  77. package/dist/plus/integrations/providers/utils.js.map +1 -1
  78. package/dist/plus/integrations/reads/broaden.js +5 -5
  79. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  80. package/dist/plus/integrations/reads/counts.d.ts +18 -4
  81. package/dist/plus/integrations/reads/counts.js +66 -15
  82. package/dist/plus/integrations/reads/counts.js.map +1 -1
  83. package/dist/plus/integrations/reads/cursors.js +1 -1
  84. package/dist/plus/integrations/reads/drains.d.ts +1 -0
  85. package/dist/plus/integrations/reads/filters.d.ts +1 -1
  86. package/dist/plus/integrations/reads/filters.js +17 -12
  87. package/dist/plus/integrations/reads/filters.js.map +1 -1
  88. package/dist/plus/integrations/reads/hierarchy.js +1 -1
  89. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  90. package/dist/plus/integrations/reads/issueTracker.js +1 -1
  91. package/dist/plus/integrations/reads/issues.js +1 -1
  92. package/dist/plus/integrations/reads/paging.js +1 -1
  93. package/dist/plus/integrations/reads/resolveRepository.d.ts +12 -11
  94. package/dist/plus/integrations/reads/resolveRepository.js +109 -18
  95. package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
  96. package/dist/plus/integrations/reads/searchIssues.js +4 -2
  97. package/dist/plus/integrations/reads/searchIssues.js.map +1 -1
  98. package/dist/plus/integrations/reads/searchPullRequests.js +9 -3
  99. package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
  100. package/dist/plus/integrations/reads/trackerIssue.d.ts +9 -5
  101. package/dist/plus/integrations/reads/trackerIssue.js +15 -9
  102. package/dist/plus/integrations/reads/trackerIssue.js.map +1 -1
  103. package/dist/plus/integrations/reads/warnings.d.ts +6 -2
  104. package/dist/plus/integrations/reads/warnings.js +15 -19
  105. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  106. package/dist/plus/integrations/utils/domain.utils.d.ts +19 -0
  107. package/dist/plus/integrations/utils/domain.utils.js +36 -1
  108. package/dist/plus/integrations/utils/domain.utils.js.map +1 -1
  109. package/dist/plus/integrations/utils/integration.utils.d.ts +1 -0
  110. package/dist/plus/integrations/utils/integration.utils.js +12 -1
  111. package/dist/plus/integrations/utils/integration.utils.js.map +1 -1
  112. package/dist/utils/env/node/exec.js +2 -2
  113. package/docs/integrations.md +176 -73
  114. package/docs/kepler-read-api-parity.md +19 -6
  115. package/package.json +1 -1
@@ -7,8 +7,8 @@ import { toCollectionScopeFailure } from "../collectionMetadata.js";
7
7
  import "../constants.js";
8
8
  import { toTokenWithInfo } from "../authentication/models.js";
9
9
  import "../providerFilters.js";
10
- import { ProviderPullRequestReviewState, getProviderPullRequestIdentity, providersMetadata, toIssueShape, toProviderPullRequestStates } from "./models.js";
11
10
  import { collectProviderPagedResult, mergeCollectionMetadata } from "./utils/providerPaging.js";
11
+ import { ProviderPullRequestReviewState, getProviderPullRequestIdentity, providersMetadata, toIssueShape, toProviderPullRequestStates } from "./models.js";
12
12
  import { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from "./gitlab/gitlab.utils.js";
13
13
  import { fromGitLabMergeRequestProvidersApi } from "./gitlab/models.js";
14
14
  import { GitHostIntegration } from "../models/gitHostIntegration.js";
@@ -56,6 +56,10 @@ function parseGitLabPullRequestFacetCursor(cursor) {
56
56
  /** How many SSH signing-key lookups (account resolve + keys fetch) to run concurrently, to avoid a request burst. */
57
57
  const sshSigningKeyResolveBatchSize = 10;
58
58
  var GitLabIntegrationBase = class extends GitHostIntegration {
59
+ /** The installation base the PAT-based reads take on self-hosted GitLab; gitlab.com passes none. */
60
+ enterpriseBaseUrlFor(session) {
61
+ return this.isEnterprise ? this.getSelfManagedApiBaseUrl(session) : void 0;
62
+ }
59
63
  /** Self-hosted GitLab uses PAT semantics and a domain-based API base; gitlab.com does not. */
60
64
  get isEnterprise() {
61
65
  return this.id === "cloud-gitlab-self-hosted";
@@ -63,13 +67,13 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
63
67
  async getProviderAccountForCommit(session, repo, rev, options) {
64
68
  return (await this.authenticationService.apis.gitlab)?.getAccountForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, {
65
69
  ...options,
66
- baseUrl: this.apiBaseUrl
70
+ baseUrl: this.apiBaseUrlFor(session)
67
71
  });
68
72
  }
69
73
  async getProviderAccountForEmail(session, repo, email, options) {
70
74
  return (await this.authenticationService.apis.gitlab)?.getAccountForEmail(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, email, {
71
75
  ...options,
72
- baseUrl: this.apiBaseUrl
76
+ baseUrl: this.apiBaseUrlFor(session)
73
77
  });
74
78
  }
75
79
  async getProviderSshSigningKeysForEmails(session, repo, emails) {
@@ -80,29 +84,29 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
80
84
  await batch(emails, sshSigningKeyResolveBatchSize, async (email) => {
81
85
  const account = await this.getProviderAccountForEmail(session, repo, email);
82
86
  if (account?.id == null) return;
83
- const keys = await api.getUserSigningKeys(this, token, account.id, { baseUrl: this.apiBaseUrl });
87
+ const keys = await api.getUserSigningKeys(this, token, account.id, { baseUrl: this.apiBaseUrlFor(session) });
84
88
  result.set(email.toLowerCase(), keys.map((k) => k.key));
85
89
  });
86
90
  return result;
87
91
  }
88
92
  async getProviderDefaultBranch(session, repo) {
89
- return (await this.authenticationService.apis.gitlab)?.getDefaultBranch(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, { baseUrl: this.apiBaseUrl });
93
+ return (await this.authenticationService.apis.gitlab)?.getDefaultBranch(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, { baseUrl: this.apiBaseUrlFor(session) });
90
94
  }
91
95
  async getProviderLinkedIssueOrPullRequest(session, repo, { id }) {
92
- return (await this.authenticationService.apis.gitlab)?.getIssueOrPullRequest(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, Number(id), { baseUrl: this.apiBaseUrl });
96
+ return (await this.authenticationService.apis.gitlab)?.getIssueOrPullRequest(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, Number(id), { baseUrl: this.apiBaseUrlFor(session) });
93
97
  }
94
98
  async getProviderIssue(session, repo, id) {
95
99
  const api = await this.authenticationService.apis.gitlab;
96
100
  const providerApi = await this.getProvidersApi();
97
101
  if (!api || !repo || !id) return;
98
- if (!await api.getProjectId(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, this.apiBaseUrl, void 0)) return;
102
+ if (!await api.getProjectId(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, this.apiBaseUrlFor(session), void 0)) return;
99
103
  const apiResult = await providerApi.getIssue(toTokenWithInfo(this.id, session), {
100
104
  namespace: repo.owner,
101
105
  name: repo.name,
102
106
  number: id
103
107
  }, {
104
108
  isPAT: this.isEnterprise,
105
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
109
+ baseUrl: this.enterpriseBaseUrlFor(session)
106
110
  });
107
111
  const issue = apiResult != null ? toIssueShape(apiResult, this) : void 0;
108
112
  return issue != null ? {
@@ -119,14 +123,14 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
119
123
  return (await this.authenticationService.apis.gitlab)?.getPullRequestForBranch(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, branch, {
120
124
  ...opts,
121
125
  include: include?.map((s) => toGitLabMergeRequestState(s)),
122
- baseUrl: this.apiBaseUrl
126
+ baseUrl: this.apiBaseUrlFor(session)
123
127
  });
124
128
  }
125
129
  async getProviderPullRequestForCommit(session, repo, rev) {
126
- return (await this.authenticationService.apis.gitlab)?.getPullRequestForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, { baseUrl: this.apiBaseUrl });
130
+ return (await this.authenticationService.apis.gitlab)?.getPullRequestForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, { baseUrl: this.apiBaseUrlFor(session) });
127
131
  }
128
132
  async getProviderPullRequest(session, resource, id) {
129
- return (await this.authenticationService.apis.gitlab)?.getPullRequest(this, toTokenWithInfo(this.id, session), resource.owner, resource.name, parseInt(id, 10), { baseUrl: this.apiBaseUrl });
133
+ return (await this.authenticationService.apis.gitlab)?.getPullRequest(this, toTokenWithInfo(this.id, session), resource.owner, resource.name, parseInt(id, 10), { baseUrl: this.apiBaseUrlFor(session) });
130
134
  }
131
135
  async getRepoInfo(repo) {
132
136
  const api = await this.getProvidersApi();
@@ -134,16 +138,16 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
134
138
  if (session == null) return void 0;
135
139
  return api.getRepo(toTokenWithInfo(this.id, session), repo.owner, repo.name, repo.project, {
136
140
  isPAT: this.isEnterprise,
137
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
141
+ baseUrl: this.enterpriseBaseUrlFor(session)
138
142
  });
139
143
  }
140
144
  async getProviderRepositoryMetadata(session, repo, cancellation) {
141
- return (await this.authenticationService.apis.gitlab)?.getRepositoryMetadata(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, { baseUrl: this.apiBaseUrl }, cancellation);
145
+ return (await this.authenticationService.apis.gitlab)?.getRepositoryMetadata(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, { baseUrl: this.apiBaseUrlFor(session) }, cancellation);
142
146
  }
143
147
  async getProviderOrganizationsForUser(session) {
144
148
  const result = await (await this.getProvidersApi()).getGitlabGroupsForCurrentUser(toTokenWithInfo(this.id, session), {
145
149
  isPAT: this.isEnterprise,
146
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
150
+ baseUrl: this.enterpriseBaseUrlFor(session)
147
151
  });
148
152
  return {
149
153
  values: result.values.map((g) => ({
@@ -167,7 +171,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
167
171
  async getProviderRepositoriesForOrg(session, org, options) {
168
172
  const result = await (await this.getProvidersApi()).getReposForCurrentUser(toTokenWithInfo(this.id, session), {
169
173
  isPAT: this.isEnterprise,
170
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0,
174
+ baseUrl: this.enterpriseBaseUrlFor(session),
171
175
  cursor: options?.cursor
172
176
  });
173
177
  return {
@@ -178,7 +182,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
178
182
  async getProviderRepositoriesForUser(session, options) {
179
183
  return (await this.getProvidersApi()).getReposForCurrentUser(toTokenWithInfo(this.id, session), {
180
184
  isPAT: this.isEnterprise,
181
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0,
185
+ baseUrl: this.enterpriseBaseUrlFor(session),
182
186
  cursor: options?.cursor
183
187
  });
184
188
  }
@@ -188,7 +192,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
188
192
  if (!username) return Promise.resolve([]);
189
193
  const apiResult = await api.getPullRequestsForUser(toTokenWithInfo(this.id, session), username, {
190
194
  isPAT: this.isEnterprise,
191
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0,
195
+ baseUrl: this.enterpriseBaseUrlFor(session),
192
196
  states: toProviderPullRequestStates(options?.state)
193
197
  });
194
198
  if (apiResult == null) return Promise.resolve([]);
@@ -227,7 +231,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
227
231
  association,
228
232
  result: await api.getGitLabPullRequestsForUserAssociation(tokenWithInfo, username, association, {
229
233
  isPAT: this.isEnterprise,
230
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0,
234
+ baseUrl: this.enterpriseBaseUrlFor(session),
231
235
  states: toProviderPullRequestStates(options?.state),
232
236
  cursor: cursors[association]
233
237
  })
@@ -286,10 +290,10 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
286
290
  const api = await this.authenticationService.apis.gitlab;
287
291
  const providerApi = await this.getProvidersApi();
288
292
  if (!api || !repos) return;
289
- const repoInput = (await Promise.allSettled(repos.map((r) => api.getProjectId(this, toTokenWithInfo(this.id, session), r.owner, r.name, this.apiBaseUrl, void 0)) ?? [])).map((result) => result.status === "fulfilled" ? result.value : void 0).filter((r) => r != null);
293
+ const repoInput = (await Promise.allSettled(repos.map((r) => api.getProjectId(this, toTokenWithInfo(this.id, session), r.owner, r.name, this.apiBaseUrlFor(session), void 0)) ?? [])).map((result) => result.status === "fulfilled" ? result.value : void 0).filter((r) => r != null);
290
294
  return (await providerApi.getIssuesForRepos(toTokenWithInfo(this.id, session), repoInput, {
291
295
  isPAT: this.isEnterprise,
292
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
296
+ baseUrl: this.enterpriseBaseUrlFor(session)
293
297
  })).values.map((issue) => toIssueShape(issue, this)).filter((result) => result != null);
294
298
  }
295
299
  /**
@@ -314,7 +318,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
314
318
  const username = options?.includeAllAssignees ? void 0 : (await this.getProviderCurrentAccount(session))?.username;
315
319
  if (!options?.includeAllAssignees && username == null) return void 0;
316
320
  if (cancellation?.aborted) throw new CancellationError();
317
- const baseUrl = this.isEnterprise ? `https://${this.domain}` : void 0;
321
+ const baseUrl = this.enterpriseBaseUrlFor(session);
318
322
  const maxPages = 20;
319
323
  const issuesByUrl = /* @__PURE__ */ new Map();
320
324
  let truncated = false;
@@ -364,7 +368,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
364
368
  return api.searchPullRequests(this, toTokenWithInfo(this.id, session), {
365
369
  search: searchQuery,
366
370
  repos: repos?.map((r) => `${r.owner}/${r.name}`),
367
- baseUrl: this.apiBaseUrl,
371
+ baseUrl: this.apiBaseUrlFor(session),
368
372
  include: options?.include
369
373
  }, cancellation);
370
374
  }
@@ -375,7 +379,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
375
379
  return await api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {
376
380
  ...options,
377
381
  isPAT: this.isEnterprise,
378
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
382
+ baseUrl: this.enterpriseBaseUrlFor(session)
379
383
  });
380
384
  } catch (ex) {
381
385
  this.showMergeErrorMessage(ex);
@@ -391,7 +395,7 @@ var GitLabIntegrationBase = class extends GitHostIntegration {
391
395
  async getProviderCurrentAccount(session) {
392
396
  const currentUser = await (await this.getProvidersApi()).getCurrentUser(toTokenWithInfo(this.id, session), {
393
397
  isPAT: this.isEnterprise,
394
- baseUrl: this.isEnterprise ? `https://${this.domain}` : void 0
398
+ baseUrl: this.enterpriseBaseUrlFor(session)
395
399
  });
396
400
  if (currentUser == null) return void 0;
397
401
  return {
@@ -420,7 +424,7 @@ var GitLabIntegration = class extends GitLabIntegrationBase {
420
424
  get domain() {
421
425
  return metadata.domain;
422
426
  }
423
- get apiBaseUrl() {
427
+ apiBaseUrlFor(_session) {
424
428
  return "https://gitlab.com/api";
425
429
  }
426
430
  access() {
@@ -436,8 +440,8 @@ var GitLabSelfHostedIntegration = class extends GitLabIntegrationBase {
436
440
  get domain() {
437
441
  return this._domain;
438
442
  }
439
- get apiBaseUrl() {
440
- return `https://${this._domain}/api`;
443
+ apiBaseUrlFor(session) {
444
+ return `${this.getSelfManagedApiBaseUrl(session)}/api`;
441
445
  }
442
446
  constructor(ctx, authenticationService, getProvidersApi, didChangeConnection, _domain) {
443
447
  super(ctx, authenticationService, getProvidersApi, didChangeConnection);
@@ -1 +1 @@
1
- {"version":3,"file":"gitlab.js","names":[],"sources":["../../../../../plus/integrations/src/providers/gitlab.ts"],"sourcesContent":["import type { CollectionMetadata, CollectionScopeFailure } from '@gitkraken/provider-apis';\nimport * as l10n from '@vscode/l10n';\nimport type { Account } 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 } 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 { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport type { RepositoryDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\nimport type { PullRequestUrlIdentity } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport type { Emitter } from '@gitlens/utils/event.js';\nimport { uniqueBy } from '@gitlens/utils/iterable.js';\nimport { batch } from '@gitlens/utils/promise.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';\nimport type { ProviderAuthenticationSession } from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport { toCollectionScopeFailure } from '../collectionMetadata.js';\nimport { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from '../constants.js';\nimport type { IntegrationServiceContext } from '../context.js';\nimport { IntegrationReadUnavailableError } 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 { AccountWideIssuesResult, SearchMyIssuesOptions } from '../models/integration.js';\nimport type { GitLabIntegrationIds } from './gitlab/gitlab.utils.js';\nimport { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from './gitlab/gitlab.utils.js';\nimport { fromGitLabMergeRequestProvidersApi } from './gitlab/models.js';\nimport type {\n\tProviderApiPagedResult,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tgetProviderPullRequestIdentity,\n\tIssueFilter,\n\tProviderPullRequestReviewState,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoIssueShape,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport type { ProvidersApi } from './providersApi.js';\nimport { collectProviderPagedResult, mergeCollectionMetadata } from './utils/providerPaging.js';\n\nconst metadata = providersMetadata[GitCloudHostIntegrationId.GitLab];\nconst authProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({\n\tid: metadata.id,\n\tscopes: metadata.scopes,\n});\n\nconst cloudEnterpriseMetadata = providersMetadata[GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted];\nconst cloudEnterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({\n\tid: cloudEnterpriseMetadata.id,\n\tscopes: cloudEnterpriseMetadata.scopes,\n});\n\ntype GitLabPullRequestAssociation = 'assigned' | 'authored' | 'reviewRequested';\ntype GitLabPullRequestFacetCursor = Partial<Record<GitLabPullRequestAssociation, string>>;\n\n/**\n * The account-wide relationships GitLab can express, and the `scope` each maps to. `undefined` means GitLab has\n * no equivalent axis (it has neither `Mention` nor `reviewed-by`), and this map is the single declaration of\n * that. Exhaustive over `PullRequestFilter` on purpose: a new member must be decided for GitLab here rather\n * than compiling through as silently unsupported. Exported for the advertised-vs-expressible capability test,\n * which is what keeps it agreeing with `supportedAccountWidePullRequestFilters`; no runtime consumer imports it.\n */\nexport const gitLabAssociationForFilter: Record<PullRequestFilter, GitLabPullRequestAssociation | undefined> = {\n\t[PullRequestFilter.Assignee]: 'assigned',\n\t[PullRequestFilter.Author]: 'authored',\n\t[PullRequestFilter.ReviewRequested]: 'reviewRequested',\n\t[PullRequestFilter.Reviewed]: undefined,\n\t[PullRequestFilter.Mention]: undefined,\n};\n\nfunction parseGitLabPullRequestFacetCursor(cursor: string | undefined): GitLabPullRequestFacetCursor {\n\tif (!cursor) return {};\n\n\ttry {\n\t\tconst parsed = JSON.parse(cursor) as { type?: unknown; cursors?: unknown };\n\t\tif (parsed.type !== 'gitlab-associations' || parsed.cursors == null || typeof parsed.cursors !== 'object') {\n\t\t\treturn {};\n\t\t}\n\n\t\tconst cursors = parsed.cursors as Record<string, unknown>;\n\t\treturn Object.fromEntries(\n\t\t\t(['assigned', 'authored', 'reviewRequested'] as const)\n\t\t\t\t.filter(association => typeof cursors[association] === 'string' && cursors[association] !== '')\n\t\t\t\t.map(association => [association, cursors[association] as string]),\n\t\t);\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport type GitLabRepositoryDescriptor = RepositoryDescriptor;\n\n/** How many SSH signing-key lookups (account resolve + keys fetch) to run concurrently, to avoid a request burst. */\nconst sshSigningKeyResolveBatchSize = 10;\n\nabstract class GitLabIntegrationBase<ID extends GitLabIntegrationIds> extends GitHostIntegration<\n\tID,\n\tGitLabRepositoryDescriptor\n> {\n\tprotected abstract get apiBaseUrl(): string;\n\n\t/** Self-hosted GitLab uses PAT semantics and a domain-based API base; gitlab.com does not. */\n\tprotected get isEnterprise(): boolean {\n\t\treturn this.id === GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted;\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getAccountForCommit(\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\t{\n\t\t\t\t...options,\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\temail: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getAccountForEmail(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\temail,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderSshSigningKeysForEmails(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\temails: string[],\n\t): Promise<Map<string, string[]>> {\n\t\tconst result = new Map<string, string[]>();\n\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tif (api == null) return result;\n\n\t\tconst token = toTokenWithInfo(this.id, session);\n\n\t\t// GitLab resolves users one email at a time (no batch search). Run them in bounded batches rather than firing all\n\t\t// (up to providerVerifyLimit) account + key lookups at once, to avoid a request burst that trips rate limiting.\n\t\tawait batch(emails, sshSigningKeyResolveBatchSize, async email => {\n\t\t\tconst account = await this.getProviderAccountForEmail(session, repo, email);\n\t\t\tif (account?.id == null) return;\n\n\t\t\tconst keys = await api.getUserSigningKeys(this, token, account.id, { baseUrl: this.apiBaseUrl });\n\t\t\tresult.set(\n\t\t\t\temail.toLowerCase(),\n\t\t\t\tkeys.map(k => k.key),\n\t\t\t);\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getDefaultBranch(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getIssueOrPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tNumber(id),\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<Issue | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tconst providerApi = await this.getProvidersApi();\n\t\tif (!api || !repo || !id) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst repoId = await api.getProjectId(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tthis.apiBaseUrl,\n\t\t\tundefined,\n\t\t);\n\t\tif (!repoId) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst apiResult = await providerApi.getIssue(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t{ namespace: repo.owner, name: repo.name, number: id },\n\t\t\t{\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\t},\n\t\t);\n\t\tconst issue = apiResult != null ? toIssueShape(apiResult, this) : undefined;\n\t\treturn issue != null ? { ...issue, type: 'issue' } : undefined;\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tbranch: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\tconst { include, ...opts } = options ?? {};\n\n\t\tconst toGitLabMergeRequestState = (await import(/* webpackChunkName: \"integrations\" */ './gitlab/models.js'))\n\t\t\t.toGitLabMergeRequestState;\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequestForBranch(\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\t{\n\t\t\t\t...opts,\n\t\t\t\tinclude: include?.map(s => toGitLabMergeRequestState(s)),\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequestForCommit(\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\t{\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresource: GitLabRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tresource.owner,\n\t\t\tresource.name,\n\t\t\tparseInt(id, 10),\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\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\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getRepositoryMetadata(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async getProviderOrganizationsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst result = await api.getGitlabGroupsForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t});\n\t\treturn {\n\t\t\tvalues: result.values.map(g => ({ id: g.id, providerId: this.id, name: g.fullPath, url: g.webUrl })),\n\t\t\t...(result.truncated ? { truncated: true } : {}),\n\t\t\t...(result.metadata != null ? { metadata: result.metadata } : {}),\n\t\t};\n\t}\n\n\t/**\n\t * GitLab has no group-scoped repos endpoint, so each page is a page of the current user's member repos\n\t * across all namespaces, filtered to `org` and its subgroups (mirroring gkcli's `gitlabOrgMatches`).\n\t * Follow `paging.cursor` to page the full list; repos the user isn't a member of aren't returned.\n\t * Because the filter is applied per page, a page can come back with `values: []` while\n\t * `paging.more` is still `true` (e.g. a page full of repos outside `org`) — don't treat an empty\n\t * page as the end of pagination, only `paging.more`/`collectPagedResults` reaching exhaustion.\n\t */\n\tprotected override async getProviderRepositoriesForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg: string,\n\t\toptions?: { cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst result = await api.getReposForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\tcursor: options?.cursor,\n\t\t});\n\t\treturn {\n\t\t\tvalues: result.values.filter(r => matchesGitLabOrgNamespace(r.namespace, org)),\n\t\t\t...(result.paging != null ? { paging: result.paging } : {}),\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> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// GitLab's membership read is already user-affiliated, so the account-wide walk is the unfiltered\n\t\t// version of the per-org read above (which pages the same source and filters by namespace).\n\t\treturn api.getReposForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\tcursor: options?.cursor,\n\t\t});\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// Resolve the username from THIS session's token (multi-account: `session` may be a non-primary\n\t\t// connection); `getCurrentAccount()` would use the primary `_session` and filter by the wrong user.\n\t\tconst username = (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (!username) {\n\t\t\treturn Promise.resolve([]);\n\t\t}\n\n\t\tconst apiResult = await api.getPullRequestsForUser(toTokenWithInfo(this.id, session), username, {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\tstates: toProviderPullRequestStates(options?.state),\n\t\t});\n\n\t\tif (apiResult == null) {\n\t\t\treturn Promise.resolve([]);\n\t\t}\n\n\t\t// now I'm going to filter prs from the result according to the repos parameter\n\t\tlet prs;\n\t\tif (repos != null) {\n\t\t\tconst repoMap = new Map<string, GitLabRepositoryDescriptor>();\n\t\t\tfor (const repo of repos) {\n\t\t\t\trepoMap.set(`${repo.owner}/${repo.name}`, repo);\n\t\t\t}\n\t\t\tprs = apiResult.values.filter(pr => {\n\t\t\t\tconst repo = repoMap.get(`${pr.repository.owner.login}/${pr.repository.name}`);\n\t\t\t\treturn repo != null;\n\t\t\t});\n\t\t} else {\n\t\t\tprs = apiResult.values;\n\t\t}\n\n\t\tconst results: IterableIterator<PullRequest> = uniqueBy(\n\t\t\t[\n\t\t\t\t...prs\n\t\t\t\t\t.filter(pr => {\n\t\t\t\t\t\tconst isAssignee = pr.assignees?.some(a => a.username === username);\n\t\t\t\t\t\tconst isRequestedReviewer = pr.reviews?.some(\n\t\t\t\t\t\t\t// Match only reviews assigned to the current user; a bare `state === ReviewRequested`\n\t\t\t\t\t\t\t// check would also match reviews requested from OTHER people, leaking their MRs in.\n\t\t\t\t\t\t\treview =>\n\t\t\t\t\t\t\t\treview.reviewer?.username === username &&\n\t\t\t\t\t\t\t\treview.state === ProviderPullRequestReviewState.ReviewRequested,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst isAuthor = pr.author?.username === username;\n\t\t\t\t\t\t// It seems like GitLab doesn't give us mentioned PRs.\n\t\t\t\t\t\t// const isMentioned = ???;\n\n\t\t\t\t\t\treturn isAssignee || isRequestedReviewer || isAuthor;\n\t\t\t\t\t})\n\t\t\t\t\t.map(pr => fromGitLabMergeRequestProvidersApi(pr, this)),\n\t\t\t],\n\t\t\tr => r.url,\n\t\t\t(original, _current) => original,\n\t\t);\n\n\t\treturn [...results];\n\t}\n\n\tprotected override async getProviderMyPullRequestsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions?: { state?: PullRequestStateFilter[]; cursor?: string; filters?: PullRequestFilter[] },\n\t): Promise<ProviderApiPagedResult<ProviderPullRequest> | undefined> {\n\t\t// Resolve the username from THIS session's token (multi-account safe) to scope the account-wide read.\n\t\tconst username = (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (username == null) return undefined;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst requested = options?.filters?.length ? new Set(options.filters) : undefined;\n\t\t// The filter contract is all-or-nothing, so refuse as soon as ONE requested member is inexpressible rather\n\t\t// than only when every one is: dropping the rest would answer a narrower question than was asked\n\t\t// (`[Author, Mention]` becoming `authored`). Throw rather than return `undefined`, which the facade reads\n\t\t// as \"no session could be resolved\" and a drain turns into a not-connected warning, misattributing a\n\t\t// refusal; `getMyPullRequestsForUserResult` recovers the throw into `{ error }`. Defense in depth:\n\t\t// `resolveAccountWidePullRequestFilters` already refuses such a set, so only a direct caller of the public\n\t\t// method reaches this.\n\t\tconst unsupported = requested == null ? [] : [...requested].filter(f => gitLabAssociationForFilter[f] == null);\n\t\tif (unsupported.length > 0) {\n\t\t\tthrow new IntegrationReadUnavailableError(\n\t\t\t\tthis.name,\n\t\t\t\t`account-wide pull request filters not expressible by GitLab: ${unsupported.join(', ')}`,\n\t\t\t);\n\t\t}\n\n\t\tconst associations: GitLabPullRequestAssociation[] =\n\t\t\trequested == null\n\t\t\t\t? ['authored', 'assigned', 'reviewRequested']\n\t\t\t\t: Array.from(requested, f => gitLabAssociationForFilter[f]).filter(a => a != null);\n\n\t\tconst cursors = parseGitLabPullRequestFacetCursor(options?.cursor);\n\t\tconst resumable = associations.filter(association => cursors[association] != null);\n\t\tconst associationsToQuery = options?.cursor != null && resumable.length > 0 ? resumable : associations;\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst settled = await Promise.allSettled(\n\t\t\tassociationsToQuery.map(async association => ({\n\t\t\t\tassociation: association,\n\t\t\t\tresult: await api.getGitLabPullRequestsForUserAssociation(tokenWithInfo, username, association, {\n\t\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\t\t\tstates: toProviderPullRequestStates(options?.state),\n\t\t\t\t\tcursor: cursors[association],\n\t\t\t\t}),\n\t\t\t})),\n\t\t);\n\t\tif (settled.every(outcome => outcome.status === 'rejected')) {\n\t\t\tconst first = settled[0];\n\t\t\tif (first?.status === 'rejected') throw first.reason;\n\t\t}\n\n\t\tconst values = new Map<string, ProviderPullRequest>();\n\t\tconst nextCursors: GitLabPullRequestFacetCursor = {};\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tlet aggregateMetadata: CollectionMetadata | undefined;\n\t\tlet truncated = false;\n\t\tlet unkeyedPullRequest = 0;\n\t\tfor (let index = 0; index < settled.length; index++) {\n\t\t\tconst outcome = settled[index];\n\t\t\tconst association = associationsToQuery[index];\n\t\t\tif (outcome == null || association == null) continue;\n\t\t\tif (outcome.status === 'rejected') {\n\t\t\t\tconst failure = toCollectionScopeFailure({ providerId: this.id }, outcome.reason);\n\t\t\t\tfailures.push({\n\t\t\t\t\t...failure,\n\t\t\t\t\tmessage: `GitLab ${association} pull requests could not be read${\n\t\t\t\t\t\tfailure.message != null ? `: ${failure.message}` : ''\n\t\t\t\t\t}`,\n\t\t\t\t});\n\t\t\t\ttruncated = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst result = outcome.value.result;\n\t\t\taggregateMetadata = mergeCollectionMetadata(aggregateMetadata, result.metadata);\n\t\t\ttruncated ||=\n\t\t\t\tresult.paging?.truncated === true ||\n\t\t\t\t(result.metadata != null && result.metadata.completeness !== 'complete');\n\t\t\tfor (const pr of result.values) {\n\t\t\t\tconst identity = getProviderPullRequestIdentity(pr) ?? `unkeyed:${unkeyedPullRequest++}`;\n\t\t\t\tif (!values.has(identity)) {\n\t\t\t\t\tvalues.set(identity, pr);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (result.paging?.more && result.paging.cursor != null && result.paging.cursor !== '{}') {\n\t\t\t\tnextCursors[association] = result.paging.cursor;\n\t\t\t}\n\t\t}\n\n\t\taggregateMetadata = mergeCollectionMetadata(\n\t\t\taggregateMetadata,\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t);\n\t\tconst hasMore = Object.keys(nextCursors).length > 0;\n\t\treturn {\n\t\t\tvalues: [...values.values()],\n\t\t\tpaging: {\n\t\t\t\tmore: hasMore,\n\t\t\t\tcursor: hasMore ? JSON.stringify({ type: 'gitlab-associations', cursors: nextCursors }) : '{}',\n\t\t\t\ttruncated: truncated || undefined,\n\t\t\t},\n\t\t\t...(aggregateMetadata != null ? { metadata: aggregateMetadata } : {}),\n\t\t};\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tconst providerApi = await this.getProvidersApi();\n\t\tif (!api || !repos) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst repoIdsResult = await Promise.allSettled(\n\t\t\trepos.map((r: GitLabRepositoryDescriptor): Promise<string | undefined> =>\n\t\t\t\tapi.getProjectId(this, toTokenWithInfo(this.id, session), r.owner, r.name, this.apiBaseUrl, undefined),\n\t\t\t) ?? [],\n\t\t);\n\t\tconst repoInput = repoIdsResult\n\t\t\t.map(result => (result.status === 'fulfilled' ? result.value : undefined))\n\t\t\t.filter((r): r is string => r != null);\n\t\tconst apiResult = await providerApi.getIssuesForRepos(toTokenWithInfo(this.id, session), repoInput, {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t});\n\n\t\treturn apiResult.values\n\t\t\t.map(issue => toIssueShape(issue, this))\n\t\t\t.filter((result): result is IssueShape => result != null);\n\t}\n\n\t/**\n\t * Account-wide \"my issues\" for GitLab. GitLab's repo-scoped issue read bails without repos, and GitLab has\n\t * no GraphQL cross-project issue field, so this goes through the SDK's REST `GET /issues` read\n\t * ({@link ProvidersApi.getIssuesForCurrentUser}). Open issues only (matching GitHub's baked `is:open`).\n\t *\n\t * Default scope is the current user's assigned issues; `includeAllAssignees` broadens to `scope=all` (every\n\t * visible issue, any assignee). The read is numbered-paged, so each page is drained to exhaustion, bounded by\n\t * a defensive backstop — a hit backstop is reported as `truncated` so the facade surfaces an incomplete read\n\t * rather than publishing a partial list as complete.\n\t *\n\t * `options.filters` selects which relationships to read: `Assignee` (the default when omitted) and `Author`,\n\t * each its own drain, unioned by url — see the comment on `passes` for why they can't be one request. Mention\n\t * is absent because GitLab's REST read exposes no first-class mention filter, and approximating it via `search`\n\t * would return a different set than asked for; the facade refuses it\n\t * (see `ProviderMetadata.supportedAccountWideIssueFilters`).\n\t */\n\tprotected override async searchProviderMyIssuesWithTruncation(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_resources?: GitLabRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchMyIssuesOptions,\n\t): Promise<AccountWideIssuesResult | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst api = await this.getProvidersApi();\n\n\t\t// Resolve the username from THIS session's token (multi-account safe), matching the PR account-wide read.\n\t\t// Only needed to scope the default (assigned-to-me) read; the all-assignees broaden drops it.\n\t\tconst username = options?.includeAllAssignees\n\t\t\t? undefined\n\t\t\t: (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (!options?.includeAllAssignees && username == null) return undefined;\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst baseUrl = this.isEnterprise ? `https://${this.domain}` : undefined;\n\t\tconst maxPages = 20;\n\t\t// Dedupe by `url`, not `IssueShape.id`: for GitLab `id` is the per-project `iid`, which collides across\n\t\t// projects in an account-wide read (two repos both have issue `#1`), so an id-keyed map would silently\n\t\t// drop distinct issues. `url` is globally unique. Matches the GitHub/GitLab account-wide PR reads.\n\t\tconst issuesByUrl = new Map<string, IssueShape>();\n\t\tlet truncated = false;\n\t\tlet collectionMetadata: CollectionMetadata | undefined;\n\n\t\t// One drain PER requested relationship, unioned by url. The account-wide filter contract is a union\n\t\t// (`authored ∪ assigned`, matching GitHub's three searches and Azure's two drains), and GitLab can express\n\t\t// only one relationship per REST call: `assignee_username` and `author_username` on the same request\n\t\t// compose with AND, so a single combined call would return the intersection — issues the user both opened\n\t\t// and is assigned to — instead of either set. Overlap between the passes is collapsed by the url map.\n\t\tconst passes: { scope: 'assigned_to_me' | 'all'; assigneeUsername?: string; authorUsername?: string }[] = [];\n\t\tif (options?.includeAllAssignees) {\n\t\t\t// Broadens past \"mine\" entirely: every visible issue, any assignee. Contradicts `filters`, which the\n\t\t\t// facade refuses before reaching here.\n\t\t\tpasses.push({ scope: 'all' });\n\t\t} else {\n\t\t\tconst filters = options?.filters;\n\t\t\t// Assignee is this read's default relationship, so it runs unless the caller narrowed to author alone.\n\t\t\tif (filters == null || filters.length === 0 || filters.includes(IssueFilter.Assignee)) {\n\t\t\t\tpasses.push({ scope: 'assigned_to_me', assigneeUsername: username });\n\t\t\t}\n\t\t\t// `scope: 'all'` is required for the author axis: paired with `assigned_to_me` GitLab would intersect\n\t\t\t// the two rather than read authored issues.\n\t\t\tif (filters?.includes(IssueFilter.Author)) {\n\t\t\t\tpasses.push({ scope: 'all', authorUsername: username });\n\t\t\t}\n\t\t}\n\n\t\tfor (const pass of passes) {\n\t\t\tconst result = await collectProviderPagedResult(\n\t\t\t\tasync cursor => {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\tconst page = await api.getIssuesForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\t\t\t\t...pass,\n\t\t\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\t\t\tbaseUrl: baseUrl,\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tsort: options?.sort,\n\t\t\t\t\t});\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\t\t\t\treturn page;\n\t\t\t\t},\n\t\t\t\tmaxPages,\n\t\t\t\t{ providerId: this.id },\n\t\t\t);\n\n\t\t\tfor (const issue of result.values) {\n\t\t\t\tconst shape = toIssueShape(issue, this);\n\t\t\t\tif (shape != null && !issuesByUrl.has(shape.url)) {\n\t\t\t\t\tissuesByUrl.set(shape.url, shape);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttruncated ||= result.truncated === true;\n\t\t\tcollectionMetadata = mergeCollectionMetadata(collectionMetadata, result.metadata);\n\t\t}\n\n\t\treturn {\n\t\t\tvalues: [...issuesByUrl.values()],\n\t\t\ttruncated: truncated,\n\t\t\t...(collectionMetadata != null ? { metadata: collectionMetadata } : {}),\n\t\t};\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tif (!api) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn api.searchPullRequests(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t{\n\t\t\t\tsearch: searchQuery,\n\t\t\t\trepos: repos?.map(r => `${r.owner}/${r.name}`),\n\t\t\t\tbaseUrl: this.apiBaseUrl,\n\t\t\t\tinclude: options?.include,\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\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\tif (!this.isPullRequest(pr)) return false;\n\n\t\tconst api = await this.getProvidersApi();\n\t\ttry {\n\t\t\tconst res = await api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {\n\t\t\t\t...options,\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t\t});\n\t\t\treturn res;\n\t\t} catch (ex) {\n\t\t\tvoid this.showMergeErrorMessage(ex);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate async showMergeErrorMessage(ex: Error) {\n\t\t// Unfortunately, providers-api does not let us know the exact reason for the error,\n\t\t// so we show the same message to everything.\n\t\t// When we update the library, we can improve the error handling here.\n\t\tconst reauthenticate = await this.ctx.hooks?.onReauthenticationRequired?.(\n\t\t\tl10n.t(\n\t\t\t\t\"{0}. Would you like to try reauthenticating to provide additional access? Your token needs to have the 'api' scope to perform merge.\",\n\t\t\t\tex.message,\n\t\t\t),\n\t\t);\n\n\t\tif (reauthenticate) {\n\t\t\tawait this.reauthenticate();\n\t\t}\n\t}\n\n\tprivate isPullRequest(pr: PullRequest | { id: string; headRefSha: string }): pr is PullRequest {\n\t\treturn (pr as PullRequest).refs != null;\n\t}\n\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst currentUser = await api.getCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.isEnterprise ? `https://${this.domain}` : undefined,\n\t\t});\n\t\tif (currentUser == null) return undefined;\n\n\t\treturn {\n\t\t\tprovider: {\n\t\t\t\tid: this.id,\n\t\t\t\tname: this.name,\n\t\t\t\tdomain: this.domain,\n\t\t\t\ticon: this.icon,\n\t\t\t},\n\t\t\tid: currentUser.id,\n\t\t\tname: currentUser.name || undefined,\n\t\t\temail: currentUser.email || undefined,\n\t\t\tavatarUrl: currentUser.avatarUrl || undefined,\n\t\t\tusername: currentUser.username || undefined,\n\t\t};\n\t}\n\n\tprotected override getProviderPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\t\treturn getGitLabPullRequestIdentityFromMaybeUrl(search, this.id);\n\t}\n}\n\nexport class GitLabIntegration extends GitLabIntegrationBase<GitCloudHostIntegrationId.GitLab> {\n\treadonly authProvider = authProvider;\n\treadonly id = GitCloudHostIntegrationId.GitLab;\n\tprotected readonly key = this.id;\n\treadonly name: string = 'GitLab';\n\tget domain(): string {\n\t\treturn metadata.domain;\n\t}\n\n\tprotected get apiBaseUrl(): string {\n\t\treturn 'https://gitlab.com/api';\n\t}\n\n\toverride access(): Promise<boolean> {\n\t\t// Always allow GitHub cloud integration access\n\t\treturn Promise.resolve(true);\n\t}\n}\n\nexport class GitLabSelfHostedIntegration extends GitLabIntegrationBase<GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted> {\n\treadonly authProvider = cloudEnterpriseAuthProvider;\n\treadonly id = GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted;\n\tprotected readonly key;\n\treadonly name = 'GitLab Self-Hosted';\n\tget domain(): string {\n\t\treturn this._domain;\n\t}\n\tprotected override get apiBaseUrl(): string {\n\t\treturn `https://${this._domain}/api`;\n\t}\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\tthis.key = `${this.id}:${this.domain}` as const;\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gitlab.js","names":[],"sources":["../../../../../plus/integrations/src/providers/gitlab.ts"],"sourcesContent":["import type { CollectionMetadata, CollectionScopeFailure } from '@gitkraken/provider-apis';\nimport * as l10n from '@vscode/l10n';\nimport type { Account } 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 } 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 { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport type { RepositoryDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\nimport type { PullRequestUrlIdentity } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport type { Emitter } from '@gitlens/utils/event.js';\nimport { uniqueBy } from '@gitlens/utils/iterable.js';\nimport { batch } from '@gitlens/utils/promise.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';\nimport type { ProviderAuthenticationSession } from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport { toCollectionScopeFailure } from '../collectionMetadata.js';\nimport { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from '../constants.js';\nimport type { IntegrationServiceContext } from '../context.js';\nimport { IntegrationReadUnavailableError } 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 { AccountWideIssuesResult, SearchMyIssuesOptions } from '../models/integration.js';\nimport type { GitLabIntegrationIds } from './gitlab/gitlab.utils.js';\nimport { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from './gitlab/gitlab.utils.js';\nimport { fromGitLabMergeRequestProvidersApi } from './gitlab/models.js';\nimport type {\n\tProviderApiPagedResult,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tgetProviderPullRequestIdentity,\n\tIssueFilter,\n\tProviderPullRequestReviewState,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoIssueShape,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport type { ProvidersApi } from './providersApi.js';\nimport { collectProviderPagedResult, mergeCollectionMetadata } from './utils/providerPaging.js';\n\nconst metadata = providersMetadata[GitCloudHostIntegrationId.GitLab];\nconst authProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({\n\tid: metadata.id,\n\tscopes: metadata.scopes,\n});\n\nconst cloudEnterpriseMetadata = providersMetadata[GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted];\nconst cloudEnterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({\n\tid: cloudEnterpriseMetadata.id,\n\tscopes: cloudEnterpriseMetadata.scopes,\n});\n\ntype GitLabPullRequestAssociation = 'assigned' | 'authored' | 'reviewRequested';\ntype GitLabPullRequestFacetCursor = Partial<Record<GitLabPullRequestAssociation, string>>;\n\n/**\n * The account-wide relationships GitLab can express, and the `scope` each maps to. `undefined` means GitLab has\n * no equivalent axis (it has neither `Mention` nor `reviewed-by`), and this map is the single declaration of\n * that. Exhaustive over `PullRequestFilter` on purpose: a new member must be decided for GitLab here rather\n * than compiling through as silently unsupported. Exported for the advertised-vs-expressible capability test,\n * which is what keeps it agreeing with `supportedAccountWidePullRequestFilters`; no runtime consumer imports it.\n */\nexport const gitLabAssociationForFilter: Record<PullRequestFilter, GitLabPullRequestAssociation | undefined> = {\n\t[PullRequestFilter.Assignee]: 'assigned',\n\t[PullRequestFilter.Author]: 'authored',\n\t[PullRequestFilter.ReviewRequested]: 'reviewRequested',\n\t[PullRequestFilter.Reviewed]: undefined,\n\t[PullRequestFilter.Mention]: undefined,\n};\n\nfunction parseGitLabPullRequestFacetCursor(cursor: string | undefined): GitLabPullRequestFacetCursor {\n\tif (!cursor) return {};\n\n\ttry {\n\t\tconst parsed = JSON.parse(cursor) as { type?: unknown; cursors?: unknown };\n\t\tif (parsed.type !== 'gitlab-associations' || parsed.cursors == null || typeof parsed.cursors !== 'object') {\n\t\t\treturn {};\n\t\t}\n\n\t\tconst cursors = parsed.cursors as Record<string, unknown>;\n\t\treturn Object.fromEntries(\n\t\t\t(['assigned', 'authored', 'reviewRequested'] as const)\n\t\t\t\t.filter(association => typeof cursors[association] === 'string' && cursors[association] !== '')\n\t\t\t\t.map(association => [association, cursors[association] as string]),\n\t\t);\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport type GitLabRepositoryDescriptor = RepositoryDescriptor;\n\n/** How many SSH signing-key lookups (account resolve + keys fetch) to run concurrently, to avoid a request burst. */\nconst sshSigningKeyResolveBatchSize = 10;\n\nabstract class GitLabIntegrationBase<ID extends GitLabIntegrationIds> extends GitHostIntegration<\n\tID,\n\tGitLabRepositoryDescriptor\n> {\n\tprotected abstract apiBaseUrlFor(session: ProviderAuthenticationSession): string;\n\n\t/** The installation base the PAT-based reads take on self-hosted GitLab; gitlab.com passes none. */\n\tprotected enterpriseBaseUrlFor(session: ProviderAuthenticationSession): string | undefined {\n\t\treturn this.isEnterprise ? this.getSelfManagedApiBaseUrl(session) : undefined;\n\t}\n\n\t/** Self-hosted GitLab uses PAT semantics and a domain-based API base; gitlab.com does not. */\n\tprotected get isEnterprise(): boolean {\n\t\treturn this.id === GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted;\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getAccountForCommit(\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\t{\n\t\t\t\t...options,\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\temail: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getAccountForEmail(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\temail,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderSshSigningKeysForEmails(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\temails: string[],\n\t): Promise<Map<string, string[]>> {\n\t\tconst result = new Map<string, string[]>();\n\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tif (api == null) return result;\n\n\t\tconst token = toTokenWithInfo(this.id, session);\n\n\t\t// GitLab resolves users one email at a time (no batch search). Run them in bounded batches rather than firing all\n\t\t// (up to providerVerifyLimit) account + key lookups at once, to avoid a request burst that trips rate limiting.\n\t\tawait batch(emails, sshSigningKeyResolveBatchSize, async email => {\n\t\t\tconst account = await this.getProviderAccountForEmail(session, repo, email);\n\t\t\tif (account?.id == null) return;\n\n\t\t\tconst keys = await api.getUserSigningKeys(this, token, account.id, {\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t});\n\t\t\tresult.set(\n\t\t\t\temail.toLowerCase(),\n\t\t\t\tkeys.map(k => k.key),\n\t\t\t);\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getDefaultBranch(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getIssueOrPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tNumber(id),\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<Issue | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tconst providerApi = await this.getProvidersApi();\n\t\tif (!api || !repo || !id) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst repoId = await api.getProjectId(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\tthis.apiBaseUrlFor(session),\n\t\t\tundefined,\n\t\t);\n\t\tif (!repoId) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst apiResult = await providerApi.getIssue(\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t{ namespace: repo.owner, name: repo.name, number: id },\n\t\t\t{\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t\tconst issue = apiResult != null ? toIssueShape(apiResult, this) : undefined;\n\t\treturn issue != null ? { ...issue, type: 'issue' } : undefined;\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tbranch: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\tconst { include, ...opts } = options ?? {};\n\n\t\tconst toGitLabMergeRequestState = (await import(/* webpackChunkName: \"integrations\" */ './gitlab/models.js'))\n\t\t\t.toGitLabMergeRequestState;\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequestForBranch(\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\t{\n\t\t\t\t...opts,\n\t\t\t\tinclude: include?.map(s => toGitLabMergeRequestState(s)),\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequestForCommit(\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\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresource: GitLabRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tresource.owner,\n\t\t\tresource.name,\n\t\t\tparseInt(id, 10),\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\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\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: GitLabRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn (await this.authenticationService.apis.gitlab)?.getRepositoryMetadata(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\trepo.owner,\n\t\t\trepo.name,\n\t\t\t{\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async getProviderOrganizationsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst result = await api.getGitlabGroupsForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t});\n\t\treturn {\n\t\t\tvalues: result.values.map(g => ({ id: g.id, providerId: this.id, name: g.fullPath, url: g.webUrl })),\n\t\t\t...(result.truncated ? { truncated: true } : {}),\n\t\t\t...(result.metadata != null ? { metadata: result.metadata } : {}),\n\t\t};\n\t}\n\n\t/**\n\t * GitLab has no group-scoped repos endpoint, so each page is a page of the current user's member repos\n\t * across all namespaces, filtered to `org` and its subgroups (mirroring gkcli's `gitlabOrgMatches`).\n\t * Follow `paging.cursor` to page the full list; repos the user isn't a member of aren't returned.\n\t * Because the filter is applied per page, a page can come back with `values: []` while\n\t * `paging.more` is still `true` (e.g. a page full of repos outside `org`) — don't treat an empty\n\t * page as the end of pagination, only `paging.more`/`collectPagedResults` reaching exhaustion.\n\t */\n\tprotected override async getProviderRepositoriesForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg: string,\n\t\toptions?: { cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst result = await api.getReposForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\tcursor: options?.cursor,\n\t\t});\n\t\treturn {\n\t\t\tvalues: result.values.filter(r => matchesGitLabOrgNamespace(r.namespace, org)),\n\t\t\t...(result.paging != null ? { paging: result.paging } : {}),\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> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// GitLab's membership read is already user-affiliated, so the account-wide walk is the unfiltered\n\t\t// version of the per-org read above (which pages the same source and filters by namespace).\n\t\treturn api.getReposForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\tcursor: options?.cursor,\n\t\t});\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\t// Resolve the username from THIS session's token (multi-account: `session` may be a non-primary\n\t\t// connection); `getCurrentAccount()` would use the primary `_session` and filter by the wrong user.\n\t\tconst username = (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (!username) {\n\t\t\treturn Promise.resolve([]);\n\t\t}\n\n\t\tconst apiResult = await api.getPullRequestsForUser(toTokenWithInfo(this.id, session), username, {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\tstates: toProviderPullRequestStates(options?.state),\n\t\t});\n\n\t\tif (apiResult == null) {\n\t\t\treturn Promise.resolve([]);\n\t\t}\n\n\t\t// now I'm going to filter prs from the result according to the repos parameter\n\t\tlet prs;\n\t\tif (repos != null) {\n\t\t\tconst repoMap = new Map<string, GitLabRepositoryDescriptor>();\n\t\t\tfor (const repo of repos) {\n\t\t\t\trepoMap.set(`${repo.owner}/${repo.name}`, repo);\n\t\t\t}\n\t\t\tprs = apiResult.values.filter(pr => {\n\t\t\t\tconst repo = repoMap.get(`${pr.repository.owner.login}/${pr.repository.name}`);\n\t\t\t\treturn repo != null;\n\t\t\t});\n\t\t} else {\n\t\t\tprs = apiResult.values;\n\t\t}\n\n\t\tconst results: IterableIterator<PullRequest> = uniqueBy(\n\t\t\t[\n\t\t\t\t...prs\n\t\t\t\t\t.filter(pr => {\n\t\t\t\t\t\tconst isAssignee = pr.assignees?.some(a => a.username === username);\n\t\t\t\t\t\tconst isRequestedReviewer = pr.reviews?.some(\n\t\t\t\t\t\t\t// Match only reviews assigned to the current user; a bare `state === ReviewRequested`\n\t\t\t\t\t\t\t// check would also match reviews requested from OTHER people, leaking their MRs in.\n\t\t\t\t\t\t\treview =>\n\t\t\t\t\t\t\t\treview.reviewer?.username === username &&\n\t\t\t\t\t\t\t\treview.state === ProviderPullRequestReviewState.ReviewRequested,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst isAuthor = pr.author?.username === username;\n\t\t\t\t\t\t// It seems like GitLab doesn't give us mentioned PRs.\n\t\t\t\t\t\t// const isMentioned = ???;\n\n\t\t\t\t\t\treturn isAssignee || isRequestedReviewer || isAuthor;\n\t\t\t\t\t})\n\t\t\t\t\t.map(pr => fromGitLabMergeRequestProvidersApi(pr, this)),\n\t\t\t],\n\t\t\tr => r.url,\n\t\t\t(original, _current) => original,\n\t\t);\n\n\t\treturn [...results];\n\t}\n\n\tprotected override async getProviderMyPullRequestsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\toptions?: { state?: PullRequestStateFilter[]; cursor?: string; filters?: PullRequestFilter[] },\n\t): Promise<ProviderApiPagedResult<ProviderPullRequest> | undefined> {\n\t\t// Resolve the username from THIS session's token (multi-account safe) to scope the account-wide read.\n\t\tconst username = (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (username == null) return undefined;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst requested = options?.filters?.length ? new Set(options.filters) : undefined;\n\t\t// The filter contract is all-or-nothing, so refuse as soon as ONE requested member is inexpressible rather\n\t\t// than only when every one is: dropping the rest would answer a narrower question than was asked\n\t\t// (`[Author, Mention]` becoming `authored`). Throw rather than return `undefined`, which the facade reads\n\t\t// as \"no session could be resolved\" and a drain turns into a not-connected warning, misattributing a\n\t\t// refusal; `getMyPullRequestsForUserResult` recovers the throw into `{ error }`. Defense in depth:\n\t\t// `resolveAccountWidePullRequestFilters` already refuses such a set, so only a direct caller of the public\n\t\t// method reaches this.\n\t\tconst unsupported = requested == null ? [] : [...requested].filter(f => gitLabAssociationForFilter[f] == null);\n\t\tif (unsupported.length > 0) {\n\t\t\tthrow new IntegrationReadUnavailableError(\n\t\t\t\tthis.name,\n\t\t\t\t`account-wide pull request filters not expressible by GitLab: ${unsupported.join(', ')}`,\n\t\t\t);\n\t\t}\n\n\t\tconst associations: GitLabPullRequestAssociation[] =\n\t\t\trequested == null\n\t\t\t\t? ['authored', 'assigned', 'reviewRequested']\n\t\t\t\t: Array.from(requested, f => gitLabAssociationForFilter[f]).filter(a => a != null);\n\n\t\tconst cursors = parseGitLabPullRequestFacetCursor(options?.cursor);\n\t\tconst resumable = associations.filter(association => cursors[association] != null);\n\t\tconst associationsToQuery = options?.cursor != null && resumable.length > 0 ? resumable : associations;\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst settled = await Promise.allSettled(\n\t\t\tassociationsToQuery.map(async association => ({\n\t\t\t\tassociation: association,\n\t\t\t\tresult: await api.getGitLabPullRequestsForUserAssociation(tokenWithInfo, username, association, {\n\t\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\t\t\tstates: toProviderPullRequestStates(options?.state),\n\t\t\t\t\tcursor: cursors[association],\n\t\t\t\t}),\n\t\t\t})),\n\t\t);\n\t\tif (settled.every(outcome => outcome.status === 'rejected')) {\n\t\t\tconst first = settled[0];\n\t\t\tif (first?.status === 'rejected') throw first.reason;\n\t\t}\n\n\t\tconst values = new Map<string, ProviderPullRequest>();\n\t\tconst nextCursors: GitLabPullRequestFacetCursor = {};\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tlet aggregateMetadata: CollectionMetadata | undefined;\n\t\tlet truncated = false;\n\t\tlet unkeyedPullRequest = 0;\n\t\tfor (let index = 0; index < settled.length; index++) {\n\t\t\tconst outcome = settled[index];\n\t\t\tconst association = associationsToQuery[index];\n\t\t\tif (outcome == null || association == null) continue;\n\t\t\tif (outcome.status === 'rejected') {\n\t\t\t\tconst failure = toCollectionScopeFailure({ providerId: this.id }, outcome.reason);\n\t\t\t\tfailures.push({\n\t\t\t\t\t...failure,\n\t\t\t\t\tmessage: `GitLab ${association} pull requests could not be read${\n\t\t\t\t\t\tfailure.message != null ? `: ${failure.message}` : ''\n\t\t\t\t\t}`,\n\t\t\t\t});\n\t\t\t\ttruncated = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst result = outcome.value.result;\n\t\t\taggregateMetadata = mergeCollectionMetadata(aggregateMetadata, result.metadata);\n\t\t\ttruncated ||=\n\t\t\t\tresult.paging?.truncated === true ||\n\t\t\t\t(result.metadata != null && result.metadata.completeness !== 'complete');\n\t\t\tfor (const pr of result.values) {\n\t\t\t\tconst identity = getProviderPullRequestIdentity(pr) ?? `unkeyed:${unkeyedPullRequest++}`;\n\t\t\t\tif (!values.has(identity)) {\n\t\t\t\t\tvalues.set(identity, pr);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (result.paging?.more && result.paging.cursor != null && result.paging.cursor !== '{}') {\n\t\t\t\tnextCursors[association] = result.paging.cursor;\n\t\t\t}\n\t\t}\n\n\t\taggregateMetadata = mergeCollectionMetadata(\n\t\t\taggregateMetadata,\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t);\n\t\tconst hasMore = Object.keys(nextCursors).length > 0;\n\t\treturn {\n\t\t\tvalues: [...values.values()],\n\t\t\tpaging: {\n\t\t\t\tmore: hasMore,\n\t\t\t\tcursor: hasMore ? JSON.stringify({ type: 'gitlab-associations', cursors: nextCursors }) : '{}',\n\t\t\t\ttruncated: truncated || undefined,\n\t\t\t},\n\t\t\t...(aggregateMetadata != null ? { metadata: aggregateMetadata } : {}),\n\t\t};\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tconst providerApi = await this.getProvidersApi();\n\t\tif (!api || !repos) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst repoIdsResult = await Promise.allSettled(\n\t\t\trepos.map((r: GitLabRepositoryDescriptor): Promise<string | undefined> =>\n\t\t\t\tapi.getProjectId(\n\t\t\t\t\tthis,\n\t\t\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t\t\tr.owner,\n\t\t\t\t\tr.name,\n\t\t\t\t\tthis.apiBaseUrlFor(session),\n\t\t\t\t\tundefined,\n\t\t\t\t),\n\t\t\t) ?? [],\n\t\t);\n\t\tconst repoInput = repoIdsResult\n\t\t\t.map(result => (result.status === 'fulfilled' ? result.value : undefined))\n\t\t\t.filter((r): r is string => r != null);\n\t\tconst apiResult = await providerApi.getIssuesForRepos(toTokenWithInfo(this.id, session), repoInput, {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t});\n\n\t\treturn apiResult.values\n\t\t\t.map(issue => toIssueShape(issue, this))\n\t\t\t.filter((result): result is IssueShape => result != null);\n\t}\n\n\t/**\n\t * Account-wide \"my issues\" for GitLab. GitLab's repo-scoped issue read bails without repos, and GitLab has\n\t * no GraphQL cross-project issue field, so this goes through the SDK's REST `GET /issues` read\n\t * ({@link ProvidersApi.getIssuesForCurrentUser}). Open issues only (matching GitHub's baked `is:open`).\n\t *\n\t * Default scope is the current user's assigned issues; `includeAllAssignees` broadens to `scope=all` (every\n\t * visible issue, any assignee). The read is numbered-paged, so each page is drained to exhaustion, bounded by\n\t * a defensive backstop — a hit backstop is reported as `truncated` so the facade surfaces an incomplete read\n\t * rather than publishing a partial list as complete.\n\t *\n\t * `options.filters` selects which relationships to read: `Assignee` (the default when omitted) and `Author`,\n\t * each its own drain, unioned by url — see the comment on `passes` for why they can't be one request. Mention\n\t * is absent because GitLab's REST read exposes no first-class mention filter, and approximating it via `search`\n\t * would return a different set than asked for; the facade refuses it\n\t * (see `ProviderMetadata.supportedAccountWideIssueFilters`).\n\t */\n\tprotected override async searchProviderMyIssuesWithTruncation(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_resources?: GitLabRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchMyIssuesOptions,\n\t): Promise<AccountWideIssuesResult | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst api = await this.getProvidersApi();\n\n\t\t// Resolve the username from THIS session's token (multi-account safe), matching the PR account-wide read.\n\t\t// Only needed to scope the default (assigned-to-me) read; the all-assignees broaden drops it.\n\t\tconst username = options?.includeAllAssignees\n\t\t\t? undefined\n\t\t\t: (await this.getProviderCurrentAccount(session))?.username;\n\t\tif (!options?.includeAllAssignees && username == null) return undefined;\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst baseUrl = this.enterpriseBaseUrlFor(session);\n\t\tconst maxPages = 20;\n\t\t// Dedupe by `url`, not `IssueShape.id`: for GitLab `id` is the per-project `iid`, which collides across\n\t\t// projects in an account-wide read (two repos both have issue `#1`), so an id-keyed map would silently\n\t\t// drop distinct issues. `url` is globally unique. Matches the GitHub/GitLab account-wide PR reads.\n\t\tconst issuesByUrl = new Map<string, IssueShape>();\n\t\tlet truncated = false;\n\t\tlet collectionMetadata: CollectionMetadata | undefined;\n\n\t\t// One drain PER requested relationship, unioned by url. The account-wide filter contract is a union\n\t\t// (`authored ∪ assigned`, matching GitHub's three searches and Azure's two drains), and GitLab can express\n\t\t// only one relationship per REST call: `assignee_username` and `author_username` on the same request\n\t\t// compose with AND, so a single combined call would return the intersection — issues the user both opened\n\t\t// and is assigned to — instead of either set. Overlap between the passes is collapsed by the url map.\n\t\tconst passes: { scope: 'assigned_to_me' | 'all'; assigneeUsername?: string; authorUsername?: string }[] = [];\n\t\tif (options?.includeAllAssignees) {\n\t\t\t// Broadens past \"mine\" entirely: every visible issue, any assignee. Contradicts `filters`, which the\n\t\t\t// facade refuses before reaching here.\n\t\t\tpasses.push({ scope: 'all' });\n\t\t} else {\n\t\t\tconst filters = options?.filters;\n\t\t\t// Assignee is this read's default relationship, so it runs unless the caller narrowed to author alone.\n\t\t\tif (filters == null || filters.length === 0 || filters.includes(IssueFilter.Assignee)) {\n\t\t\t\tpasses.push({ scope: 'assigned_to_me', assigneeUsername: username });\n\t\t\t}\n\t\t\t// `scope: 'all'` is required for the author axis: paired with `assigned_to_me` GitLab would intersect\n\t\t\t// the two rather than read authored issues.\n\t\t\tif (filters?.includes(IssueFilter.Author)) {\n\t\t\t\tpasses.push({ scope: 'all', authorUsername: username });\n\t\t\t}\n\t\t}\n\n\t\tfor (const pass of passes) {\n\t\t\tconst result = await collectProviderPagedResult(\n\t\t\t\tasync cursor => {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\tconst page = await api.getIssuesForCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\t\t\t\t...pass,\n\t\t\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\t\t\tbaseUrl: baseUrl,\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tsort: options?.sort,\n\t\t\t\t\t});\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\t\t\t\treturn page;\n\t\t\t\t},\n\t\t\t\tmaxPages,\n\t\t\t\t{ providerId: this.id },\n\t\t\t);\n\n\t\t\tfor (const issue of result.values) {\n\t\t\t\tconst shape = toIssueShape(issue, this);\n\t\t\t\tif (shape != null && !issuesByUrl.has(shape.url)) {\n\t\t\t\t\tissuesByUrl.set(shape.url, shape);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttruncated ||= result.truncated === true;\n\t\t\tcollectionMetadata = mergeCollectionMetadata(collectionMetadata, result.metadata);\n\t\t}\n\n\t\treturn {\n\t\t\tvalues: [...issuesByUrl.values()],\n\t\t\ttruncated: truncated,\n\t\t\t...(collectionMetadata != null ? { metadata: collectionMetadata } : {}),\n\t\t};\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: GitLabRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tconst api = await this.authenticationService.apis.gitlab;\n\t\tif (!api) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn api.searchPullRequests(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\t{\n\t\t\t\tsearch: searchQuery,\n\t\t\t\trepos: repos?.map(r => `${r.owner}/${r.name}`),\n\t\t\t\tbaseUrl: this.apiBaseUrlFor(session),\n\t\t\t\tinclude: options?.include,\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\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\tif (!this.isPullRequest(pr)) return false;\n\n\t\tconst api = await this.getProvidersApi();\n\t\ttry {\n\t\t\tconst res = await api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {\n\t\t\t\t...options,\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t\t});\n\t\t\treturn res;\n\t\t} catch (ex) {\n\t\t\tvoid this.showMergeErrorMessage(ex);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate async showMergeErrorMessage(ex: Error) {\n\t\t// Unfortunately, providers-api does not let us know the exact reason for the error,\n\t\t// so we show the same message to everything.\n\t\t// When we update the library, we can improve the error handling here.\n\t\tconst reauthenticate = await this.ctx.hooks?.onReauthenticationRequired?.(\n\t\t\tl10n.t(\n\t\t\t\t\"{0}. Would you like to try reauthenticating to provide additional access? Your token needs to have the 'api' scope to perform merge.\",\n\t\t\t\tex.message,\n\t\t\t),\n\t\t);\n\n\t\tif (reauthenticate) {\n\t\t\tawait this.reauthenticate();\n\t\t}\n\t}\n\n\tprivate isPullRequest(pr: PullRequest | { id: string; headRefSha: string }): pr is PullRequest {\n\t\treturn (pr as PullRequest).refs != null;\n\t}\n\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst currentUser = await api.getCurrentUser(toTokenWithInfo(this.id, session), {\n\t\t\tisPAT: this.isEnterprise,\n\t\t\tbaseUrl: this.enterpriseBaseUrlFor(session),\n\t\t});\n\t\tif (currentUser == null) return undefined;\n\n\t\treturn {\n\t\t\tprovider: {\n\t\t\t\tid: this.id,\n\t\t\t\tname: this.name,\n\t\t\t\tdomain: this.domain,\n\t\t\t\ticon: this.icon,\n\t\t\t},\n\t\t\tid: currentUser.id,\n\t\t\tname: currentUser.name || undefined,\n\t\t\temail: currentUser.email || undefined,\n\t\t\tavatarUrl: currentUser.avatarUrl || undefined,\n\t\t\tusername: currentUser.username || undefined,\n\t\t};\n\t}\n\n\tprotected override getProviderPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\t\treturn getGitLabPullRequestIdentityFromMaybeUrl(search, this.id);\n\t}\n}\n\nexport class GitLabIntegration extends GitLabIntegrationBase<GitCloudHostIntegrationId.GitLab> {\n\treadonly authProvider = authProvider;\n\treadonly id = GitCloudHostIntegrationId.GitLab;\n\tprotected readonly key = this.id;\n\treadonly name: string = 'GitLab';\n\tget domain(): string {\n\t\treturn metadata.domain;\n\t}\n\n\tprotected apiBaseUrlFor(_session: ProviderAuthenticationSession): string {\n\t\treturn 'https://gitlab.com/api';\n\t}\n\n\toverride access(): Promise<boolean> {\n\t\t// Always allow GitHub cloud integration access\n\t\treturn Promise.resolve(true);\n\t}\n}\n\nexport class GitLabSelfHostedIntegration extends GitLabIntegrationBase<GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted> {\n\treadonly authProvider = cloudEnterpriseAuthProvider;\n\treadonly id = GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted;\n\tprotected readonly key;\n\treadonly name = 'GitLab Self-Hosted';\n\tget domain(): string {\n\t\treturn this._domain;\n\t}\n\tprotected override apiBaseUrlFor(session: ProviderAuthenticationSession): string {\n\t\treturn `${this.getSelfManagedApiBaseUrl(session)}/api`;\n\t}\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\tthis.key = `${this.id}:${this.domain}` as const;\n\t}\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { IssueSorting } from "../../../git/models/issue.js";
2
+ import "../providerFilters.js";
2
3
  //#region ../plus/integrations/src/providers/issueSorts.d.ts
3
4
  /** GitHub and GHE: one `search` channel serves all three issue reads, so all three order the same way. */
4
5
  export declare const githubIssueSorts: IssueSorting[];
@@ -76,6 +76,15 @@ export declare class JiraServerIntegration extends IssuesIntegration<IssuesSelfM
76
76
  key: string;
77
77
  }): Promise<IssueOrPullRequest | undefined>;
78
78
  protected getProviderIssue(session: ProviderAuthenticationSession, _resource: JiraServerResourceDescriptor, id: string): Promise<Issue | undefined>;
79
+ /**
80
+ * The point read behind `getTrackerIssue` (#5872). `resourceId` is this connection's single synthetic
81
+ * resource — the host itself, see {@link JiraServerResourceDescriptor} — so it selects nothing further here:
82
+ * the host was chosen upstream by `domain` (or the connection's configured domain) and the request is
83
+ * addressed to the SESSION's base URL like every other read. No `resourceUrl` is needed either, unlike Jira
84
+ * Cloud: its REST `self` link is an API endpoint, whereas `getJiraServerIssue` builds the browser link from
85
+ * the base URL it was addressed to. A key that names no issue resolves to `undefined`, a proven absence.
86
+ */
87
+ protected getProviderIssueByResourceId(session: ProviderAuthenticationSession, _resourceId: string, id: string, _resourceUrl: string | undefined): Promise<Issue | undefined>;
79
88
  /**
80
89
  * Caches are keyed by the ADDRESS the read was made against as well as the token: one integration instance
81
90
  * exists per configured host and two hosts can hold the same token, so a token-only key would serve one
@@ -3,9 +3,9 @@ import { throwIfCallerContractError, toCollectionScopeFailure } from "../collect
3
3
  import "../constants.js";
4
4
  import { toTokenWithInfo } from "../authentication/models.js";
5
5
  import "../providerFilters.js";
6
- import { providersMetadata, toAccount, toIssueShape } from "./models.js";
7
- import { areDomainsOnSameHost, baseUrlFromDomain } from "../utils/domain.utils.js";
8
6
  import { mergeCollectionMetadata } from "./utils/providerPaging.js";
7
+ import { areDomainsOnSameHost, baseUrlFromDomain } from "../utils/domain.utils.js";
8
+ import { providersMetadata, toAccount, toIssueShape } from "./models.js";
9
9
  import { IssuesIntegration } from "../models/issuesIntegration.js";
10
10
  //#region ../plus/integrations/src/providers/jira-server.ts
11
11
  const metadata = providersMetadata["jira-server"];
@@ -303,6 +303,17 @@ var JiraServerIntegration = class extends IssuesIntegration {
303
303
  } : void 0;
304
304
  }
305
305
  /**
306
+ * The point read behind `getTrackerIssue` (#5872). `resourceId` is this connection's single synthetic
307
+ * resource — the host itself, see {@link JiraServerResourceDescriptor} — so it selects nothing further here:
308
+ * the host was chosen upstream by `domain` (or the connection's configured domain) and the request is
309
+ * addressed to the SESSION's base URL like every other read. No `resourceUrl` is needed either, unlike Jira
310
+ * Cloud: its REST `self` link is an API endpoint, whereas `getJiraServerIssue` builds the browser link from
311
+ * the base URL it was addressed to. A key that names no issue resolves to `undefined`, a proven absence.
312
+ */
313
+ getProviderIssueByResourceId(session, _resourceId, id, _resourceUrl) {
314
+ return this.getProviderIssue(session, this.resourceFor(session), id);
315
+ }
316
+ /**
306
317
  * Caches are keyed by the ADDRESS the read was made against as well as the token: one integration instance
307
318
  * exists per configured host and two hosts can hold the same token, so a token-only key would serve one
308
319
  * host's projects for the other — and the host alone is not enough either, because a connection re-pointed