@gitkraken/core-gitlens 0.9.9 → 0.10.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 (53) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/dist/git/errors.d.ts +7 -0
  3. package/dist/git/errors.js +14 -1
  4. package/dist/git/errors.js.map +1 -1
  5. package/dist/git/providers/status.d.ts +6 -1
  6. package/dist/git/run.types.d.ts +9 -4
  7. package/dist/git-cli/exec/git.js +36 -16
  8. package/dist/git-cli/exec/git.js.map +1 -1
  9. package/dist/git-cli/providers/diff.d.ts +5 -2
  10. package/dist/git-cli/providers/diff.js +21 -9
  11. package/dist/git-cli/providers/diff.js.map +1 -1
  12. package/dist/git-cli/providers/patch.js +5 -7
  13. package/dist/git-cli/providers/patch.js.map +1 -1
  14. package/dist/git-cli/providers/status.d.ts +0 -1
  15. package/dist/git-cli/providers/status.js +119 -142
  16. package/dist/git-cli/providers/status.js.map +1 -1
  17. package/dist/plus/git-github/providers/github/status.d.ts +0 -1
  18. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  19. package/dist/plus/integrations/authentication/cloudIntegrationService.js +24 -7
  20. package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -1
  21. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +7 -0
  22. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +13 -3
  23. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -1
  24. package/dist/plus/integrations/integrationService.js +4 -2
  25. package/dist/plus/integrations/integrationService.js.map +1 -1
  26. package/dist/plus/integrations/models/gitHostIntegration.js +20 -20
  27. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  28. package/dist/plus/integrations/models/integration.d.ts +29 -3
  29. package/dist/plus/integrations/models/integration.js +53 -12
  30. package/dist/plus/integrations/models/integration.js.map +1 -1
  31. package/dist/plus/integrations/models/issuesIntegration.js +9 -9
  32. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  33. package/dist/plus/integrations/providers/azureDevOps.js +1 -1
  34. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  35. package/dist/plus/integrations/providers/azureDevOpsServer.js +1 -1
  36. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  37. package/dist/plus/integrations/providers/bitbucket-server.js +1 -1
  38. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  39. package/dist/plus/integrations/providers/bitbucket.js +1 -1
  40. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  41. package/dist/plus/integrations/providers/github.js +2 -2
  42. package/dist/plus/integrations/providers/github.js.map +1 -1
  43. package/dist/plus/integrations/providers/gitlab.js +1 -1
  44. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  45. package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
  46. package/dist/plus/integrations/reads/drains.d.ts +1 -0
  47. package/dist/utils/cancellation.d.ts +4 -1
  48. package/dist/utils/cancellation.js +4 -2
  49. package/dist/utils/cancellation.js.map +1 -1
  50. package/dist/utils/env/node/exec.d.ts +5 -1
  51. package/dist/utils/env/node/exec.js +8 -5
  52. package/dist/utils/env/node/exec.js.map +1 -1
  53. package/package.json +1 -1
