@gitkraken/core-gitlens 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/dist/git/cache.js +2 -0
  3. package/dist/git/cache.js.map +1 -1
  4. package/dist/git/models/issue.d.ts +3 -1
  5. package/dist/git/models/issue.js.map +1 -1
  6. package/dist/git/providers/branches.d.ts +4 -2
  7. package/dist/git/utils/issue.utils.d.ts +3 -1
  8. package/dist/git/utils/issue.utils.js +5 -1
  9. package/dist/git/utils/issue.utils.js.map +1 -1
  10. package/dist/git/watching/worktreeSummary.d.ts +20 -9
  11. package/dist/git/watching/worktreeSummary.js +24 -22
  12. package/dist/git/watching/worktreeSummary.js.map +1 -1
  13. package/dist/git-cli/providers/branches.js +26 -4
  14. package/dist/git-cli/providers/branches.js.map +1 -1
  15. package/dist/plus/integrations/models/gitHostIntegration.js +3 -1
  16. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  17. package/dist/plus/integrations/models/integration.js +1 -1
  18. package/dist/plus/integrations/providers/azure/azure.js +3 -2
  19. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  20. package/dist/plus/integrations/providers/azure/models.d.ts +27 -10
  21. package/dist/plus/integrations/providers/azure/models.js +39 -19
  22. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  23. package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +19 -0
  24. package/dist/plus/integrations/providers/azure/workItemStateCategories.js +32 -0
  25. package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -0
  26. package/dist/plus/integrations/providers/azureDevOps.js +5 -5
  27. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  28. package/dist/plus/integrations/providers/issueSorts.d.ts +0 -1
  29. package/dist/plus/integrations/providers/jira-server.js +11 -5
  30. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  31. package/dist/plus/integrations/providers/jira.d.ts +5 -2
  32. package/dist/plus/integrations/providers/jira.js +45 -30
  33. package/dist/plus/integrations/providers/jira.js.map +1 -1
  34. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +3 -4
  35. package/dist/plus/integrations/providers/jiraIssueByKey.js +3 -4
  36. package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
  37. package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +5 -5
  38. package/dist/plus/integrations/providers/linearIssuesEtag.js +6 -6
  39. package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -1
  40. package/dist/plus/integrations/providers/models.d.ts +11 -1
  41. package/dist/plus/integrations/providers/models.js +9 -9
  42. package/dist/plus/integrations/providers/models.js.map +1 -1
  43. package/dist/plus/integrations/providers/providersApi.d.ts +30 -32
  44. package/dist/plus/integrations/providers/providersApi.js +149 -46
  45. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  46. package/dist/plus/integrations/providers/utils/jiraIssueDrains.d.ts +27 -15
  47. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js +72 -10
  48. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js.map +1 -1
  49. package/dist/plus/integrations/reads/batchEtags.d.ts +5 -2
  50. package/dist/plus/integrations/reads/batchEtags.js +31 -10
  51. package/dist/plus/integrations/reads/batchEtags.js.map +1 -1
  52. package/dist/plus/integrations/reads/cursors.js +1 -1
  53. package/dist/plus/integrations/reads/drains.d.ts +0 -1
  54. package/dist/plus/integrations/reads/hierarchy.js +2 -2
  55. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  56. package/dist/plus/integrations/reads/hierarchy.utils.d.ts +13 -0
  57. package/dist/plus/integrations/reads/hierarchy.utils.js +26 -1
  58. package/dist/plus/integrations/reads/hierarchy.utils.js.map +1 -1
  59. package/dist/plus/integrations/reads/issueTracker.js +4 -4
  60. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  61. package/dist/plus/integrations/reads/issues.js +1 -1
  62. package/dist/plus/integrations/reads/pullRequestBranches.js +10 -3
  63. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
  64. package/dist/plus/integrations/results.d.ts +28 -3
  65. package/dist/plus/integrations/results.js +22 -3
  66. package/dist/plus/integrations/results.js.map +1 -1
  67. package/dist/plus/integrations/utils/integration.utils.d.ts +6 -1
  68. package/dist/plus/integrations/utils/integration.utils.js +8 -1
  69. package/dist/plus/integrations/utils/integration.utils.js.map +1 -1
  70. package/docs/integrations.md +54 -19
  71. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"azureDevOps.js","names":[],"sources":["../../../../../plus/integrations/src/providers/azureDevOps.ts"],"sourcesContent":["import type { CollectionMetadata, CollectionScope, CollectionScopeFailure } from '@gitkraken/provider-apis';\nimport { GitPullRequestState } from '@gitkraken/provider-apis';\nimport type { Account, UnidentifiedAuthor } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { Issue, IssueShape } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestType } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type {\n\tPullRequest,\n\tPullRequestMergeMethod,\n\tPullRequestProjection,\n\tPullRequestShape,\n\tPullRequestState,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport type { ResourceDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\nimport type { PullRequestUrlIdentity } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { chunk } from '@gitlens/utils/array.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { mapSettledBounded } from '@gitlens/utils/promise.js';\nimport { PromiseCache } from '@gitlens/utils/promiseCache.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type {\n\tAuthenticationSessionLike as AuthenticationSession,\n\tProviderAuthenticationSession,\n\tTokenWithInfo,\n} from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport type { ProviderRefusal } from '../collectionMetadata.js';\nimport { throwIfCallerContractError, toCollectionScopeFailure } from '../collectionMetadata.js';\nimport type { GitSelfManagedHostIntegrationId } from '../constants.js';\nimport { GitCloudHostIntegrationId, providerFanOutConcurrency } from '../constants.js';\nimport { AuthenticationError } from '../errors.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 { ProviderWarningCause, ProviderWarningScope } from '../results.js';\nimport { decodePathSegment } from '../utils/domain.utils.js';\nimport { getAzurePullRequestIdentityFromMaybeUrl } from './azure/azure.utils.js';\nimport type {\n\tAzureOrganizationDescriptor,\n\tAzureProjectDescriptor,\n\tAzureProjectInputDescriptor,\n\tAzureRemoteRepositoryDescriptor,\n\tAzureRepositoryDescriptor,\n\tAzureWorkItemResponse,\n} from './azure/models.js';\nimport {\n\tazureWorkItemsEtagFieldsMaxIds,\n\ttoAzurePullRequestEtagFields,\n\ttoAzureWorkItemEtagFields,\n} from './azure/models.js';\nimport type {\n\tProviderApiCollectionResult,\n\tProviderApiPagedResult,\n\tProviderAzureResource,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepoInput,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tfromProviderIssue,\n\tfromProviderPullRequest,\n\tgetProviderPullRequestIdentity,\n\tIssueFilter,\n\tproviderPullRequestMatchesSearch,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoIssueShape,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport { discoveryCacheTtl } from './utils/discoveryCache.js';\nimport {\n\tcollectProviderPagedResult,\n\tflatSettledResultsOrThrow,\n\tmergeCollectionMetadata,\n\tresolveBranchPullRequests,\n\tselectBranchPullRequests,\n} from './utils/providerPaging.js';\n\nexport function getAzureRepositoryIdentity(repo: Pick<AzureRepositoryDescriptor, 'owner' | 'name' | 'project'>): {\n\tresourceName: string;\n\tprojectName?: string;\n\trepositoryName: string;\n} {\n\tconst match = /^([^/]+)\\/_git\\/([^/]+)$/i.exec(repo.name);\n\treturn {\n\t\tresourceName: repo.owner,\n\t\tprojectName: repo.project ?? match?.[1],\n\t\trepositoryName: match?.[2] ?? repo.name,\n\t};\n}\n\nexport function getAzureRepositoryApiBaseUrl(\n\tbaseUrl: string,\n\trepo: Pick<AzureRepositoryDescriptor, 'owner' | 'virtualDirectory'>,\n): string {\n\tconst directory = repo.virtualDirectory?.split('/');\n\tif (directory?.some(segment => !segment || segment === '.' || segment === '..')) {\n\t\tthrow new Error(`Invalid Azure virtual directory '${repo.virtualDirectory}'.`);\n\t}\n\n\tconst url = new URL(baseUrl);\n\tconst toUrl = (segments: string[]) => `${url.protocol}//${url.host}${segments.map(s => `/${s}`).join('')}`;\n\tconst configured = url.pathname.split('/').filter(Boolean);\n\t// A connection addressed at the host root takes the repository's own directory.\n\tif (!configured.length) return toUrl(directory?.map(encodeURIComponent) ?? []);\n\n\t// Otherwise the address is the installation, optionally followed by the repository's collection, which\n\t// requests append themselves (as the owner). IIS serves these paths case-insensitively.\n\tconst namesCollection = sameAzurePathSegment(configured.at(-1)!, repo.owner);\n\tconst installation = namesCollection ? configured.slice(0, -1) : configured;\n\tif (directory == null) return toUrl(installation);\n\n\tfor (const candidate of namesCollection ? [configured, installation] : [configured]) {\n\t\tif (candidate.length === directory.length && candidate.every((s, i) => sameAzurePathSegment(s, directory[i]))) {\n\t\t\treturn toUrl(candidate);\n\t\t}\n\t}\n\tthrow new Error('Azure repository virtual directory does not match the configured installation');\n}\n\nfunction sameAzurePathSegment(encoded: string, value: string): boolean {\n\treturn decodePathSegment(encoded).toLowerCase() === value.toLowerCase();\n}\n\n/**\n * Whether two collection or project names name the same scope. Azure DevOps treats them case-insensitively, so a\n * name typed by hand must still select the collection or project discovery reported.\n */\nexport function sameAzureName(a: string, b: string): boolean {\n\treturn a.toLowerCase() === b.toLowerCase();\n}\n\n/** The distinct names in `names`, compared as Azure compares them, keeping the first spelling of each. */\nexport function uniqueAzureNames(names: readonly string[]): string[] {\n\tconst unique: string[] = [];\n\tfor (const name of names) {\n\t\tif (!unique.some(n => sameAzureName(n, name))) {\n\t\t\tunique.push(name);\n\t\t}\n\t}\n\treturn unique;\n}\n\n/**\n * Flags the reviews of `pr` that name one of the current user's groups (see `PullRequestReviewer.isMyGroup`), which a\n * reviewer read finds through that group rather than through the user.\n */\nexport function markMyGroupReviews(pr: ProviderPullRequest, groupIds: ReadonlySet<string>): ProviderPullRequest {\n\tif (pr.reviews == null || !pr.reviews.some(r => groupIds.has(r.reviewer.id))) return pr;\n\n\treturn { ...pr, reviews: pr.reviews.map(r => (groupIds.has(r.reviewer.id) ? { ...r, isMyGroup: true } : r)) };\n}\n\n/** One read a reviewer relationship takes in a project or repository, and the rows of it the relationship keeps. */\nexport interface AzureReviewerRead {\n\tfilter: { reviewerId?: string; states?: GitPullRequestState[] };\n\tkeep?: (pr: ProviderPullRequest) => boolean;\n}\n\n/**\n * The reads a reviewer relationship over `states` (omitted: open) takes for `userId`, whose groups are `groupIds`:\n *\n * - Open pull requests: all of them, kept when one names the user, or names one of the user's groups and the user\n * didn't write it. Azure's reviewer filter only matches the identity it names, never the groups that identity is in,\n * and a group asked to review the user's own pull request isn't asking the user.\n * - Closed and merged ones: Azure's own filter for the user. They are every pull request a project ever had, too many\n * to read whole on every read, so a group's request is only followed while the pull request is open.\n */\nexport function toAzureReviewerReads(\n\tuserId: string,\n\tgroupIds: ReadonlySet<string>,\n\tstates: readonly GitPullRequestState[] | undefined,\n): AzureReviewerRead[] {\n\tconst reads: AzureReviewerRead[] = [];\n\tif (states == null || states.includes(GitPullRequestState.Open)) {\n\t\treads.push({\n\t\t\tfilter: { states: [GitPullRequestState.Open] },\n\t\t\tkeep: pr =>\n\t\t\t\tpr.reviews?.some(\n\t\t\t\t\tr => r.reviewer.id === userId || (groupIds.has(r.reviewer.id) && pr.author?.id !== userId),\n\t\t\t\t) ?? false,\n\t\t});\n\t}\n\n\tconst closed = states?.filter(s => s !== GitPullRequestState.Open) ?? [];\n\tif (closed.length > 0) {\n\t\treads.push({ filter: { reviewerId: userId, states: closed } });\n\t}\n\treturn reads;\n}\n\n/**\n * Matches an org/project descriptor against a caller-supplied name, mirroring the facade's own\n * key/id/name comparison so `listIssuesPage({ org, project })` narrows on the same identifiers a consumer\n * already got back from `listOrgs`/`listProjects`.\n */\nfunction azureResourceMatches(resource: { key?: string; id?: string; name?: string }, value: string): boolean {\n\treturn resource.key === value || resource.id === value || resource.name === value;\n}\n\nexport abstract class AzureDevOpsIntegrationBase<\n\tTIntegrationId extends GitCloudHostIntegrationId.AzureDevOps | GitSelfManagedHostIntegrationId.AzureDevOpsServer,\n\tTRepositoryDescriptor extends AzureRepositoryDescriptor = AzureRepositoryDescriptor,\n> extends GitHostIntegration<TIntegrationId, TRepositoryDescriptor> {\n\tprotected abstract apiBaseUrlFor(session: ProviderAuthenticationSession): string;\n\tprotected getApiOptions(\n\t\tsession: ProviderAuthenticationSession,\n\t\tdoNotConvertToPat: boolean = false,\n\t): {\n\t\ttokenWithInfo: TokenWithInfo<TIntegrationId>;\n\t\toptions: { isPAT: boolean; baseUrl?: string };\n\t} {\n\t\t// The secret is handed over raw: `isPAT` tells provider-apis to send it as an HTTP Basic credential, which\n\t\t// it encodes itself as `base64(':' + token)`. Pre-encoding here would be encoded a second time and refused\n\t\t// by Azure DevOps. `getCurrentUser` is the one read that needs a bearer token, and passes\n\t\t// `doNotConvertToPat` to get one.\n\t\tconst usePat = !doNotConvertToPat;\n\t\tconst tokenWithInfo = toTokenWithInfo<TIntegrationId>(this.id, session);\n\t\treturn {\n\t\t\ttokenWithInfo: tokenWithInfo,\n\t\t\toptions: { isPAT: usePat },\n\t\t};\n\t}\n\n\t/**\n\t * The options for a request addressed below one collection (an Azure DevOps Services organization).\n\t *\n\t * The same as {@link getApiOptions} unless a self-managed address already names the collection, which requests\n\t * append themselves: see the server override, which keeps it from being applied twice.\n\t */\n\tprotected getCollectionApiOptions(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_collection: string,\n\t): { isPAT: boolean; baseUrl?: string } {\n\t\treturn this.getApiOptions(session).options;\n\t}\n\n\t/** The base a request or link below `collection` appends the collection to; see {@link getCollectionApiOptions}. */\n\tprotected collectionApiBaseUrl(session: ProviderAuthenticationSession, _collection: string): string {\n\t\treturn this.apiBaseUrlFor(session);\n\t}\n\n\t/** Reads the organizations (Azure DevOps Server: the collections) the account can see. */\n\tprotected async requestResourcesForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\tuserId: string,\n\t): Promise<ProviderAzureResource[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo, options } = this.getApiOptions(session);\n\t\treturn api.getAzureResourcesForUser(tokenWithInfo, userId, options);\n\t}\n\n\t/**\n\t * The identity id a pull-request creator/reviewer filter must carry for `collection`.\n\t *\n\t * On Azure DevOps Services that is the account id, one per user. The server override resolves it per collection,\n\t * since Azure DevOps Server gives one person a different id in each collection than at the server level.\n\t */\n\tprotected async getFilterUserId(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_collection: string,\n\t): Promise<string | undefined> {\n\t\treturn (await this.getProviderCurrentAccount(session))?.id;\n\t}\n\n\t/**\n\t * The current user's groups per credential, collection and user, kept for {@link discoveryCacheTtl} like the other\n\t * discovered sets: membership changes rarely, and a sweep that reads every few minutes would otherwise pay for it\n\t * every time. A failed read isn't kept, and a re-sync drops them all (see {@link invalidateDiscoveryCaches}).\n\t */\n\tprivate readonly _reviewerGroupIds = new PromiseCache<string, Set<string>>({\n\t\tcapacity: 50,\n\t\tcreateTTL: discoveryCacheTtl,\n\t});\n\n\t/**\n\t * Every group the current user (`userId`, as {@link getFilterUserId} resolved it) is a member of in `collection`:\n\t * teams and security groups, in any project, directly or through other groups. Two requests per collection,\n\t * however many groups, and none while the last read is kept.\n\t */\n\tprotected getReviewerGroupIds(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcollection: string,\n\t\tuserId: string,\n\t): Promise<Set<string>> {\n\t\treturn this._reviewerGroupIds.getOrCreate(\n\t\t\tJSON.stringify([this.discoveryKey(session), collection.toLowerCase(), userId]),\n\t\t\tasync () => {\n\t\t\t\tconst api = await this.getProvidersApi();\n\t\t\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\t\t\tconst ids = await api.getAzureGroupIdsForUser(\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\tcollection,\n\t\t\t\t\tuserId,\n\t\t\t\t\tthis.getCollectionApiOptions(session, collection),\n\t\t\t\t);\n\t\t\t\treturn new Set(ids);\n\t\t\t},\n\t\t);\n\t}\n\n\toverride invalidateDiscoveryCaches(): void {\n\t\tsuper.invalidateDiscoveryCaches();\n\t\tthis._reviewerGroupIds.clear();\n\t}\n\n\t/**\n\t * For one read, the current account as each organization's pull requests identify it, given the account itself\n\t * (`undefined` when it couldn't be read). Azure DevOps Services gives a person one id, so that is `account`; the\n\t * server override resolves each collection's own, once per read.\n\t */\n\tprotected getOrganizationViewers(\n\t\t_session: ProviderAuthenticationSession,\n\t\taccount: { id: string; username?: string } | undefined,\n\t): (org: string) => Promise<{ id: string; username?: string } | undefined> {\n\t\treturn () => Promise.resolve(account);\n\t}\n\n\t/**\n\t * What the discovery caches (account, organizations, projects, and their stored copies) are keyed by. Azure DevOps\n\t * Services has a single address, so the credential alone identifies what it discovers; the server override adds\n\t * the installation address.\n\t */\n\tprotected discoveryKey(session: ProviderAuthenticationSession): string {\n\t\treturn session.accessToken;\n\t}\n\n\tprivate _accounts: Map<string, Account | undefined> | undefined;\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst key = this.discoveryKey(session);\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\n\t\tconst cachedAccount = this._accounts.get(key);\n\t\tif (cachedAccount == null) {\n\t\t\tconst user = await this._requestForCurrentUser(session);\n\t\t\tthis._accounts.set(key, user);\n\t\t}\n\n\t\treturn this._accounts.get(key);\n\t}\n\n\tprotected async _requestForCurrentUser(session: ProviderAuthenticationSession): Promise<Account | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo, options } = this.getApiOptions(session, true);\n\t\tconst user = await api.getCurrentUser(tokenWithInfo, options);\n\t\treturn user\n\t\t\t? {\n\t\t\t\t\tprovider: this,\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\temail: user.email ?? undefined,\n\t\t\t\t\tavatarUrl: user.avatarUrl ?? undefined,\n\t\t\t\t\tusername: user.username ?? undefined,\n\t\t\t\t}\n\t\t\t: undefined;\n\t}\n\n\t/**\n\t * Bypasses the account cache so a previously accepted credential cannot vouch for one that is now refused.\n\t */\n\tprotected override async validateCredential(session: ProviderAuthenticationSession): Promise<void> {\n\t\tif ((await this._requestForCurrentUser(session)) == null) {\n\t\t\tthrow new Error('Azure DevOps did not confirm the credential');\n\t\t}\n\t}\n\n\t/**\n\t * Names a confirmed credential's refusal from the answers Azure DevOps gives, captured live (#5890):\n\t * - `VS403463` in the explanation is a Conditional Access policy;\n\t * - a typed `UnauthorizedRequestException` body is an organization or project the account has no access to;\n\t * - a `401` to an OAuth token that explains nothing (sent as Basic), or only `TF400813` (sent as Bearer), is an\n\t * organization whose \"Third-party application access via OAuth\" policy is off. It is the same answer an\n\t * expired token gets, which is why this is only asked once the credential passed. The policy does not govern\n\t * personal access tokens, so a PAT is never given it.\n\t *\n\t * Any other explanation is left unnamed, so the warning keeps Azure's own words rather than a guess.\n\t */\n\tprotected override describeRefusal(\n\t\tsession: ProviderAuthenticationSession,\n\t\trefusal: ProviderRefusal,\n\t\tscope: ProviderWarningScope,\n\t): ProviderWarningCause | undefined {\n\t\tconst code = /\\b(?:TF|VS)\\d{6}\\b/.exec(refusal.detail ?? '')?.[0];\n\t\tif (code === 'VS403463') return { reason: 'conditional-access', code: code };\n\t\tif (refusal.typeKey === 'UnauthorizedRequestException') {\n\t\t\treturn { reason: 'access-denied', ...(code != null ? { code: code } : {}) };\n\t\t}\n\t\tif (\n\t\t\tthis.id !== GitCloudHostIntegrationId.AzureDevOps ||\n\t\t\tsession.type !== 'oauth' ||\n\t\t\trefusal.status !== 401 ||\n\t\t\trefusal.typeKey != null ||\n\t\t\t(refusal.detail != null && code !== 'TF400813')\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// The organization's name, for the policy page, comes from the discovery the failure was recorded under. Most\n\t\t// reads record the organization's id, the repo-scoped ones its name.\n\t\tconst org =\n\t\t\tscope.resourceId != null\n\t\t\t\t? this._organizations\n\t\t\t\t\t\t?.get(this.discoveryKey(session))\n\t\t\t\t\t\t?.find(o => o.id === scope.resourceId || o.name === scope.resourceId)?.name\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\treason: 'oauth-app-not-allowed',\n\t\t\t...(code != null ? { code: code } : {}),\n\t\t\t...(org != null\n\t\t\t\t? {\n\t\t\t\t\t\tremedyUrl: `${this.apiBaseUrlFor(session)}/${encodeURIComponent(org)}/_settings/organizationPolicy`,\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tprivate _organizations: Map<string, AzureOrganizationDescriptor[] | undefined> | undefined;\n\tprotected async getProviderResourcesForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\tforce: boolean = false,\n\t): Promise<AzureOrganizationDescriptor[] | undefined> {\n\t\tthis._organizations ??= new Map<string, AzureOrganizationDescriptor[] | undefined>();\n\t\tconst key = this.discoveryKey(session);\n\t\tconst cachedResources = this._organizations.get(key);\n\n\t\tif (cachedResources == null || force) {\n\t\t\tconst account = await this.getProviderCurrentAccount(session);\n\t\t\tif (account?.id == null) return undefined;\n\n\t\t\tconst resources = await this.requestResourcesForUser(session, account.id);\n\t\t\tthis._organizations.set(key, resources != null ? resources.map(r => ({ ...r, key: r.id })) : undefined);\n\t\t}\n\n\t\treturn this._organizations.get(key);\n\t}\n\n\tprivate _projects: Map<string, AzureProjectDescriptor[] | undefined> | undefined;\n\t/**\n\t * Discovers (and caches) each resource's projects. Only resources whose drain completed cleanly are cached;\n\t * a rejected or backstop-truncated drain is left uncached (retried next call). When `failures` is supplied,\n\t * a rejected resource is recorded there as a structured {@link CollectionScopeFailure} so an account-wide\n\t * caller can surface the incomplete project set (a whole org's PRs/issues silently missing otherwise) as a\n\t * scope-aware warning + `fetchFailed` rather than an all-pages success over a hole.\n\t */\n\tprotected async getProviderProjectsForResources(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresources: AzureOrganizationDescriptor[],\n\t\tforce: boolean = false,\n\t\tfailures?: CollectionScopeFailure[],\n\t): Promise<ProviderApiCollectionResult<AzureProjectDescriptor>> {\n\t\tthis._projects ??= new Map<string, AzureProjectDescriptor[] | undefined>();\n\t\tconst discoveryKey = this.discoveryKey(session);\n\n\t\tlet resourcesWithoutProjects = [];\n\t\tif (force) {\n\t\t\tresourcesWithoutProjects = resources;\n\t\t} else {\n\t\t\tfor (const resource of resources) {\n\t\t\t\tconst resourceKey = `${discoveryKey}:${resource.id}`;\n\t\t\t\tconst cachedProjects = this._projects.get(resourceKey);\n\t\t\t\tif (cachedProjects == null) {\n\t\t\t\t\tresourcesWithoutProjects.push(resource);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst allProjects: AzureProjectDescriptor[] = [];\n\t\tlet resultMetadata: CollectionMetadata | undefined;\n\n\t\tif (resourcesWithoutProjects.length > 0) {\n\t\t\tconst api = await this.getProvidersApi();\n\t\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\t\t// The projects API is paginated; a single call would drop every project past the first page (and\n\t\t\t// with it their repos and PRs). Drain all pages per resource, threading the returned cursor.\n\t\t\t// Per-resource (not a shared flatSettled) so a resource whose drain was truncated (hit the paging\n\t\t\t// backstop) or rejected is NOT cached — caching a partial list here would make every later repo/PR/\n\t\t\t// issue read for that org silently inherit an incomplete project set. Leaving it uncached means the\n\t\t\t// next call retries it. The scope is passed so a page-level failure preserves the prefix already\n\t\t\t// fetched and records a structured failure instead of re-throwing.\n\t\t\tconst drains = await Promise.allSettled(\n\t\t\t\tresourcesWithoutProjects.map(async resource => ({\n\t\t\t\t\tresource: resource,\n\t\t\t\t\tresult: await collectProviderPagedResult(\n\t\t\t\t\t\tcursor =>\n\t\t\t\t\t\t\tapi.getAzureProjectsForResource(tokenWithInfo, resource.name, {\n\t\t\t\t\t\t\t\t...this.getCollectionApiOptions(session, resource.name),\n\t\t\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t20,\n\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t),\n\t\t\t\t})),\n\t\t\t);\n\n\t\t\t// `allSettled` preserves order, so `drains[i]` is `resourcesWithoutProjects[i]`.\n\t\t\tdrains.forEach((drain, i) => {\n\t\t\t\t// A rejected resource drain contributes nothing and is left uncached (retried next call). Record\n\t\t\t\t// it as a structured failure so an account-wide caller can warn on the org whose projects (and\n\t\t\t\t// thus PRs/issues) are missing, instead of silently narrowing the read.\n\t\t\t\tif (drain.status !== 'fulfilled') {\n\t\t\t\t\tconst resource = resourcesWithoutProjects[i];\n\t\t\t\t\tconst failure = toCollectionScopeFailure(\n\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t\tdrain.reason,\n\t\t\t\t\t);\n\t\t\t\t\tfailures?.push(failure);\n\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, {\n\t\t\t\t\t\tcompleteness: 'partial',\n\t\t\t\t\t\tfailures: [failure],\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst { resource, result } = drain.value;\n\t\t\t\tconst projects = result.values\n\t\t\t\t\t.filter(p => p.namespace === resource.name)\n\t\t\t\t\t.map(p => ({\n\t\t\t\t\t\tid: p.id,\n\t\t\t\t\t\tname: p.name,\n\t\t\t\t\t\tresourceId: resource.id,\n\t\t\t\t\t\tresourceName: resource.name,\n\t\t\t\t\t\tkey: p.id,\n\t\t\t\t\t}));\n\n\t\t\t\tif (result.metadata != null) {\n\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, result.metadata);\n\t\t\t\t}\n\n\t\t\t\tconst metadataIncomplete = result.metadata != null && result.metadata.completeness !== 'complete';\n\t\t\t\tif (result.truncated || metadataIncomplete) {\n\t\t\t\t\t// A truncated drain is an incomplete project set; include its partial values in the current\n\t\t\t\t\t// result but don't cache it as if complete. Add a structured failure for the truncation unless\n\t\t\t\t\t// the drain already recorded a page-level failure for this resource.\n\t\t\t\t\tif (\n\t\t\t\t\t\tresult.truncated &&\n\t\t\t\t\t\t!result.metadata?.failures?.some(\n\t\t\t\t\t\t\tf => f.scope?.resourceId === resource.id && f.kind !== 'unknown',\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst failure = toCollectionScopeFailure(\n\t\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t\t\tnew Error('Project discovery was truncated before all pages were read'),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfailures?.push(failure);\n\t\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, {\n\t\t\t\t\t\t\tcompleteness: 'partial',\n\t\t\t\t\t\t\tfailures: [failure],\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tallProjects.push(...projects);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._projects!.set(`${discoveryKey}:${resource.id}`, projects);\n\t\t\t});\n\t\t}\n\n\t\tconst cachedProjects = resources.reduce<AzureProjectDescriptor[]>((projects, resource) => {\n\t\t\tconst resourceProjects = this._projects!.get(`${discoveryKey}:${resource.id}`);\n\t\t\tif (resourceProjects != null) {\n\t\t\t\tprojects.push(...resourceProjects);\n\t\t\t}\n\t\t\treturn projects;\n\t\t}, []);\n\t\tallProjects.push(...cachedProjects);\n\n\t\tconst projectsByIdentity = new Map<string, AzureProjectDescriptor>();\n\t\tfor (const project of allProjects) {\n\t\t\tconst identity = `${project.resourceId}:${project.id}`;\n\t\t\tif (!projectsByIdentity.has(identity)) {\n\t\t\t\tprojectsByIdentity.set(identity, project);\n\t\t\t}\n\t\t}\n\t\tconst values = [...projectsByIdentity.values()];\n\t\treturn resultMetadata != null ? { values: values, metadata: resultMetadata } : { values: values };\n\t}\n\n\tprivate async getRepoDescriptorsForProjects(\n\t\tsession: ProviderAuthenticationSession,\n\t\tprojects: AzureProjectDescriptor[],\n\t): Promise<Map<string, AzureRemoteRepositoryDescriptor[] | undefined>> {\n\t\tconst descriptors = new Map<string, AzureRemoteRepositoryDescriptor[] | undefined>();\n\t\tif (projects.length === 0) return descriptors;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tawait Promise.all(\n\t\t\tprojects.map(async project => {\n\t\t\t\tconst repos = (\n\t\t\t\t\tawait api.getReposForAzureProject(\n\t\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t\tproject.resourceName,\n\t\t\t\t\t\tproject.name,\n\t\t\t\t\t\tthis.getCollectionApiOptions(session, project.resourceName),\n\t\t\t\t\t)\n\t\t\t\t)?.values;\n\t\t\t\tif (repos != null && repos.length > 0) {\n\t\t\t\t\tdescriptors.set(\n\t\t\t\t\t\tproject.id,\n\t\t\t\t\t\trepos.map(r => ({\n\t\t\t\t\t\t\tid: r.id,\n\t\t\t\t\t\t\tnodeId: r.graphQLId ?? undefined,\n\t\t\t\t\t\t\tresourceName: project.resourceName,\n\t\t\t\t\t\t\tname: r.name,\n\t\t\t\t\t\t\tprojectName: project.name,\n\t\t\t\t\t\t\turl: r.webUrl ?? undefined,\n\t\t\t\t\t\t\tcloneUrlHttps: r.httpsUrl ?? undefined,\n\t\t\t\t\t\t\tcloneUrlSsh: r.sshUrl ?? undefined,\n\t\t\t\t\t\t\tkey: r.id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\treturn descriptors;\n\t}\n\n\tprotected override async getProviderOrganizationsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null) return undefined;\n\n\t\treturn {\n\t\t\tvalues: orgs.map(o => ({\n\t\t\t\tid: o.id,\n\t\t\t\tproviderId: this.id,\n\t\t\t\tname: o.name,\n\t\t\t\turl: `${this.collectionApiBaseUrl(session, o.name)}/${o.name}`,\n\t\t\t})),\n\t\t};\n\t}\n\n\tprotected override async getProviderProjectsForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg?: string,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\t// Azure is the one git host with a project tier: repos live under org (resource) → project. Enumerate\n\t\t// the user's orgs (optionally scoped to `org`), read their projects, and surface each as an org-shaped\n\t\t// entry so the ProviderBackend facade can list them uniformly.\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null) return undefined;\n\t\tif (orgs.length === 0) {\n\t\t\treturn { values: [], paging: { cursor: '{}', more: false } };\n\t\t}\n\n\t\tconst scopedOrgs = org != null ? orgs.filter(o => o.name === org || o.id === org) : orgs;\n\t\tif (scopedOrgs.length === 0) return { values: [] };\n\n\t\tconst projects = await this.getProviderProjectsForResources(session, scopedOrgs);\n\t\tif (projects.values.length === 0 && projects.metadata == null) return { values: [] };\n\n\t\treturn {\n\t\t\tvalues: projects.values.map(p => ({\n\t\t\t\tid: p.id,\n\t\t\t\tproviderId: this.id,\n\t\t\t\tname: p.name,\n\t\t\t\torg: p.resourceName,\n\t\t\t\turl: `${this.collectionApiBaseUrl(session, p.resourceName)}/${p.resourceName}/${p.name}`,\n\t\t\t})),\n\t\t\t...(projects.metadata != null ? { metadata: projects.metadata } : {}),\n\t\t};\n\t}\n\n\t/**\n\t * With `options.project`, returns one page of that project's repos (follow `paging.cursor` to page).\n\t * Without a project it fans out across every project under `org` and returns them all at once — there's\n\t * no single cursor to page a parallel merge — skipping any project that fails to list rather than\n\t * failing the whole org. If any successful project drain hits the defensive page backstop, the merged\n\t * result is marked `truncated` without exposing a synthetic cursor.\n\t */\n\tprotected override async getProviderRepositoriesForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg: string,\n\t\toptions?: { project?: string; cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst apiOptions = this.getCollectionApiOptions(session, org);\n\n\t\tif (options?.project) {\n\t\t\treturn api.getReposForAzureProject(tokenWithInfo, org, options.project, {\n\t\t\t\t...apiOptions,\n\t\t\t\tcursor: options.cursor,\n\t\t\t});\n\t\t}\n\n\t\tconst orgDescriptor = (await this.getProviderResourcesForUser(session))?.find(o => o.name === org);\n\t\tif (orgDescriptor == null) return undefined;\n\n\t\tconst discoveryFailures: CollectionScopeFailure[] = [];\n\t\tconst projects = await this.getProviderProjectsForResources(session, [orgDescriptor], false, discoveryFailures);\n\t\t// An empty result is only proven-empty when discovery itself succeeded; a rejected project-discovery\n\t\t// leaves the repo set unknowable, so surface the discovery metadata rather than publishing a hole as a\n\t\t// complete list.\n\t\tif (projects.values.length === 0) {\n\t\t\treturn { values: [], metadata: projects.metadata };\n\t\t}\n\n\t\tlet repoMetadata: CollectionMetadata | undefined;\n\t\tconst results = await Promise.allSettled(\n\t\t\tprojects.values.map(p =>\n\t\t\t\tcollectProviderPagedResult(\n\t\t\t\t\tcursor =>\n\t\t\t\t\t\tapi.getReposForAzureProject(tokenWithInfo, org, p.name, { ...apiOptions, cursor: cursor }),\n\t\t\t\t\t20,\n\t\t\t\t\t{ providerId: this.id, resourceId: org, projectId: p.name },\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst values: ProviderRepository[] = [];\n\t\tlet truncated = false;\n\t\tfor (const result of results) {\n\t\t\t// With a per-project scope, collectProviderPagedResult catches page-level failures itself and returns\n\t\t\t// them as metadata rather than rejecting. A rejected promise here is an unexpected internal error.\n\t\t\tif (result.status !== 'fulfilled') {\n\t\t\t\ttruncated = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvalues.push(...result.value.values);\n\t\t\tif (result.value.metadata != null) {\n\t\t\t\trepoMetadata = mergeCollectionMetadata(repoMetadata, result.value.metadata);\n\t\t\t}\n\t\t\ttruncated ||= result.value.truncated === true;\n\t\t}\n\n\t\tconst metadata = mergeCollectionMetadata(repoMetadata, projects.metadata);\n\t\treturn {\n\t\t\tvalues: values,\n\t\t\t...(metadata != null ? { metadata: metadata } : {}),\n\t\t\t...(truncated || (metadata != null && metadata.completeness !== 'complete') ? { truncated: true } : {}),\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\tconst api = await this.getProvidersApi();\n\t\tif (pr.refs == null || pr.project == null) return false;\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst apiOptions = this.getCollectionApiOptions(session, pr.repository.owner);\n\n\t\ttry {\n\t\t\tconst merged = await api.mergePullRequest(tokenWithInfo, pr, {\n\t\t\t\t...options,\n\t\t\t\t...apiOptions,\n\t\t\t});\n\t\t\treturn merged;\n\t\t} catch (ex) {\n\t\t\tthis.showMergeErrorMessage(ex);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprotected showMergeErrorMessage(ex: Error): void {\n\t\tthis.ctx.hooks?.ui?.onError?.(\n\t\t\t`${ex.message}. Check branch policies, and ensure you have the necessary permissions to merge the pull request.`,\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<UnidentifiedAuthor | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tgetAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\toptions,\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\t_session: AuthenticationSession,\n\t\t_repo: AzureRepositoryDescriptor,\n\t\t_email: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo) },\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t\ttype: undefined | IssueOrPullRequestType,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tid,\n\t\t\t{\n\t\t\t\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\t\ttype: type,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\tsession: ProviderAuthenticationSession,\n\t\tproject: AzureProjectInputDescriptor,\n\t\tid: string,\n\t): Promise<Issue | undefined> {\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\tif (user?.username == null) return undefined;\n\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\tconst projects = await this.getProviderProjectsForResources(session, orgs);\n\t\tif (projects.values.length === 0) return undefined;\n\n\t\tconst matchingProject = projects.values.find(p => p.resourceName === project.owner && p.name === project.name);\n\t\tif (matchingProject == null) return undefined;\n\n\t\treturn (await this.authenticationService.apis.azure)?.getIssue(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tmatchingProject,\n\t\t\tid,\n\t\t\t{\n\t\t\t\tbaseUrl: this.collectionApiBaseUrl(session, matchingProject.resourceName),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tbranch: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tgetAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\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; converted\n\t * like the repo-scoped list rows. Not through {@link getProviderIssue}: that read swallows every failure but a\n\t * rejected credential into `undefined`, discovers every project of every organization first, and converts\n\t * differently from the list reads.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tif (c.project == null) throw new Error(`Azure DevOps needs a project to read work item ${c.number}`);\n\n\t\t\tconst issue = await api.getAzureWorkItem(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, project: c.project },\n\t\t\t\tc.number,\n\t\t\t\tthis.getCollectionApiOptions(session, c.owner),\n\t\t\t);\n\t\t\tif (issue == null) return undefined;\n\n\t\t\tconst shape = toIssueShape(issue, this, { projection: 'batch' });\n\t\t\tif (shape == null) {\n\t\t\t\tthrow new Error(`Azure DevOps returned work item ${c.number} without a URL or change date`);\n\t\t\t}\n\n\t\t\treturn shape;\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; converted\n\t * like the repo-scoped list rows — not through {@link fromAzureProviderPullRequest}, which only the\n\t * account-wide searches use.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst viewerFor = this.getOrganizationViewers(session, options?.currentAccount);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst pr = await api.getPullRequestForRepo(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, name: c.repo, project: c.project },\n\t\t\t\tc.number,\n\t\t\t\t{ ...this.getCollectionApiOptions(session, c.owner), includeRemoteInfo: true },\n\t\t\t);\n\t\t\tif (pr == null) return undefined;\n\n\t\t\treturn fromProviderPullRequest(pr, this, { currentAccount: await viewerFor(c.owner), projection: 'batch' });\n\t\t});\n\t}\n\n\t/**\n\t * The cheap check behind the batch issue read's etags: one request per organization, project and\n\t * {@link azureWorkItemsEtagFieldsMaxIds} distinct ids, where {@link getProviderIssuesBatch} sends one per target,\n\t * asking only for each work item's change state. A request that throws rejects only its own targets' slots, with\n\t * its error classified as the full read's would be.\n\t *\n\t * Never proves an absence. Azure silently leaves out every id it can't return, whether missing, hidden or failing,\n\t * so such a target's slot is rejected and the full read, whose not-found does prove an absence, decides. So is a\n\t * work item in another project, which the full read fails. When no target was answered and nothing failed, the\n\t * check declines instead, so a batch of only such ids costs a full read, not a failure.\n\t *\n\t * A work item has no reactions, and its full row no count, so `'reactions'` reads nothing and costs nothing.\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\t_options: { etagIncludes?: readonly IssueEtagInclude[] },\n\t\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined> {\n\t\tconst slots = new Array<PromiseSettledResult<IssueEtagFields | undefined>>(coordinates.length);\n\t\tlet answered = false;\n\t\tlet failed = false;\n\n\t\t// Each organization and project's distinct ids, with the targets asking for each.\n\t\tconst byProject = new Map<string, { owner: string; project: string; ids: Map<number, number[]> }>();\n\t\tfor (const [index, c] of coordinates.entries()) {\n\t\t\tif (c.project == null) {\n\t\t\t\t// Required as the full read requires it, so a check never answers for a target the full read refuses.\n\t\t\t\tslots[index] = {\n\t\t\t\t\tstatus: 'rejected',\n\t\t\t\t\treason: new Error(`Azure DevOps needs a project to read work item ${c.number}`),\n\t\t\t\t};\n\t\t\t\tfailed = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst key = JSON.stringify([c.owner, c.project]);\n\t\t\tlet group = byProject.get(key);\n\t\t\tif (group == null) {\n\t\t\t\tgroup = { owner: c.owner, project: c.project, ids: new Map() };\n\t\t\t\tbyProject.set(key, group);\n\t\t\t}\n\n\t\t\tlet indices = group.ids.get(c.number);\n\t\t\tif (indices == null) {\n\t\t\t\tindices = [];\n\t\t\t\tgroup.ids.set(c.number, indices);\n\t\t\t}\n\t\t\tindices.push(index);\n\t\t}\n\n\t\tconst requests = [...byProject.values()].flatMap(group =>\n\t\t\tchunk([...group.ids], azureWorkItemsEtagFieldsMaxIds).map(entries => ({ ...group, entries: entries })),\n\t\t);\n\t\tif (!requests.length) return slots;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst answers = await mapSettledBounded(requests, providerFanOutConcurrency, r =>\n\t\t\tapi.getAzureWorkItemsEtagFields(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: r.owner, project: r.project },\n\t\t\t\tr.entries.map(([id]) => id),\n\t\t\t\tthis.getCollectionApiOptions(session, r.owner),\n\t\t\t),\n\t\t);\n\n\t\tfor (const [i, answer] of answers.entries()) {\n\t\t\tconst { project, entries } = requests[i];\n\t\t\tif (answer.status === 'rejected') {\n\t\t\t\tfailed = true;\n\t\t\t\tfor (const [, indices] of entries) {\n\t\t\t\t\tfor (const index of indices) {\n\t\t\t\t\t\tslots[index] = answer;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// By id, never by position: Azure leaves out the ids it can't return.\n\t\t\tconst workItems = new Map<unknown, AzureWorkItemResponse>();\n\t\t\tfor (const workItem of answer.value) {\n\t\t\t\tworkItems.set(workItem.id, workItem);\n\t\t\t}\n\n\t\t\tfor (const [id, indices] of entries) {\n\t\t\t\tconst workItem = workItems.get(id);\n\t\t\t\tlet slot: PromiseSettledResult<IssueEtagFields | undefined>;\n\t\t\t\tif (workItem == null) {\n\t\t\t\t\tslot = { status: 'rejected', reason: new Error(`Azure DevOps did not return work item ${id}`) };\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tslot = { status: 'fulfilled', value: toAzureWorkItemEtagFields(workItem, project) };\n\t\t\t\t\t\tanswered = true;\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tslot = { status: 'rejected', reason: ex };\n\t\t\t\t\t\tfailed = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tslots[index] = slot;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn answered || failed ? slots : undefined;\n\t}\n\n\t/**\n\t * The cheap check behind the batch pull request read's etags: still one request per target, as Azure DevOps has\n\t * no read of several pull requests by id, but only the one {@link getProviderPullRequestsBatch} sends first —\n\t * not the repository read provider-apis adds to it for clone URLs, once per pull request. Settled per target,\n\t * with absence proven by the same not-found rule as the full read.\n\t *\n\t * Azure DevOps reports no update time, so a full row's `updatedDate` is its close time, else its creation time,\n\t * and moves only when it closes. Its etag therefore adds a `revision` of the fields that change without it —\n\t * title, description, target branch, and every reviewer and their vote — read off the same response at no extra\n\t * cost. It sees a pull request's state, draft flag, head commit and those fields, and, when included, its\n\t * mergeability and its required reviewers' review decision; never a comment or a label, which its full row\n\t * doesn't carry either. A full row carries no check rollup, so the `checks` include adds nothing and costs nothing.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\t// Required as provider-apis requires it for the full read.\n\t\t\tif (c.project == null) throw new Error(`Azure DevOps needs a project to read pull request ${c.number}`);\n\n\t\t\tconst pr = await api.getAzurePullRequest(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, project: c.project, name: c.repo },\n\t\t\t\tc.number,\n\t\t\t\tthis.getCollectionApiOptions(session, c.owner),\n\t\t\t);\n\t\t\treturn pr != null ? toAzurePullRequestEtagFields(pr, etagIncludes) : undefined;\n\t\t});\n\t}\n\n\t/**\n\t * Two steps, because provider-apis has no source-branch filter: a direct Azure read finds each branch's matching\n\t * pull request ids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is\n\t * the one `getPullRequestsBatch` returns for that pull request, `url` and `authoredByMe` included.\n\t *\n\t * Serves only a branch in the base repository: an Azure DevOps fork shares its organization and is identified\n\t * by repository, so `headOwner` can't name one — the manager read refuses one that names a different owner.\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 api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\tconst found = await mapSettledBounded(targets, providerFanOutConcurrency, async t => {\n\t\t\tif (t.project == null || t.headOwner != null) {\n\t\t\t\tthrow new Error(`Azure DevOps needs a project and no head owner to find ${t.branch}'s pull requests`);\n\t\t\t}\n\n\t\t\t// One past the cap, since Azure reports no total to tell a full page from a truncated one.\n\t\t\tconst rows = await api.getAzurePullRequestsForBranch(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: t.owner, project: t.project, name: t.repo },\n\t\t\t\tt.branch,\n\t\t\t\toptions.limit + 1,\n\t\t\t\tthis.getCollectionApiOptions(session, t.owner),\n\t\t\t);\n\t\t\tif (rows == null) return { numbers: [], truncated: false };\n\n\t\t\tconst ref = `refs/heads/${t.branch}`;\n\t\t\tconst { values, truncated } = selectBranchPullRequests(rows, {\n\t\t\t\tmatchesHead: pr => pr.sourceRefName === ref && pr.forkSource == null,\n\t\t\t\t// Azure reports no update time; this is the one the batch read's rows carry.\n\t\t\t\tupdatedAt: pr => Date.parse(pr.closedDate || pr.creationDate),\n\t\t\t\tmap: pr => pr.pullRequestId,\n\t\t\t\tlimit: options.limit,\n\t\t\t\tmore: rows.length > options.limit,\n\t\t\t});\n\t\t\treturn { numbers: values, truncated: truncated };\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\tprotected override async getProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresource: AzureRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.getPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tresource.owner,\n\t\t\tresource.project ?? resource.name,\n\t\t\tid,\n\t\t\t{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), resource) },\n\t\t);\n\t}\n\n\tprotected override getProviderPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\t\treturn getAzurePullRequestIdentityFromMaybeUrl(search, this.id);\n\t}\n\n\tpublic override async getRepoInfo(repo: {\n\t\towner: string;\n\t\tname: string;\n\t\tproject?: string;\n\t\tvirtualDirectory?: string;\n\t\tconnectionId?: string;\n\t}): Promise<ProviderRepository | undefined> {\n\t\tconst identity = getAzureRepositoryIdentity(repo);\n\t\tif (identity.projectName == null) return undefined;\n\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\tconst { tokenWithInfo, options } = this.getApiOptions(session);\n\t\treturn api.getRepo(tokenWithInfo, identity.resourceName, identity.repositoryName, identity.projectName, {\n\t\t\t...options,\n\t\t\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo) },\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (repos != null) {\n\t\t\t// TODO: implement repos version\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Legacy array-returning path (Launchpad/focus view): the account-wide read, mapped to the normalized model.\n\t\t// Its metadata (partial/failures) isn't surfaced here because this path's return type has no warning channel.\n\t\tconst result = await this.getProviderMyPullRequestsForUser(session, {\n\t\t\tstate: options?.state != null ? [options.state] : undefined,\n\t\t});\n\t\tif (result == null) return undefined;\n\n\t\t// Both served from the discovery caches the read above just filled.\n\t\tconst projects = (\n\t\t\tawait this.getProviderProjectsForResources(session, (await this.getProviderResourcesForUser(session)) ?? [])\n\t\t).values;\n\t\tif (projects.length === 0) return undefined;\n\n\t\tconst repoDescriptors = [\n\t\t\t...((await this.getRepoDescriptorsForProjects(session, projects)) ?? new Map()).values(),\n\t\t]\n\t\t\t.filter(r => r != null)\n\t\t\t.flat();\n\t\treturn result.values.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects, 'search'));\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\tconst api = await this.getProvidersApi();\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\t// Azure routes authorLogin/assigneeLogins to `searchCriteria.creatorId`/`reviewerId`, which require the\n\t\t// identity GUID, not the display name — matching the repo-scoped path in gitHostIntegration.ts. Using\n\t\t// `username` here would match nothing and return zero PRs. The GUID is resolved per organization below\n\t\t// (see `getFilterUserId`); this only checks there is a user at all.\n\t\tif (user?.id == null) return undefined;\n\n\t\t// Azure PRs are org + project scoped: enumerate the user's orgs and their projects, then read authored\n\t\t// and assigned PRs across all of them. Return the raw provider shape (not the normalized model) so the\n\t\t// ProviderBackend surface stays uniform with the other providers.\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\t// Structured per-scope failures from BOTH project discovery (a whole org dropped) and the per-project PR\n\t\t// drains, so the facade warns on the failed scope + sets `fetchFailed` instead of silently narrowing.\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tconst projects = await this.getProviderProjectsForResources(session, orgs, false, failures);\n\t\tif (projects.values.length === 0) {\n\t\t\t// Project discovery itself was incomplete (e.g. a truncated org); surface the metadata so the facade\n\t\t\t// can warn and set fetchFailed rather than reporting an empty account.\n\t\t\tconst incomplete = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\t\treturn {\n\t\t\t\tvalues: [],\n\t\t\t\tpaging: { cursor: '{}', more: false, truncated: incomplete || undefined },\n\t\t\t\t...(projects.metadata != null ? { metadata: projects.metadata } : {}),\n\t\t\t};\n\t\t}\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst states = toProviderPullRequestStates(options?.state);\n\t\tconst maxPagesPerProject = 20;\n\n\t\t// Drain each project fully (numbered pages) for both the authored and assigned reads. Azure has no\n\t\t// single cross-project cursor, so the aggregate is one page; `truncated` is set only if a project hit\n\t\t// the backstop with more pages remaining.\n\t\tlet truncated = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\t// Drain one project's numbered pages, returning its PRs and any per-page failure. Returns per-project\n\t\t// (not mutating shared state) so the fan-out below can be settled independently: one project's read\n\t\t// failure must not discard every other project's already-drained PRs.\n\t\tconst drainProject = async (\n\t\t\tproject: { namespace: string; project: string },\n\t\t\tscope: CollectionScope,\n\t\t\tfilter: {\n\t\t\t\tauthorLogin?: string;\n\t\t\t\tassigneeLogins?: string[];\n\t\t\t\treviewerId?: string;\n\t\t\t\tstates?: GitPullRequestState[];\n\t\t\t},\n\t\t): Promise<{ prs: ProviderPullRequest[]; projectIdentity: string; failure?: CollectionScopeFailure }> => {\n\t\t\tconst collected: ProviderPullRequest[] = [];\n\t\t\tconst projectIdentity = `${project.namespace}/${project.project}`;\n\t\t\tlet page: number | undefined;\n\t\t\tfor (let i = 0; i < maxPagesPerProject; i++) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await api.getPullRequestsForAzureProject(tokenWithInfo, project, {\n\t\t\t\t\t\t// Addressed below the project's own collection, applied once even when the configured address\n\t\t\t\t\t\t// already names it (the request appends the collection as `namespace`).\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, project.namespace),\n\t\t\t\t\t\t// A reviewer read narrows the states itself (see `toAzureReviewerReads`).\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t\tpage: page,\n\t\t\t\t\t});\n\t\t\t\t\tif (result == null) {\n\t\t\t\t\t\tif (page == null) break;\n\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\t\tfailure: toCollectionScopeFailure(\n\t\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\t\tnew Error('Azure DevOps returned no page after advertising a continuation'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tcollected.push(...result.data);\n\t\t\t\t\tif (!result.hasMore) break;\n\t\t\t\t\tif (result.nextPage == null || result.nextPage === page) {\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\t\tfailure: toCollectionScopeFailure(\n\t\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\t\tnew Error('Azure DevOps returned no advancing pull request continuation'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tpage = result.nextPage;\n\t\t\t\t\tif (i === maxPagesPerProject - 1) {\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t}\n\t\t\t\t} catch (ex) {\n\t\t\t\t\t// A page failure after the first page leaves the already-drained prefix intact; record the\n\t\t\t\t\t// failure at the project scope instead of re-throwing and discarding the prefix.\n\t\t\t\t\ttruncated = true;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\tfailure: toCollectionScopeFailure(scope, ex),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { prs: collected, projectIdentity: projectIdentity };\n\t\t};\n\n\t\t// Settle per-project failures instead of rejecting the whole sweep. `drainProject` already catches its own\n\t\t// page-level failures, so the structured failure (attributed to that project) is preserved rather than\n\t\t// re-thrown — re-throwing an auth/rate-limit rejection would discard every other project's already-drained\n\t\t// PRs. Auth/rate-limit stay actionable through the failure's kind (the facade maps it to an `auth`/`rate-limit`\n\t\t// warning + `fetchFailed`), matching the SDK's model. `failures` was declared above so project-discovery\n\t\t// failures and per-project drain failures share it.\n\t\tconst requested = options?.filters?.length ? new Set(options.filters) : undefined;\n\t\tconst wantAuthored = requested == null || requested.has(PullRequestFilter.Author);\n\t\t// Azure has no assignee concept distinct from reviewer. Both neutral relationships map to reviewerId.\n\t\tconst wantReviewed =\n\t\t\trequested == null ||\n\t\t\trequested.has(PullRequestFilter.Assignee) ||\n\t\t\trequested.has(PullRequestFilter.ReviewRequested);\n\t\tconst userIds = new Map<string, string | undefined>();\n\t\tconst identityFailures = new Map<string, unknown>();\n\t\tfor (const org of uniqueAzureNames(projects.values.map(p => p.resourceName))) {\n\t\t\ttry {\n\t\t\t\tuserIds.set(org.toLowerCase(), await this.getFilterUserId(session, org));\n\t\t\t} catch (ex) {\n\t\t\t\tthrowIfCallerContractError(ex);\n\t\t\t\tif (ex instanceof AuthenticationError) throw ex;\n\n\t\t\t\tidentityFailures.set(org.toLowerCase(), ex);\n\t\t\t}\n\t\t}\n\t\tconst groups = wantReviewed\n\t\t\t? await this.getReviewerGroupsByOrganization(session, projects.values, userIds, failures)\n\t\t\t: undefined;\n\t\tif (groups?.incomplete) {\n\t\t\ttruncated = true;\n\t\t}\n\t\tconst outcomes = await Promise.all(\n\t\t\tprojects.values.flatMap(p => {\n\t\t\t\tconst project = { namespace: p.resourceName, project: p.name };\n\t\t\t\tconst scope = { providerId: this.id, resourceId: p.resourceId, projectId: p.name };\n\t\t\t\tconst userId = userIds.get(p.resourceName.toLowerCase());\n\t\t\t\tif (userId == null) {\n\t\t\t\t\tfailures.push(\n\t\t\t\t\t\ttoCollectionScopeFailure(\n\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\tidentityFailures.get(p.resourceName.toLowerCase()) ??\n\t\t\t\t\t\t\t\tnew Error('The current user could not be resolved here'),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\ttruncated = true;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst drains = [];\n\t\t\t\tif (wantAuthored) {\n\t\t\t\t\tdrains.push(drainProject(project, scope, { authorLogin: userId }));\n\t\t\t\t}\n\t\t\t\tif (wantReviewed) {\n\t\t\t\t\tconst groupIds = groups?.byOrganization.get(p.resourceName.toLowerCase()) ?? new Set<string>();\n\t\t\t\t\tfor (const { filter, keep } of toAzureReviewerReads(userId, groupIds, states)) {\n\t\t\t\t\t\tdrains.push(\n\t\t\t\t\t\t\tdrainProject(project, scope, filter).then(o =>\n\t\t\t\t\t\t\t\tkeep != null ? { ...o, prs: o.prs.filter(keep) } : o,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn drains;\n\t\t\t}),\n\t\t);\n\n\t\t// Azure's `pullRequestId` is not account-global. Prefer repository + PR id, then the org-qualified URL.\n\t\t// If neither is available, preserve the row instead of collapsing unrelated repositories by numeric id.\n\t\tconst prsByIdentity = new Map<string, ProviderPullRequest>();\n\t\tfor (const outcome of outcomes) {\n\t\t\tif (outcome.failure != null) {\n\t\t\t\tfailures.push(outcome.failure);\n\t\t\t}\n\t\t\tfor (const pr of outcome.prs) {\n\t\t\t\tconst key =\n\t\t\t\t\tgetProviderPullRequestIdentity(pr) ?? `project:${outcome.projectIdentity}:pull-request:${pr.id}`;\n\t\t\t\tif (!prsByIdentity.has(key)) {\n\t\t\t\t\tprsByIdentity.set(key, pr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst metadata: CollectionMetadata | undefined = mergeCollectionMetadata(\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t\tprojects.metadata,\n\t\t);\n\n\t\tconst groupIds = groups?.groupIds ?? new Set<string>();\n\t\treturn {\n\t\t\tvalues: Array.from(prsByIdentity.values(), pr => markMyGroupReviews(pr, groupIds)),\n\t\t\tpaging: { cursor: '{}', more: false, truncated: truncated || undefined },\n\t\t\tmetadata: metadata,\n\t\t};\n\t}\n\n\t/**\n\t * Per organization (keyed by its lowercased name), every group the user is in (see {@link getReviewerGroupIds}),\n\t * and their union. An organization whose groups can't be read gets none and is recorded in `failures`, with the\n\t * read reported `incomplete`: what only its groups review is missing, while what names the user is still read.\n\t * Organizations whose user could not be resolved are left out; the read already reports them.\n\t */\n\tprivate async getReviewerGroupsByOrganization(\n\t\tsession: ProviderAuthenticationSession,\n\t\tprojects: readonly AzureProjectDescriptor[],\n\t\tuserIds: ReadonlyMap<string, string | undefined>,\n\t\tfailures: CollectionScopeFailure[],\n\t): Promise<{ byOrganization: Map<string, Set<string>>; groupIds: Set<string>; incomplete: boolean }> {\n\t\tconst byOrganization = new Map<string, Set<string>>();\n\t\tconst groupIds = new Set<string>();\n\t\tlet incomplete = false;\n\t\tawait Promise.all(\n\t\t\tuniqueAzureNames(projects.map(p => p.resourceName)).map(async org => {\n\t\t\t\tconst userId = userIds.get(org.toLowerCase());\n\t\t\t\tif (userId == null) return;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst ids = await this.getReviewerGroupIds(session, org, userId);\n\t\t\t\t\tbyOrganization.set(org.toLowerCase(), ids);\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tgroupIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tconst resourceId = projects.find(p => sameAzureName(p.resourceName, org))!.resourceId;\n\t\t\t\t\tfailures.push(toCollectionScopeFailure({ providerId: this.id, resourceId: resourceId }, ex));\n\t\t\t\t\tincomplete = true;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\treturn { byOrganization: byOrganization, groupIds: groupIds, incomplete: incomplete };\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\t// `getProviderProjectsForResources` returns a collection result ({ values, metadata }); this search\n\t\t// path only needs the resolved projects, so read `.values`.\n\t\tconst projects = (await this.getProviderProjectsForResources(session, orgs)).values;\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\tif (projects.length === 0) return undefined;\n\n\t\tconst repoDescriptorsByProject = await this.getRepoDescriptorsForProjects(session, projects);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst repoDescriptors = [...repoDescriptorsByProject.values()].filter(r => r != null).flat();\n\t\tconst requestedRepos = repos?.map(getAzureRepositoryIdentity);\n\t\tconst repoInputs =\n\t\t\trequestedRepos == null\n\t\t\t\t? undefined\n\t\t\t\t: repoDescriptors.filter(r =>\n\t\t\t\t\t\trequestedRepos.some(\n\t\t\t\t\t\t\trepo =>\n\t\t\t\t\t\t\t\trepo.resourceName === r.resourceName &&\n\t\t\t\t\t\t\t\trepo.repositoryName === r.name &&\n\t\t\t\t\t\t\t\t(repo.projectName == null || repo.projectName === r.projectName),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\tif (repoInputs?.length === 0) return [];\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst states = toProviderPullRequestStates(options?.include);\n\t\tconst searchScopes: { project: { namespace: string; project: string }; repo?: ProviderRepoInput }[] =\n\t\t\trepoInputs != null\n\t\t\t\t? repoInputs.flatMap(repo =>\n\t\t\t\t\t\trepo.projectName == null\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tproject: { namespace: repo.resourceName, project: repo.projectName },\n\t\t\t\t\t\t\t\t\t\trepo: {\n\t\t\t\t\t\t\t\t\t\t\tid: repo.id,\n\t\t\t\t\t\t\t\t\t\t\tname: repo.name,\n\t\t\t\t\t\t\t\t\t\t\tnamespace: repo.resourceName,\n\t\t\t\t\t\t\t\t\t\t\tproject: repo.projectName,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t)\n\t\t\t\t: projects.map(project => ({\n\t\t\t\t\t\tproject: { namespace: project.resourceName, project: project.name },\n\t\t\t\t\t}));\n\n\t\tconst providerPullRequests = flatSettledResultsOrThrow(\n\t\t\tawait mapSettledBounded(searchScopes, providerFanOutConcurrency, async scope => {\n\t\t\t\tconst values: ProviderPullRequest[] = [];\n\t\t\t\tlet page: number | undefined;\n\t\t\t\tfor (let i = 0; i < 20; i++) {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\tconst result = await api.getPullRequestsForAzureProject(tokenWithInfo, scope.project, {\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, scope.project.namespace),\n\t\t\t\t\t\tpage: page,\n\t\t\t\t\t\trepo: scope.repo,\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t});\n\t\t\t\t\tif (result == null) break;\n\n\t\t\t\t\tvalues.push(...result.data);\n\t\t\t\t\tif (!result.hasMore || result.nextPage == null) break;\n\n\t\t\t\t\tpage = result.nextPage;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}),\n\t\t);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\treturn [...new Map(providerPullRequests.map(pr => [pr.url ?? `${pr.repository.id}:${pr.id}`, pr])).values()]\n\t\t\t.filter(pr => providerPullRequestMatchesSearch(pr, searchQuery))\n\t\t\t.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects, 'text-search'));\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\treturn (await this.searchProviderMyIssuesWithTruncation(session, repos))?.values;\n\t}\n\n\t/**\n\t * Account-wide \"my issues\" for Azure = the user's authored + assigned work items across every project of\n\t * every org. Azure's issue read is numbered-page, so each (project × filter) read is drained to exhaustion\n\t * (bounded by a defensive per-read backstop). Unlike a silent `flatSettled`, a project read that was\n\t * truncated by the backstop or rejected outright is recorded as `truncated`, so the facade reports an\n\t * incomplete read instead of publishing a partial list as complete.\n\t *\n\t * `searchOptions.org`/`.project` narrow the fan-out server-side (each drain is already a per-project read,\n\t * so scoping just selects which projects to drain). Without this there was no way to ask for \"work items in\n\t * project P\": a consumer had to filter the account-wide page client-side, which desynchronizes the filtered\n\t * `items` from the `hasMore`/`currentPage` of the pre-filter read — a project-less page reads as \"no issues\"\n\t * while `hasMore` is still true.\n\t */\n\tprotected override async searchProviderMyIssuesWithTruncation(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_resources?: ResourceDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\tsearchOptions?: SearchMyIssuesOptions,\n\t): Promise<AccountWideIssuesResult | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\tif (user?.username == null) return undefined;\n\n\t\tconst allOrgs = await this.getProviderResourcesForUser(session);\n\t\tif (allOrgs == null) return undefined;\n\t\tif (allOrgs.length === 0) return { values: [], truncated: false };\n\n\t\t// Scope by org first so project discovery only fans out over the requested account. An org filter that\n\t\t// matches nothing is an empty-but-successful read, not an unsupported one: returning `undefined` here\n\t\t// would be reported as \"account-wide issue search is not supported by this provider\".\n\t\tconst orgs =\n\t\t\tsearchOptions?.org != null ? allOrgs.filter(o => azureResourceMatches(o, searchOptions.org!)) : allOrgs;\n\t\tif (orgs.length === 0) return { values: [], truncated: false };\n\n\t\t// Structured per-scope failures from BOTH project discovery (a whole org dropped) and the per-project\n\t\t// issue drains, so the facade warns on the failed scope + sets `fetchFailed` instead of narrowing silently.\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tconst discovered = await this.getProviderProjectsForResources(session, orgs, false, failures);\n\t\tconst projects =\n\t\t\tsearchOptions?.project != null\n\t\t\t\t? {\n\t\t\t\t\t\t...discovered,\n\t\t\t\t\t\tvalues: discovered.values.filter(p => azureResourceMatches(p, searchOptions.project!)),\n\t\t\t\t\t}\n\t\t\t\t: discovered;\n\t\tif (projects.values.length === 0) {\n\t\t\t// An explicitly-scoped read that found no matching project is an empty SUCCESS: `undefined` here is\n\t\t\t// reported as \"account-wide issue search is not supported by this provider\", which would send the\n\t\t\t// consumer down a repo-scoped fallback for what is simply an empty scope. Only an incomplete discovery\n\t\t\t// (which may itself have dropped the requested project) is truncated, and its metadata is forwarded so\n\t\t\t// the facade still warns on the failed scope.\n\t\t\treturn projects.metadata != null\n\t\t\t\t? {\n\t\t\t\t\t\tvalues: [],\n\t\t\t\t\t\ttruncated: projects.metadata.completeness !== 'complete',\n\t\t\t\t\t\tmetadata: projects.metadata,\n\t\t\t\t\t}\n\t\t\t\t: { values: [], truncated: false };\n\t\t}\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\t// Drain one (project × filter) read fully, threading the provider's paging cursor. The scope is passed so\n\t\t// a page-level failure preserves the already-drained prefix and records a structured failure instead of\n\t\t// re-throwing.\n\t\tconst drain = async (\n\t\t\tp: AzureProjectDescriptor,\n\t\t\tfilter: { assigneeLogins?: string[]; authorLogin?: string },\n\t\t): Promise<{\n\t\t\tissues: IssueShape[];\n\t\t\tprojectKey: string;\n\t\t\ttruncated: boolean;\n\t\t\tmetadata?: CollectionMetadata;\n\t\t}> => {\n\t\t\tconst result = await collectProviderPagedResult(\n\t\t\t\tcursor =>\n\t\t\t\t\tapi.getIssuesForAzureProject(tokenWithInfo, p.resourceName, p.name, {\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, p.resourceName),\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tsort: searchOptions?.sort,\n\t\t\t\t\t}),\n\t\t\t\t20,\n\t\t\t\t{ providerId: this.id, resourceId: p.resourceId, projectId: p.name },\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tissues: result.values.map(i => fromProviderIssue(i, this, { project: p, projection: 'account' })),\n\t\t\t\t// Azure work-item ids are organization-scoped. Include both org and project so the\n\t\t\t\t// assigned/authored passes dedupe the same item without collapsing another org's item.\n\t\t\t\tprojectKey: `${p.resourceId}:${p.id}`,\n\t\t\t\ttruncated: result.truncated ?? false,\n\t\t\t\tmetadata: result.metadata,\n\t\t\t};\n\t\t};\n\n\t\t// `includeAllAssignees` broadens to every issue in each project (any assignee, any author), so a single\n\t\t// unfiltered drain per project replaces the assigned+authored pair — an unfiltered assignee drain already\n\t\t// subsumes the authored one.\n\t\t//\n\t\t// `filters` narrows the other way: unfiltered, \"my issues\" here is assigned ∪ authored, which is wider than\n\t\t// `assignee:@me`. Selecting the drains is the only correct place to narrow — dropping authored-only items\n\t\t// from the returned page would leave them counted in the per-project paging that produced it.\n\t\tconst filters = searchOptions?.filters;\n\t\tconst wantAssigned = !filters?.length || filters.includes(IssueFilter.Assignee);\n\t\tconst wantAuthored = !filters?.length || filters.includes(IssueFilter.Author);\n\t\tconst outcomes = await Promise.all(\n\t\t\tprojects.values.flatMap(p => {\n\t\t\t\tif (searchOptions?.includeAllAssignees) return [drain(p, {})];\n\n\t\t\t\tconst drains = [];\n\t\t\t\tif (wantAssigned) {\n\t\t\t\t\tdrains.push(drain(p, { assigneeLogins: [user.username!] }));\n\t\t\t\t}\n\t\t\t\tif (wantAuthored) {\n\t\t\t\t\tdrains.push(drain(p, { authorLogin: user.username! }));\n\t\t\t\t}\n\t\t\t\treturn drains;\n\t\t\t}),\n\t\t);\n\n\t\tconst issuesById = new Map<string, IssueShape>();\n\t\tlet truncated = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\tlet drainMetadata: CollectionMetadata | undefined;\n\t\tfor (const outcome of outcomes) {\n\t\t\tif (outcome.truncated) {\n\t\t\t\ttruncated = true;\n\t\t\t}\n\t\t\tif (outcome.metadata != null) {\n\t\t\t\tdrainMetadata = mergeCollectionMetadata(drainMetadata, outcome.metadata);\n\t\t\t}\n\n\t\t\tfor (const issue of outcome.issues) {\n\t\t\t\tconst key = `${outcome.projectKey}:${issue.nodeId ?? issue.id}`;\n\t\t\t\tif (!issuesById.has(key)) {\n\t\t\t\t\tissuesById.set(key, issue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst metadata: CollectionMetadata | undefined = mergeCollectionMetadata(\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t\tmergeCollectionMetadata(drainMetadata, projects.metadata),\n\t\t);\n\n\t\treturn { values: [...issuesById.values()], truncated: truncated, metadata: metadata };\n\t}\n\n\tprotected override async providerOnConnect(): Promise<void> {\n\t\tif (this._session == null) return;\n\n\t\tconst discoveryKey = this.discoveryKey(this._session);\n\n\t\tconst canHydrateStoredProjects = (metadata: CollectionMetadata | undefined): boolean =>\n\t\t\tmetadata == null || metadata.completeness === 'complete';\n\n\t\tconst storedAccount = this.ctx.storage.get(`azure:${discoveryKey}:account`);\n\t\tconst storedOrganizations = this.ctx.storage.get(`azure:${discoveryKey}:organizations`);\n\t\tconst storedProjects = this.ctx.storage.get(`azure:${discoveryKey}:projects`);\n\t\tlet account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;\n\n\t\tlet organizations = storedOrganizations?.data?.map((o: AzureOrganizationDescriptor) => ({ ...o }));\n\n\t\tconst storedProjectsData = storedProjects?.data as\n\t\t\t| ProviderApiCollectionResult<AzureProjectDescriptor>\n\t\t\t| AzureProjectDescriptor[]\n\t\t\t| undefined;\n\t\tlet projects: ProviderApiCollectionResult<AzureProjectDescriptor> | undefined;\n\t\tif (!Array.isArray(storedProjectsData) && Array.isArray(storedProjectsData?.values)) {\n\t\t\tconst hydrated = {\n\t\t\t\tvalues: storedProjectsData.values.map((p: AzureProjectDescriptor) => ({ ...p })),\n\t\t\t\t...(storedProjectsData.metadata != null ? { metadata: storedProjectsData.metadata } : {}),\n\t\t\t};\n\t\t\tif (canHydrateStoredProjects(hydrated.metadata)) {\n\t\t\t\tprojects = hydrated;\n\t\t\t}\n\t\t}\n\n\t\tif (storedAccount == null) {\n\t\t\taccount = await this.getProviderCurrentAccount(this._session);\n\t\t\tif (account != null) {\n\t\t\t\t// Clear all other stored organizations and projects and accounts when our session changes\n\t\t\t\tawait this.ctx.storage.deleteWithPrefix('azure');\n\t\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:account`, {\n\t\t\t\t\tv: 1,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tid: account.id,\n\t\t\t\t\t\tname: account.name,\n\t\t\t\t\t\temail: account.email,\n\t\t\t\t\t\tavatarUrl: account.avatarUrl,\n\t\t\t\t\t\tusername: account.username,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\t\tthis._accounts.set(discoveryKey, account);\n\n\t\tif (storedOrganizations == null) {\n\t\t\torganizations = await this.getProviderResourcesForUser(this._session, true);\n\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:organizations`, {\n\t\t\t\tv: 1,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tdata: organizations,\n\t\t\t});\n\t\t}\n\n\t\tthis._organizations ??= new Map<string, AzureOrganizationDescriptor[] | undefined>();\n\t\tthis._organizations.set(discoveryKey, organizations);\n\n\t\tif (projects == null && organizations?.length) {\n\t\t\tprojects = await this.getProviderProjectsForResources(this._session, organizations);\n\t\t\tif (projects != null && canHydrateStoredProjects(projects.metadata)) {\n\t\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:projects`, {\n\t\t\t\t\tv: 2,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: projects,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait this.ctx.storage.delete(`azure:${discoveryKey}:projects`);\n\t\t\t}\n\t\t}\n\n\t\tthis._projects ??= new Map<string, AzureProjectDescriptor[] | undefined>();\n\t\tif (projects != null && canHydrateStoredProjects(projects.metadata)) {\n\t\t\tfor (const project of projects.values) {\n\t\t\t\tconst projectKey = `${discoveryKey}:${project.resourceId}`;\n\t\t\t\tconst projects = this._projects.get(projectKey);\n\t\t\t\tif (projects == null) {\n\t\t\t\t\tthis._projects.set(projectKey, [project]);\n\t\t\t\t} else if (!projects.some(p => p.id === project.id)) {\n\t\t\t\t\tprojects.push(project);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override providerOnDisconnect(): void {\n\t\tthis._organizations = undefined;\n\t\tthis._projects = undefined;\n\t\tthis._accounts = undefined;\n\t\tthis._reviewerGroupIds.clear();\n\t}\n\n\tprotected fromAzureProviderPullRequest(\n\t\tazurePullRequest: ProviderPullRequest,\n\t\trepoDescriptors: AzureRemoteRepositoryDescriptor[],\n\t\tprojectDescriptors: AzureProjectDescriptor[],\n\t\tprojection: PullRequestProjection,\n\t): PullRequest {\n\t\tconst baseRepoDescriptor = repoDescriptors.find(r => r.id === azurePullRequest.repository.id);\n\t\tconst headRepoDescriptor =\n\t\t\tazurePullRequest.headRepository != null\n\t\t\t\t? repoDescriptors.find(r => r.id === azurePullRequest.headRepository!.id)\n\t\t\t\t: undefined;\n\t\tlet project: AzureProjectDescriptor | undefined;\n\t\tif (baseRepoDescriptor != null) {\n\t\t\tazurePullRequest.repository.remoteInfo = {\n\t\t\t\t...azurePullRequest.repository.remoteInfo,\n\t\t\t\tcloneUrlHTTPS: baseRepoDescriptor.cloneUrlHttps ?? '',\n\t\t\t\tcloneUrlSSH: baseRepoDescriptor.cloneUrlSsh ?? '',\n\t\t\t};\n\t\t}\n\n\t\tif (headRepoDescriptor != null) {\n\t\t\tazurePullRequest.headRepository = {\n\t\t\t\t...azurePullRequest.headRepository,\n\t\t\t\tid: azurePullRequest.headRepository?.id ?? headRepoDescriptor.id,\n\t\t\t\tname: azurePullRequest.headRepository?.name ?? headRepoDescriptor.name,\n\t\t\t\towner: {\n\t\t\t\t\tlogin: azurePullRequest.headRepository?.owner.login ?? headRepoDescriptor.resourceName,\n\t\t\t\t},\n\t\t\t\tremoteInfo: {\n\t\t\t\t\t...azurePullRequest.headRepository?.remoteInfo,\n\t\t\t\t\tcloneUrlHTTPS: headRepoDescriptor.cloneUrlHttps ?? '',\n\t\t\t\t\tcloneUrlSSH: headRepoDescriptor.cloneUrlSsh ?? '',\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (baseRepoDescriptor?.projectName != null) {\n\t\t\tproject = projectDescriptors.find(\n\t\t\t\tp => p.resourceName === baseRepoDescriptor.resourceName && p.name === baseRepoDescriptor.projectName,\n\t\t\t);\n\t\t}\n\t\treturn fromProviderPullRequest(azurePullRequest, this, { project: project, projection: projection });\n\t}\n}\n\nconst cloudMetadata = providersMetadata[GitCloudHostIntegrationId.AzureDevOps];\nconst cloudAuthProvider = Object.freeze({ id: cloudMetadata.id, scopes: cloudMetadata.scopes });\n\nexport class AzureDevOpsIntegration extends AzureDevOpsIntegrationBase<GitCloudHostIntegrationId.AzureDevOps> {\n\treadonly authProvider: IntegrationAuthenticationProviderDescriptor = cloudAuthProvider;\n\treadonly id = GitCloudHostIntegrationId.AzureDevOps;\n\tprotected readonly key = this.id;\n\treadonly name: string = 'Azure DevOps';\n\tget domain(): string {\n\t\treturn cloudMetadata.domain;\n\t}\n\tprotected override apiBaseUrlFor(_session: ProviderAuthenticationSession): string {\n\t\treturn 'https://dev.azure.com';\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"azureDevOps.js","names":[],"sources":["../../../../../plus/integrations/src/providers/azureDevOps.ts"],"sourcesContent":["import type { CollectionMetadata, CollectionScope, CollectionScopeFailure } from '@gitkraken/provider-apis';\nimport { GitPullRequestState } from '@gitkraken/provider-apis';\nimport type { Account, UnidentifiedAuthor } from '@gitlens/git/models/author.js';\nimport type { DefaultBranch } from '@gitlens/git/models/defaultBranch.js';\nimport type { Issue, IssueShape } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestType } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type {\n\tPullRequest,\n\tPullRequestMergeMethod,\n\tPullRequestProjection,\n\tPullRequestShape,\n\tPullRequestState,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport type { RepositoryMetadata } from '@gitlens/git/models/repositoryMetadata.js';\nimport type { ResourceDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\nimport type { PullRequestUrlIdentity } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { chunk } from '@gitlens/utils/array.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { mapSettledBounded } from '@gitlens/utils/promise.js';\nimport { PromiseCache } from '@gitlens/utils/promiseCache.js';\nimport type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';\nimport type {\n\tAuthenticationSessionLike as AuthenticationSession,\n\tProviderAuthenticationSession,\n\tTokenWithInfo,\n} from '../authentication/models.js';\nimport { toTokenWithInfo } from '../authentication/models.js';\nimport type { ProviderRefusal } from '../collectionMetadata.js';\nimport { throwIfCallerContractError, toCollectionScopeFailure } from '../collectionMetadata.js';\nimport type { GitSelfManagedHostIntegrationId } from '../constants.js';\nimport { GitCloudHostIntegrationId, providerFanOutConcurrency } from '../constants.js';\nimport { AuthenticationError } from '../errors.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 { ProviderWarningCause, ProviderWarningScope } from '../results.js';\nimport { decodePathSegment } from '../utils/domain.utils.js';\nimport { getAzurePullRequestIdentityFromMaybeUrl } from './azure/azure.utils.js';\nimport type {\n\tAzureOrganizationDescriptor,\n\tAzureProjectDescriptor,\n\tAzureProjectInputDescriptor,\n\tAzureRemoteRepositoryDescriptor,\n\tAzureRepositoryDescriptor,\n\tAzureWorkItemEtagRead,\n} from './azure/models.js';\nimport {\n\tazureWorkItemsEtagFieldsMaxIds,\n\ttoAzurePullRequestEtagFields,\n\ttoAzureWorkItemEtagFields,\n} from './azure/models.js';\nimport type {\n\tProviderApiCollectionResult,\n\tProviderApiPagedResult,\n\tProviderAzureResource,\n\tProviderHierarchyResult,\n\tProviderOrganization,\n\tProviderPullRequest,\n\tProviderRepoInput,\n\tProviderRepository,\n} from './models.js';\nimport {\n\tfromProviderIssue,\n\tfromProviderPullRequest,\n\tgetProviderPullRequestIdentity,\n\tIssueFilter,\n\tproviderPullRequestMatchesSearch,\n\tprovidersMetadata,\n\tPullRequestFilter,\n\ttoIssueShape,\n\ttoProviderPullRequestStates,\n} from './models.js';\nimport { discoveryCacheTtl } from './utils/discoveryCache.js';\nimport {\n\tcollectProviderPagedResult,\n\tflatSettledResultsOrThrow,\n\tmergeCollectionMetadata,\n\tresolveBranchPullRequests,\n\tselectBranchPullRequests,\n} from './utils/providerPaging.js';\n\nexport function getAzureRepositoryIdentity(repo: Pick<AzureRepositoryDescriptor, 'owner' | 'name' | 'project'>): {\n\tresourceName: string;\n\tprojectName?: string;\n\trepositoryName: string;\n} {\n\tconst match = /^([^/]+)\\/_git\\/([^/]+)$/i.exec(repo.name);\n\treturn {\n\t\tresourceName: repo.owner,\n\t\tprojectName: repo.project ?? match?.[1],\n\t\trepositoryName: match?.[2] ?? repo.name,\n\t};\n}\n\nexport function getAzureRepositoryApiBaseUrl(\n\tbaseUrl: string,\n\trepo: Pick<AzureRepositoryDescriptor, 'owner' | 'virtualDirectory'>,\n): string {\n\tconst directory = repo.virtualDirectory?.split('/');\n\tif (directory?.some(segment => !segment || segment === '.' || segment === '..')) {\n\t\tthrow new Error(`Invalid Azure virtual directory '${repo.virtualDirectory}'.`);\n\t}\n\n\tconst url = new URL(baseUrl);\n\tconst toUrl = (segments: string[]) => `${url.protocol}//${url.host}${segments.map(s => `/${s}`).join('')}`;\n\tconst configured = url.pathname.split('/').filter(Boolean);\n\t// A connection addressed at the host root takes the repository's own directory.\n\tif (!configured.length) return toUrl(directory?.map(encodeURIComponent) ?? []);\n\n\t// Otherwise the address is the installation, optionally followed by the repository's collection, which\n\t// requests append themselves (as the owner). IIS serves these paths case-insensitively.\n\tconst namesCollection = sameAzurePathSegment(configured.at(-1)!, repo.owner);\n\tconst installation = namesCollection ? configured.slice(0, -1) : configured;\n\tif (directory == null) return toUrl(installation);\n\n\tfor (const candidate of namesCollection ? [configured, installation] : [configured]) {\n\t\tif (candidate.length === directory.length && candidate.every((s, i) => sameAzurePathSegment(s, directory[i]))) {\n\t\t\treturn toUrl(candidate);\n\t\t}\n\t}\n\tthrow new Error('Azure repository virtual directory does not match the configured installation');\n}\n\nfunction sameAzurePathSegment(encoded: string, value: string): boolean {\n\treturn decodePathSegment(encoded).toLowerCase() === value.toLowerCase();\n}\n\n/**\n * Whether two collection or project names name the same scope. Azure DevOps treats them case-insensitively, so a\n * name typed by hand must still select the collection or project discovery reported.\n */\nexport function sameAzureName(a: string, b: string): boolean {\n\treturn a.toLowerCase() === b.toLowerCase();\n}\n\n/** The distinct names in `names`, compared as Azure compares them, keeping the first spelling of each. */\nexport function uniqueAzureNames(names: readonly string[]): string[] {\n\tconst unique: string[] = [];\n\tfor (const name of names) {\n\t\tif (!unique.some(n => sameAzureName(n, name))) {\n\t\t\tunique.push(name);\n\t\t}\n\t}\n\treturn unique;\n}\n\n/**\n * Flags the reviews of `pr` that name one of the current user's groups (see `PullRequestReviewer.isMyGroup`), which a\n * reviewer read finds through that group rather than through the user.\n */\nexport function markMyGroupReviews(pr: ProviderPullRequest, groupIds: ReadonlySet<string>): ProviderPullRequest {\n\tif (pr.reviews == null || !pr.reviews.some(r => groupIds.has(r.reviewer.id))) return pr;\n\n\treturn { ...pr, reviews: pr.reviews.map(r => (groupIds.has(r.reviewer.id) ? { ...r, isMyGroup: true } : r)) };\n}\n\n/** One read a reviewer relationship takes in a project or repository, and the rows of it the relationship keeps. */\nexport interface AzureReviewerRead {\n\tfilter: { reviewerId?: string; states?: GitPullRequestState[] };\n\tkeep?: (pr: ProviderPullRequest) => boolean;\n}\n\n/**\n * The reads a reviewer relationship over `states` (omitted: open) takes for `userId`, whose groups are `groupIds`:\n *\n * - Open pull requests: all of them, kept when one names the user, or names one of the user's groups and the user\n * didn't write it. Azure's reviewer filter only matches the identity it names, never the groups that identity is in,\n * and a group asked to review the user's own pull request isn't asking the user.\n * - Closed and merged ones: Azure's own filter for the user. They are every pull request a project ever had, too many\n * to read whole on every read, so a group's request is only followed while the pull request is open.\n */\nexport function toAzureReviewerReads(\n\tuserId: string,\n\tgroupIds: ReadonlySet<string>,\n\tstates: readonly GitPullRequestState[] | undefined,\n): AzureReviewerRead[] {\n\tconst reads: AzureReviewerRead[] = [];\n\tif (states == null || states.includes(GitPullRequestState.Open)) {\n\t\treads.push({\n\t\t\tfilter: { states: [GitPullRequestState.Open] },\n\t\t\tkeep: pr =>\n\t\t\t\tpr.reviews?.some(\n\t\t\t\t\tr => r.reviewer.id === userId || (groupIds.has(r.reviewer.id) && pr.author?.id !== userId),\n\t\t\t\t) ?? false,\n\t\t});\n\t}\n\n\tconst closed = states?.filter(s => s !== GitPullRequestState.Open) ?? [];\n\tif (closed.length > 0) {\n\t\treads.push({ filter: { reviewerId: userId, states: closed } });\n\t}\n\treturn reads;\n}\n\n/**\n * Matches an org/project descriptor against a caller-supplied name, mirroring the facade's own\n * key/id/name comparison so `listIssuesPage({ org, project })` narrows on the same identifiers a consumer\n * already got back from `listOrgs`/`listProjects`.\n */\nfunction azureResourceMatches(resource: { key?: string; id?: string; name?: string }, value: string): boolean {\n\treturn resource.key === value || resource.id === value || resource.name === value;\n}\n\nexport abstract class AzureDevOpsIntegrationBase<\n\tTIntegrationId extends GitCloudHostIntegrationId.AzureDevOps | GitSelfManagedHostIntegrationId.AzureDevOpsServer,\n\tTRepositoryDescriptor extends AzureRepositoryDescriptor = AzureRepositoryDescriptor,\n> extends GitHostIntegration<TIntegrationId, TRepositoryDescriptor> {\n\tprotected abstract apiBaseUrlFor(session: ProviderAuthenticationSession): string;\n\tprotected getApiOptions(\n\t\tsession: ProviderAuthenticationSession,\n\t\tdoNotConvertToPat: boolean = false,\n\t): {\n\t\ttokenWithInfo: TokenWithInfo<TIntegrationId>;\n\t\toptions: { isPAT: boolean; baseUrl?: string };\n\t} {\n\t\t// The secret is handed over raw: `isPAT` tells provider-apis to send it as an HTTP Basic credential, which\n\t\t// it encodes itself as `base64(':' + token)`. Pre-encoding here would be encoded a second time and refused\n\t\t// by Azure DevOps. `getCurrentUser` is the one read that needs a bearer token, and passes\n\t\t// `doNotConvertToPat` to get one.\n\t\tconst usePat = !doNotConvertToPat;\n\t\tconst tokenWithInfo = toTokenWithInfo<TIntegrationId>(this.id, session);\n\t\treturn {\n\t\t\ttokenWithInfo: tokenWithInfo,\n\t\t\toptions: { isPAT: usePat },\n\t\t};\n\t}\n\n\t/**\n\t * The options for a request addressed below one collection (an Azure DevOps Services organization).\n\t *\n\t * The same as {@link getApiOptions} unless a self-managed address already names the collection, which requests\n\t * append themselves: see the server override, which keeps it from being applied twice.\n\t */\n\tprotected getCollectionApiOptions(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_collection: string,\n\t): { isPAT: boolean; baseUrl?: string } {\n\t\treturn this.getApiOptions(session).options;\n\t}\n\n\t/** The base a request or link below `collection` appends the collection to; see {@link getCollectionApiOptions}. */\n\tprotected collectionApiBaseUrl(session: ProviderAuthenticationSession, _collection: string): string {\n\t\treturn this.apiBaseUrlFor(session);\n\t}\n\n\t/** Reads the organizations (Azure DevOps Server: the collections) the account can see. */\n\tprotected async requestResourcesForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\tuserId: string,\n\t): Promise<ProviderAzureResource[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo, options } = this.getApiOptions(session);\n\t\treturn api.getAzureResourcesForUser(tokenWithInfo, userId, options);\n\t}\n\n\t/**\n\t * The identity id a pull-request creator/reviewer filter must carry for `collection`.\n\t *\n\t * On Azure DevOps Services that is the account id, one per user. The server override resolves it per collection,\n\t * since Azure DevOps Server gives one person a different id in each collection than at the server level.\n\t */\n\tprotected async getFilterUserId(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_collection: string,\n\t): Promise<string | undefined> {\n\t\treturn (await this.getProviderCurrentAccount(session))?.id;\n\t}\n\n\t/**\n\t * The current user's groups per credential, collection and user, kept for {@link discoveryCacheTtl} like the other\n\t * discovered sets: membership changes rarely, and a sweep that reads every few minutes would otherwise pay for it\n\t * every time. A failed read isn't kept, and a re-sync drops them all (see {@link invalidateDiscoveryCaches}).\n\t */\n\tprivate readonly _reviewerGroupIds = new PromiseCache<string, Set<string>>({\n\t\tcapacity: 50,\n\t\tcreateTTL: discoveryCacheTtl,\n\t});\n\n\t/**\n\t * Every group the current user (`userId`, as {@link getFilterUserId} resolved it) is a member of in `collection`:\n\t * teams and security groups, in any project, directly or through other groups. Two requests per collection,\n\t * however many groups, and none while the last read is kept.\n\t */\n\tprotected getReviewerGroupIds(\n\t\tsession: ProviderAuthenticationSession,\n\t\tcollection: string,\n\t\tuserId: string,\n\t): Promise<Set<string>> {\n\t\treturn this._reviewerGroupIds.getOrCreate(\n\t\t\tJSON.stringify([this.discoveryKey(session), collection.toLowerCase(), userId]),\n\t\t\tasync () => {\n\t\t\t\tconst api = await this.getProvidersApi();\n\t\t\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\t\t\tconst ids = await api.getAzureGroupIdsForUser(\n\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\tcollection,\n\t\t\t\t\tuserId,\n\t\t\t\t\tthis.getCollectionApiOptions(session, collection),\n\t\t\t\t);\n\t\t\t\treturn new Set(ids);\n\t\t\t},\n\t\t);\n\t}\n\n\toverride invalidateDiscoveryCaches(): void {\n\t\tsuper.invalidateDiscoveryCaches();\n\t\tthis._reviewerGroupIds.clear();\n\t}\n\n\t/**\n\t * For one read, the current account as each organization's pull requests identify it, given the account itself\n\t * (`undefined` when it couldn't be read). Azure DevOps Services gives a person one id, so that is `account`; the\n\t * server override resolves each collection's own, once per read.\n\t */\n\tprotected getOrganizationViewers(\n\t\t_session: ProviderAuthenticationSession,\n\t\taccount: { id: string; username?: string } | undefined,\n\t): (org: string) => Promise<{ id: string; username?: string } | undefined> {\n\t\treturn () => Promise.resolve(account);\n\t}\n\n\t/**\n\t * What the discovery caches (account, organizations, projects, and their stored copies) are keyed by. Azure DevOps\n\t * Services has a single address, so the credential alone identifies what it discovers; the server override adds\n\t * the installation address.\n\t */\n\tprotected discoveryKey(session: ProviderAuthenticationSession): string {\n\t\treturn session.accessToken;\n\t}\n\n\tprivate _accounts: Map<string, Account | undefined> | undefined;\n\tprotected override async getProviderCurrentAccount(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<Account | undefined> {\n\t\tconst key = this.discoveryKey(session);\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\n\t\tconst cachedAccount = this._accounts.get(key);\n\t\tif (cachedAccount == null) {\n\t\t\tconst user = await this._requestForCurrentUser(session);\n\t\t\tthis._accounts.set(key, user);\n\t\t}\n\n\t\treturn this._accounts.get(key);\n\t}\n\n\tprotected async _requestForCurrentUser(session: ProviderAuthenticationSession): Promise<Account | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo, options } = this.getApiOptions(session, true);\n\t\tconst user = await api.getCurrentUser(tokenWithInfo, options);\n\t\treturn user\n\t\t\t? {\n\t\t\t\t\tprovider: this,\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\temail: user.email ?? undefined,\n\t\t\t\t\tavatarUrl: user.avatarUrl ?? undefined,\n\t\t\t\t\tusername: user.username ?? undefined,\n\t\t\t\t}\n\t\t\t: undefined;\n\t}\n\n\t/**\n\t * Bypasses the account cache so a previously accepted credential cannot vouch for one that is now refused.\n\t */\n\tprotected override async validateCredential(session: ProviderAuthenticationSession): Promise<void> {\n\t\tif ((await this._requestForCurrentUser(session)) == null) {\n\t\t\tthrow new Error('Azure DevOps did not confirm the credential');\n\t\t}\n\t}\n\n\t/**\n\t * Names a confirmed credential's refusal from the answers Azure DevOps gives, captured live (#5890):\n\t * - `VS403463` in the explanation is a Conditional Access policy;\n\t * - a typed `UnauthorizedRequestException` body is an organization or project the account has no access to;\n\t * - a `401` to an OAuth token that explains nothing (sent as Basic), or only `TF400813` (sent as Bearer), is an\n\t * organization whose \"Third-party application access via OAuth\" policy is off. It is the same answer an\n\t * expired token gets, which is why this is only asked once the credential passed. The policy does not govern\n\t * personal access tokens, so a PAT is never given it.\n\t *\n\t * Any other explanation is left unnamed, so the warning keeps Azure's own words rather than a guess.\n\t */\n\tprotected override describeRefusal(\n\t\tsession: ProviderAuthenticationSession,\n\t\trefusal: ProviderRefusal,\n\t\tscope: ProviderWarningScope,\n\t): ProviderWarningCause | undefined {\n\t\tconst code = /\\b(?:TF|VS)\\d{6}\\b/.exec(refusal.detail ?? '')?.[0];\n\t\tif (code === 'VS403463') return { reason: 'conditional-access', code: code };\n\t\tif (refusal.typeKey === 'UnauthorizedRequestException') {\n\t\t\treturn { reason: 'access-denied', ...(code != null ? { code: code } : {}) };\n\t\t}\n\t\tif (\n\t\t\tthis.id !== GitCloudHostIntegrationId.AzureDevOps ||\n\t\t\tsession.type !== 'oauth' ||\n\t\t\trefusal.status !== 401 ||\n\t\t\trefusal.typeKey != null ||\n\t\t\t(refusal.detail != null && code !== 'TF400813')\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// The organization's name, for the policy page, comes from the discovery the failure was recorded under. Most\n\t\t// reads record the organization's id, the repo-scoped ones its name.\n\t\tconst org =\n\t\t\tscope.resourceId != null\n\t\t\t\t? this._organizations\n\t\t\t\t\t\t?.get(this.discoveryKey(session))\n\t\t\t\t\t\t?.find(o => o.id === scope.resourceId || o.name === scope.resourceId)?.name\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\treason: 'oauth-app-not-allowed',\n\t\t\t...(code != null ? { code: code } : {}),\n\t\t\t...(org != null\n\t\t\t\t? {\n\t\t\t\t\t\tremedyUrl: `${this.apiBaseUrlFor(session)}/${encodeURIComponent(org)}/_settings/organizationPolicy`,\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tprivate _organizations: Map<string, AzureOrganizationDescriptor[] | undefined> | undefined;\n\tprotected async getProviderResourcesForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t\tforce: boolean = false,\n\t): Promise<AzureOrganizationDescriptor[] | undefined> {\n\t\tthis._organizations ??= new Map<string, AzureOrganizationDescriptor[] | undefined>();\n\t\tconst key = this.discoveryKey(session);\n\t\tconst cachedResources = this._organizations.get(key);\n\n\t\tif (cachedResources == null || force) {\n\t\t\tconst account = await this.getProviderCurrentAccount(session);\n\t\t\tif (account?.id == null) return undefined;\n\n\t\t\tconst resources = await this.requestResourcesForUser(session, account.id);\n\t\t\tthis._organizations.set(key, resources != null ? resources.map(r => ({ ...r, key: r.id })) : undefined);\n\t\t}\n\n\t\treturn this._organizations.get(key);\n\t}\n\n\tprivate _projects: Map<string, AzureProjectDescriptor[] | undefined> | undefined;\n\t/**\n\t * Discovers (and caches) each resource's projects. Only resources whose drain completed cleanly are cached;\n\t * a rejected or backstop-truncated drain is left uncached (retried next call). When `failures` is supplied,\n\t * a rejected resource is recorded there as a structured {@link CollectionScopeFailure} so an account-wide\n\t * caller can surface the incomplete project set (a whole org's PRs/issues silently missing otherwise) as a\n\t * scope-aware warning + `fetchFailed` rather than an all-pages success over a hole.\n\t */\n\tprotected async getProviderProjectsForResources(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresources: AzureOrganizationDescriptor[],\n\t\tforce: boolean = false,\n\t\tfailures?: CollectionScopeFailure[],\n\t): Promise<ProviderApiCollectionResult<AzureProjectDescriptor>> {\n\t\tthis._projects ??= new Map<string, AzureProjectDescriptor[] | undefined>();\n\t\tconst discoveryKey = this.discoveryKey(session);\n\n\t\tlet resourcesWithoutProjects = [];\n\t\tif (force) {\n\t\t\tresourcesWithoutProjects = resources;\n\t\t} else {\n\t\t\tfor (const resource of resources) {\n\t\t\t\tconst resourceKey = `${discoveryKey}:${resource.id}`;\n\t\t\t\tconst cachedProjects = this._projects.get(resourceKey);\n\t\t\t\tif (cachedProjects == null) {\n\t\t\t\t\tresourcesWithoutProjects.push(resource);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst allProjects: AzureProjectDescriptor[] = [];\n\t\tlet resultMetadata: CollectionMetadata | undefined;\n\n\t\tif (resourcesWithoutProjects.length > 0) {\n\t\t\tconst api = await this.getProvidersApi();\n\t\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\t\t// The projects API is paginated; a single call would drop every project past the first page (and\n\t\t\t// with it their repos and PRs). Drain all pages per resource, threading the returned cursor.\n\t\t\t// Per-resource (not a shared flatSettled) so a resource whose drain was truncated (hit the paging\n\t\t\t// backstop) or rejected is NOT cached — caching a partial list here would make every later repo/PR/\n\t\t\t// issue read for that org silently inherit an incomplete project set. Leaving it uncached means the\n\t\t\t// next call retries it. The scope is passed so a page-level failure preserves the prefix already\n\t\t\t// fetched and records a structured failure instead of re-throwing.\n\t\t\tconst drains = await Promise.allSettled(\n\t\t\t\tresourcesWithoutProjects.map(async resource => ({\n\t\t\t\t\tresource: resource,\n\t\t\t\t\tresult: await collectProviderPagedResult(\n\t\t\t\t\t\tcursor =>\n\t\t\t\t\t\t\tapi.getAzureProjectsForResource(tokenWithInfo, resource.name, {\n\t\t\t\t\t\t\t\t...this.getCollectionApiOptions(session, resource.name),\n\t\t\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t20,\n\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t),\n\t\t\t\t})),\n\t\t\t);\n\n\t\t\t// `allSettled` preserves order, so `drains[i]` is `resourcesWithoutProjects[i]`.\n\t\t\tdrains.forEach((drain, i) => {\n\t\t\t\t// A rejected resource drain contributes nothing and is left uncached (retried next call). Record\n\t\t\t\t// it as a structured failure so an account-wide caller can warn on the org whose projects (and\n\t\t\t\t// thus PRs/issues) are missing, instead of silently narrowing the read.\n\t\t\t\tif (drain.status !== 'fulfilled') {\n\t\t\t\t\tconst resource = resourcesWithoutProjects[i];\n\t\t\t\t\tconst failure = toCollectionScopeFailure(\n\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t\tdrain.reason,\n\t\t\t\t\t);\n\t\t\t\t\tfailures?.push(failure);\n\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, {\n\t\t\t\t\t\tcompleteness: 'partial',\n\t\t\t\t\t\tfailures: [failure],\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst { resource, result } = drain.value;\n\t\t\t\tconst projects = result.values\n\t\t\t\t\t.filter(p => p.namespace === resource.name)\n\t\t\t\t\t.map(p => ({\n\t\t\t\t\t\tid: p.id,\n\t\t\t\t\t\tname: p.name,\n\t\t\t\t\t\tresourceId: resource.id,\n\t\t\t\t\t\tresourceName: resource.name,\n\t\t\t\t\t\tkey: p.id,\n\t\t\t\t\t}));\n\n\t\t\t\tif (result.metadata != null) {\n\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, result.metadata);\n\t\t\t\t}\n\n\t\t\t\tconst metadataIncomplete = result.metadata != null && result.metadata.completeness !== 'complete';\n\t\t\t\tif (result.truncated || metadataIncomplete) {\n\t\t\t\t\t// A truncated drain is an incomplete project set; include its partial values in the current\n\t\t\t\t\t// result but don't cache it as if complete. Add a structured failure for the truncation unless\n\t\t\t\t\t// the drain already recorded a page-level failure for this resource.\n\t\t\t\t\tif (\n\t\t\t\t\t\tresult.truncated &&\n\t\t\t\t\t\t!result.metadata?.failures?.some(\n\t\t\t\t\t\t\tf => f.scope?.resourceId === resource.id && f.kind !== 'unknown',\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst failure = toCollectionScopeFailure(\n\t\t\t\t\t\t\t{ providerId: this.id, resourceId: resource.id },\n\t\t\t\t\t\t\tnew Error('Project discovery was truncated before all pages were read'),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfailures?.push(failure);\n\t\t\t\t\t\tresultMetadata = mergeCollectionMetadata(resultMetadata, {\n\t\t\t\t\t\t\tcompleteness: 'partial',\n\t\t\t\t\t\t\tfailures: [failure],\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tallProjects.push(...projects);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._projects!.set(`${discoveryKey}:${resource.id}`, projects);\n\t\t\t});\n\t\t}\n\n\t\tconst cachedProjects = resources.reduce<AzureProjectDescriptor[]>((projects, resource) => {\n\t\t\tconst resourceProjects = this._projects!.get(`${discoveryKey}:${resource.id}`);\n\t\t\tif (resourceProjects != null) {\n\t\t\t\tprojects.push(...resourceProjects);\n\t\t\t}\n\t\t\treturn projects;\n\t\t}, []);\n\t\tallProjects.push(...cachedProjects);\n\n\t\tconst projectsByIdentity = new Map<string, AzureProjectDescriptor>();\n\t\tfor (const project of allProjects) {\n\t\t\tconst identity = `${project.resourceId}:${project.id}`;\n\t\t\tif (!projectsByIdentity.has(identity)) {\n\t\t\t\tprojectsByIdentity.set(identity, project);\n\t\t\t}\n\t\t}\n\t\tconst values = [...projectsByIdentity.values()];\n\t\treturn resultMetadata != null ? { values: values, metadata: resultMetadata } : { values: values };\n\t}\n\n\tprivate async getRepoDescriptorsForProjects(\n\t\tsession: ProviderAuthenticationSession,\n\t\tprojects: AzureProjectDescriptor[],\n\t): Promise<Map<string, AzureRemoteRepositoryDescriptor[] | undefined>> {\n\t\tconst descriptors = new Map<string, AzureRemoteRepositoryDescriptor[] | undefined>();\n\t\tif (projects.length === 0) return descriptors;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tawait Promise.all(\n\t\t\tprojects.map(async project => {\n\t\t\t\tconst repos = (\n\t\t\t\t\tawait api.getReposForAzureProject(\n\t\t\t\t\t\ttokenWithInfo,\n\t\t\t\t\t\tproject.resourceName,\n\t\t\t\t\t\tproject.name,\n\t\t\t\t\t\tthis.getCollectionApiOptions(session, project.resourceName),\n\t\t\t\t\t)\n\t\t\t\t)?.values;\n\t\t\t\tif (repos != null && repos.length > 0) {\n\t\t\t\t\tdescriptors.set(\n\t\t\t\t\t\tproject.id,\n\t\t\t\t\t\trepos.map(r => ({\n\t\t\t\t\t\t\tid: r.id,\n\t\t\t\t\t\t\tnodeId: r.graphQLId ?? undefined,\n\t\t\t\t\t\t\tresourceName: project.resourceName,\n\t\t\t\t\t\t\tname: r.name,\n\t\t\t\t\t\t\tprojectName: project.name,\n\t\t\t\t\t\t\turl: r.webUrl ?? undefined,\n\t\t\t\t\t\t\tcloneUrlHttps: r.httpsUrl ?? undefined,\n\t\t\t\t\t\t\tcloneUrlSsh: r.sshUrl ?? undefined,\n\t\t\t\t\t\t\tkey: r.id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\treturn descriptors;\n\t}\n\n\tprotected override async getProviderOrganizationsForUser(\n\t\tsession: ProviderAuthenticationSession,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null) return undefined;\n\n\t\treturn {\n\t\t\tvalues: orgs.map(o => ({\n\t\t\t\tid: o.id,\n\t\t\t\tproviderId: this.id,\n\t\t\t\tname: o.name,\n\t\t\t\turl: `${this.collectionApiBaseUrl(session, o.name)}/${o.name}`,\n\t\t\t})),\n\t\t};\n\t}\n\n\tprotected override async getProviderProjectsForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg?: string,\n\t): Promise<ProviderHierarchyResult<ProviderOrganization> | undefined> {\n\t\t// Azure is the one git host with a project tier: repos live under org (resource) → project. Enumerate\n\t\t// the user's orgs (optionally scoped to `org`), read their projects, and surface each as an org-shaped\n\t\t// entry so the ProviderBackend facade can list them uniformly.\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null) return undefined;\n\t\tif (orgs.length === 0) {\n\t\t\treturn { values: [], paging: { cursor: '{}', more: false } };\n\t\t}\n\n\t\tconst scopedOrgs = org != null ? orgs.filter(o => o.name === org || o.id === org) : orgs;\n\t\tif (scopedOrgs.length === 0) return { values: [] };\n\n\t\tconst projects = await this.getProviderProjectsForResources(session, scopedOrgs);\n\t\tif (projects.values.length === 0 && projects.metadata == null) return { values: [] };\n\n\t\treturn {\n\t\t\tvalues: projects.values.map(p => ({\n\t\t\t\tid: p.id,\n\t\t\t\tproviderId: this.id,\n\t\t\t\tname: p.name,\n\t\t\t\torg: p.resourceName,\n\t\t\t\turl: `${this.collectionApiBaseUrl(session, p.resourceName)}/${p.resourceName}/${p.name}`,\n\t\t\t})),\n\t\t\t...(projects.metadata != null ? { metadata: projects.metadata } : {}),\n\t\t};\n\t}\n\n\t/**\n\t * With `options.project`, returns one page of that project's repos (follow `paging.cursor` to page).\n\t * Without a project it fans out across every project under `org` and returns them all at once — there's\n\t * no single cursor to page a parallel merge — skipping any project that fails to list rather than\n\t * failing the whole org. If any successful project drain hits the defensive page backstop, the merged\n\t * result is marked `truncated` without exposing a synthetic cursor.\n\t */\n\tprotected override async getProviderRepositoriesForOrg(\n\t\tsession: ProviderAuthenticationSession,\n\t\torg: string,\n\t\toptions?: { project?: string; cursor?: string },\n\t): Promise<ProviderHierarchyResult<ProviderRepository> | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst apiOptions = this.getCollectionApiOptions(session, org);\n\n\t\tif (options?.project) {\n\t\t\treturn api.getReposForAzureProject(tokenWithInfo, org, options.project, {\n\t\t\t\t...apiOptions,\n\t\t\t\tcursor: options.cursor,\n\t\t\t});\n\t\t}\n\n\t\tconst orgDescriptor = (await this.getProviderResourcesForUser(session))?.find(o => o.name === org);\n\t\tif (orgDescriptor == null) return undefined;\n\n\t\tconst discoveryFailures: CollectionScopeFailure[] = [];\n\t\tconst projects = await this.getProviderProjectsForResources(session, [orgDescriptor], false, discoveryFailures);\n\t\t// An empty result is only proven-empty when discovery itself succeeded; a rejected project-discovery\n\t\t// leaves the repo set unknowable, so surface the discovery metadata rather than publishing a hole as a\n\t\t// complete list.\n\t\tif (projects.values.length === 0) {\n\t\t\treturn { values: [], metadata: projects.metadata };\n\t\t}\n\n\t\tlet repoMetadata: CollectionMetadata | undefined;\n\t\tconst results = await Promise.allSettled(\n\t\t\tprojects.values.map(p =>\n\t\t\t\tcollectProviderPagedResult(\n\t\t\t\t\tcursor =>\n\t\t\t\t\t\tapi.getReposForAzureProject(tokenWithInfo, org, p.name, { ...apiOptions, cursor: cursor }),\n\t\t\t\t\t20,\n\t\t\t\t\t{ providerId: this.id, resourceId: org, projectId: p.name },\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst values: ProviderRepository[] = [];\n\t\tlet truncated = false;\n\t\tfor (const result of results) {\n\t\t\t// With a per-project scope, collectProviderPagedResult catches page-level failures itself and returns\n\t\t\t// them as metadata rather than rejecting. A rejected promise here is an unexpected internal error.\n\t\t\tif (result.status !== 'fulfilled') {\n\t\t\t\ttruncated = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvalues.push(...result.value.values);\n\t\t\tif (result.value.metadata != null) {\n\t\t\t\trepoMetadata = mergeCollectionMetadata(repoMetadata, result.value.metadata);\n\t\t\t}\n\t\t\ttruncated ||= result.value.truncated === true;\n\t\t}\n\n\t\tconst metadata = mergeCollectionMetadata(repoMetadata, projects.metadata);\n\t\treturn {\n\t\t\tvalues: values,\n\t\t\t...(metadata != null ? { metadata: metadata } : {}),\n\t\t\t...(truncated || (metadata != null && metadata.completeness !== 'complete') ? { truncated: true } : {}),\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\tconst api = await this.getProvidersApi();\n\t\tif (pr.refs == null || pr.project == null) return false;\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst apiOptions = this.getCollectionApiOptions(session, pr.repository.owner);\n\n\t\ttry {\n\t\t\tconst merged = await api.mergePullRequest(tokenWithInfo, pr, {\n\t\t\t\t...options,\n\t\t\t\t...apiOptions,\n\t\t\t});\n\t\t\treturn merged;\n\t\t} catch (ex) {\n\t\t\tthis.showMergeErrorMessage(ex);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprotected showMergeErrorMessage(ex: Error): void {\n\t\tthis.ctx.hooks?.ui?.onError?.(\n\t\t\t`${ex.message}. Check branch policies, and ensure you have the necessary permissions to merge the pull request.`,\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\trev: string,\n\t\toptions?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<UnidentifiedAuthor | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tgetAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\toptions,\n\t\t);\n\t}\n\n\tprotected override async getProviderAccountForEmail(\n\t\t_session: AuthenticationSession,\n\t\t_repo: AzureRepositoryDescriptor,\n\t\t_email: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t},\n\t): Promise<Account | undefined> {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tprotected override async getProviderDefaultBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<DefaultBranch | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo) },\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async getProviderLinkedIssueOrPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\t{ id }: { id: string; key: string },\n\t\ttype: undefined | IssueOrPullRequestType,\n\t): Promise<IssueOrPullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tid,\n\t\t\t{\n\t\t\t\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\t\ttype: type,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderIssue(\n\t\tsession: ProviderAuthenticationSession,\n\t\tproject: AzureProjectInputDescriptor,\n\t\tid: string,\n\t): Promise<Issue | undefined> {\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\tif (user?.username == null) return undefined;\n\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\tconst projects = await this.getProviderProjectsForResources(session, orgs);\n\t\tif (projects.values.length === 0) return undefined;\n\n\t\tconst matchingProject = projects.values.find(p => p.resourceName === project.owner && p.name === project.name);\n\t\tif (matchingProject == null) return undefined;\n\n\t\treturn (await this.authenticationService.apis.azure)?.getIssue(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tmatchingProject,\n\t\t\tid,\n\t\t\t{\n\t\t\t\tbaseUrl: this.collectionApiBaseUrl(session, matchingProject.resourceName),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForBranch(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tbranch: string,\n\t\t_options?: {\n\t\t\tavatarSize?: number;\n\t\t\tinclude?: PullRequestState[];\n\t\t},\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected override async getProviderPullRequestForCommit(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\trev: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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\tgetAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\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; converted\n\t * like the repo-scoped list rows. Not through {@link getProviderIssue}: that read swallows every failure but a\n\t * rejected credential into `undefined`, discovers every project of every organization first, and converts\n\t * differently from the list reads.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tif (c.project == null) throw new Error(`Azure DevOps needs a project to read work item ${c.number}`);\n\n\t\t\tconst issue = await api.getAzureWorkItem(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, project: c.project },\n\t\t\t\tc.number,\n\t\t\t\tthis.getCollectionApiOptions(session, c.owner),\n\t\t\t);\n\t\t\tif (issue == null) return undefined;\n\n\t\t\tconst shape = toIssueShape(issue, this, { projection: 'batch' });\n\t\t\tif (shape == null) {\n\t\t\t\tthrow new Error(`Azure DevOps returned work item ${c.number} without a URL or change date`);\n\t\t\t}\n\n\t\t\treturn shape;\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; converted\n\t * like the repo-scoped list rows — not through {@link fromAzureProviderPullRequest}, which only the\n\t * account-wide searches use.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestShape | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst viewerFor = this.getOrganizationViewers(session, options?.currentAccount);\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\tconst pr = await api.getPullRequestForRepo(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, name: c.repo, project: c.project },\n\t\t\t\tc.number,\n\t\t\t\t{ ...this.getCollectionApiOptions(session, c.owner), includeRemoteInfo: true },\n\t\t\t);\n\t\t\tif (pr == null) return undefined;\n\n\t\t\treturn fromProviderPullRequest(pr, this, { currentAccount: await viewerFor(c.owner), projection: 'batch' });\n\t\t});\n\t}\n\n\t/**\n\t * The cheap check behind the batch issue read's etags: one request per organization, project and\n\t * {@link azureWorkItemsEtagFieldsMaxIds} distinct ids, where {@link getProviderIssuesBatch} sends one per target,\n\t * asking only for each work item's change state. A request that throws rejects only its own targets' slots, with\n\t * its error classified as the full read's would be.\n\t *\n\t * Never proves an absence. Azure silently leaves out every id it can't return, whether missing, hidden or failing,\n\t * so such a target's slot is rejected and the full read, whose not-found does prove an absence, decides. So is a\n\t * work item in another project, which the full read fails. When no target was answered and nothing failed, the\n\t * check declines instead, so a batch of only such ids costs a full read, not a failure.\n\t *\n\t * A work item has no reactions, and its full row no count, so `'reactions'` reads nothing and costs nothing.\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\t_options: { etagIncludes?: readonly IssueEtagInclude[] },\n\t\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<IssueEtagFields | undefined>[] | undefined> {\n\t\tconst slots = new Array<PromiseSettledResult<IssueEtagFields | undefined>>(coordinates.length);\n\t\tlet answered = false;\n\t\tlet failed = false;\n\n\t\t// Each organization and project's distinct ids, with the targets asking for each.\n\t\tconst byProject = new Map<string, { owner: string; project: string; ids: Map<number, number[]> }>();\n\t\tfor (const [index, c] of coordinates.entries()) {\n\t\t\tif (c.project == null) {\n\t\t\t\t// Required as the full read requires it, so a check never answers for a target the full read refuses.\n\t\t\t\tslots[index] = {\n\t\t\t\t\tstatus: 'rejected',\n\t\t\t\t\treason: new Error(`Azure DevOps needs a project to read work item ${c.number}`),\n\t\t\t\t};\n\t\t\t\tfailed = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst key = JSON.stringify([c.owner, c.project]);\n\t\t\tlet group = byProject.get(key);\n\t\t\tif (group == null) {\n\t\t\t\tgroup = { owner: c.owner, project: c.project, ids: new Map() };\n\t\t\t\tbyProject.set(key, group);\n\t\t\t}\n\n\t\t\tlet indices = group.ids.get(c.number);\n\t\t\tif (indices == null) {\n\t\t\t\tindices = [];\n\t\t\t\tgroup.ids.set(c.number, indices);\n\t\t\t}\n\t\t\tindices.push(index);\n\t\t}\n\n\t\tconst requests = [...byProject.values()].flatMap(group =>\n\t\t\tchunk([...group.ids], azureWorkItemsEtagFieldsMaxIds).map(entries => ({ ...group, entries: entries })),\n\t\t);\n\t\tif (!requests.length) return slots;\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst answers = await mapSettledBounded(requests, providerFanOutConcurrency, r =>\n\t\t\tapi.getAzureWorkItemsEtagFields(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: r.owner, project: r.project },\n\t\t\t\tr.entries.map(([id]) => id),\n\t\t\t\tthis.getCollectionApiOptions(session, r.owner),\n\t\t\t),\n\t\t);\n\n\t\tfor (const [i, answer] of answers.entries()) {\n\t\t\tconst { project, entries } = requests[i];\n\t\t\tif (answer.status === 'rejected') {\n\t\t\t\tfailed = true;\n\t\t\t\tfor (const [, indices] of entries) {\n\t\t\t\t\tfor (const index of indices) {\n\t\t\t\t\t\tslots[index] = answer;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// By id, never by position: Azure leaves out the ids it can't return.\n\t\t\tconst workItems = new Map<unknown, AzureWorkItemEtagRead>();\n\t\t\tfor (const read of answer.value) {\n\t\t\t\tworkItems.set(read.workItem.id, read);\n\t\t\t}\n\n\t\t\tfor (const [id, indices] of entries) {\n\t\t\t\tconst read = workItems.get(id);\n\t\t\t\tlet slot: PromiseSettledResult<IssueEtagFields | undefined>;\n\t\t\t\tif (read == null) {\n\t\t\t\t\tslot = { status: 'rejected', reason: new Error(`Azure DevOps did not return work item ${id}`) };\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tslot = {\n\t\t\t\t\t\t\tstatus: 'fulfilled',\n\t\t\t\t\t\t\tvalue: toAzureWorkItemEtagFields(read.workItem, project, read.category),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tanswered = true;\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tslot = { status: 'rejected', reason: ex };\n\t\t\t\t\t\tfailed = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tslots[index] = slot;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn answered || failed ? slots : undefined;\n\t}\n\n\t/**\n\t * The cheap check behind the batch pull request read's etags: still one request per target, as Azure DevOps has\n\t * no read of several pull requests by id, but only the one {@link getProviderPullRequestsBatch} sends first —\n\t * not the repository read provider-apis adds to it for clone URLs, once per pull request. Settled per target,\n\t * with absence proven by the same not-found rule as the full read.\n\t *\n\t * Azure DevOps reports no update time, so a full row's `updatedDate` is its close time, else its creation time,\n\t * and moves only when it closes. Its etag therefore adds a `revision` of the fields that change without it —\n\t * title, description, target branch, and every reviewer and their vote — read off the same response at no extra\n\t * cost. It sees a pull request's state, draft flag, head commit and those fields, and, when included, its\n\t * mergeability and its required reviewers' review decision; never a comment or a label, which its full row\n\t * doesn't carry either. A full row carries no check rollup, so the `checks` include adds nothing and costs nothing.\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\t_cancellation?: AbortSignal,\n\t): Promise<PromiseSettledResult<PullRequestEtagFields | undefined>[] | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst etagIncludes = options.etagIncludes ?? [];\n\n\t\treturn mapSettledBounded(coordinates, providerFanOutConcurrency, async c => {\n\t\t\t// Required as provider-apis requires it for the full read.\n\t\t\tif (c.project == null) throw new Error(`Azure DevOps needs a project to read pull request ${c.number}`);\n\n\t\t\tconst pr = await api.getAzurePullRequest(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: c.owner, project: c.project, name: c.repo },\n\t\t\t\tc.number,\n\t\t\t\tthis.getCollectionApiOptions(session, c.owner),\n\t\t\t);\n\t\t\treturn pr != null ? toAzurePullRequestEtagFields(pr, etagIncludes) : undefined;\n\t\t});\n\t}\n\n\t/**\n\t * Two steps, because provider-apis has no source-branch filter: a direct Azure read finds each branch's matching\n\t * pull request ids, one request per target, then {@link getProviderPullRequestsBatch} resolves them — so a row is\n\t * the one `getPullRequestsBatch` returns for that pull request, `url` and `authoredByMe` included.\n\t *\n\t * Serves only a branch in the base repository: an Azure DevOps fork shares its organization and is identified\n\t * by repository, so `headOwner` can't name one — the manager read refuses one that names a different owner.\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 api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\tconst found = await mapSettledBounded(targets, providerFanOutConcurrency, async t => {\n\t\t\tif (t.project == null || t.headOwner != null) {\n\t\t\t\tthrow new Error(`Azure DevOps needs a project and no head owner to find ${t.branch}'s pull requests`);\n\t\t\t}\n\n\t\t\t// One past the cap, since Azure reports no total to tell a full page from a truncated one.\n\t\t\tconst rows = await api.getAzurePullRequestsForBranch(\n\t\t\t\ttokenWithInfo,\n\t\t\t\t{ namespace: t.owner, project: t.project, name: t.repo },\n\t\t\t\tt.branch,\n\t\t\t\toptions.limit + 1,\n\t\t\t\tthis.getCollectionApiOptions(session, t.owner),\n\t\t\t);\n\t\t\tif (rows == null) return { numbers: [], truncated: false };\n\n\t\t\tconst ref = `refs/heads/${t.branch}`;\n\t\t\tconst { values, truncated } = selectBranchPullRequests(rows, {\n\t\t\t\tmatchesHead: pr => pr.sourceRefName === ref && pr.forkSource == null,\n\t\t\t\t// Azure reports no update time; this is the one the batch read's rows carry.\n\t\t\t\tupdatedAt: pr => Date.parse(pr.closedDate || pr.creationDate),\n\t\t\t\tmap: pr => pr.pullRequestId,\n\t\t\t\tlimit: options.limit,\n\t\t\t\tmore: rows.length > options.limit,\n\t\t\t});\n\t\t\treturn { numbers: values, truncated: truncated };\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\tprotected override async getProviderPullRequest(\n\t\tsession: ProviderAuthenticationSession,\n\t\tresource: AzureRepositoryDescriptor,\n\t\tid: string,\n\t): Promise<PullRequest | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.getPullRequest(\n\t\t\tthis,\n\t\t\ttoTokenWithInfo(this.id, session),\n\t\t\tresource.owner,\n\t\t\tresource.project ?? resource.name,\n\t\t\tid,\n\t\t\t{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), resource) },\n\t\t);\n\t}\n\n\tprotected override getProviderPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\t\treturn getAzurePullRequestIdentityFromMaybeUrl(search, this.id);\n\t}\n\n\tpublic override async getRepoInfo(repo: {\n\t\towner: string;\n\t\tname: string;\n\t\tproject?: string;\n\t\tvirtualDirectory?: string;\n\t\tconnectionId?: string;\n\t}): Promise<ProviderRepository | undefined> {\n\t\tconst identity = getAzureRepositoryIdentity(repo);\n\t\tif (identity.projectName == null) return undefined;\n\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\tconst { tokenWithInfo, options } = this.getApiOptions(session);\n\t\treturn api.getRepo(tokenWithInfo, identity.resourceName, identity.repositoryName, identity.projectName, {\n\t\t\t...options,\n\t\t\tbaseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo),\n\t\t});\n\t}\n\n\tprotected override async getProviderRepositoryMetadata(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepo: AzureRepositoryDescriptor,\n\t\tcancellation?: AbortSignal,\n\t): Promise<RepositoryMetadata | undefined> {\n\t\treturn (await this.authenticationService.apis.azure)?.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{ baseUrl: getAzureRepositoryApiBaseUrl(this.apiBaseUrlFor(session), repo) },\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprotected override async searchProviderMyPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\toptions?: SearchMyPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (repos != null) {\n\t\t\t// TODO: implement repos version\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Legacy array-returning path (Launchpad/focus view): the account-wide read, mapped to the normalized model.\n\t\t// Its metadata (partial/failures) isn't surfaced here because this path's return type has no warning channel.\n\t\tconst result = await this.getProviderMyPullRequestsForUser(session, {\n\t\t\tstate: options?.state != null ? [options.state] : undefined,\n\t\t});\n\t\tif (result == null) return undefined;\n\n\t\t// Both served from the discovery caches the read above just filled.\n\t\tconst projects = (\n\t\t\tawait this.getProviderProjectsForResources(session, (await this.getProviderResourcesForUser(session)) ?? [])\n\t\t).values;\n\t\tif (projects.length === 0) return undefined;\n\n\t\tconst repoDescriptors = [\n\t\t\t...((await this.getRepoDescriptorsForProjects(session, projects)) ?? new Map()).values(),\n\t\t]\n\t\t\t.filter(r => r != null)\n\t\t\t.flat();\n\t\treturn result.values.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects, 'search'));\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\tconst api = await this.getProvidersApi();\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\t// Azure routes authorLogin/assigneeLogins to `searchCriteria.creatorId`/`reviewerId`, which require the\n\t\t// identity GUID, not the display name — matching the repo-scoped path in gitHostIntegration.ts. Using\n\t\t// `username` here would match nothing and return zero PRs. The GUID is resolved per organization below\n\t\t// (see `getFilterUserId`); this only checks there is a user at all.\n\t\tif (user?.id == null) return undefined;\n\n\t\t// Azure PRs are org + project scoped: enumerate the user's orgs and their projects, then read authored\n\t\t// and assigned PRs across all of them. Return the raw provider shape (not the normalized model) so the\n\t\t// ProviderBackend surface stays uniform with the other providers.\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\t// Structured per-scope failures from BOTH project discovery (a whole org dropped) and the per-project PR\n\t\t// drains, so the facade warns on the failed scope + sets `fetchFailed` instead of silently narrowing.\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tconst projects = await this.getProviderProjectsForResources(session, orgs, false, failures);\n\t\tif (projects.values.length === 0) {\n\t\t\t// Project discovery itself was incomplete (e.g. a truncated org); surface the metadata so the facade\n\t\t\t// can warn and set fetchFailed rather than reporting an empty account.\n\t\t\tconst incomplete = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\t\treturn {\n\t\t\t\tvalues: [],\n\t\t\t\tpaging: { cursor: '{}', more: false, truncated: incomplete || undefined },\n\t\t\t\t...(projects.metadata != null ? { metadata: projects.metadata } : {}),\n\t\t\t};\n\t\t}\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst states = toProviderPullRequestStates(options?.state);\n\t\tconst maxPagesPerProject = 20;\n\n\t\t// Drain each project fully (numbered pages) for both the authored and assigned reads. Azure has no\n\t\t// single cross-project cursor, so the aggregate is one page; `truncated` is set only if a project hit\n\t\t// the backstop with more pages remaining.\n\t\tlet truncated = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\t// Drain one project's numbered pages, returning its PRs and any per-page failure. Returns per-project\n\t\t// (not mutating shared state) so the fan-out below can be settled independently: one project's read\n\t\t// failure must not discard every other project's already-drained PRs.\n\t\tconst drainProject = async (\n\t\t\tproject: { namespace: string; project: string },\n\t\t\tscope: CollectionScope,\n\t\t\tfilter: {\n\t\t\t\tauthorLogin?: string;\n\t\t\t\tassigneeLogins?: string[];\n\t\t\t\treviewerId?: string;\n\t\t\t\tstates?: GitPullRequestState[];\n\t\t\t},\n\t\t): Promise<{ prs: ProviderPullRequest[]; projectIdentity: string; failure?: CollectionScopeFailure }> => {\n\t\t\tconst collected: ProviderPullRequest[] = [];\n\t\t\tconst projectIdentity = `${project.namespace}/${project.project}`;\n\t\t\tlet page: number | undefined;\n\t\t\tfor (let i = 0; i < maxPagesPerProject; i++) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await api.getPullRequestsForAzureProject(tokenWithInfo, project, {\n\t\t\t\t\t\t// Addressed below the project's own collection, applied once even when the configured address\n\t\t\t\t\t\t// already names it (the request appends the collection as `namespace`).\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, project.namespace),\n\t\t\t\t\t\t// A reviewer read narrows the states itself (see `toAzureReviewerReads`).\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t\tpage: page,\n\t\t\t\t\t});\n\t\t\t\t\tif (result == null) {\n\t\t\t\t\t\tif (page == null) break;\n\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\t\tfailure: toCollectionScopeFailure(\n\t\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\t\tnew Error('Azure DevOps returned no page after advertising a continuation'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tcollected.push(...result.data);\n\t\t\t\t\tif (!result.hasMore) break;\n\t\t\t\t\tif (result.nextPage == null || result.nextPage === page) {\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\t\tfailure: toCollectionScopeFailure(\n\t\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\t\tnew Error('Azure DevOps returned no advancing pull request continuation'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tpage = result.nextPage;\n\t\t\t\t\tif (i === maxPagesPerProject - 1) {\n\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t}\n\t\t\t\t} catch (ex) {\n\t\t\t\t\t// A page failure after the first page leaves the already-drained prefix intact; record the\n\t\t\t\t\t// failure at the project scope instead of re-throwing and discarding the prefix.\n\t\t\t\t\ttruncated = true;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tprs: collected,\n\t\t\t\t\t\tprojectIdentity: projectIdentity,\n\t\t\t\t\t\tfailure: toCollectionScopeFailure(scope, ex),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { prs: collected, projectIdentity: projectIdentity };\n\t\t};\n\n\t\t// Settle per-project failures instead of rejecting the whole sweep. `drainProject` already catches its own\n\t\t// page-level failures, so the structured failure (attributed to that project) is preserved rather than\n\t\t// re-thrown — re-throwing an auth/rate-limit rejection would discard every other project's already-drained\n\t\t// PRs. Auth/rate-limit stay actionable through the failure's kind (the facade maps it to an `auth`/`rate-limit`\n\t\t// warning + `fetchFailed`), matching the SDK's model. `failures` was declared above so project-discovery\n\t\t// failures and per-project drain failures share it.\n\t\tconst requested = options?.filters?.length ? new Set(options.filters) : undefined;\n\t\tconst wantAuthored = requested == null || requested.has(PullRequestFilter.Author);\n\t\t// Azure has no assignee concept distinct from reviewer. Both neutral relationships map to reviewerId.\n\t\tconst wantReviewed =\n\t\t\trequested == null ||\n\t\t\trequested.has(PullRequestFilter.Assignee) ||\n\t\t\trequested.has(PullRequestFilter.ReviewRequested);\n\t\tconst userIds = new Map<string, string | undefined>();\n\t\tconst identityFailures = new Map<string, unknown>();\n\t\tfor (const org of uniqueAzureNames(projects.values.map(p => p.resourceName))) {\n\t\t\ttry {\n\t\t\t\tuserIds.set(org.toLowerCase(), await this.getFilterUserId(session, org));\n\t\t\t} catch (ex) {\n\t\t\t\tthrowIfCallerContractError(ex);\n\t\t\t\tif (ex instanceof AuthenticationError) throw ex;\n\n\t\t\t\tidentityFailures.set(org.toLowerCase(), ex);\n\t\t\t}\n\t\t}\n\t\tconst groups = wantReviewed\n\t\t\t? await this.getReviewerGroupsByOrganization(session, projects.values, userIds, failures)\n\t\t\t: undefined;\n\t\tif (groups?.incomplete) {\n\t\t\ttruncated = true;\n\t\t}\n\t\tconst outcomes = await Promise.all(\n\t\t\tprojects.values.flatMap(p => {\n\t\t\t\tconst project = { namespace: p.resourceName, project: p.name };\n\t\t\t\tconst scope = { providerId: this.id, resourceId: p.resourceId, projectId: p.name };\n\t\t\t\tconst userId = userIds.get(p.resourceName.toLowerCase());\n\t\t\t\tif (userId == null) {\n\t\t\t\t\tfailures.push(\n\t\t\t\t\t\ttoCollectionScopeFailure(\n\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\tidentityFailures.get(p.resourceName.toLowerCase()) ??\n\t\t\t\t\t\t\t\tnew Error('The current user could not be resolved here'),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\ttruncated = true;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst drains = [];\n\t\t\t\tif (wantAuthored) {\n\t\t\t\t\tdrains.push(drainProject(project, scope, { authorLogin: userId }));\n\t\t\t\t}\n\t\t\t\tif (wantReviewed) {\n\t\t\t\t\tconst groupIds = groups?.byOrganization.get(p.resourceName.toLowerCase()) ?? new Set<string>();\n\t\t\t\t\tfor (const { filter, keep } of toAzureReviewerReads(userId, groupIds, states)) {\n\t\t\t\t\t\tdrains.push(\n\t\t\t\t\t\t\tdrainProject(project, scope, filter).then(o =>\n\t\t\t\t\t\t\t\tkeep != null ? { ...o, prs: o.prs.filter(keep) } : o,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn drains;\n\t\t\t}),\n\t\t);\n\n\t\t// Azure's `pullRequestId` is not account-global. Prefer repository + PR id, then the org-qualified URL.\n\t\t// If neither is available, preserve the row instead of collapsing unrelated repositories by numeric id.\n\t\tconst prsByIdentity = new Map<string, ProviderPullRequest>();\n\t\tfor (const outcome of outcomes) {\n\t\t\tif (outcome.failure != null) {\n\t\t\t\tfailures.push(outcome.failure);\n\t\t\t}\n\t\t\tfor (const pr of outcome.prs) {\n\t\t\t\tconst key =\n\t\t\t\t\tgetProviderPullRequestIdentity(pr) ?? `project:${outcome.projectIdentity}:pull-request:${pr.id}`;\n\t\t\t\tif (!prsByIdentity.has(key)) {\n\t\t\t\t\tprsByIdentity.set(key, pr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst metadata: CollectionMetadata | undefined = mergeCollectionMetadata(\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t\tprojects.metadata,\n\t\t);\n\n\t\tconst groupIds = groups?.groupIds ?? new Set<string>();\n\t\treturn {\n\t\t\tvalues: Array.from(prsByIdentity.values(), pr => markMyGroupReviews(pr, groupIds)),\n\t\t\tpaging: { cursor: '{}', more: false, truncated: truncated || undefined },\n\t\t\tmetadata: metadata,\n\t\t};\n\t}\n\n\t/**\n\t * Per organization (keyed by its lowercased name), every group the user is in (see {@link getReviewerGroupIds}),\n\t * and their union. An organization whose groups can't be read gets none and is recorded in `failures`, with the\n\t * read reported `incomplete`: what only its groups review is missing, while what names the user is still read.\n\t * Organizations whose user could not be resolved are left out; the read already reports them.\n\t */\n\tprivate async getReviewerGroupsByOrganization(\n\t\tsession: ProviderAuthenticationSession,\n\t\tprojects: readonly AzureProjectDescriptor[],\n\t\tuserIds: ReadonlyMap<string, string | undefined>,\n\t\tfailures: CollectionScopeFailure[],\n\t): Promise<{ byOrganization: Map<string, Set<string>>; groupIds: Set<string>; incomplete: boolean }> {\n\t\tconst byOrganization = new Map<string, Set<string>>();\n\t\tconst groupIds = new Set<string>();\n\t\tlet incomplete = false;\n\t\tawait Promise.all(\n\t\t\tuniqueAzureNames(projects.map(p => p.resourceName)).map(async org => {\n\t\t\t\tconst userId = userIds.get(org.toLowerCase());\n\t\t\t\tif (userId == null) return;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst ids = await this.getReviewerGroupIds(session, org, userId);\n\t\t\t\t\tbyOrganization.set(org.toLowerCase(), ids);\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tgroupIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tconst resourceId = projects.find(p => sameAzureName(p.resourceName, org))!.resourceId;\n\t\t\t\t\tfailures.push(toCollectionScopeFailure({ providerId: this.id, resourceId: resourceId }, ex));\n\t\t\t\t\tincomplete = true;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\treturn { byOrganization: byOrganization, groupIds: groupIds, incomplete: incomplete };\n\t}\n\n\tprotected override async searchProviderPullRequests(\n\t\tsession: ProviderAuthenticationSession,\n\t\tsearchQuery: string,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t\tcancellation?: AbortSignal,\n\t\toptions?: SearchPullRequestsOptions,\n\t): Promise<PullRequest[] | undefined> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst orgs = await this.getProviderResourcesForUser(session);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\tif (orgs == null || orgs.length === 0) return undefined;\n\n\t\t// `getProviderProjectsForResources` returns a collection result ({ values, metadata }); this search\n\t\t// path only needs the resolved projects, so read `.values`.\n\t\tconst projects = (await this.getProviderProjectsForResources(session, orgs)).values;\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\t\tif (projects.length === 0) return undefined;\n\n\t\tconst repoDescriptorsByProject = await this.getRepoDescriptorsForProjects(session, projects);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tconst repoDescriptors = [...repoDescriptorsByProject.values()].filter(r => r != null).flat();\n\t\tconst requestedRepos = repos?.map(getAzureRepositoryIdentity);\n\t\tconst repoInputs =\n\t\t\trequestedRepos == null\n\t\t\t\t? undefined\n\t\t\t\t: repoDescriptors.filter(r =>\n\t\t\t\t\t\trequestedRepos.some(\n\t\t\t\t\t\t\trepo =>\n\t\t\t\t\t\t\t\trepo.resourceName === r.resourceName &&\n\t\t\t\t\t\t\t\trepo.repositoryName === r.name &&\n\t\t\t\t\t\t\t\t(repo.projectName == null || repo.projectName === r.projectName),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\tif (repoInputs?.length === 0) return [];\n\n\t\tconst api = await this.getProvidersApi();\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\t\tconst states = toProviderPullRequestStates(options?.include);\n\t\tconst searchScopes: { project: { namespace: string; project: string }; repo?: ProviderRepoInput }[] =\n\t\t\trepoInputs != null\n\t\t\t\t? repoInputs.flatMap(repo =>\n\t\t\t\t\t\trepo.projectName == null\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tproject: { namespace: repo.resourceName, project: repo.projectName },\n\t\t\t\t\t\t\t\t\t\trepo: {\n\t\t\t\t\t\t\t\t\t\t\tid: repo.id,\n\t\t\t\t\t\t\t\t\t\t\tname: repo.name,\n\t\t\t\t\t\t\t\t\t\t\tnamespace: repo.resourceName,\n\t\t\t\t\t\t\t\t\t\t\tproject: repo.projectName,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t)\n\t\t\t\t: projects.map(project => ({\n\t\t\t\t\t\tproject: { namespace: project.resourceName, project: project.name },\n\t\t\t\t\t}));\n\n\t\tconst providerPullRequests = flatSettledResultsOrThrow(\n\t\t\tawait mapSettledBounded(searchScopes, providerFanOutConcurrency, async scope => {\n\t\t\t\tconst values: ProviderPullRequest[] = [];\n\t\t\t\tlet page: number | undefined;\n\t\t\t\tfor (let i = 0; i < 20; i++) {\n\t\t\t\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\t\t\t\tconst result = await api.getPullRequestsForAzureProject(tokenWithInfo, scope.project, {\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, scope.project.namespace),\n\t\t\t\t\t\tpage: page,\n\t\t\t\t\t\trepo: scope.repo,\n\t\t\t\t\t\tstates: states,\n\t\t\t\t\t});\n\t\t\t\t\tif (result == null) break;\n\n\t\t\t\t\tvalues.push(...result.data);\n\t\t\t\t\tif (!result.hasMore || result.nextPage == null) break;\n\n\t\t\t\t\tpage = result.nextPage;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}),\n\t\t);\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\treturn [...new Map(providerPullRequests.map(pr => [pr.url ?? `${pr.repository.id}:${pr.id}`, pr])).values()]\n\t\t\t.filter(pr => providerPullRequestMatchesSearch(pr, searchQuery))\n\t\t\t.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects, 'text-search'));\n\t}\n\n\tprotected override async searchProviderMyIssues(\n\t\tsession: ProviderAuthenticationSession,\n\t\trepos?: AzureRepositoryDescriptor[],\n\t): Promise<IssueShape[] | undefined> {\n\t\treturn (await this.searchProviderMyIssuesWithTruncation(session, repos))?.values;\n\t}\n\n\t/**\n\t * Account-wide \"my issues\" for Azure = the user's authored + assigned work items across every project of\n\t * every org. Azure's issue read is numbered-page, so each (project × filter) read is drained to exhaustion\n\t * (bounded by a defensive per-read backstop). Unlike a silent `flatSettled`, a project read that was\n\t * truncated by the backstop or rejected outright is recorded as `truncated`, so the facade reports an\n\t * incomplete read instead of publishing a partial list as complete.\n\t *\n\t * `searchOptions.org`/`.project` narrow the fan-out server-side (each drain is already a per-project read,\n\t * so scoping just selects which projects to drain). Without this there was no way to ask for \"work items in\n\t * project P\": a consumer had to filter the account-wide page client-side, which desynchronizes the filtered\n\t * `items` from the `hasMore`/`currentPage` of the pre-filter read — a project-less page reads as \"no issues\"\n\t * while `hasMore` is still true.\n\t */\n\tprotected override async searchProviderMyIssuesWithTruncation(\n\t\tsession: ProviderAuthenticationSession,\n\t\t_resources?: ResourceDescriptor[],\n\t\t_cancellation?: AbortSignal,\n\t\tsearchOptions?: SearchMyIssuesOptions,\n\t): Promise<AccountWideIssuesResult | undefined> {\n\t\tconst api = await this.getProvidersApi();\n\n\t\tconst user = await this.getProviderCurrentAccount(session);\n\t\tif (user?.username == null) return undefined;\n\n\t\tconst allOrgs = await this.getProviderResourcesForUser(session);\n\t\tif (allOrgs == null) return undefined;\n\t\tif (allOrgs.length === 0) return { values: [], truncated: false };\n\n\t\t// Scope by org first so project discovery only fans out over the requested account. An org filter that\n\t\t// matches nothing is an empty-but-successful read, not an unsupported one: returning `undefined` here\n\t\t// would be reported as \"account-wide issue search is not supported by this provider\".\n\t\tconst orgs =\n\t\t\tsearchOptions?.org != null ? allOrgs.filter(o => azureResourceMatches(o, searchOptions.org!)) : allOrgs;\n\t\tif (orgs.length === 0) return { values: [], truncated: false };\n\n\t\t// Structured per-scope failures from BOTH project discovery (a whole org dropped) and the per-project\n\t\t// issue drains, so the facade warns on the failed scope + sets `fetchFailed` instead of narrowing silently.\n\t\tconst failures: CollectionScopeFailure[] = [];\n\t\tconst discovered = await this.getProviderProjectsForResources(session, orgs, false, failures);\n\t\tconst projects =\n\t\t\tsearchOptions?.project != null\n\t\t\t\t? {\n\t\t\t\t\t\t...discovered,\n\t\t\t\t\t\tvalues: discovered.values.filter(p => azureResourceMatches(p, searchOptions.project!)),\n\t\t\t\t\t}\n\t\t\t\t: discovered;\n\t\tif (projects.values.length === 0) {\n\t\t\t// An explicitly-scoped read that found no matching project is an empty SUCCESS: `undefined` here is\n\t\t\t// reported as \"account-wide issue search is not supported by this provider\", which would send the\n\t\t\t// consumer down a repo-scoped fallback for what is simply an empty scope. Only an incomplete discovery\n\t\t\t// (which may itself have dropped the requested project) is truncated, and its metadata is forwarded so\n\t\t\t// the facade still warns on the failed scope.\n\t\t\treturn projects.metadata != null\n\t\t\t\t? {\n\t\t\t\t\t\tvalues: [],\n\t\t\t\t\t\ttruncated: projects.metadata.completeness !== 'complete',\n\t\t\t\t\t\tmetadata: projects.metadata,\n\t\t\t\t\t}\n\t\t\t\t: { values: [], truncated: false };\n\t\t}\n\n\t\tconst { tokenWithInfo } = this.getApiOptions(session);\n\n\t\t// Drain one (project × filter) read fully, threading the provider's paging cursor. The scope is passed so\n\t\t// a page-level failure preserves the already-drained prefix and records a structured failure instead of\n\t\t// re-throwing.\n\t\tconst drain = async (\n\t\t\tp: AzureProjectDescriptor,\n\t\t\tfilter: { assigneeLogins?: string[]; authorLogin?: string },\n\t\t): Promise<{\n\t\t\tissues: IssueShape[];\n\t\t\tprojectKey: string;\n\t\t\ttruncated: boolean;\n\t\t\tmetadata?: CollectionMetadata;\n\t\t}> => {\n\t\t\tconst result = await collectProviderPagedResult(\n\t\t\t\tcursor =>\n\t\t\t\t\tapi.getIssuesForAzureProject(tokenWithInfo, p.resourceName, p.name, {\n\t\t\t\t\t\t...this.getCollectionApiOptions(session, p.resourceName),\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t\tcursor: cursor,\n\t\t\t\t\t\tsort: searchOptions?.sort,\n\t\t\t\t\t}),\n\t\t\t\t20,\n\t\t\t\t{ providerId: this.id, resourceId: p.resourceId, projectId: p.name },\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tissues: result.values.map(i => fromProviderIssue(i, this, { project: p, projection: 'account' })),\n\t\t\t\t// Azure work-item ids are organization-scoped. Include both org and project so the\n\t\t\t\t// assigned/authored passes dedupe the same item without collapsing another org's item.\n\t\t\t\tprojectKey: `${p.resourceId}:${p.id}`,\n\t\t\t\ttruncated: result.truncated ?? false,\n\t\t\t\tmetadata: result.metadata,\n\t\t\t};\n\t\t};\n\n\t\t// `includeAllAssignees` broadens to every issue in each project (any assignee, any author), so a single\n\t\t// unfiltered drain per project replaces the assigned+authored pair — an unfiltered assignee drain already\n\t\t// subsumes the authored one.\n\t\t//\n\t\t// `filters` narrows the other way: unfiltered, \"my issues\" here is assigned ∪ authored, which is wider than\n\t\t// `assignee:@me`. Selecting the drains is the only correct place to narrow — dropping authored-only items\n\t\t// from the returned page would leave them counted in the per-project paging that produced it.\n\t\tconst filters = searchOptions?.filters;\n\t\tconst wantAssigned = !filters?.length || filters.includes(IssueFilter.Assignee);\n\t\tconst wantAuthored = !filters?.length || filters.includes(IssueFilter.Author);\n\t\tconst outcomes = await Promise.all(\n\t\t\tprojects.values.flatMap(p => {\n\t\t\t\tif (searchOptions?.includeAllAssignees) return [drain(p, {})];\n\n\t\t\t\tconst drains = [];\n\t\t\t\tif (wantAssigned) {\n\t\t\t\t\tdrains.push(drain(p, { assigneeLogins: [user.username!] }));\n\t\t\t\t}\n\t\t\t\tif (wantAuthored) {\n\t\t\t\t\tdrains.push(drain(p, { authorLogin: user.username! }));\n\t\t\t\t}\n\t\t\t\treturn drains;\n\t\t\t}),\n\t\t);\n\n\t\tconst issuesById = new Map<string, IssueShape>();\n\t\tlet truncated = projects.metadata != null && projects.metadata.completeness !== 'complete';\n\t\tlet drainMetadata: CollectionMetadata | undefined;\n\t\tfor (const outcome of outcomes) {\n\t\t\tif (outcome.truncated) {\n\t\t\t\ttruncated = true;\n\t\t\t}\n\t\t\tif (outcome.metadata != null) {\n\t\t\t\tdrainMetadata = mergeCollectionMetadata(drainMetadata, outcome.metadata);\n\t\t\t}\n\n\t\t\tfor (const issue of outcome.issues) {\n\t\t\t\tconst key = `${outcome.projectKey}:${issue.nodeId ?? issue.id}`;\n\t\t\t\tif (!issuesById.has(key)) {\n\t\t\t\t\tissuesById.set(key, issue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst metadata: CollectionMetadata | undefined = mergeCollectionMetadata(\n\t\t\tfailures.length > 0 ? { completeness: 'partial', failures: failures } : undefined,\n\t\t\tmergeCollectionMetadata(drainMetadata, projects.metadata),\n\t\t);\n\n\t\treturn { values: [...issuesById.values()], truncated: truncated, metadata: metadata };\n\t}\n\n\tprotected override async providerOnConnect(): Promise<void> {\n\t\tif (this._session == null) return;\n\n\t\tconst discoveryKey = this.discoveryKey(this._session);\n\n\t\tconst canHydrateStoredProjects = (metadata: CollectionMetadata | undefined): boolean =>\n\t\t\tmetadata == null || metadata.completeness === 'complete';\n\n\t\tconst storedAccount = this.ctx.storage.get(`azure:${discoveryKey}:account`);\n\t\tconst storedOrganizations = this.ctx.storage.get(`azure:${discoveryKey}:organizations`);\n\t\tconst storedProjects = this.ctx.storage.get(`azure:${discoveryKey}:projects`);\n\t\tlet account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;\n\n\t\tlet organizations = storedOrganizations?.data?.map((o: AzureOrganizationDescriptor) => ({ ...o }));\n\n\t\tconst storedProjectsData = storedProjects?.data as\n\t\t\t| ProviderApiCollectionResult<AzureProjectDescriptor>\n\t\t\t| AzureProjectDescriptor[]\n\t\t\t| undefined;\n\t\tlet projects: ProviderApiCollectionResult<AzureProjectDescriptor> | undefined;\n\t\tif (!Array.isArray(storedProjectsData) && Array.isArray(storedProjectsData?.values)) {\n\t\t\tconst hydrated = {\n\t\t\t\tvalues: storedProjectsData.values.map((p: AzureProjectDescriptor) => ({ ...p })),\n\t\t\t\t...(storedProjectsData.metadata != null ? { metadata: storedProjectsData.metadata } : {}),\n\t\t\t};\n\t\t\tif (canHydrateStoredProjects(hydrated.metadata)) {\n\t\t\t\tprojects = hydrated;\n\t\t\t}\n\t\t}\n\n\t\tif (storedAccount == null) {\n\t\t\taccount = await this.getProviderCurrentAccount(this._session);\n\t\t\tif (account != null) {\n\t\t\t\t// Clear all other stored organizations and projects and accounts when our session changes\n\t\t\t\tawait this.ctx.storage.deleteWithPrefix('azure');\n\t\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:account`, {\n\t\t\t\t\tv: 1,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tid: account.id,\n\t\t\t\t\t\tname: account.name,\n\t\t\t\t\t\temail: account.email,\n\t\t\t\t\t\tavatarUrl: account.avatarUrl,\n\t\t\t\t\t\tusername: account.username,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._accounts ??= new Map<string, Account | undefined>();\n\t\tthis._accounts.set(discoveryKey, account);\n\n\t\tif (storedOrganizations == null) {\n\t\t\torganizations = await this.getProviderResourcesForUser(this._session, true);\n\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:organizations`, {\n\t\t\t\tv: 1,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tdata: organizations,\n\t\t\t});\n\t\t}\n\n\t\tthis._organizations ??= new Map<string, AzureOrganizationDescriptor[] | undefined>();\n\t\tthis._organizations.set(discoveryKey, organizations);\n\n\t\tif (projects == null && organizations?.length) {\n\t\t\tprojects = await this.getProviderProjectsForResources(this._session, organizations);\n\t\t\tif (projects != null && canHydrateStoredProjects(projects.metadata)) {\n\t\t\t\tawait this.ctx.storage.store(`azure:${discoveryKey}:projects`, {\n\t\t\t\t\tv: 2,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tdata: projects,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait this.ctx.storage.delete(`azure:${discoveryKey}:projects`);\n\t\t\t}\n\t\t}\n\n\t\tthis._projects ??= new Map<string, AzureProjectDescriptor[] | undefined>();\n\t\tif (projects != null && canHydrateStoredProjects(projects.metadata)) {\n\t\t\tfor (const project of projects.values) {\n\t\t\t\tconst projectKey = `${discoveryKey}:${project.resourceId}`;\n\t\t\t\tconst projects = this._projects.get(projectKey);\n\t\t\t\tif (projects == null) {\n\t\t\t\t\tthis._projects.set(projectKey, [project]);\n\t\t\t\t} else if (!projects.some(p => p.id === project.id)) {\n\t\t\t\t\tprojects.push(project);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override providerOnDisconnect(): void {\n\t\tthis._organizations = undefined;\n\t\tthis._projects = undefined;\n\t\tthis._accounts = undefined;\n\t\tthis._reviewerGroupIds.clear();\n\t}\n\n\tprotected fromAzureProviderPullRequest(\n\t\tazurePullRequest: ProviderPullRequest,\n\t\trepoDescriptors: AzureRemoteRepositoryDescriptor[],\n\t\tprojectDescriptors: AzureProjectDescriptor[],\n\t\tprojection: PullRequestProjection,\n\t): PullRequest {\n\t\tconst baseRepoDescriptor = repoDescriptors.find(r => r.id === azurePullRequest.repository.id);\n\t\tconst headRepoDescriptor =\n\t\t\tazurePullRequest.headRepository != null\n\t\t\t\t? repoDescriptors.find(r => r.id === azurePullRequest.headRepository!.id)\n\t\t\t\t: undefined;\n\t\tlet project: AzureProjectDescriptor | undefined;\n\t\tif (baseRepoDescriptor != null) {\n\t\t\tazurePullRequest.repository.remoteInfo = {\n\t\t\t\t...azurePullRequest.repository.remoteInfo,\n\t\t\t\tcloneUrlHTTPS: baseRepoDescriptor.cloneUrlHttps ?? '',\n\t\t\t\tcloneUrlSSH: baseRepoDescriptor.cloneUrlSsh ?? '',\n\t\t\t};\n\t\t}\n\n\t\tif (headRepoDescriptor != null) {\n\t\t\tazurePullRequest.headRepository = {\n\t\t\t\t...azurePullRequest.headRepository,\n\t\t\t\tid: azurePullRequest.headRepository?.id ?? headRepoDescriptor.id,\n\t\t\t\tname: azurePullRequest.headRepository?.name ?? headRepoDescriptor.name,\n\t\t\t\towner: {\n\t\t\t\t\tlogin: azurePullRequest.headRepository?.owner.login ?? headRepoDescriptor.resourceName,\n\t\t\t\t},\n\t\t\t\tremoteInfo: {\n\t\t\t\t\t...azurePullRequest.headRepository?.remoteInfo,\n\t\t\t\t\tcloneUrlHTTPS: headRepoDescriptor.cloneUrlHttps ?? '',\n\t\t\t\t\tcloneUrlSSH: headRepoDescriptor.cloneUrlSsh ?? '',\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (baseRepoDescriptor?.projectName != null) {\n\t\t\tproject = projectDescriptors.find(\n\t\t\t\tp => p.resourceName === baseRepoDescriptor.resourceName && p.name === baseRepoDescriptor.projectName,\n\t\t\t);\n\t\t}\n\t\treturn fromProviderPullRequest(azurePullRequest, this, { project: project, projection: projection });\n\t}\n}\n\nconst cloudMetadata = providersMetadata[GitCloudHostIntegrationId.AzureDevOps];\nconst cloudAuthProvider = Object.freeze({ id: cloudMetadata.id, scopes: cloudMetadata.scopes });\n\nexport class AzureDevOpsIntegration extends AzureDevOpsIntegrationBase<GitCloudHostIntegrationId.AzureDevOps> {\n\treadonly authProvider: IntegrationAuthenticationProviderDescriptor = cloudAuthProvider;\n\treadonly id = GitCloudHostIntegrationId.AzureDevOps;\n\tprotected readonly key = this.id;\n\treadonly name: string = 'Azure DevOps';\n\tget domain(): string {\n\t\treturn cloudMetadata.domain;\n\t}\n\tprotected override apiBaseUrlFor(_session: ProviderAuthenticationSession): string {\n\t\treturn 'https://dev.azure.com';\n\t}\n}\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { IssueSorting } from "../../../git/models/issue.js";
2
- import "../providerFilters.js";
3
2
  //#region ../plus/integrations/src/providers/issueSorts.d.ts
4
3
  /** GitHub and GHE: one `search` channel serves all three issue reads, so all three order the same way. */
5
4
  export declare const githubIssueSorts: IssueSorting[];
@@ -1,14 +1,14 @@
1
1
  import { Logger as _logger } from "../../../utils/logger.js";
2
2
  import "../constants.js";
3
3
  import { isJiraMissingProjectError } from "./providerErrors.js";
4
- import { toCollectionScopeFailure } from "../collectionMetadata.js";
4
+ import { isIncompleteCollection, toCollectionScopeFailure } from "../collectionMetadata.js";
5
5
  import { toTokenWithInfo } from "../authentication/models.js";
6
- import { mergeCollectionMetadata } from "./utils/providerPaging.js";
7
6
  import { areDomainsOnSameHost, baseUrlFromDomain } from "../utils/domain.utils.js";
7
+ import { mergeCollectionMetadata } from "./utils/providerPaging.js";
8
8
  import { providersMetadata, toAccount, toIssueShape, toProviderIssueStates } from "./models.js";
9
9
  import { IssuesIntegration, groupProjectIssuesSearches } from "../models/issuesIntegration.js";
10
10
  import { DiscoveryCache } from "./utils/discoveryCache.js";
11
- import { drainJiraIssues, readUserScopedJiraIssues, searchJiraProjectIssues, toUniqueJiraIssueShapes } from "./utils/jiraIssueDrains.js";
11
+ import { drainJiraIssues, readUserScopedJiraIssues, searchJiraProjectIssues, summarizePageMetadata, toUniqueJiraIssueShapes, withFailureScope } from "./utils/jiraIssueDrains.js";
12
12
  import { JIRA_MAX_PROJECT_KEYS_PER_REQUEST } from "@gitkraken/provider-apis";
13
13
  //#region ../plus/integrations/src/providers/jira-server.ts
14
14
  const metadata = providersMetadata["jira-server"];
@@ -107,7 +107,7 @@ var JiraServerIntegration = class extends IssuesIntegration {
107
107
  const resourceId = this.resourceFor(session).id;
108
108
  const descriptors = projects.map((p) => ({
109
109
  id: p.id,
110
- key: p.name,
110
+ key: p.key?.trim() || p.id,
111
111
  name: p.name,
112
112
  resourceId
113
113
  }));
@@ -186,6 +186,7 @@ var JiraServerIntegration = class extends IssuesIntegration {
186
186
  async searchProviderProjectIssues(session, requests) {
187
187
  const { options } = requests[0];
188
188
  if (options.user == null) return void 0;
189
+ if (requests.length === 1) return void 0;
189
190
  const tokenWithInfo = toTokenWithInfo(this.id, session);
190
191
  const api = await this.getProvidersApi();
191
192
  const baseUrl = this.apiBaseUrlFor(session);
@@ -224,6 +225,7 @@ var JiraServerIntegration = class extends IssuesIntegration {
224
225
  let cursor;
225
226
  let truncated = false;
226
227
  let metadata;
228
+ const pages = [];
227
229
  const stopIncomplete = (reason) => {
228
230
  truncated = true;
229
231
  metadata = mergeCollectionMetadata(metadata, {
@@ -242,6 +244,10 @@ var JiraServerIntegration = class extends IssuesIntegration {
242
244
  break;
243
245
  }
244
246
  results.push(...page.data.map((issue) => toIssueShape(issue, this, { projection: "account" })).filter((r) => r != null));
247
+ if (page.metadata != null) {
248
+ truncated ||= isIncompleteCollection(page.metadata);
249
+ pages.push(withFailureScope(page.metadata, accountScope));
250
+ }
245
251
  if (!page.hasMore) break;
246
252
  if (page.nextCursor == null || page.nextCursor === cursor) {
247
253
  stopIncomplete("Jira Server returned no advancing issue continuation");
@@ -253,7 +259,7 @@ var JiraServerIntegration = class extends IssuesIntegration {
253
259
  return {
254
260
  values: results,
255
261
  truncated,
256
- metadata
262
+ metadata: mergeCollectionMetadata(summarizePageMetadata(pages), metadata)
257
263
  };
258
264
  }
259
265
  async getProviderLinkedIssueOrPullRequest(session, _resource, { key }) {