@@ -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\tPullRequestShape,\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, mapSettledBounded } 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, providerFanOutConcurrency } 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 {\n\tAccountWideIssuesResult,\n\tIssueEtagFields,\n\tIssueEtagInclude,\n\tPullRequestEtagFields,\n\tPullRequestEtagInclude,\n\tSearchMyIssuesOptions,\n} from '../models/integration.js';\nimport type { GitLabIntegrationIds } from './gitlab/gitlab.utils.js';\nimport { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from './gitlab/gitlab.utils.js';\nimport {\n\tfromGitLabMergeRequestProvidersApi,\n\tgitLabEtagFieldsMaxIids,\n\tgitLabEtagFieldsWithChecksMaxIids,\n\ttoGitLabIssueEtagFields,\n\ttoGitLabPullRequestEtagFields,\n} from './gitlab/models.js';\nimport type {\n\tProviderApiPagedResult,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tfromProviderPullRequest,\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 {\n\tcollectProviderPagedResult,\n\tmergeCollectionMetadata,\n\treadEtagFieldsByRepository,\n\tresolveBranchPullRequests,\n} 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, { projection: 'point' }) : 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\t/**\n\t * One request per target, settled independently so one target's failure rejects only its own slot; through the\n\t * SDK's issue read and the conversion the repo-scoped list rows take. GitLens' own GitLab client can't alias\n\t * the read instead: it fails a whole document on any GraphQL error, where a batch needs per-target errors.\n\t */\n\tprotected override async getProviderIssuesBatch(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst baseUrl = this.enterpriseBaseUrlFor(session);\n\t\t// The confirming read must ask the same host, over the same protocol, as the read it confirms.\n\t\tconst confirmBaseUrl = this.apiBaseUrlFor(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst issue = await api.getIssueForRepo(tokenWithInfo, { namespace: c.owner, name: c.repo }, c.number, {\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: baseUrl,\n\t\t\t});\n\t\t\tif (issue != null) {\n\t\t\t\tconst shape = toIssueShape(issue, this, { projection: 'batch' });\n\t\t\t\tif (shape == null) throw new Error(`GitLab returned issue ${c.number} without a URL or update time`);\n\n\t\t\t\treturn shape;\n\t\t\t}\n\n\t\t\t// provider-apis' \"not found\" can come from a reply carrying only GraphQL errors (see `getIssueForRepo`),\n\t\t\t// so only our own strict read can prove the miss.\n\t\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\t\tif (gitlab == null) {\n\t\t\t\tthrow new IntegrationReadUnavailableError(this.name, 'cannot confirm a missing issue');\n\t\t\t}\n\n\t\t\tconst exists = await gitlab.hasIssue(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tc.owner,\n\t\t\t\tc.repo,\n\t\t\t\tc.number,\n\t\t\t\t{ baseUrl: confirmBaseUrl, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\t// Our own query can't produce the list rows' shape, so a disagreement fails rather than answering thinner.\n\t\t\tif (exists) throw new Error(`GitLab reported issue ${c.number} missing, then found it`);\n\n\t\t\treturn undefined;\n\t\t});\n\t}\n\n\t/**\n\t * One request per target, settled independently so one target's failure rejects only its own slot; through\n\t * the same SDK read and conversion the manager's list rows take.\n\t */\n\tprotected override async getProviderPullRequestsBatch(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { currentAccount?: { id: string; username?: string } } | undefined,\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst baseUrl = this.enterpriseBaseUrlFor(session);\n\t\t// The confirming read must ask the same host, over the same protocol, as the read it confirms.\n\t\tconst confirmBaseUrl = this.apiBaseUrlFor(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst pr = await api.getPullRequestForRepo(tokenWithInfo, { namespace: c.owner, name: c.repo }, c.number, {\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: baseUrl,\n\t\t\t});\n\t\t\tif (pr != null) {\n\t\t\t\treturn fromProviderPullRequest(pr, this, {\n\t\t\t\t\tcurrentAccount: options?.currentAccount,\n\t\t\t\t\tprojection: 'batch',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// provider-apis' GitLab GraphQL helper ignores the response's `errors`, so a reply carrying only errors\n\t\t\t// (e.g. a server-side timeout) comes back as `null`, the same as not-found. Our own client throws on\n\t\t\t// `errors`, and `strict` makes it answer `undefined` only for a real miss.\n\t\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\t\tif (gitlab == null) {\n\t\t\t\tthrow new IntegrationReadUnavailableError(this.name, 'cannot confirm a missing merge request');\n\t\t\t}\n\n\t\t\tconst confirmed = await gitlab.getPullRequest(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tc.owner,\n\t\t\t\tc.repo,\n\t\t\t\tc.number,\n\t\t\t\t{ baseUrl: confirmBaseUrl, strict: true, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\t// Our own client's row can't produce the list rows' shape (`id` is the iid, not the global id; no\n\t\t\t// `authoredByMe`), so a disagreement fails rather than answering with a different identity.\n\t\t\tif (confirmed != null) throw new Error(`GitLab reported pull request ${c.number} missing, then found it`);\n\n\t\t\treturn undefined;\n\t\t});\n\t}\n\n\t/**\n\t * The cheap check behind the batch issue read's etags: GitLens' own GitLab client reads each project's issues by\n\t * iid, up to {@link gitLabEtagFieldsMaxIids} in ONE request, where {@link getProviderIssuesBatch} sends one or\n\t * two per target. Each row is converted as provider-apis and `toIssueShape` convert the full one, so both reads\n\t * compute the same etag, and `'reactions'` adds the upvote count the full row's `thumbsUpCount` comes from. A\n\t * request that throws rejects only its own targets' slots.\n\t */\n\tprotected override async getProviderIssuesEtagFields(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { etagIncludes?: readonly IssueEtagInclude[] },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The host and protocol the full read's confirming read asks.\n\t\tconst baseUrl = this.apiBaseUrlFor(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn readEtagFieldsByRepository(\n\t\t\tcoordinates,\n\t\t\tgitLabEtagFieldsMaxIids,\n\t\t\t(owner, repo, iids) =>\n\t\t\t\tgitlab.getIssuesEtagFields(\n\t\t\t\t\tthis,\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t`${owner}/${repo}`,\n\t\t\t\t\tiids,\n\t\t\t\t\t{ baseUrl: baseUrl, etagIncludes: etagIncludes, deferFailure: true },\n\t\t\t\t\tcancellation,\n\t\t\t\t),\n\t\t\tnode => toGitLabIssueEtagFields(node, etagIncludes),\n\t\t);\n\t}\n\n\t/**\n\t * The cheap check behind the batch pull request read's etags: {@link getProviderIssuesEtagFields}'s requests and\n\t * failure isolation over merge requests, selecting a merge request's change state plus the fields of each of\n\t * `options.etagIncludes`. Every include is meaningful here: a full row carries a mergeability, a review decision\n\t * and a check rollup, each of which can change without moving `updatedAt`.\n\t */\n\tprotected override async getProviderPullRequestsEtagFields(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { etagIncludes?: readonly PullRequestEtagInclude[] },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The host and protocol the full read's confirming read asks.\n\t\tconst baseUrl = this.apiBaseUrlFor(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn readEtagFieldsByRepository(\n\t\t\tcoordinates,\n\t\t\tetagIncludes.includes('checks') ? gitLabEtagFieldsWithChecksMaxIids : gitLabEtagFieldsMaxIids,\n\t\t\t(owner, repo, iids) =>\n\t\t\t\tgitlab.getMergeRequestsEtagFields(\n\t\t\t\t\tthis,\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t`${owner}/${repo}`,\n\t\t\t\t\tiids,\n\t\t\t\t\t{ baseUrl: baseUrl, etagIncludes: etagIncludes, deferFailure: true },\n\t\t\t\t\tcancellation,\n\t\t\t\t),\n\t\t\tnode => toGitLabPullRequestEtagFields(node, etagIncludes),\n\t\t);\n\t}\n\n\t/**\n\t * Two steps, because provider-apis has no source-branch filter: GitLens' own GitLab client finds each branch's\n\t * matching iids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is\n\t * the one `getPullRequestsBatch` returns for that merge request, `url` and `authoredByMe` included.\n\t */\n\tprotected override async getProviderPullRequestsForBranches(\n\t\tsession: ProviderAuthenticationSession,\n\t\ttargets: readonly { owner: string; repo: string; project?: string; branch: string; headOwner?: string }[],\n\t\toptions: { currentAccount?: { id: string; username?: string }; limit: number },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<{ pullRequests: PullRequestShape[]; truncated: boolean }>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The session's own host and protocol, as the batch read's confirming read uses.\n\t\tconst apiBaseUrl = this.apiBaseUrlFor(session);\n\n\t\tconst found = await mapSettledBounded(targets, providerFanOutConcurrency, t =>\n\t\t\tgitlab.getPullRequestNumbersForBranch(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tt.owner,\n\t\t\t\tt.repo,\n\t\t\t\tt.branch,\n\t\t\t\t{ baseUrl: apiBaseUrl, headOwner: t.headOwner, limit: options.limit, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t),\n\t\t);\n\t\treturn resolveBranchPullRequests(targets, found, coordinates =>\n\t\t\tthis.getProviderPullRequestsBatch(\n\t\t\t\tsession,\n\t\t\t\tcoordinates,\n\t\t\t\t{ currentAccount: options.currentAccount },\n\t\t\t\tcancellation,\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, 'search')),\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, { projection: 'account' }))\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, { projection: 'account' });\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
+ {"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\tPullRequestShape,\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, mapSettledBounded } 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, providerFanOutConcurrency } 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 {\n\tAccountWideIssuesResult,\n\tIssueEtagFields,\n\tIssueEtagInclude,\n\tPullRequestEtagFields,\n\tPullRequestEtagInclude,\n\tSearchMyIssuesOptions,\n} from '../models/integration.js';\nimport type { GitLabIntegrationIds } from './gitlab/gitlab.utils.js';\nimport { getGitLabPullRequestIdentityFromMaybeUrl, matchesGitLabOrgNamespace } from './gitlab/gitlab.utils.js';\nimport {\n\tfromGitLabMergeRequestProvidersApi,\n\tgitLabEtagFieldsMaxIids,\n\tgitLabEtagFieldsWithChecksMaxIids,\n\ttoGitLabIssueEtagFields,\n\ttoGitLabPullRequestEtagFields,\n} from './gitlab/models.js';\nimport type {\n\tProviderApiPagedResult,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tfromProviderPullRequest,\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 {\n\tcollectProviderPagedResult,\n\tmergeCollectionMetadata,\n\treadEtagFieldsByRepository,\n\tresolveBranchPullRequests,\n} 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, { projection: 'point' }) : 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\t/**\n\t * One request per target, settled independently so one target's failure rejects only its own slot; through the\n\t * SDK's issue read and the conversion the repo-scoped list rows take. GitLens' own GitLab client can't alias\n\t * the read instead: it fails a whole document on any GraphQL error, where a batch needs per-target errors.\n\t */\n\tprotected override async getProviderIssuesBatch(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst baseUrl = this.enterpriseBaseUrlFor(session);\n\t\t// The confirming read must ask the same host, over the same protocol, as the read it confirms.\n\t\tconst confirmBaseUrl = this.apiBaseUrlFor(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst issue = await api.getIssueForRepo(tokenWithInfo, { namespace: c.owner, name: c.repo }, c.number, {\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: baseUrl,\n\t\t\t});\n\t\t\tif (issue != null) {\n\t\t\t\tconst shape = toIssueShape(issue, this, { projection: 'batch' });\n\t\t\t\tif (shape == null) throw new Error(`GitLab returned issue ${c.number} without a URL or update time`);\n\n\t\t\t\treturn shape;\n\t\t\t}\n\n\t\t\t// provider-apis' \"not found\" can come from a reply carrying only GraphQL errors (see `getIssueForRepo`),\n\t\t\t// so only our own strict read can prove the miss.\n\t\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\t\tif (gitlab == null) {\n\t\t\t\tthrow new IntegrationReadUnavailableError(this.name, 'cannot confirm a missing issue');\n\t\t\t}\n\n\t\t\tconst exists = await gitlab.hasIssue(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tc.owner,\n\t\t\t\tc.repo,\n\t\t\t\tc.number,\n\t\t\t\t{ baseUrl: confirmBaseUrl, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\t// Our own query can't produce the list rows' shape, so a disagreement fails rather than answering thinner.\n\t\t\tif (exists) throw new Error(`GitLab reported issue ${c.number} missing, then found it`);\n\n\t\t\treturn undefined;\n\t\t});\n\t}\n\n\t/**\n\t * One request per target, settled independently so one target's failure rejects only its own slot; through\n\t * the same SDK read and conversion the manager's list rows take.\n\t */\n\tprotected override async getProviderPullRequestsBatch(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { currentAccount?: { id: string; username?: string } } | undefined,\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\tconst baseUrl = this.enterpriseBaseUrlFor(session);\n\t\t// The confirming read must ask the same host, over the same protocol, as the read it confirms.\n\t\tconst confirmBaseUrl = this.apiBaseUrlFor(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst pr = await api.getPullRequestForRepo(tokenWithInfo, { namespace: c.owner, name: c.repo }, c.number, {\n\t\t\t\tisPAT: this.isEnterprise,\n\t\t\t\tbaseUrl: baseUrl,\n\t\t\t});\n\t\t\tif (pr != null) {\n\t\t\t\treturn fromProviderPullRequest(pr, this, {\n\t\t\t\t\tcurrentAccount: options?.currentAccount,\n\t\t\t\t\tprojection: 'batch',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// provider-apis' GitLab GraphQL helper ignores the response's `errors`, so a reply carrying only errors\n\t\t\t// (e.g. a server-side timeout) comes back as `null`, the same as not-found. Our own client throws on\n\t\t\t// `errors`, and `strict` makes it answer `undefined` only for a real miss.\n\t\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\t\tif (gitlab == null) {\n\t\t\t\tthrow new IntegrationReadUnavailableError(this.name, 'cannot confirm a missing merge request');\n\t\t\t}\n\n\t\t\tconst confirmed = await gitlab.getPullRequest(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tc.owner,\n\t\t\t\tc.repo,\n\t\t\t\tc.number,\n\t\t\t\t{ baseUrl: confirmBaseUrl, strict: true, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\t// Our own client's row can't produce the list rows' shape (`id` is the iid, not the global id; no\n\t\t\t// `authoredByMe`), so a disagreement fails rather than answering with a different identity.\n\t\t\tif (confirmed != null) throw new Error(`GitLab reported pull request ${c.number} missing, then found it`);\n\n\t\t\treturn undefined;\n\t\t});\n\t}\n\n\t/**\n\t * The cheap check behind the batch issue read's etags: GitLens' own GitLab client reads each project's issues by\n\t * iid, up to {@link gitLabEtagFieldsMaxIids} in ONE request, where {@link getProviderIssuesBatch} sends one or\n\t * two per target. Each row is converted as provider-apis and `toIssueShape` convert the full one, so both reads\n\t * compute the same etag, and `'reactions'` adds the upvote count the full row's `thumbsUpCount` comes from. A\n\t * request that throws rejects only its own targets' slots.\n\t */\n\tprotected override async getProviderIssuesEtagFields(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { etagIncludes?: readonly IssueEtagInclude[] },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The host and protocol the full read's confirming read asks.\n\t\tconst baseUrl = this.apiBaseUrlFor(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn readEtagFieldsByRepository(\n\t\t\tcoordinates,\n\t\t\tgitLabEtagFieldsMaxIids,\n\t\t\t(owner, repo, iids) =>\n\t\t\t\tgitlab.getIssuesEtagFields(\n\t\t\t\t\tthis,\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t`${owner}/${repo}`,\n\t\t\t\t\tiids,\n\t\t\t\t\t{ baseUrl: baseUrl, etagIncludes: etagIncludes, deferFailure: true },\n\t\t\t\t\tcancellation,\n\t\t\t\t),\n\t\t\tnode => toGitLabIssueEtagFields(node, etagIncludes),\n\t\t);\n\t}\n\n\t/**\n\t * The cheap check behind the batch pull request read's etags: {@link getProviderIssuesEtagFields}'s requests and\n\t * failure isolation over merge requests, selecting a merge request's change state plus the fields of each of\n\t * `options.etagIncludes`. Every include is meaningful here: a full row carries a mergeability, a review decision\n\t * and a check rollup, each of which can change without moving `updatedAt`.\n\t */\n\tprotected override async getProviderPullRequestsEtagFields(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcoordinates: readonly { owner: string; repo: string; number: number; project?: string }[],\n\t\toptions: { etagIncludes?: readonly PullRequestEtagInclude[] },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The host and protocol the full read's confirming read asks.\n\t\tconst baseUrl = this.apiBaseUrlFor(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn readEtagFieldsByRepository(\n\t\t\tcoordinates,\n\t\t\tetagIncludes.includes('checks') ? gitLabEtagFieldsWithChecksMaxIids : gitLabEtagFieldsMaxIids,\n\t\t\t(owner, repo, iids) =>\n\t\t\t\tgitlab.getMergeRequestsEtagFields(\n\t\t\t\t\tthis,\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t`${owner}/${repo}`,\n\t\t\t\t\tiids,\n\t\t\t\t\t{ baseUrl: baseUrl, etagIncludes: etagIncludes, deferFailure: true },\n\t\t\t\t\tcancellation,\n\t\t\t\t),\n\t\t\tnode => toGitLabPullRequestEtagFields(node, etagIncludes),\n\t\t);\n\t}\n\n\t/**\n\t * Two steps, because provider-apis has no source-branch filter: GitLens' own GitLab client finds each branch's\n\t * matching iids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is\n\t * the one `getPullRequestsBatch` returns for that merge request, `url` and `authoredByMe` included.\n\t */\n\tprotected override async getProviderPullRequestsForBranches(\n\t\tsession: ProviderAuthenticationSession,\n\t\ttargets: readonly { owner: string; repo: string; project?: string; branch: string; headOwner?: string }[],\n\t\toptions: { currentAccount?: { id: string; username?: string }; limit: number },\n\t\tcancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<{ pullRequests: PullRequestShape[]; truncated: boolean }>[] | undefined> {\n\t\tconst gitlab = await this.authenticationService.apis.gitlab;\n\t\tif (gitlab == null) return undefined;\n\n\t\tconst tokenWithInfo = toTokenWithInfo(this.id, session);\n\t\t// The session's own host and protocol, as the batch read's confirming read uses.\n\t\tconst apiBaseUrl = this.apiBaseUrlFor(session);\n\n\t\tconst found = await mapSettledBounded(targets, providerFanOutConcurrency, t =>\n\t\t\tgitlab.getPullRequestNumbersForBranch(\n\t\t\t\tthis,\n\t\t\t\ttokenWithInfo,\n\t\t\t\tt.owner,\n\t\t\t\tt.repo,\n\t\t\t\tt.branch,\n\t\t\t\t{ baseUrl: apiBaseUrl, headOwner: t.headOwner, limit: options.limit, deferFailure: true },\n\t\t\t\tcancellation,\n\t\t\t),\n\t\t);\n\t\treturn resolveBranchPullRequests(targets, found, coordinates =>\n\t\t\tthis.getProviderPullRequestsBatch(\n\t\t\t\tsession,\n\t\t\t\tcoordinates,\n\t\t\t\t{ currentAccount: options.currentAccount },\n\t\t\t\tcancellation,\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.resolveReadSessionOrThrow(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, 'search')),\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, { projection: 'account' }))\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, { projection: 'account' });\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[];
@@ -1,6 +1,7 @@
1
1
  import { PullRequest, PullRequestFilter, PullRequestStateFilter } from "../../../git/models/pullRequest.js";
2
2
  import { IntegrationIds } from "../constants.js";
3
3
  import { ProviderWarning } from "../results.js";
4
+ import "../providerFilters.js";
4
5
  import { ProviderPullRequest, ProviderReposInput, ProviderRepository } from "../providers/models.js";
5
6
  import { GitHostIntegration } from "../models/gitHostIntegration.js";
6
7
  import { IntegrationResult } from "../models/integration.js";
@@ -1,4 +1,6 @@
1
1
  //#region ../utils/src/cancellation.d.ts
2
+ /** Why an operation was cancelled: a caller abort, a timeout, or a termination whose cause is unknown. */
3
+ export type CancellationReason = 'aborted' | 'timeout' | 'unknown';
2
4
  /**
3
5
  * A standalone CancellationError for use in the library.
4
6
  * Uses a symbol brand so that both this class and the extension's
@@ -7,8 +9,9 @@
7
9
  */
8
10
  export declare class CancellationError extends Error {
9
11
  readonly original?: Error | undefined;
12
+ readonly reason?: CancellationReason | undefined;
10
13
  private readonly _cancellationErrorBrand;
11
- constructor(original?: Error | undefined);
14
+ constructor(original?: Error | undefined, reason?: CancellationReason | undefined);
12
15
  }
13
16
  export declare function isCancellationError(ex: unknown): ex is CancellationError;
14
17
  /**
@@ -9,10 +9,12 @@ const cancellationErrorBrand = Symbol.for("CancellationError");
9
9
  */
10
10
  var CancellationError = class extends Error {
11
11
  original;
12
+ reason;
12
13
  _cancellationErrorBrand = true;
13
- constructor(original) {
14
+ constructor(original, reason) {
14
15
  super();
15
16
  this.original = original;
17
+ this.reason = reason;
16
18
  Object.defineProperty(this, cancellationErrorBrand, {
17
19
  value: true,
18
20
  writable: true,
@@ -61,7 +63,7 @@ function raceWithSignal(promise, signal) {
61
63
  function raceWithTimeout(promise, ms, abortOnTimeout) {
62
64
  return new Promise((resolve, reject) => {
63
65
  const timer = setTimeout(() => {
64
- const error = new CancellationError(/* @__PURE__ */ new Error(`Timed out after ${ms}ms`));
66
+ const error = new CancellationError(/* @__PURE__ */ new Error(`Timed out after ${ms}ms`), "timeout");
65
67
  abortOnTimeout?.abort(error);
66
68
  reject(error);
67
69
  }, ms);
@@ -1 +1 @@
1
- {"version":3,"file":"cancellation.js","names":[],"sources":["../../../utils/src/cancellation.ts"],"sourcesContent":["import { getScopedCounter } from './counter.js';\n\nconst cancellationErrorBrand = Symbol.for('CancellationError');\n\n/**\n * A standalone CancellationError for use in the library.\n * Uses a symbol brand so that both this class and the extension's\n * CancellationError (which extends vscode.CancellationError) are\n * recognized by `isCancellationError`.\n */\nexport class CancellationError extends Error {\n\t// TS-only nominal brand (not read anywhere) — without it, `CancellationError` has the same\n\t// structural shape as any other `Error` subtype, so `isCancellationError`'s negative narrowing\n\t// (`if (isCancellationError(ex)) throw ex;`) collapses an unrelated error union to `never` instead\n\t// of leaving it narrowed. The runtime brand stays a symbol (below) for the cross-realm check.\n\tprivate readonly _cancellationErrorBrand: true = true;\n\n\tconstructor(public readonly original?: Error) {\n\t\tsuper();\n\t\t// A symbol-keyed computed class field can't be typed for `isolatedDeclarations` (only well-known\n\t\t// symbols like `Symbol.iterator` qualify), so the brand is set here with the same runtime shape\n\t\t// (writable/enumerable/configurable) a plain field assignment would produce.\n\t\tObject.defineProperty(this, cancellationErrorBrand, {\n\t\t\tvalue: true,\n\t\t\twritable: true,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t});\n\t\tthis.name = 'CancellationError';\n\n\t\tif (this.original) {\n\t\t\tif (this.original.message.startsWith('Operation cancelled')) {\n\t\t\t\tthis.message = this.original.message;\n\t\t\t} else {\n\t\t\t\tthis.message = `Operation cancelled; ${this.original.message}`;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.message = 'Operation cancelled';\n\t\t}\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport function isCancellationError(ex: unknown): ex is CancellationError {\n\treturn (\n\t\t(ex instanceof Error && (cancellationErrorBrand in ex || ex.name === 'CancellationError')) ||\n\t\t(ex instanceof DOMException && ex.name === 'AbortError')\n\t);\n}\n\n/**\n * Races a promise against an `AbortSignal`. If the signal fires before\n * the promise settles, the returned promise rejects with `CancellationError`.\n * If the promise settles first, the signal listener is cleaned up.\n */\nexport function raceWithSignal<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n\tif (signal.aborted) return Promise.reject(new CancellationError());\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst onAbort = () => reject(new CancellationError());\n\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t\tpromise.then(\n\t\t\tv => {\n\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\tresolve(v);\n\t\t\t},\n\t\t\t(e: unknown) => {\n\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\treject(e instanceof Error ? e : new Error(String(e)));\n\t\t\t},\n\t\t);\n\t});\n}\n\n/**\n * Races a promise against a timeout. If `ms` elapses before the promise settles, the returned promise\n * rejects with `CancellationError`. If the promise settles first, the timer is cleared. Parallels\n * `raceWithSignal`, with a timer standing in for the signal.\n *\n * When `abortOnTimeout` is provided, it is aborted on timeout — so a caller can link the underlying operation to\n * it (e.g. via `AbortSignal.any`) and have it torn down instead of orphaned. Abort is best-effort (a truly-stuck\n * op may ignore it); the returned promise rejects on timeout regardless of whether the underlying op settles.\n */\nexport function raceWithTimeout<T>(promise: Promise<T>, ms: number, abortOnTimeout?: AbortController): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tconst error = new CancellationError(new Error(`Timed out after ${ms}ms`));\n\t\t\tabortOnTimeout?.abort(error);\n\t\t\treject(error);\n\t\t}, ms);\n\t\t// Don't let the timeout timer keep a (Node) process alive on its own — a still-pending promise shouldn't\n\t\t// hold the event loop open just for its backstop (no-op in the browser, where setTimeout returns a number).\n\t\tif (typeof timer !== 'number') {\n\t\t\ttimer.unref();\n\t\t}\n\t\tpromise.then(\n\t\t\tv => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve(v);\n\t\t\t},\n\t\t\t(e: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(e instanceof Error ? e : new Error(String(e)));\n\t\t\t},\n\t\t);\n\t});\n}\n\n/**\n * Aggregates multiple caller `AbortSignal`s into a single signal that\n * only fires when **all** callers have cancelled (the inverse of `AbortSignal.any()`).\n *\n * Designed for shared-promise caching: each caller registers their signal,\n * and the underlying operation receives the aggregate signal. Individual callers\n * can cancel early (via `raceWithSignal`), but the operation continues as long\n * as at least one caller is still active.\n */\nexport class AbortAggregate {\n\tprivate readonly controller = new AbortController();\n\tprivate activeCount = 0;\n\t/** One listener-remover per registration (NOT keyed by signal), so adding the same signal twice is safe. */\n\tprivate readonly cleanups = new Set<() => void>();\n\n\t/** The aggregate signal — only fires when all callers have cancelled. */\n\tget signal(): AbortSignal {\n\t\treturn this.controller.signal;\n\t}\n\n\t/**\n\t * Register a caller.\n\t * - If `cancellation` is provided, the caller is auto-removed when it fires.\n\t * - If `cancellation` is `undefined`, the caller is \"permanent\" — the aggregate\n\t * can never fire while it's active. Call the returned cleanup on promise settle.\n\t * - The same signal instance may safely be added more than once — each registration is tracked and cleaned up\n\t * independently, so no listener leaks.\n\t * @returns A cleanup function to unregister the caller.\n\t */\n\tadd(cancellation?: AbortSignal): () => void {\n\t\tthis.activeCount++;\n\n\t\tif (cancellation == null) {\n\t\t\treturn () => {\n\t\t\t\tthis.activeCount--;\n\t\t\t\tthis.checkAbort();\n\t\t\t};\n\t\t}\n\n\t\tif (cancellation.aborted) {\n\t\t\tthis.activeCount--;\n\t\t\tthis.checkAbort();\n\t\t\treturn () => {};\n\t\t}\n\n\t\t// Track this registration's listener removal individually (a Set of removers, NOT keyed by the signal) so\n\t\t// adding the same signal twice can't overwrite the other's cleanup. `settled` keeps both exit paths (abort\n\t\t// vs. manual cleanup) idempotent and preserves the accounting: only `onAbort` decrements `activeCount`.\n\t\tlet settled = false;\n\t\tlet remove: () => void;\n\t\tconst onAbort = () => {\n\t\t\tif (settled) return;\n\n\t\t\tsettled = true;\n\t\t\tthis.cleanups.delete(remove);\n\t\t\tthis.activeCount--;\n\t\t\tthis.checkAbort();\n\t\t};\n\t\tremove = () => cancellation.removeEventListener('abort', onAbort);\n\t\tcancellation.addEventListener('abort', onAbort, { once: true });\n\t\tthis.cleanups.add(remove);\n\n\t\treturn () => {\n\t\t\tif (settled) return;\n\n\t\t\tsettled = true;\n\t\t\tthis.cleanups.delete(remove);\n\t\t\tremove();\n\t\t};\n\t}\n\n\tprivate checkAbort(): void {\n\t\tif (this.activeCount <= 0 && !this.controller.signal.aborted) {\n\t\t\tthis.controller.abort();\n\t\t}\n\t}\n\n\t/** Remove all abort listeners. Call when the cached promise settles. */\n\tdispose(): void {\n\t\tfor (const remove of this.cleanups) {\n\t\t\tremove();\n\t\t}\n\t\tthis.cleanups.clear();\n\t}\n}\n\nconst signalIds = new WeakMap<AbortSignal, number>();\nconst signalIdCounter = getScopedCounter();\n\n/**\n * Returns a stable, unique numeric ID for the given AbortSignal.\n * Used to differentiate concurrent git commands that have different\n * cancellation signals, so one caller aborting doesn't cancel another.\n */\nexport function getAbortSignalId(signal: AbortSignal | undefined): string {\n\tif (signal == null) return '';\n\n\tlet id = signalIds.get(signal);\n\tif (id == null) {\n\t\tid = signalIdCounter.next();\n\t\tsignalIds.set(signal, id);\n\t}\n\treturn String(id);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cancellation.js","names":[],"sources":["../../../utils/src/cancellation.ts"],"sourcesContent":["import { getScopedCounter } from './counter.js';\n\nconst cancellationErrorBrand = Symbol.for('CancellationError');\n\n/** Why an operation was cancelled: a caller abort, a timeout, or a termination whose cause is unknown. */\nexport type CancellationReason = 'aborted' | 'timeout' | 'unknown';\n\n/**\n * A standalone CancellationError for use in the library.\n * Uses a symbol brand so that both this class and the extension's\n * CancellationError (which extends vscode.CancellationError) are\n * recognized by `isCancellationError`.\n */\nexport class CancellationError extends Error {\n\t// TS-only nominal brand (not read anywhere) — without it, `CancellationError` has the same\n\t// structural shape as any other `Error` subtype, so `isCancellationError`'s negative narrowing\n\t// (`if (isCancellationError(ex)) throw ex;`) collapses an unrelated error union to `never` instead\n\t// of leaving it narrowed. The runtime brand stays a symbol (below) for the cross-realm check.\n\tprivate readonly _cancellationErrorBrand: true = true;\n\n\tconstructor(\n\t\tpublic readonly original?: Error,\n\t\tpublic readonly reason?: CancellationReason,\n\t) {\n\t\tsuper();\n\t\t// A symbol-keyed computed class field can't be typed for `isolatedDeclarations` (only well-known\n\t\t// symbols like `Symbol.iterator` qualify), so the brand is set here with the same runtime shape\n\t\t// (writable/enumerable/configurable) a plain field assignment would produce.\n\t\tObject.defineProperty(this, cancellationErrorBrand, {\n\t\t\tvalue: true,\n\t\t\twritable: true,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t});\n\t\tthis.name = 'CancellationError';\n\n\t\tif (this.original) {\n\t\t\tif (this.original.message.startsWith('Operation cancelled')) {\n\t\t\t\tthis.message = this.original.message;\n\t\t\t} else {\n\t\t\t\tthis.message = `Operation cancelled; ${this.original.message}`;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.message = 'Operation cancelled';\n\t\t}\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport function isCancellationError(ex: unknown): ex is CancellationError {\n\treturn (\n\t\t(ex instanceof Error && (cancellationErrorBrand in ex || ex.name === 'CancellationError')) ||\n\t\t(ex instanceof DOMException && ex.name === 'AbortError')\n\t);\n}\n\n/**\n * Races a promise against an `AbortSignal`. If the signal fires before\n * the promise settles, the returned promise rejects with `CancellationError`.\n * If the promise settles first, the signal listener is cleaned up.\n */\nexport function raceWithSignal<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n\tif (signal.aborted) return Promise.reject(new CancellationError());\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst onAbort = () => reject(new CancellationError());\n\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t\tpromise.then(\n\t\t\tv => {\n\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\tresolve(v);\n\t\t\t},\n\t\t\t(e: unknown) => {\n\t\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\t\treject(e instanceof Error ? e : new Error(String(e)));\n\t\t\t},\n\t\t);\n\t});\n}\n\n/**\n * Races a promise against a timeout. If `ms` elapses before the promise settles, the returned promise\n * rejects with `CancellationError`. If the promise settles first, the timer is cleared. Parallels\n * `raceWithSignal`, with a timer standing in for the signal.\n *\n * When `abortOnTimeout` is provided, it is aborted on timeout — so a caller can link the underlying operation to\n * it (e.g. via `AbortSignal.any`) and have it torn down instead of orphaned. Abort is best-effort (a truly-stuck\n * op may ignore it); the returned promise rejects on timeout regardless of whether the underlying op settles.\n */\nexport function raceWithTimeout<T>(promise: Promise<T>, ms: number, abortOnTimeout?: AbortController): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tconst error = new CancellationError(new Error(`Timed out after ${ms}ms`), 'timeout');\n\t\t\tabortOnTimeout?.abort(error);\n\t\t\treject(error);\n\t\t}, ms);\n\t\t// Don't let the timeout timer keep a (Node) process alive on its own — a still-pending promise shouldn't\n\t\t// hold the event loop open just for its backstop (no-op in the browser, where setTimeout returns a number).\n\t\tif (typeof timer !== 'number') {\n\t\t\ttimer.unref();\n\t\t}\n\t\tpromise.then(\n\t\t\tv => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve(v);\n\t\t\t},\n\t\t\t(e: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(e instanceof Error ? e : new Error(String(e)));\n\t\t\t},\n\t\t);\n\t});\n}\n\n/**\n * Aggregates multiple caller `AbortSignal`s into a single signal that\n * only fires when **all** callers have cancelled (the inverse of `AbortSignal.any()`).\n *\n * Designed for shared-promise caching: each caller registers their signal,\n * and the underlying operation receives the aggregate signal. Individual callers\n * can cancel early (via `raceWithSignal`), but the operation continues as long\n * as at least one caller is still active.\n */\nexport class AbortAggregate {\n\tprivate readonly controller = new AbortController();\n\tprivate activeCount = 0;\n\t/** One listener-remover per registration (NOT keyed by signal), so adding the same signal twice is safe. */\n\tprivate readonly cleanups = new Set<() => void>();\n\n\t/** The aggregate signal — only fires when all callers have cancelled. */\n\tget signal(): AbortSignal {\n\t\treturn this.controller.signal;\n\t}\n\n\t/**\n\t * Register a caller.\n\t * - If `cancellation` is provided, the caller is auto-removed when it fires.\n\t * - If `cancellation` is `undefined`, the caller is \"permanent\" — the aggregate\n\t * can never fire while it's active. Call the returned cleanup on promise settle.\n\t * - The same signal instance may safely be added more than once — each registration is tracked and cleaned up\n\t * independently, so no listener leaks.\n\t * @returns A cleanup function to unregister the caller.\n\t */\n\tadd(cancellation?: AbortSignal): () => void {\n\t\tthis.activeCount++;\n\n\t\tif (cancellation == null) {\n\t\t\treturn () => {\n\t\t\t\tthis.activeCount--;\n\t\t\t\tthis.checkAbort();\n\t\t\t};\n\t\t}\n\n\t\tif (cancellation.aborted) {\n\t\t\tthis.activeCount--;\n\t\t\tthis.checkAbort();\n\t\t\treturn () => {};\n\t\t}\n\n\t\t// Track this registration's listener removal individually (a Set of removers, NOT keyed by the signal) so\n\t\t// adding the same signal twice can't overwrite the other's cleanup. `settled` keeps both exit paths (abort\n\t\t// vs. manual cleanup) idempotent and preserves the accounting: only `onAbort` decrements `activeCount`.\n\t\tlet settled = false;\n\t\tlet remove: () => void;\n\t\tconst onAbort = () => {\n\t\t\tif (settled) return;\n\n\t\t\tsettled = true;\n\t\t\tthis.cleanups.delete(remove);\n\t\t\tthis.activeCount--;\n\t\t\tthis.checkAbort();\n\t\t};\n\t\tremove = () => cancellation.removeEventListener('abort', onAbort);\n\t\tcancellation.addEventListener('abort', onAbort, { once: true });\n\t\tthis.cleanups.add(remove);\n\n\t\treturn () => {\n\t\t\tif (settled) return;\n\n\t\t\tsettled = true;\n\t\t\tthis.cleanups.delete(remove);\n\t\t\tremove();\n\t\t};\n\t}\n\n\tprivate checkAbort(): void {\n\t\tif (this.activeCount <= 0 && !this.controller.signal.aborted) {\n\t\t\tthis.controller.abort();\n\t\t}\n\t}\n\n\t/** Remove all abort listeners. Call when the cached promise settles. */\n\tdispose(): void {\n\t\tfor (const remove of this.cleanups) {\n\t\t\tremove();\n\t\t}\n\t\tthis.cleanups.clear();\n\t}\n}\n\nconst signalIds = new WeakMap<AbortSignal, number>();\nconst signalIdCounter = getScopedCounter();\n\n/**\n * Returns a stable, unique numeric ID for the given AbortSignal.\n * Used to differentiate concurrent git commands that have different\n * cancellation signals, so one caller aborting doesn't cancel another.\n */\nexport function getAbortSignalId(signal: AbortSignal | undefined): string {\n\tif (signal == null) return '';\n\n\tlet id = signalIds.get(signal);\n\tif (id == null) {\n\t\tid = signalIdCounter.next();\n\t\tsignalIds.set(signal, id);\n\t}\n\treturn String(id);\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { CancellationReason } from "../../cancellation.js";
1
2
  import { Writable } from "stream";
2
3
  //#region ../utils/src/env/node/exec.d.ts
3
4
  interface RunErrorContext {
@@ -17,7 +18,8 @@ export declare class RunError extends Error {
17
18
  constructor(context: RunErrorContext, stdout: string, stderr: string);
18
19
  }
19
20
  export declare class CancelledRunError extends RunError {
20
- constructor(cmd: string, killed: boolean, code?: number | string | undefined, signal?: NodeJS.Signals);
21
+ readonly reason: CancellationReason;
22
+ constructor(cmd: string, killed: boolean, code?: number | string | undefined, signal?: NodeJS.Signals, reason?: CancellationReason);
21
23
  }
22
24
  /**
23
25
  * Finds the executable and parameters to run on Windows. This method
@@ -94,6 +96,8 @@ export interface RunExitResult {
94
96
  readonly exitCode?: number;
95
97
  /** Set when the process was terminated by a signal instead of exiting; {@link exitCode} is then absent. */
96
98
  readonly signal?: NodeJS.Signals;
99
+ /** Whether Node itself killed the process (its spawn `timeout`), as opposed to an external signal. */
100
+ readonly killed?: boolean;
97
101
  }
98
102
  export interface RunResult<T extends string | Buffer> extends RunExitResult {
99
103
  stdout: T;
@@ -27,7 +27,8 @@ var RunError = class extends Error {
27
27
  }
28
28
  };
29
29
  var CancelledRunError = class extends RunError {
30
- constructor(cmd, killed, code, signal = "SIGTERM") {
30
+ reason;
31
+ constructor(cmd, killed, code, signal = "SIGTERM", reason = "unknown") {
31
32
  super({
32
33
  message: `Operation cancelled; command=${cmd}`,
33
34
  cmd,
@@ -35,6 +36,7 @@ var CancelledRunError = class extends RunError {
35
36
  code,
36
37
  signal
37
38
  }, "", "");
39
+ this.reason = reason;
38
40
  this.name = "CancelledRunError";
39
41
  Error.captureStackTrace?.(this, new.target);
40
42
  }
@@ -158,7 +160,7 @@ function run(command, args, encoding, options) {
158
160
  }
159
161
  if (error != null) {
160
162
  if (error.signal === "SIGTERM") {
161
- reject(new CancelledRunError(`${command} ${args.join(" ")}`, true, error.code ?? void 0, error.signal));
163
+ reject(new CancelledRunError(`${command} ${args.join(" ")}`, true, error.code ?? void 0, error.signal, cancellation?.aborted ? "aborted" : error.killed ? "timeout" : "unknown"));
162
164
  return;
163
165
  }
164
166
  if (bufferExceededRegex.test(error.message)) error.message = `Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`;
@@ -229,7 +231,7 @@ function runSpawn(command, args, encoding, options) {
229
231
  }
230
232
  proc.once("error", async (ex) => {
231
233
  if (ex?.name === "AbortError") {
232
- reject(new CancelledRunError(`${command} ${args.join(" ")}`, true));
234
+ reject(new CancelledRunError(`${command} ${args.join(" ")}`, true, void 0, void 0, "aborted"));
233
235
  return;
234
236
  }
235
237
  const stdio = getStdio(errorEncoding);
@@ -240,7 +242,8 @@ function runSpawn(command, args, encoding, options) {
240
242
  if (options?.exitCodeOnly) {
241
243
  resolve({
242
244
  exitCode: code ?? void 0,
243
- signal: signal ?? void 0
245
+ signal: signal ?? void 0,
246
+ killed: proc.killed
244
247
  });
245
248
  return;
246
249
  }
@@ -249,7 +252,7 @@ function runSpawn(command, args, encoding, options) {
249
252
  const { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;
250
253
  if (stderr.length && !options?.quiet && scope?.enabled("debug")) scope?.warn(`[EXEC] '${command} ${args.join(" ")}' \u2022 ${stderr}`);
251
254
  if (signal === "SIGTERM") {
252
- reject(new CancelledRunError(`${command} ${args.join(" ")}`, true, code ?? void 0, signal));
255
+ reject(new CancelledRunError(`${command} ${args.join(" ")}`, true, code ?? void 0, signal, proc.killed ? "timeout" : "unknown"));
253
256
  return;
254
257
  }
255
258
  reject(new RunError({
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","names":["joinPaths"],"sources":["../../../../../utils/src/env/node/exec.ts"],"sourcesContent":["import type { ExecFileException, ExecFileOptions } from 'child_process';\nimport { exec, execFile, spawn } from 'child_process';\nimport type { Stats } from 'fs';\nimport { access, constants } from 'fs';\nimport { stat } from 'fs/promises';\nimport { join as joinPaths } from 'path';\nimport * as process from 'process';\nimport type { Writable } from 'stream';\nimport { getScopedLogger, maybeStartScopedLogger } from '../../logger.scoped.js';\nimport { normalizePath } from '../../path.js';\nimport { isWindows } from './platform.js';\n\n// -- Error types --\n\ninterface RunErrorContext {\n\tmessage: string;\n\tcmd?: string | undefined;\n\tkilled?: boolean | undefined;\n\tcode?: string | number | null | undefined;\n\tsignal?: NodeJS.Signals | undefined;\n}\n\nexport class RunError extends Error {\n\treadonly cmd?: string | undefined;\n\treadonly killed?: boolean | undefined;\n\treadonly code?: string | number | undefined;\n\treadonly signal?: NodeJS.Signals | undefined;\n\treadonly stdout: string;\n\treadonly stderr: string;\n\n\tconstructor(context: RunErrorContext, stdout: string, stderr: string) {\n\t\tsuper(context.message);\n\n\t\tthis.cmd = context.cmd;\n\t\tthis.killed = context.killed;\n\t\tthis.code = context.code ?? undefined;\n\t\tthis.signal = context.signal;\n\t\tthis.stdout = stdout?.trim() ?? '';\n\t\tthis.stderr = stderr?.trim() ?? '';\n\n\t\tthis.name = 'RunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport class CancelledRunError extends RunError {\n\tconstructor(cmd: string, killed: boolean, code?: number | string | undefined, signal: NodeJS.Signals = 'SIGTERM') {\n\t\tsuper(\n\t\t\t{ message: `Operation cancelled; command=${cmd}`, cmd: cmd, killed: killed, code: code, signal: signal },\n\t\t\t'',\n\t\t\t'',\n\t\t);\n\n\t\tthis.name = 'CancelledRunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n// -- Execution utilities --\n\nconst slashesRegex = /[\\\\/]/;\nconst ps1Regex = /\\.ps1$/i;\nconst batOrCmdRegex = /\\.(bat|cmd)$/i;\nconst jsRegex = /\\.(js)$/i;\n\n/**\n * Search PATH to see if a file exists in any of the path folders.\n *\n * @param {string} exe The file to search for\n * @return {string} A fully qualified path, or the original path if nothing\n * is found\n *\n * @private\n */\nasync function runDownPath(exe: string): Promise<string> {\n\t// NB: Windows won't search PATH looking for executables in spawn like\n\t// Posix does\n\n\t// Files with any directory path don't get this applied\n\tif (slashesRegex.test(exe)) return exe;\n\n\tconst target = joinPaths('.', exe);\n\ttry {\n\t\tconst stats = await stat(target);\n\t\tif (stats?.isFile() && isExecutable(stats)) return target;\n\t} catch {}\n\n\tconst path = process.env.PATH;\n\tif (path != null && path.length !== 0) {\n\t\tconst haystack = path.split(isWindows ? ';' : ':');\n\t\tfor (const p of haystack) {\n\t\t\tconst needle = joinPaths(p, exe);\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(needle);\n\t\t\t\tif (stats?.isFile() && isExecutable(stats)) return needle;\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\treturn exe;\n}\n\nfunction isExecutable(stats: Stats) {\n\tif (isWindows) return true;\n\n\tconst isGroup = stats.gid ? stats.gid === process.getgid?.() : true;\n\tconst isUser = stats.uid ? stats.uid === process.getuid?.() : true;\n\n\treturn Boolean(stats.mode & 0o0001 || (stats.mode & 0o0010 && isGroup) || (stats.mode & 0o0100 && isUser));\n}\n\n/**\n * Finds the executable and parameters to run on Windows. This method\n * mimics the POSIX behavior of being able to run scripts as executables by\n * replacing the passed-in executable with the script runner, for PowerShell,\n * CMD, and node scripts.\n *\n * This method also does the work of running down PATH, which spawn on Windows\n * also doesn't do, unlike on POSIX.\n */\nexport async function findExecutable(exe: string, args: string[]): Promise<{ cmd: string; args: string[] }> {\n\t// POSIX can just execute scripts directly, no need for silly goosery\n\tif (!isWindows) return { cmd: await runDownPath(exe), args: args };\n\n\tif (!(await fsExists(exe))) {\n\t\t// NB: When you write something like `surf-client ... -- surf-build` on Windows,\n\t\t// a shell would normally convert that to surf-build.cmd, but since it's passed\n\t\t// in as an argument, it doesn't happen\n\t\tconst possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];\n\t\tfor (const ext of possibleExts) {\n\t\t\tconst possibleFullPath = await runDownPath(`${exe}${ext}`);\n\n\t\t\tif (await fsExists(possibleFullPath)) return findExecutable(possibleFullPath, args);\n\t\t}\n\t}\n\n\tif (ps1Regex.test(exe)) {\n\t\tconst cmd = joinPaths(\n\t\t\tprocess.env.SYSTEMROOT ?? 'C:\\\\WINDOWS',\n\t\t\t'System32',\n\t\t\t'WindowsPowerShell',\n\t\t\t'v1.0',\n\t\t\t'PowerShell.exe',\n\t\t);\n\t\tconst psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];\n\n\t\treturn { cmd: cmd, args: [...psargs, ...args] };\n\t}\n\n\tif (batOrCmdRegex.test(exe)) {\n\t\tconst cmd = joinPaths(process.env.SYSTEMROOT ?? 'C:\\\\WINDOWS', 'System32', 'cmd.exe');\n\t\tconst cmdArgs = ['/C', exe, ...args];\n\n\t\treturn { cmd: cmd, args: cmdArgs };\n\t}\n\n\tif (jsRegex.test(exe)) {\n\t\tconst cmd = process.execPath;\n\t\tconst nodeArgs = [exe];\n\n\t\treturn { cmd: cmd, args: [...nodeArgs, ...args] };\n\t}\n\n\treturn { cmd: exe, args: args };\n}\n\nexport async function getWindowsShortPath(path: string): Promise<string> {\n\treturn new Promise<string>((resolve, reject) => {\n\t\texec(`for %I in (\"${path}\") do @echo %~sI`, (error, stdout, _stderr) => {\n\t\t\tif (error != null) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve(normalizePath(stdout.trim()));\n\t\t});\n\t});\n}\n\nexport interface RunOptions<TEncoding = BufferEncoding | 'buffer'> {\n\tcwd?: string;\n\treadonly env?: Record<string, string | undefined>;\n\treadonly encoding?: TEncoding;\n\t/**\n\t * Decodes non-UTF-8 output. Called when `encoding` is not utf8/binary/buffer.\n\t * Provided by the host via the `GitOptions.decode` option.\n\t * If absent and a non-UTF-8 encoding is requested, throws at runtime.\n\t */\n\treadonly decode?: (data: Uint8Array, options?: { readonly encoding: string }) => string | Promise<string>;\n\t/**\n\t * The size the output buffer to allocate to the spawned process. Set this\n\t * if you are anticipating a large amount of output.\n\t *\n\t * If not specified, this will be 10MB (10485760 bytes) which should be\n\t * enough for most Git operations.\n\t */\n\treadonly maxBuffer?: number;\n\treadonly cancellation?: AbortSignal;\n\t/**\n\t * An optional string or buffer which will be written to\n\t * the child process stdin stream immediately immediately\n\t * after spawning the process.\n\t */\n\treadonly stdin?: string | Buffer;\n\t/**\n\t * The encoding to use when writing to stdin, if the stdin\n\t * parameter is a string.\n\t */\n\treadonly stdinEncoding?: string;\n\treadonly timeout?: number;\n\t/**\n\t * When true, suppresses the `[EXEC]` stderr warning emitted on debug-enabled scopes.\n\t * Use for commands whose failure is expected (e.g. paired with `errors: 'ignore'`).\n\t */\n\treadonly quiet?: boolean;\n}\n\nconst bufferExceededRegex = /stdout maxBuffer( length)? exceeded/;\n\ntype ExitCodeOnlyRunOptions<TEncoding = BufferEncoding | 'buffer'> = RunOptions<TEncoding> & { exitCodeOnly: true };\n\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions: ExitCodeOnlyRunOptions<BufferEncoding>,\n): Promise<number>;\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding>,\n): Promise<string>;\nexport function run<T extends number | string>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding> & { exitCodeOnly?: boolean },\n): Promise<T> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.run');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions<BufferEncoding> & ExecFileOptions = {\n\t\tmaxBuffer: 1000 * 1024 * 1024,\n\t\t...options,\n\t};\n\n\tconst promise = new Promise<T>((resolve, reject) => {\n\t\tconst proc = execFile(\n\t\t\tcommand,\n\t\t\targs,\n\t\t\t{ ...opts, signal: cancellation },\n\t\t\tasync (error: ExecFileException | null, stdout, stderr) => {\n\t\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t\tresolve((error?.code ?? proc.exitCode) as T);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (error != null) {\n\t\t\t\t\tif (error.signal === 'SIGTERM') {\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew CancelledRunError(\n\t\t\t\t\t\t\t\t`${command} ${args.join(' ')}`,\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\terror.code ?? undefined,\n\t\t\t\t\t\t\t\terror.signal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (bufferExceededRegex.test(error.message)) {\n\t\t\t\t\t\terror.message = `Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet stdoutDecoded: string;\n\t\t\t\t\tlet stderrDecoded: string;\n\t\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\t\t// stdout & stderr can be `Buffer` or `string\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstdoutDecoded = stdout.toString();\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstderrDecoded = stderr.toString();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstdoutDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tstderrDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stderr, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treject(new RunError(error, stdoutDecoded, stderrDecoded));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (stderr && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\tresolve(stdout as T);\n\t\t\t\t} else {\n\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\t(await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t)) as T,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (stdin != null) {\n\t\t\tendStdin(proc.stdin, stdin, stdinEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\n/**\n * Writes a child's whole input and closes it. A child can exit, or be killed on cancellation, before reading all of\n * it, and the pipe then errors (EPIPE, or EOF on Windows). Unlistened, that error is thrown as an uncaught exception\n * and takes down the whole host process, so it is dropped: the child's exit status and stderr already report the\n * failure, and a child that chose to stop reading answered from what it read.\n */\nexport function endStdin(stream: Writable | null, stdin: string | Buffer, stdinEncoding: string | undefined): void {\n\tif (stream == null) return;\n\n\tstream.on('error', () => {});\n\tif (typeof stdin === 'string') {\n\t\tstream.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t} else {\n\t\tstream.end(stdin);\n\t}\n}\n\nexport interface RunExitResult {\n\t/**\n\t * The process's exit code. ABSENT when the process never exited normally — killed by a signal, in which\n\t * case {@link signal} is set. Deliberately optional rather than defaulted to `0`: a signalled process\n\t * reported as `exitCode: 0` is indistinguishable from a clean success, so callers would read a partial\n\t * or empty stdout as a complete answer.\n\t */\n\treadonly exitCode?: number;\n\t/** Set when the process was terminated by a signal instead of exiting; {@link exitCode} is then absent. */\n\treadonly signal?: NodeJS.Signals;\n}\n\nexport interface RunResult<T extends string | Buffer> extends RunExitResult {\n\tstdout: T;\n\tstderr: T;\n}\n\nexport function runSpawn(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: ExitCodeOnlyRunOptions,\n): Promise<RunExitResult>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions,\n): Promise<RunResult<T>>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions & { exitCodeOnly?: boolean },\n): Promise<RunExitResult | RunResult<T>> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.runSpawn');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions = options;\n\n\tconst promise = new Promise<RunExitResult | RunResult<T>>((resolve, reject) => {\n\t\tconst proc = spawn(command, args, { ...opts, signal: cancellation });\n\t\tconst errorEncoding = encoding === 'buffer' ? 'utf8' : encoding;\n\n\t\tconst stdoutBuffers: Buffer[] = [];\n\t\tproc.stdout.on('data', (data: Buffer) => stdoutBuffers.push(data));\n\n\t\tconst stderrBuffers: Buffer[] = [];\n\t\tproc.stderr.on('data', (data: Buffer) => stderrBuffers.push(data));\n\n\t\tfunction getStdio<T>(\n\t\t\tencoding: BufferEncoding | 'buffer' | string,\n\t\t): { stdout: T; stderr: T } | Promise<{ stdout: T; stderr: T }> {\n\t\t\tconst stdout = Buffer.concat(stdoutBuffers);\n\t\t\tconst stderr = Buffer.concat(stderrBuffers);\n\t\t\tif (encoding === 'utf8' || encoding === 'binary') {\n\t\t\t\treturn { stdout: stdout.toString(encoding) as T, stderr: stderr.toString(encoding) as T };\n\t\t\t}\n\t\t\tif (encoding === 'buffer') {\n\t\t\t\treturn { stdout: stdout as T, stderr: stderr as T };\n\t\t\t}\n\n\t\t\tif (decode == null) {\n\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t}\n\n\t\t\treturn Promise.all([\n\t\t\t\tdecode(stdout, encoding ? { encoding: encoding } : undefined),\n\t\t\t\tdecode(stderr, encoding ? { encoding: encoding } : undefined),\n\t\t\t]).then(([decodedStdout, decodedStderr]) => ({\n\t\t\t\tstdout: decodedStdout as T,\n\t\t\t\tstderr: decodedStderr as T,\n\t\t\t}));\n\t\t}\n\n\t\tproc.once('error', async ex => {\n\t\t\tif (ex?.name === 'AbortError') {\n\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\n\t\t\treject(new RunError(ex, stdout, stderr));\n\t\t});\n\n\t\tproc.once('close', async (code, signal) => {\n\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t// Resolves unconditionally, so this is the one path that can hand back a signalled run. `code`\n\t\t\t\t// is null exactly when the process was killed — report the signal rather than coercing to `0`,\n\t\t\t\t// which would claim a clean success for a command that never finished. Note this returns BEFORE\n\t\t\t\t// the SIGTERM-to-cancellation diversion below, so callers have to classify that themselves.\n\t\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined });\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (code !== 0 || signal) {\n\t\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (signal === 'SIGTERM') {\n\t\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true, code ?? undefined, signal));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treject(\n\t\t\t\t\tnew RunError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Command failed with exit code ${code}`,\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\tsignal: signal ?? undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<T>(encoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${typeof stderr === 'string' ? stderr : stderr.toString()}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// The guard above already rejected every non-zero and every signalled close, so this is a clean\n\t\t\t// zero exit — `code` cannot be null here. (The optional typing exists for the `exitCodeOnly`\n\t\t\t// branch, which is where a codeless result can genuinely surface.)\n\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined, stdout: stdout, stderr: stderr });\n\t\t});\n\n\t\tif (stdin != null) {\n\t\t\tendStdin(proc.stdin, stdin, stdinEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport async function fsExists(path: string): Promise<boolean> {\n\treturn new Promise<boolean>(resolve => access(path, constants.F_OK, err => resolve(err == null)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"exec.js","names":["joinPaths"],"sources":["../../../../../utils/src/env/node/exec.ts"],"sourcesContent":["import type { ExecFileException, ExecFileOptions } from 'child_process';\nimport { exec, execFile, spawn } from 'child_process';\nimport type { Stats } from 'fs';\nimport { access, constants } from 'fs';\nimport { stat } from 'fs/promises';\nimport { join as joinPaths } from 'path';\nimport * as process from 'process';\nimport type { Writable } from 'stream';\nimport type { CancellationReason } from '../../cancellation.js';\nimport { getScopedLogger, maybeStartScopedLogger } from '../../logger.scoped.js';\nimport { normalizePath } from '../../path.js';\nimport { isWindows } from './platform.js';\n\n// -- Error types --\n\ninterface RunErrorContext {\n\tmessage: string;\n\tcmd?: string | undefined;\n\tkilled?: boolean | undefined;\n\tcode?: string | number | null | undefined;\n\tsignal?: NodeJS.Signals | undefined;\n}\n\nexport class RunError extends Error {\n\treadonly cmd?: string | undefined;\n\treadonly killed?: boolean | undefined;\n\treadonly code?: string | number | undefined;\n\treadonly signal?: NodeJS.Signals | undefined;\n\treadonly stdout: string;\n\treadonly stderr: string;\n\n\tconstructor(context: RunErrorContext, stdout: string, stderr: string) {\n\t\tsuper(context.message);\n\n\t\tthis.cmd = context.cmd;\n\t\tthis.killed = context.killed;\n\t\tthis.code = context.code ?? undefined;\n\t\tthis.signal = context.signal;\n\t\tthis.stdout = stdout?.trim() ?? '';\n\t\tthis.stderr = stderr?.trim() ?? '';\n\n\t\tthis.name = 'RunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport class CancelledRunError extends RunError {\n\treadonly reason: CancellationReason;\n\n\tconstructor(\n\t\tcmd: string,\n\t\tkilled: boolean,\n\t\tcode?: number | string | undefined,\n\t\tsignal: NodeJS.Signals = 'SIGTERM',\n\t\treason: CancellationReason = 'unknown',\n\t) {\n\t\tsuper(\n\t\t\t{ message: `Operation cancelled; command=${cmd}`, cmd: cmd, killed: killed, code: code, signal: signal },\n\t\t\t'',\n\t\t\t'',\n\t\t);\n\n\t\tthis.reason = reason;\n\n\t\tthis.name = 'CancelledRunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n// -- Execution utilities --\n\nconst slashesRegex = /[\\\\/]/;\nconst ps1Regex = /\\.ps1$/i;\nconst batOrCmdRegex = /\\.(bat|cmd)$/i;\nconst jsRegex = /\\.(js)$/i;\n\n/**\n * Search PATH to see if a file exists in any of the path folders.\n *\n * @param {string} exe The file to search for\n * @return {string} A fully qualified path, or the original path if nothing\n * is found\n *\n * @private\n */\nasync function runDownPath(exe: string): Promise<string> {\n\t// NB: Windows won't search PATH looking for executables in spawn like\n\t// Posix does\n\n\t// Files with any directory path don't get this applied\n\tif (slashesRegex.test(exe)) return exe;\n\n\tconst target = joinPaths('.', exe);\n\ttry {\n\t\tconst stats = await stat(target);\n\t\tif (stats?.isFile() && isExecutable(stats)) return target;\n\t} catch {}\n\n\tconst path = process.env.PATH;\n\tif (path != null && path.length !== 0) {\n\t\tconst haystack = path.split(isWindows ? ';' : ':');\n\t\tfor (const p of haystack) {\n\t\t\tconst needle = joinPaths(p, exe);\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(needle);\n\t\t\t\tif (stats?.isFile() && isExecutable(stats)) return needle;\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\treturn exe;\n}\n\nfunction isExecutable(stats: Stats) {\n\tif (isWindows) return true;\n\n\tconst isGroup = stats.gid ? stats.gid === process.getgid?.() : true;\n\tconst isUser = stats.uid ? stats.uid === process.getuid?.() : true;\n\n\treturn Boolean(stats.mode & 0o0001 || (stats.mode & 0o0010 && isGroup) || (stats.mode & 0o0100 && isUser));\n}\n\n/**\n * Finds the executable and parameters to run on Windows. This method\n * mimics the POSIX behavior of being able to run scripts as executables by\n * replacing the passed-in executable with the script runner, for PowerShell,\n * CMD, and node scripts.\n *\n * This method also does the work of running down PATH, which spawn on Windows\n * also doesn't do, unlike on POSIX.\n */\nexport async function findExecutable(exe: string, args: string[]): Promise<{ cmd: string; args: string[] }> {\n\t// POSIX can just execute scripts directly, no need for silly goosery\n\tif (!isWindows) return { cmd: await runDownPath(exe), args: args };\n\n\tif (!(await fsExists(exe))) {\n\t\t// NB: When you write something like `surf-client ... -- surf-build` on Windows,\n\t\t// a shell would normally convert that to surf-build.cmd, but since it's passed\n\t\t// in as an argument, it doesn't happen\n\t\tconst possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];\n\t\tfor (const ext of possibleExts) {\n\t\t\tconst possibleFullPath = await runDownPath(`${exe}${ext}`);\n\n\t\t\tif (await fsExists(possibleFullPath)) return findExecutable(possibleFullPath, args);\n\t\t}\n\t}\n\n\tif (ps1Regex.test(exe)) {\n\t\tconst cmd = joinPaths(\n\t\t\tprocess.env.SYSTEMROOT ?? 'C:\\\\WINDOWS',\n\t\t\t'System32',\n\t\t\t'WindowsPowerShell',\n\t\t\t'v1.0',\n\t\t\t'PowerShell.exe',\n\t\t);\n\t\tconst psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];\n\n\t\treturn { cmd: cmd, args: [...psargs, ...args] };\n\t}\n\n\tif (batOrCmdRegex.test(exe)) {\n\t\tconst cmd = joinPaths(process.env.SYSTEMROOT ?? 'C:\\\\WINDOWS', 'System32', 'cmd.exe');\n\t\tconst cmdArgs = ['/C', exe, ...args];\n\n\t\treturn { cmd: cmd, args: cmdArgs };\n\t}\n\n\tif (jsRegex.test(exe)) {\n\t\tconst cmd = process.execPath;\n\t\tconst nodeArgs = [exe];\n\n\t\treturn { cmd: cmd, args: [...nodeArgs, ...args] };\n\t}\n\n\treturn { cmd: exe, args: args };\n}\n\nexport async function getWindowsShortPath(path: string): Promise<string> {\n\treturn new Promise<string>((resolve, reject) => {\n\t\texec(`for %I in (\"${path}\") do @echo %~sI`, (error, stdout, _stderr) => {\n\t\t\tif (error != null) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve(normalizePath(stdout.trim()));\n\t\t});\n\t});\n}\n\nexport interface RunOptions<TEncoding = BufferEncoding | 'buffer'> {\n\tcwd?: string;\n\treadonly env?: Record<string, string | undefined>;\n\treadonly encoding?: TEncoding;\n\t/**\n\t * Decodes non-UTF-8 output. Called when `encoding` is not utf8/binary/buffer.\n\t * Provided by the host via the `GitOptions.decode` option.\n\t * If absent and a non-UTF-8 encoding is requested, throws at runtime.\n\t */\n\treadonly decode?: (data: Uint8Array, options?: { readonly encoding: string }) => string | Promise<string>;\n\t/**\n\t * The size the output buffer to allocate to the spawned process. Set this\n\t * if you are anticipating a large amount of output.\n\t *\n\t * If not specified, this will be 10MB (10485760 bytes) which should be\n\t * enough for most Git operations.\n\t */\n\treadonly maxBuffer?: number;\n\treadonly cancellation?: AbortSignal;\n\t/**\n\t * An optional string or buffer which will be written to\n\t * the child process stdin stream immediately immediately\n\t * after spawning the process.\n\t */\n\treadonly stdin?: string | Buffer;\n\t/**\n\t * The encoding to use when writing to stdin, if the stdin\n\t * parameter is a string.\n\t */\n\treadonly stdinEncoding?: string;\n\treadonly timeout?: number;\n\t/**\n\t * When true, suppresses the `[EXEC]` stderr warning emitted on debug-enabled scopes.\n\t * Use for commands whose failure is expected (e.g. paired with `errors: 'ignore'`).\n\t */\n\treadonly quiet?: boolean;\n}\n\nconst bufferExceededRegex = /stdout maxBuffer( length)? exceeded/;\n\ntype ExitCodeOnlyRunOptions<TEncoding = BufferEncoding | 'buffer'> = RunOptions<TEncoding> & { exitCodeOnly: true };\n\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions: ExitCodeOnlyRunOptions<BufferEncoding>,\n): Promise<number>;\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding>,\n): Promise<string>;\nexport function run<T extends number | string>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding> & { exitCodeOnly?: boolean },\n): Promise<T> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.run');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions<BufferEncoding> & ExecFileOptions = {\n\t\tmaxBuffer: 1000 * 1024 * 1024,\n\t\t...options,\n\t};\n\n\tconst promise = new Promise<T>((resolve, reject) => {\n\t\tconst proc = execFile(\n\t\t\tcommand,\n\t\t\targs,\n\t\t\t{ ...opts, signal: cancellation },\n\t\t\tasync (error: ExecFileException | null, stdout, stderr) => {\n\t\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t\tresolve((error?.code ?? proc.exitCode) as T);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (error != null) {\n\t\t\t\t\tif (error.signal === 'SIGTERM') {\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew CancelledRunError(\n\t\t\t\t\t\t\t\t`${command} ${args.join(' ')}`,\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\terror.code ?? undefined,\n\t\t\t\t\t\t\t\terror.signal,\n\t\t\t\t\t\t\t\tcancellation?.aborted ? 'aborted' : error.killed ? 'timeout' : 'unknown',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (bufferExceededRegex.test(error.message)) {\n\t\t\t\t\t\terror.message = `Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet stdoutDecoded: string;\n\t\t\t\t\tlet stderrDecoded: string;\n\t\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\t\t// stdout & stderr can be `Buffer` or `string\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstdoutDecoded = stdout.toString();\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstderrDecoded = stderr.toString();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstdoutDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tstderrDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stderr, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treject(new RunError(error, stdoutDecoded, stderrDecoded));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (stderr && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\tresolve(stdout as T);\n\t\t\t\t} else {\n\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\t(await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t)) as T,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (stdin != null) {\n\t\t\tendStdin(proc.stdin, stdin, stdinEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\n/**\n * Writes a child's whole input and closes it. A child can exit, or be killed on cancellation, before reading all of\n * it, and the pipe then errors (EPIPE, or EOF on Windows). Unlistened, that error is thrown as an uncaught exception\n * and takes down the whole host process, so it is dropped: the child's exit status and stderr already report the\n * failure, and a child that chose to stop reading answered from what it read.\n */\nexport function endStdin(stream: Writable | null, stdin: string | Buffer, stdinEncoding: string | undefined): void {\n\tif (stream == null) return;\n\n\tstream.on('error', () => {});\n\tif (typeof stdin === 'string') {\n\t\tstream.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t} else {\n\t\tstream.end(stdin);\n\t}\n}\n\nexport interface RunExitResult {\n\t/**\n\t * The process's exit code. ABSENT when the process never exited normally — killed by a signal, in which\n\t * case {@link signal} is set. Deliberately optional rather than defaulted to `0`: a signalled process\n\t * reported as `exitCode: 0` is indistinguishable from a clean success, so callers would read a partial\n\t * or empty stdout as a complete answer.\n\t */\n\treadonly exitCode?: number;\n\t/** Set when the process was terminated by a signal instead of exiting; {@link exitCode} is then absent. */\n\treadonly signal?: NodeJS.Signals;\n\t/** Whether Node itself killed the process (its spawn `timeout`), as opposed to an external signal. */\n\treadonly killed?: boolean;\n}\n\nexport interface RunResult<T extends string | Buffer> extends RunExitResult {\n\tstdout: T;\n\tstderr: T;\n}\n\nexport function runSpawn(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: ExitCodeOnlyRunOptions,\n): Promise<RunExitResult>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions,\n): Promise<RunResult<T>>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions & { exitCodeOnly?: boolean },\n): Promise<RunExitResult | RunResult<T>> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.runSpawn');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions = options;\n\n\tconst promise = new Promise<RunExitResult | RunResult<T>>((resolve, reject) => {\n\t\tconst proc = spawn(command, args, { ...opts, signal: cancellation });\n\t\tconst errorEncoding = encoding === 'buffer' ? 'utf8' : encoding;\n\n\t\tconst stdoutBuffers: Buffer[] = [];\n\t\tproc.stdout.on('data', (data: Buffer) => stdoutBuffers.push(data));\n\n\t\tconst stderrBuffers: Buffer[] = [];\n\t\tproc.stderr.on('data', (data: Buffer) => stderrBuffers.push(data));\n\n\t\tfunction getStdio<T>(\n\t\t\tencoding: BufferEncoding | 'buffer' | string,\n\t\t): { stdout: T; stderr: T } | Promise<{ stdout: T; stderr: T }> {\n\t\t\tconst stdout = Buffer.concat(stdoutBuffers);\n\t\t\tconst stderr = Buffer.concat(stderrBuffers);\n\t\t\tif (encoding === 'utf8' || encoding === 'binary') {\n\t\t\t\treturn { stdout: stdout.toString(encoding) as T, stderr: stderr.toString(encoding) as T };\n\t\t\t}\n\t\t\tif (encoding === 'buffer') {\n\t\t\t\treturn { stdout: stdout as T, stderr: stderr as T };\n\t\t\t}\n\n\t\t\tif (decode == null) {\n\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t}\n\n\t\t\treturn Promise.all([\n\t\t\t\tdecode(stdout, encoding ? { encoding: encoding } : undefined),\n\t\t\t\tdecode(stderr, encoding ? { encoding: encoding } : undefined),\n\t\t\t]).then(([decodedStdout, decodedStderr]) => ({\n\t\t\t\tstdout: decodedStdout as T,\n\t\t\t\tstderr: decodedStderr as T,\n\t\t\t}));\n\t\t}\n\n\t\tproc.once('error', async ex => {\n\t\t\tif (ex?.name === 'AbortError') {\n\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true, undefined, undefined, 'aborted'));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\n\t\t\treject(new RunError(ex, stdout, stderr));\n\t\t});\n\n\t\tproc.once('close', async (code, signal) => {\n\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t// Resolves unconditionally, so this is the one path that can hand back a signalled run. `code`\n\t\t\t\t// is null exactly when the process was killed — report the signal rather than coercing to `0`,\n\t\t\t\t// which would claim a clean success for a command that never finished. Note this returns BEFORE\n\t\t\t\t// the SIGTERM-to-cancellation diversion below, so callers have to classify that themselves.\n\t\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined, killed: proc.killed });\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (code !== 0 || signal) {\n\t\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (signal === 'SIGTERM') {\n\t\t\t\t\t// Only Node's spawn `timeout` kills it (a caller abort rejected above, from `'error'`); an\n\t\t\t\t\t// external SIGTERM leaves `proc.killed` false\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew CancelledRunError(\n\t\t\t\t\t\t\t`${command} ${args.join(' ')}`,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tcode ?? undefined,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\tproc.killed ? 'timeout' : 'unknown',\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treject(\n\t\t\t\t\tnew RunError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Command failed with exit code ${code}`,\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\tsignal: signal ?? undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<T>(encoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${typeof stderr === 'string' ? stderr : stderr.toString()}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// The guard above already rejected every non-zero and every signalled close, so this is a clean\n\t\t\t// zero exit — `code` cannot be null here. (The optional typing exists for the `exitCodeOnly`\n\t\t\t// branch, which is where a codeless result can genuinely surface.)\n\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined, stdout: stdout, stderr: stderr });\n\t\t});\n\n\t\tif (stdin != null) {\n\t\t\tendStdin(proc.stdin, stdin, stdinEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport async function fsExists(path: string): Promise<boolean> {\n\treturn new Promise<boolean>(resolve => access(path, constants.F_OK, err => resolve(err == null)));\n}\n"],"mappings":"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"}