@gitkraken/core-gitlens 0.7.1 → 0.8.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.
- package/CHANGELOG.md +48 -1
- package/dist/git/cache.d.ts +18 -5
- package/dist/git/cache.js +26 -8
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +5 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/errors.d.ts +28 -1
- package/dist/git/errors.js +45 -1
- package/dist/git/errors.js.map +1 -1
- package/dist/git/providers/branches.d.ts +5 -1
- package/dist/git/providers/commits.d.ts +24 -1
- package/dist/git/providers/config.d.ts +7 -1
- package/dist/git/providers/operations.d.ts +6 -0
- package/dist/git/providers/provider.d.ts +17 -0
- package/dist/git/providers/refs.d.ts +38 -3
- package/dist/git/providers/revision.d.ts +5 -1
- package/dist/git/providers/staging.d.ts +12 -0
- package/dist/git/providers/worktrees.d.ts +23 -3
- package/dist/git/run.types.d.ts +6 -0
- package/dist/git-cli/cliGitProvider.d.ts +17 -1
- package/dist/git-cli/cliGitProvider.js +37 -1
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +12 -2
- package/dist/git-cli/exec/git.js +48 -17
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +4 -1
- package/dist/git-cli/exec/gitQueue.js +1 -1
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +10 -1
- package/dist/git-cli/providers/branches.js +15 -8
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +23 -1
- package/dist/git-cli/providers/commits.js +57 -8
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.js +4 -3
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +1 -0
- package/dist/git-cli/providers/operations.js +39 -3
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.js +20 -41
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +2 -2
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +15 -3
- package/dist/git-cli/providers/refs.js +115 -10
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +3 -1
- package/dist/git-cli/providers/revision.js +9 -5
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +8 -0
- package/dist/git-cli/providers/staging.js +59 -7
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +31 -2
- package/dist/git-cli/providers/worktrees.js +75 -7
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -3
- package/dist/plus/git-github/api/github.js +237 -24
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
- package/dist/plus/git-github/providers/github/branches.js +2 -1
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
- package/dist/plus/git-github/providers/github/refs.js +4 -4
- package/dist/plus/git-github/providers/github/refs.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts +3 -1
- package/dist/plus/git-github/providers/github/revision.js +1 -1
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +48 -3
- package/dist/plus/integrations/collectionMetadata.js +138 -8
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/errors.d.ts +3 -1
- package/dist/plus/integrations/errors.js +7 -3
- package/dist/plus/integrations/errors.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +6 -3
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +36 -10
- package/dist/plus/integrations/integrationService.js +16 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +107 -37
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +129 -14
- package/dist/plus/integrations/models/gitHostIntegration.js +142 -18
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +117 -11
- package/dist/plus/integrations/models/integration.js +175 -13
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
- package/dist/plus/integrations/models/issuesIntegration.js +42 -10
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +14 -18
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
- package/dist/plus/integrations/providers/azure/models.js +112 -1
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +73 -3
- package/dist/plus/integrations/providers/azureDevOps.js +117 -3
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +2 -2
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +48 -2
- package/dist/plus/integrations/providers/bitbucket-server.js +51 -1
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +45 -2
- package/dist/plus/integrations/providers/bitbucket.js +41 -2
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +49 -5
- package/dist/plus/integrations/providers/github.js +102 -7
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +1 -1
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +49 -2
- package/dist/plus/integrations/providers/gitlab.js +80 -4
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
- package/dist/plus/integrations/providers/jira-server.js +5 -8
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +9 -0
- package/dist/plus/integrations/providers/jira.js +13 -1
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/linear.js +1 -1
- package/dist/plus/integrations/providers/models.d.ts +13 -2
- package/dist/plus/integrations/providers/models.js +11 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
- package/dist/plus/integrations/providers/providerErrors.js +10 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +60 -1
- package/dist/plus/integrations/providers/providersApi.js +137 -2
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/providers/utils.d.ts +1 -1
- package/dist/plus/integrations/reads/broaden.js +1 -1
- package/dist/plus/integrations/reads/context.d.ts +1 -1
- package/dist/plus/integrations/reads/counts.js +1 -1
- package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
- package/dist/plus/integrations/reads/currentAccount.js +46 -0
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
- package/dist/plus/integrations/reads/drains.d.ts +5 -2
- package/dist/plus/integrations/reads/drains.js +8 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +1 -1
- package/dist/plus/integrations/reads/hierarchy.utils.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
- package/dist/plus/integrations/reads/issueBatch.js +193 -48
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +1 -1
- package/dist/plus/integrations/reads/issues.js +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequests.js +3 -3
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js +4 -4
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +87 -6
- package/dist/plus/integrations/results.js +9 -2
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/utils/env/node/exec.js +3 -3
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +175 -35
- package/docs/kepler-git-write-api-parity.md +239 -0
- package/docs/kepler-read-api-parity.md +75 -28
- package/package.json +1 -1
- package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
- package/dist/plus/integrations/reads/trackerIssue.js +0 -60
- package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectionMetadata.js","names":[],"sources":["../../../../plus/integrations/src/collectionMetadata.ts"],"sourcesContent":["import type {\n\tCollectionMetadata,\n\tCollectionOmission,\n\tCollectionScope,\n\tCollectionScopeFailure,\n} from '@gitkraken/provider-apis';\n// Matched by its `code` discriminator rather than by `instanceof`: the SDK ships one bundle per entry point, so\n// the class reached through the root is not the same object as the one reached through `/providers`.\nimport { isInvalidRequestError, isUnsupportedSortError } from '@gitkraken/provider-apis';\nimport {\n\tAuthenticationError,\n\tRequestClientError,\n\tRequestNotFoundError,\n\tRequestRateLimitError,\n} from '@gitlens/git/errors.js';\nimport type { TokenWithInfo } from './authentication/models.js';\nimport type { IntegrationIds } from './constants.js';\nimport { isRateLimitResponse } from './errors.js';\nimport type { ProviderWarning, ProviderWarningOmission } from './results.js';\nimport { appendDedupedWarning } from './results.js';\n\n/**\n * Re-throws an error that is a fact about the CALL rather than about one scope of a fan-out.\n *\n * Every provider fan-out catches per-scope rejections and records them as {@link CollectionScopeFailure}s, which is\n * right for auth, rate limits and a missing project: those really did happen to one scope, and the siblings that\n * succeeded must survive. A caller-contract error is the opposite — it is identical for every scope and was decided\n * before any request went out — so degrading it would hand back N indistinguishable failures and an empty `partial`\n * page, describing an invalid call as an incomplete read.\n *\n * Today that means the SDK's `UnsupportedSortError` and `InvalidRequestError` — the two codes it lists in its own\n * `CALLER_CONTRACT_ERROR_CODES`, both documented as \"never degraded into a `CollectionScopeFailure` or an\n * omission\". The second covers arguments rejected before the first request goes out: a project key list longer\n * than one Jira search can carry (or an empty one), a non-integer `pageSize`, an unknown current-user filter, or a\n * Jira Server read with no `baseUrl` to address. Called from every fan-out rather than spelled out in each, so a\n * fan-out added later inherits the rule instead of silently omitting it — which is exactly how Azure's\n * account-wide drain came to degrade it while its three siblings did not.\n */\nexport function throwIfCallerContractError(ex: unknown): void {\n\tif (isUnsupportedSortError(ex) || isInvalidRequestError(ex)) throw ex;\n}\n\n/**\n * Maps a caught GitLens request error to the SDK collection failure vocabulary used inside provider fan-outs.\n */\nexport function toCollectionFailureKind(ex: unknown): CollectionScopeFailure['kind'] {\n\tif (ex instanceof AuthenticationError) return 'authentication';\n\tif (ex instanceof RequestRateLimitError) return 'rate-limit';\n\tif (ex instanceof RequestNotFoundError) return 'not-found';\n\treturn 'provider';\n}\n\n/** Builds a structured SDK scope failure from a caught GitLens request error. */\nexport function toCollectionScopeFailure(scope: CollectionScopeFailure['scope'], ex: unknown): CollectionScopeFailure {\n\treturn {\n\t\tscope: scope,\n\t\tkind: toCollectionFailureKind(ex),\n\t\t...(ex instanceof Error && ex.message ? { message: ex.message } : {}),\n\t};\n}\n\nfunction collectionFailureKindToWarningKind(kind: CollectionScopeFailure['kind']): ProviderWarning['kind'] {\n\tswitch (kind) {\n\t\tcase 'authentication':\n\t\t\treturn 'auth';\n\t\tcase 'rate-limit':\n\t\t\treturn 'rate-limit';\n\t\tcase 'not-found':\n\t\t\treturn 'not-found';\n\t\tdefault:\n\t\t\treturn 'other';\n\t}\n}\n\nfunction getCollectionFailureStatus(message: string | undefined): number | undefined {\n\tif (message == null) return undefined;\n\n\tconst match = /\\((\\d{3})\\)/.exec(message) ?? /^(?:HTTP\\s+)?(\\d{3})\\b/i.exec(message.trim());\n\treturn match != null ? Number(match[1]) : undefined;\n}\n\nfunction toCollectionFailureWarningKind(failure: CollectionScopeFailure): ProviderWarning['kind'] {\n\tconst mapped = collectionFailureKindToWarningKind(failure.kind);\n\tif (mapped !== 'other' || (failure.kind !== 'provider' && failure.kind !== 'unknown')) return mapped;\n\n\t// provider-apis currently groups several HTTP statuses under `provider` in partial fan-outs. The custom\n\t// fetch adapter retains the status in `message`, so recover the same neutral classification the thrown-error\n\t// path exposes instead of downgrading these structured failures to `other`.\n\tconst status = getCollectionFailureStatus(failure.message);\n\tswitch (status) {\n\t\tcase 401:\n\t\t\treturn 'auth';\n\t\tcase 403:\n\t\t\treturn isRateLimitResponse({ status: status, message: failure.message }) ? 'rate-limit' : 'auth';\n\t\tcase 404:\n\t\tcase 410:\n\t\tcase 422:\n\t\t\treturn 'not-found';\n\t\tcase 429:\n\t\t\treturn 'rate-limit';\n\t\tdefault:\n\t\t\treturn mapped;\n\t}\n}\n\nexport function toCollectionFailureError(failure: CollectionScopeFailure, tokenWithInfo: TokenWithInfo): Error {\n\tconst error = new Error(failure.message ?? 'Provider request failed');\n\tconst kind = toCollectionFailureWarningKind(failure);\n\tconst { accessToken, ...tokenInfo } = tokenWithInfo;\n\tif (kind === 'auth') return new AuthenticationError(tokenInfo, error.message, error);\n\tif (kind === 'rate-limit') return new RequestRateLimitError(error, accessToken, undefined);\n\tif (kind === 'not-found') return new RequestNotFoundError(error);\n\n\tconst status = getCollectionFailureStatus(failure.message);\n\tif (kind === 'other' && status != null && status >= 400 && status < 500) {\n\t\treturn new RequestClientError(error);\n\t}\n\n\treturn error;\n}\n\n/** ` (resource r, project p, repository o/n)` for the scope IDs present; empty when the scope names none. */\nfunction collectionScopeText(scope: CollectionScope | undefined): string {\n\tconst parts: string[] = [];\n\tif (scope?.resourceId != null) {\n\t\tparts.push(`resource ${scope.resourceId}`);\n\t}\n\tif (scope?.projectId != null) {\n\t\tparts.push(`project ${scope.projectId}`);\n\t}\n\tif (scope?.repositoryId != null) {\n\t\tparts.push(`repository ${scope.repositoryId}`);\n\t}\n\n\treturn parts.length ? ` (${parts.join(', ')})` : '';\n}\n\nfunction collectionFailureMessage(failure: CollectionScopeFailure): string {\n\tconst detail = failure.message != null ? `: ${failure.message}` : '';\n\treturn `Failed to read ${failure.kind} scope${collectionScopeText(failure.scope)}${detail}`;\n}\n\n/**\n * Explains one omission in the consumer's terms — what was left out and, where the SDK reports it, how much.\n *\n * An omission is a completeness fact, never a failure: the read succeeded, and the provider (or the SDK's own\n * recovery budget) is what withheld results. That is why these never contribute to `fetchFailed`. Whether a\n * retry would recover anything is a separate question this layer cannot answer — see the `recovery` note on\n * {@link toProviderWarningOmission}.\n */\nfunction collectionOmissionMessage(omission: CollectionOmission): string {\n\tconst scopeText = collectionScopeText(omission.scope);\n\tswitch (omission.kind) {\n\t\tcase 'provider-limit':\n\t\t\t// `totalCount` is the only figure saying how much was withheld; both fields are optional, so degrade\n\t\t\t// through the shapes the SDK can actually emit rather than printing `undefined`.\n\t\t\tif (omission.totalCount != null && omission.limit != null) {\n\t\t\t\treturn `Search${scopeText} matched ${omission.totalCount} results, but the provider exposes at most ${omission.limit}`;\n\t\t\t}\n\t\t\tif (omission.limit != null) {\n\t\t\t\treturn `Search${scopeText} exceeded the provider limit of ${omission.limit} results`;\n\t\t\t}\n\t\t\treturn `Search${scopeText} exceeded the provider's result limit`;\n\t\tcase 'recovery-budget':\n\t\t\treturn `Stopped recovering omitted results${scopeText} after reaching the request budget${\n\t\t\t\tomission.limit != null ? ` of ${omission.limit} requests` : ''\n\t\t\t}`;\n\t\tcase 'pagination-incomplete':\n\t\t\treturn `More results are available${scopeText} than this read returned`;\n\t\tdefault:\n\t\t\t// `CollectionOmissionKind` is a closed union, so this is unreachable today. Kept as a compile-time\n\t\t\t// guard rather than a silent fallback: an SDK bump that adds a kind breaks the build here instead\n\t\t\t// of quietly degrading it to a vague message.\n\t\t\tomission.kind satisfies never;\n\t\t\treturn `Some results were omitted${scopeText}; the read is incomplete`;\n\t}\n}\n\n/**\n * Forwards an SDK omission as the structured signal consumers read instead of parsing {@link\n * collectionOmissionMessage}'s prose.\n *\n * `results.ts` re-spells `CollectionOmissionKind` rather than importing it, so the published warning surface\n * carries no `@gitkraken/provider-apis` types (see the export block in `index.ts`). The return type is what\n * keeps the two unions honest: an SDK bump that adds a member fails to compile here, alongside\n * `collectionOmissionMessage`'s `satisfies never`.\n *\n * `scope` is copied because the SDK's own object is retained and re-merged across drained pages\n * (`providerPaging.ts`), and this one crosses the package boundary.\n *\n * `recovery` is always `'none'`, deliberately, and a scoped `pagination-incomplete` is why it looks wrong: the\n * SDK emits that one shape from situations with opposite remedies and says so itself — \"Either the read\n * deliberately took one page per scope, or the provider advertised another page it gave no way to reach.\" Its\n * `collectAcrossScopes` producers (Azure, Bitbucket, Bitbucket Server) are the first, its `drainAcrossScopes`\n * producers (GitLab, Jira) the second, and those report an omission only when a cursor STALLED — so re-reading\n * that scope stalls at the identical page. Nothing in `CollectionOmission` separates the two, so claiming\n * recoverability would ship the dead-end button `recovery` exists to prevent. Making the recoverable case\n * claimable needs provider-apis to say whether a scope was drained or merely sampled: a fact to forward, not\n * to guess here.\n */\nfunction toProviderWarningOmission(omission: CollectionOmission): ProviderWarningOmission {\n\treturn {\n\t\tkind: omission.kind,\n\t\trecovery: 'none',\n\t\t...(omission.limit != null ? { limit: omission.limit } : {}),\n\t\t// The SDK types this `number | null | undefined`; normalize to one absence for consumers.\n\t\t...(omission.totalCount != null ? { totalCount: omission.totalCount } : {}),\n\t\t...(omission.scope != null ? { scope: { ...omission.scope } } : {}),\n\t};\n}\n\n/**\n * Whether SDK metadata describes a read that may be missing results.\n *\n * A reported omission counts on its own rather than deferring to `completeness`. The SDK does couple the\n * two — every site that emits an omission degrades completeness in the same call — so today the omission\n * clause changes no outcome. It is defensive: the two facts arrive as independent fields, and a read that\n * names what it left out must not be publishable as whole if a future producer sets only one of them.\n *\n * This is the single definition of \"may be missing results\", shared with `getPagedResult`, so one metadata\n * object cannot be truncated at one layer and complete at another.\n */\nexport function isIncompleteCollection(metadata: CollectionMetadata | undefined): boolean {\n\tif (metadata == null) return false;\n\n\treturn metadata.completeness !== 'complete' || (metadata.omissions?.length ?? 0) > 0;\n}\n\n/** Converts internal SDK collection metadata into neutral provider facade signals. */\nexport function assessCollectionMetadata(\n\tproviderId: IntegrationIds,\n\tdomain: string | undefined,\n\tconnectionId: string | undefined,\n\tmetadata: CollectionMetadata | undefined,\n): { warnings: ProviderWarning[]; fetchFailed: boolean; truncated: boolean } {\n\tif (metadata == null) return { warnings: [], fetchFailed: false, truncated: false };\n\n\tconst warnings: ProviderWarning[] = [];\n\tconst failures = metadata.failures ?? [];\n\tfor (const failure of failures) {\n\t\tconst kind = toCollectionFailureWarningKind(failure);\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\tmessage: collectionFailureMessage(failure),\n\t\t\tkind: kind,\n\t\t\tisAuth: kind === 'auth',\n\t\t});\n\t}\n\n\t// Omissions explain WHY a read is incomplete when nothing failed — a provider cap, an exhausted recovery\n\t// budget, an undrained scope. They classify as `other`, never `auth`, and are deliberately excluded from\n\t// `fetchFailed` below: the request itself succeeded. `omission` carries that same fact structurally, so a\n\t// consumer can act on it without parsing the message.\n\tconst omissions = metadata.omissions ?? [];\n\tfor (const omission of omissions) {\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\tmessage: collectionOmissionMessage(omission),\n\t\t\tkind: 'other',\n\t\t\tisAuth: false,\n\t\t\tomission: toProviderWarningOmission(omission),\n\t\t});\n\t}\n\n\tconst incomplete = isIncompleteCollection(metadata);\n\t// Only fall back to the generic message when nothing more specific was reported; an omission already\n\t// explains the incompleteness in the consumer's terms, so adding this on top would be noise.\n\t//\n\t// This one deliberately carries no `omission`: it fires precisely when the SDK reported incompleteness\n\t// WITHOUT saying what was left out, so there is no structured fact to forward and synthesizing one would\n\t// assert a specificity this layer does not have.\n\tif (incomplete && failures.length === 0 && omissions.length === 0) {\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\tmessage:\n\t\t\t\tmetadata.completeness === 'partial'\n\t\t\t\t\t? 'Some results were omitted; the read is incomplete'\n\t\t\t\t\t: 'Result completeness could not be confirmed',\n\t\t\tkind: 'other',\n\t\t\tisAuth: false,\n\t\t});\n\t}\n\n\treturn { warnings: warnings, fetchFailed: failures.length > 0, truncated: incomplete };\n}\n\n/**\n * Appends neutral warnings derived from SDK metadata and returns its failure/truncation assessment.\n *\n * `reported` says whether the metadata described this read's incompleteness at all. A caller that would\n * otherwise add its own generic \"this was truncated\" warning uses it to stay quiet — the same rule\n * {@link assessCollectionMetadata} applies to its own generic fallback, one layer up: whatever the metadata\n * reported already names this provider and, unless it was that same fallback, says something a consumer can\n * act on. Restating it in a weaker vocabulary is how one gap becomes two warnings with two different verdicts.\n *\n * `truncated` is the near-synonym that must NOT be used for that question: it comes from\n * {@link isIncompleteCollection}, which does not consider failures, so metadata carrying a typed failure\n * alongside `completeness: 'complete'` reports `truncated: false` while having already appended the warning\n * that explains everything. Gating on it would restate exactly the case this field exists to keep quiet.\n */\nexport function mergeAssessmentInto(\n\twarnings: ProviderWarning[],\n\tproviderId: IntegrationIds,\n\tdomain: string | undefined,\n\tconnectionId: string | undefined,\n\tmetadata: CollectionMetadata | undefined,\n): { fetchFailed: boolean; truncated: boolean; reported: boolean } {\n\tconst assessment = assessCollectionMetadata(providerId, domain, connectionId, metadata);\n\tfor (const warning of assessment.warnings) {\n\t\tappendDedupedWarning(warnings, warning);\n\t}\n\treturn {\n\t\tfetchFailed: assessment.fetchFailed,\n\t\ttruncated: assessment.truncated,\n\t\t// What the assessment PRODUCED, not what `appendDedupedWarning` accepted: a warning dropped as a\n\t\t// duplicate is still one the consumer will see, so it still makes a restatement redundant.\n\t\treported: assessment.warnings.length > 0,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collectionMetadata.js","names":[],"sources":["../../../../plus/integrations/src/collectionMetadata.ts"],"sourcesContent":["import type {\n\tCollectionMetadata,\n\tCollectionOmission,\n\tCollectionScope,\n\tCollectionScopeFailure,\n} from '@gitkraken/provider-apis';\n// Matched by its `code` discriminator rather than by `instanceof`: the SDK ships one bundle per entry point, so\n// the class reached through the root is not the same object as the one reached through `/providers`.\nimport { isInvalidRequestError, isUnsupportedSortError } from '@gitkraken/provider-apis';\nimport {\n\tAuthenticationError,\n\tRequestClientError,\n\tRequestNotFoundError,\n\tRequestRateLimitError,\n} from '@gitlens/git/errors.js';\nimport type { TokenWithInfo } from './authentication/models.js';\nimport type { IntegrationIds } from './constants.js';\nimport type { ResponseHeaders } from './errors.js';\nimport { getResponseHeader, isRateLimitResponse } from './errors.js';\nimport { getProviderResponseBodyMessage } from './providers/providerErrors.js';\nimport type {\n\tProviderWarning,\n\tProviderWarningCause,\n\tProviderWarningOmission,\n\tProviderWarningScope,\n} from './results.js';\nimport { appendDedupedWarning, providerWarningMessage } from './results.js';\n\n/**\n * Re-throws an error that is a fact about the CALL rather than about one scope of a fan-out.\n *\n * Every provider fan-out catches per-scope rejections and records them as {@link CollectionScopeFailure}s, which is\n * right for auth, rate limits and a missing project: those really did happen to one scope, and the siblings that\n * succeeded must survive. A caller-contract error is the opposite — it is identical for every scope and was decided\n * before any request went out — so degrading it would hand back N indistinguishable failures and an empty `partial`\n * page, describing an invalid call as an incomplete read.\n *\n * Today that means the SDK's `UnsupportedSortError` and `InvalidRequestError` — the two codes it lists in its own\n * `CALLER_CONTRACT_ERROR_CODES`, both documented as \"never degraded into a `CollectionScopeFailure` or an\n * omission\". The second covers arguments rejected before the first request goes out: a project key list longer\n * than one Jira search can carry (or an empty one), a non-integer `pageSize`, an unknown current-user filter, or a\n * Jira Server read with no `baseUrl` to address. Called from every fan-out rather than spelled out in each, so a\n * fan-out added later inherits the rule instead of silently omitting it — which is exactly how Azure's\n * account-wide drain came to degrade it while its three siblings did not.\n */\nexport function throwIfCallerContractError(ex: unknown): void {\n\tif (isUnsupportedSortError(ex) || isInvalidRequestError(ex)) throw ex;\n}\n\n/**\n * Maps a caught GitLens request error to the SDK collection failure vocabulary used inside provider fan-outs.\n */\nexport function toCollectionFailureKind(ex: unknown): CollectionScopeFailure['kind'] {\n\tif (ex instanceof AuthenticationError) return 'authentication';\n\tif (ex instanceof RequestRateLimitError) return 'rate-limit';\n\tif (ex instanceof RequestNotFoundError) return 'not-found';\n\treturn 'provider';\n}\n\n/**\n * What an authentication refusal's response said, kept on the failure so the provider can name its cause once the\n * credential behind it is confirmed (see `IntegrationBase.confirmScopedAuthFailures`). Only these facts are kept,\n * never the response: its headers carry the provider's session cookies.\n */\nexport interface ProviderRefusal {\n\tstatus: number;\n\t/** The provider's own explanation: Azure DevOps' `X-TFS-ServiceError`, or the error body's message. */\n\tdetail?: string;\n\t/** The provider's error type, when the body names one (Azure DevOps `typeKey`). */\n\ttypeKey?: string;\n}\n\n/** A scope failure as recorded here: the SDK's shape, plus what the refusal said and, once it is known, why. */\nexport interface ProviderScopeFailure extends CollectionScopeFailure {\n\trefusal?: ProviderRefusal;\n\tcause?: ProviderWarningCause;\n\t/** The provider pinned the refusal on the credential itself, so it is published for the connection, unscoped. */\n\tcredentialRefused?: true;\n}\n\n/**\n * Reads the refusal off an `AuthenticationError` that carries the provider's response: the SDK adapter's plain\n * `{ status, headers, body }` (`providersApi.ts`), or the `Response` of a `ProviderFetchError`, whose body was\n * already read into its message.\n */\nfunction toProviderRefusal(ex: unknown): ProviderRefusal | undefined {\n\tif (!(ex instanceof AuthenticationError)) return undefined;\n\n\tconst response = (ex.original as { response?: unknown } | undefined)?.response as\n\t\t| { status?: unknown; headers?: ResponseHeaders; body?: unknown }\n\t\t| undefined;\n\tif (typeof response?.status !== 'number') return undefined;\n\n\t// Only a structured body: a string one is a page (a proxy's, a sign-in form), not an explanation.\n\tconst body = typeof response.body === 'object' && response.body != null ? response.body : undefined;\n\tconst detail =\n\t\tdecodeServiceError(getResponseHeader(response.headers, 'x-tfs-serviceerror')) ??\n\t\tgetProviderResponseBodyMessage(body);\n\tconst typeKey = body != null && 'typeKey' in body ? body.typeKey : undefined;\n\n\treturn {\n\t\tstatus: response.status,\n\t\t...(detail ? { detail: detail } : {}),\n\t\t...(typeof typeKey === 'string' ? { typeKey: typeKey } : {}),\n\t};\n}\n\n/** Azure DevOps sends `X-TFS-ServiceError` percent-encoded. */\nfunction decodeServiceError(value: unknown): string | undefined {\n\tif (typeof value !== 'string' || !value) return undefined;\n\n\ttry {\n\t\treturn decodeURIComponent(value).trim() || undefined;\n\t} catch {\n\t\treturn value.trim() || undefined;\n\t}\n}\n\n/**\n * Builds a structured SDK scope failure from a caught GitLens request error.\n *\n * An authentication refusal is described in the provider's own words when it gives any, and otherwise by the\n * error the provider's response raised, sanitized like any warning's (a page becomes its status), rather than by\n * `AuthenticationError`'s generic \"credentials are either invalid or expired\": a scope refusing a sound credential\n * is the case this failure exists to tell apart, and that sentence says the opposite.\n */\nexport function toCollectionScopeFailure(scope: CollectionScopeFailure['scope'], ex: unknown): ProviderScopeFailure {\n\tconst refusal = toProviderRefusal(ex);\n\tconst message =\n\t\trefusal != null ? (refusal.detail ?? providerWarningMessage((ex as AuthenticationError).original)) : undefined;\n\treturn {\n\t\tscope: scope,\n\t\tkind: toCollectionFailureKind(ex),\n\t\t...(message ? { message: message } : ex instanceof Error && ex.message ? { message: ex.message } : {}),\n\t\t...(refusal != null ? { refusal: refusal } : {}),\n\t};\n}\n\nfunction collectionFailureKindToWarningKind(kind: CollectionScopeFailure['kind']): ProviderWarning['kind'] {\n\tswitch (kind) {\n\t\tcase 'authentication':\n\t\t\treturn 'auth';\n\t\tcase 'rate-limit':\n\t\t\treturn 'rate-limit';\n\t\tcase 'not-found':\n\t\t\treturn 'not-found';\n\t\tdefault:\n\t\t\treturn 'other';\n\t}\n}\n\nfunction getCollectionFailureStatus(message: string | undefined): number | undefined {\n\tif (message == null) return undefined;\n\n\tconst match = /\\((\\d{3})\\)/.exec(message) ?? /^(?:HTTP\\s+)?(\\d{3})\\b/i.exec(message.trim());\n\treturn match != null ? Number(match[1]) : undefined;\n}\n\nfunction toCollectionFailureWarningKind(failure: CollectionScopeFailure): ProviderWarning['kind'] {\n\tconst mapped = collectionFailureKindToWarningKind(failure.kind);\n\tif (mapped !== 'other' || (failure.kind !== 'provider' && failure.kind !== 'unknown')) return mapped;\n\n\t// provider-apis currently groups several HTTP statuses under `provider` in partial fan-outs. The custom\n\t// fetch adapter retains the status in `message`, so recover the same neutral classification the thrown-error\n\t// path exposes instead of downgrading these structured failures to `other`.\n\tconst status = getCollectionFailureStatus(failure.message);\n\tswitch (status) {\n\t\tcase 401:\n\t\t\treturn 'auth';\n\t\tcase 403:\n\t\t\treturn isRateLimitResponse({ status: status, message: failure.message }) ? 'rate-limit' : 'auth';\n\t\tcase 404:\n\t\tcase 410:\n\t\tcase 422:\n\t\t\treturn 'not-found';\n\t\tcase 429:\n\t\t\treturn 'rate-limit';\n\t\tdefault:\n\t\t\treturn mapped;\n\t}\n}\n\nexport function toCollectionFailureError(failure: CollectionScopeFailure, tokenWithInfo: TokenWithInfo): Error {\n\tconst error = new Error(failure.message ?? 'Provider request failed');\n\tconst kind = toCollectionFailureWarningKind(failure);\n\tconst { accessToken, ...tokenInfo } = tokenWithInfo;\n\tif (kind === 'auth') return new AuthenticationError(tokenInfo, error.message, error);\n\tif (kind === 'rate-limit') return new RequestRateLimitError(error, accessToken, undefined);\n\tif (kind === 'not-found') return new RequestNotFoundError(error);\n\n\tconst status = getCollectionFailureStatus(failure.message);\n\tif (kind === 'other' && status != null && status >= 400 && status < 500) {\n\t\treturn new RequestClientError(error);\n\t}\n\n\treturn error;\n}\n\n/** ` (resource r, project p, repository o/n)` for the scope IDs present; empty when the scope names none. */\nfunction collectionScopeText(scope: CollectionScope | undefined): string {\n\tconst parts: string[] = [];\n\tif (scope?.resourceId != null) {\n\t\tparts.push(`resource ${scope.resourceId}`);\n\t}\n\tif (scope?.projectId != null) {\n\t\tparts.push(`project ${scope.projectId}`);\n\t}\n\tif (scope?.repositoryId != null) {\n\t\tparts.push(`repository ${scope.repositoryId}`);\n\t}\n\n\treturn parts.length ? ` (${parts.join(', ')})` : '';\n}\n\n/** The cause in the consumer's terms, for the prose that goes with the structured {@link ProviderWarningCause}. */\nfunction causeText(cause: ProviderWarningCause): string {\n\tswitch (cause.reason) {\n\t\tcase 'oauth-app-not-allowed':\n\t\t\treturn 'the organization does not allow third-party OAuth apps';\n\t\tcase 'access-denied':\n\t\t\treturn 'the account has no access to it';\n\t\tcase 'conditional-access':\n\t\t\treturn 'a Conditional Access policy blocked the request';\n\t\tdefault:\n\t\t\tcause.reason satisfies never;\n\t\t\treturn 'the provider refused the request';\n\t}\n}\n\nfunction collectionFailureMessage(failure: ProviderScopeFailure): string {\n\tconst text = failure.cause != null ? causeText(failure.cause) : failure.message;\n\tconst detail = text != null ? `: ${text}` : '';\n\treturn `Failed to read ${failure.kind} scope${collectionScopeText(failure.scope)}${detail}`;\n}\n\n/**\n * Forwards the part of a failure's scope below the provider, so a consumer can tell \"one organization refused\n * this token\" from \"the connection's token is dead\" without parsing {@link collectionFailureMessage}.\n *\n * `providerId` is dropped: the warning already names its provider, and a scope naming nothing below it is a\n * failure of the connection itself. That is the distinction `getOrganizationsForUserResult` also draws before\n * counting an auth failure against the connection, though it reads a scope with no keys but `providerId`, so an\n * absent scope does not count there. Forwarding such a scope would make an account-wide failure look confined.\n *\n * Copied field by field, for the reason {@link toProviderWarningOmission} copies its scope.\n */\nfunction toProviderWarningScope(scope: CollectionScope | undefined): ProviderWarningScope | undefined {\n\tif (scope == null) return undefined;\n\n\tconst { resourceId, projectId, repositoryId } = scope;\n\tif (resourceId == null && projectId == null && repositoryId == null) return undefined;\n\n\treturn {\n\t\t...(resourceId != null ? { resourceId: resourceId } : {}),\n\t\t...(projectId != null ? { projectId: projectId } : {}),\n\t\t...(repositoryId != null ? { repositoryId: repositoryId } : {}),\n\t};\n}\n\n/**\n * Whether `metadata` reports authentication failures only for scopes below the provider, with none for the\n * connection itself. A credential revoked since a provider cached its discovery produces exactly this shape,\n * the same one a scope's own refusal does; `IntegrationBase.confirmScopedAuthFailures` tells them apart.\n *\n * Classified exactly as {@link assessCollectionMetadata} classifies the warnings, so it agrees with what a\n * consumer would be shown.\n */\nexport function hasOnlyScopedAuthFailures(metadata: CollectionMetadata | undefined): boolean {\n\tlet scoped = false;\n\tfor (const failure of metadata?.failures ?? []) {\n\t\tif (toCollectionFailureWarningKind(failure) !== 'auth') continue;\n\t\tif (toProviderWarningScope(failure.scope) == null || (failure as ProviderScopeFailure).credentialRefused) {\n\t\t\treturn false;\n\t\t}\n\n\t\tscoped = true;\n\t}\n\treturn scoped;\n}\n\n/** The scoped authentication failures in `metadata` that kept their refusal, with the scope they are forwarded as. */\nfunction* refusedScopes(\n\tmetadata: CollectionMetadata | undefined,\n): Generator<{ failure: ProviderScopeFailure & { refusal: ProviderRefusal }; scope: ProviderWarningScope }> {\n\tfor (const failure of (metadata?.failures ?? []) as ProviderScopeFailure[]) {\n\t\tif (\n\t\t\tfailure.refusal == null ||\n\t\t\tfailure.credentialRefused ||\n\t\t\ttoCollectionFailureWarningKind(failure) !== 'auth'\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst scope = toProviderWarningScope(failure.scope);\n\t\tif (scope == null) continue;\n\n\t\tyield { failure: failure as ProviderScopeFailure & { refusal: ProviderRefusal }, scope: scope };\n\t}\n}\n\n/**\n * Marks each scoped authentication failure in `metadata` whose refusal the provider pins on the credential, so it is\n * published for the connection rather than for its scope. Returns whether any was.\n */\nexport function markCredentialRefusals(\n\tmetadata: CollectionMetadata | undefined,\n\tisCredentialRefusal: (refusal: ProviderRefusal) => boolean,\n): boolean {\n\tlet marked = false;\n\tfor (const { failure } of refusedScopes(metadata)) {\n\t\tif (!isCredentialRefusal(failure.refusal)) continue;\n\n\t\tfailure.credentialRefused = true;\n\t\tmarked = true;\n\t}\n\treturn marked;\n}\n\n/**\n * Names the cause of each scoped authentication failure in `metadata` that kept its refusal. Only for a read whose\n * credential was just confirmed: before that, the refusals this can name look exactly like a dead credential.\n */\nexport function attributeScopedAuthFailures(\n\tmetadata: CollectionMetadata | undefined,\n\tdescribe: (refusal: ProviderRefusal, scope: ProviderWarningScope) => ProviderWarningCause | undefined,\n): void {\n\tfor (const { failure, scope } of refusedScopes(metadata)) {\n\t\tif (failure.cause != null) continue;\n\n\t\tconst cause = describe(failure.refusal, scope);\n\t\tif (cause != null) {\n\t\t\tfailure.cause = cause;\n\t\t}\n\t}\n}\n\n/**\n * Explains one omission in the consumer's terms — what was left out and, where the SDK reports it, how much.\n *\n * An omission is a completeness fact, never a failure: the read succeeded, and the provider (or the SDK's own\n * recovery budget) is what withheld results. That is why these never contribute to `fetchFailed`. Whether a\n * retry would recover anything is a separate question this layer cannot answer — see the `recovery` note on\n * {@link toProviderWarningOmission}.\n */\nfunction collectionOmissionMessage(omission: CollectionOmission): string {\n\tconst scopeText = collectionScopeText(omission.scope);\n\tswitch (omission.kind) {\n\t\tcase 'provider-limit':\n\t\t\t// `totalCount` is the only figure saying how much was withheld; both fields are optional, so degrade\n\t\t\t// through the shapes the SDK can actually emit rather than printing `undefined`.\n\t\t\tif (omission.totalCount != null && omission.limit != null) {\n\t\t\t\treturn `Search${scopeText} matched ${omission.totalCount} results, but the provider exposes at most ${omission.limit}`;\n\t\t\t}\n\t\t\tif (omission.limit != null) {\n\t\t\t\treturn `Search${scopeText} exceeded the provider limit of ${omission.limit} results`;\n\t\t\t}\n\t\t\treturn `Search${scopeText} exceeded the provider's result limit`;\n\t\tcase 'recovery-budget':\n\t\t\treturn `Stopped recovering omitted results${scopeText} after reaching the request budget${\n\t\t\t\tomission.limit != null ? ` of ${omission.limit} requests` : ''\n\t\t\t}`;\n\t\tcase 'pagination-incomplete':\n\t\t\treturn `More results are available${scopeText} than this read returned`;\n\t\tdefault:\n\t\t\t// `CollectionOmissionKind` is a closed union, so this is unreachable today. Kept as a compile-time\n\t\t\t// guard rather than a silent fallback: an SDK bump that adds a kind breaks the build here instead\n\t\t\t// of quietly degrading it to a vague message.\n\t\t\tomission.kind satisfies never;\n\t\t\treturn `Some results were omitted${scopeText}; the read is incomplete`;\n\t}\n}\n\n/**\n * Forwards an SDK omission as the structured signal consumers read instead of parsing {@link\n * collectionOmissionMessage}'s prose.\n *\n * `results.ts` re-spells `CollectionOmissionKind` rather than importing it, so the published warning surface\n * carries no `@gitkraken/provider-apis` types (see the export block in `index.ts`). The return type is what\n * keeps the two unions honest: an SDK bump that adds a member fails to compile here, alongside\n * `collectionOmissionMessage`'s `satisfies never`.\n *\n * `scope` is copied because the SDK's own object is retained and re-merged across drained pages\n * (`providerPaging.ts`), and this one crosses the package boundary.\n *\n * `recovery` is always `'none'`, deliberately, and a scoped `pagination-incomplete` is why it looks wrong: the\n * SDK emits that one shape from situations with opposite remedies and says so itself — \"Either the read\n * deliberately took one page per scope, or the provider advertised another page it gave no way to reach.\" Its\n * `collectAcrossScopes` producers (Azure, Bitbucket, Bitbucket Server) are the first, its `drainAcrossScopes`\n * producers (GitLab, Jira) the second, and those report an omission only when a cursor STALLED — so re-reading\n * that scope stalls at the identical page. Nothing in `CollectionOmission` separates the two, so claiming\n * recoverability would ship the dead-end button `recovery` exists to prevent. Making the recoverable case\n * claimable needs provider-apis to say whether a scope was drained or merely sampled: a fact to forward, not\n * to guess here.\n */\nfunction toProviderWarningOmission(omission: CollectionOmission): ProviderWarningOmission {\n\treturn {\n\t\tkind: omission.kind,\n\t\trecovery: 'none',\n\t\t...(omission.limit != null ? { limit: omission.limit } : {}),\n\t\t// The SDK types this `number | null | undefined`; normalize to one absence for consumers.\n\t\t...(omission.totalCount != null ? { totalCount: omission.totalCount } : {}),\n\t\t...(omission.scope != null ? { scope: { ...omission.scope } } : {}),\n\t};\n}\n\n/**\n * Whether SDK metadata describes a read that may be missing results.\n *\n * A reported omission counts on its own rather than deferring to `completeness`. The SDK does couple the\n * two — every site that emits an omission degrades completeness in the same call — so today the omission\n * clause changes no outcome. It is defensive: the two facts arrive as independent fields, and a read that\n * names what it left out must not be publishable as whole if a future producer sets only one of them.\n *\n * This is the single definition of \"may be missing results\", shared with `getPagedResult`, so one metadata\n * object cannot be truncated at one layer and complete at another.\n */\nexport function isIncompleteCollection(metadata: CollectionMetadata | undefined): boolean {\n\tif (metadata == null) return false;\n\n\treturn metadata.completeness !== 'complete' || (metadata.omissions?.length ?? 0) > 0;\n}\n\n/** Converts internal SDK collection metadata into neutral provider facade signals. */\nexport function assessCollectionMetadata(\n\tproviderId: IntegrationIds,\n\tdomain: string | undefined,\n\tconnectionId: string | undefined,\n\tmetadata: CollectionMetadata | undefined,\n): { warnings: ProviderWarning[]; fetchFailed: boolean; truncated: boolean } {\n\tif (metadata == null) return { warnings: [], fetchFailed: false, truncated: false };\n\n\tconst warnings: ProviderWarning[] = [];\n\tconst failures: ProviderScopeFailure[] = metadata.failures ?? [];\n\tfor (const failure of failures) {\n\t\tconst kind = toCollectionFailureWarningKind(failure);\n\t\tconst scope = failure.credentialRefused ? undefined : toProviderWarningScope(failure.scope);\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\t// A credential-level refusal names no scope in prose either, so every scope's copy of it is one warning.\n\t\t\tmessage: collectionFailureMessage(failure.credentialRefused ? { ...failure, scope: undefined } : failure),\n\t\t\tkind: kind,\n\t\t\tisAuth: kind === 'auth',\n\t\t\t...(scope != null ? { scope: scope } : {}),\n\t\t\t// Copied for the reason the scope is: the failure object is retained and re-merged across pages.\n\t\t\t...(failure.cause != null ? { cause: { ...failure.cause } } : {}),\n\t\t});\n\t}\n\n\t// Omissions explain WHY a read is incomplete when nothing failed — a provider cap, an exhausted recovery\n\t// budget, an undrained scope. They classify as `other`, never `auth`, and are deliberately excluded from\n\t// `fetchFailed` below: the request itself succeeded. `omission` carries that same fact structurally, so a\n\t// consumer can act on it without parsing the message.\n\tconst omissions = metadata.omissions ?? [];\n\tfor (const omission of omissions) {\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\tmessage: collectionOmissionMessage(omission),\n\t\t\tkind: 'other',\n\t\t\tisAuth: false,\n\t\t\tomission: toProviderWarningOmission(omission),\n\t\t});\n\t}\n\n\tconst incomplete = isIncompleteCollection(metadata);\n\t// Only fall back to the generic message when nothing more specific was reported; an omission already\n\t// explains the incompleteness in the consumer's terms, so adding this on top would be noise.\n\t//\n\t// This one deliberately carries no `omission`: it fires precisely when the SDK reported incompleteness\n\t// WITHOUT saying what was left out, so there is no structured fact to forward and synthesizing one would\n\t// assert a specificity this layer does not have.\n\tif (incomplete && failures.length === 0 && omissions.length === 0) {\n\t\tappendDedupedWarning(warnings, {\n\t\t\tproviderId: providerId,\n\t\t\tdomain: domain,\n\t\t\tconnectionId: connectionId,\n\t\t\tmessage:\n\t\t\t\tmetadata.completeness === 'partial'\n\t\t\t\t\t? 'Some results were omitted; the read is incomplete'\n\t\t\t\t\t: 'Result completeness could not be confirmed',\n\t\t\tkind: 'other',\n\t\t\tisAuth: false,\n\t\t});\n\t}\n\n\treturn { warnings: warnings, fetchFailed: failures.length > 0, truncated: incomplete };\n}\n\n/**\n * Appends neutral warnings derived from SDK metadata and returns its failure/truncation assessment.\n *\n * `reported` says whether the metadata described this read's incompleteness at all. A caller that would\n * otherwise add its own generic \"this was truncated\" warning uses it to stay quiet — the same rule\n * {@link assessCollectionMetadata} applies to its own generic fallback, one layer up: whatever the metadata\n * reported already names this provider and, unless it was that same fallback, says something a consumer can\n * act on. Restating it in a weaker vocabulary is how one gap becomes two warnings with two different verdicts.\n *\n * `truncated` is the near-synonym that must NOT be used for that question: it comes from\n * {@link isIncompleteCollection}, which does not consider failures, so metadata carrying a typed failure\n * alongside `completeness: 'complete'` reports `truncated: false` while having already appended the warning\n * that explains everything. Gating on it would restate exactly the case this field exists to keep quiet.\n */\nexport function mergeAssessmentInto(\n\twarnings: ProviderWarning[],\n\tproviderId: IntegrationIds,\n\tdomain: string | undefined,\n\tconnectionId: string | undefined,\n\tmetadata: CollectionMetadata | undefined,\n): { fetchFailed: boolean; truncated: boolean; reported: boolean } {\n\tconst assessment = assessCollectionMetadata(providerId, domain, connectionId, metadata);\n\tfor (const warning of assessment.warnings) {\n\t\tappendDedupedWarning(warnings, warning);\n\t}\n\treturn {\n\t\tfetchFailed: assessment.fetchFailed,\n\t\ttruncated: assessment.truncated,\n\t\t// What the assessment PRODUCED, not what `appendDedupedWarning` accepted: a warning dropped as a\n\t\t// duplicate is still one the consumer will see, so it still makes a restatement redundant.\n\t\treported: assessment.warnings.length > 0,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -57,7 +57,9 @@ export declare function isRateLimitResponse(ex: {
|
|
|
57
57
|
* duck-typing on `get` rather than `instanceof Headers`, so this works in both the Node and webworker builds
|
|
58
58
|
* without depending on the global being present.
|
|
59
59
|
*/
|
|
60
|
-
type ResponseHeaders = Pick<Headers, 'get'> | Record<string, unknown>;
|
|
60
|
+
export type ResponseHeaders = Pick<Headers, 'get'> | Record<string, unknown>;
|
|
61
|
+
/** Reads one header off either shape of {@link ResponseHeaders}; names are the lower-case ones both shapes use. */
|
|
62
|
+
export declare function getResponseHeader(headers: ResponseHeaders | undefined, name: string): unknown;
|
|
61
63
|
/**
|
|
62
64
|
* Builds a {@link RequestRateLimitError} from a provider error response, reading the reset epoch from the
|
|
63
65
|
* standard `x-ratelimit-reset` header when present. Accepts both header shapes in use: the `fetch` `Headers`
|
|
@@ -100,14 +100,18 @@ function isRateLimitResponse(ex) {
|
|
|
100
100
|
const message = ex.message?.toLowerCase();
|
|
101
101
|
return message != null && (message.includes("rate limit") || message.includes("ratelimit"));
|
|
102
102
|
}
|
|
103
|
+
/** Reads one header off either shape of {@link ResponseHeaders}; names are the lower-case ones both shapes use. */
|
|
104
|
+
function getResponseHeader(headers, name) {
|
|
105
|
+
if (headers == null) return void 0;
|
|
106
|
+
return typeof headers.get === "function" ? headers.get(name) : headers[name];
|
|
107
|
+
}
|
|
103
108
|
/**
|
|
104
109
|
* Builds a {@link RequestRateLimitError} from a provider error response, reading the reset epoch from the
|
|
105
110
|
* standard `x-ratelimit-reset` header when present. Accepts both header shapes in use: the `fetch` `Headers`
|
|
106
111
|
* instance the direct clients get, and the plain object the SDK attaches to its errors.
|
|
107
112
|
*/
|
|
108
113
|
function toRateLimitError(ex, token) {
|
|
109
|
-
const
|
|
110
|
-
const raw = headers == null ? void 0 : typeof headers.get === "function" ? headers.get("x-ratelimit-reset") : headers["x-ratelimit-reset"];
|
|
114
|
+
const raw = getResponseHeader(ex.response?.headers, "x-ratelimit-reset");
|
|
111
115
|
let resetAt;
|
|
112
116
|
if (typeof raw === "string" || typeof raw === "number") {
|
|
113
117
|
resetAt = parseInt(String(raw), 10);
|
|
@@ -125,6 +129,6 @@ function toError(ex) {
|
|
|
125
129
|
return ex instanceof Error ? ex : new Error(String(ex));
|
|
126
130
|
}
|
|
127
131
|
//#endregion
|
|
128
|
-
export { AuthenticationError, AuthenticationErrorReason, IntegrationReadUnavailableError, ProviderFetchError, RequestClientError, RequestNotFoundError, RequestRateLimitError, isRateLimitResponse, toError, toRateLimitError };
|
|
132
|
+
export { AuthenticationError, AuthenticationErrorReason, IntegrationReadUnavailableError, ProviderFetchError, RequestClientError, RequestNotFoundError, RequestRateLimitError, getResponseHeader, isRateLimitResponse, toError, toRateLimitError };
|
|
129
133
|
|
|
130
134
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../../../../plus/integrations/src/errors.ts"],"sourcesContent":["export type { AuthTokenInfo } from '@gitlens/git/errors.js';\nexport {\n\tAuthenticationError,\n\tAuthenticationErrorReason,\n\tRequestClientError,\n\tRequestNotFoundError,\n\tRequestRateLimitError,\n} from '@gitlens/git/errors.js';\n\nimport { RequestRateLimitError } from '@gitlens/git/errors.js';\n\n/**\n * Thrown by a provider read when it can't produce a result for a reason that is NOT \"the account is empty\":\n * a prerequisite is missing (e.g. Trello has no app key) or a required scope can't be resolved (e.g. the\n * Linear viewer id, needed to scope \"my issues\"). Returning an empty/undefined result in these cases would be\n * indistinguishable from a genuinely empty account; throwing this lets the result cores recover it into an\n * `{ error }` the facade surfaces as a warning + `fetchFailed`.\n */\nexport class IntegrationReadUnavailableError extends Error {\n\tconstructor(provider: string, reason: string) {\n\t\tsuper(`${provider} read unavailable: ${reason}`);\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n/**\n * Thrown by integration provider HTTP clients when an upstream request fails.\n */\nexport class ProviderFetchError extends Error {\n\tget status(): number {\n\t\treturn this.response.status;\n\t}\n\n\tget statusText(): string {\n\t\treturn this.response.statusText;\n\t}\n\n\t/**\n\t * Builds the error with the upstream body folded into the message, for clients that hold a `Response` whose\n\t * body has not been read (i.e. every non-`ok` path). Use this rather than the constructor whenever the body is\n\t * still available: the status line alone cannot distinguish a throttled request from a permission failure on\n\t * the statuses hosts overload (see {@link isRateLimitResponse}), and only the body says which one it is.\n\t *\n\t * Never throws: the body is best-effort, so an unreadable, empty, or already-consumed one simply yields the\n\t * status-line-only message the constructor would have produced.\n\t */\n\tstatic async fromResponse(provider: string, response: Response): Promise<ProviderFetchError> {\n\t\treturn new ProviderFetchError(provider, response, await readErrorBodyMessage(response));\n\t}\n\n\tconstructor(\n\t\tprovider: string,\n\t\tpublic readonly response: Response,\n\t\terrors?: { message: string }[],\n\t) {\n\t\tsuper(\n\t\t\t`${provider} request failed: ${!response.ok ? `(${response.status}) ${response.statusText}. ` : ''}${\n\t\t\t\terrors?.length ? errors[0].message : ''\n\t\t\t}`,\n\t\t);\n\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n/** Cap on the body text folded into an error message, so an HTML error page can't become the message. */\nconst maxErrorBodyLength = 500;\n\n/**\n * Best-effort human-readable message from an error response body, in the `errors` shape the\n * {@link ProviderFetchError} constructor takes. Tolerant by design — every host in use words its errors\n * differently and some do not send JSON at all:\n * - Azure DevOps — `{ message: \"TF400733: ...\" }`\n * - Bitbucket — `{ error: { message: \"...\" } }`, and bare text for a throttled request\n * - GitLab — `{ message: \"...\" }` or `{ error: \"...\" }`\n * Anything unrecognized falls back to the raw text, which is what the substring check wants anyway.\n */\nasync function readErrorBodyMessage(response: Response): Promise<{ message: string }[] | undefined> {\n\tlet text;\n\ttry {\n\t\t// `bodyUsed` is not a guarantee (a stream can fail mid-read), hence the catch — but it avoids the throw\n\t\t// entirely on the common path where something upstream already consumed the body.\n\t\tif (response.bodyUsed) return undefined;\n\n\t\ttext = (await response.text())?.trim();\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!text) return undefined;\n\n\tlet message: string | undefined;\n\ttry {\n\t\tconst body: unknown = JSON.parse(text);\n\t\tif (body != null && typeof body === 'object') {\n\t\t\tconst { message: m, error } = body as { message?: unknown; error?: unknown };\n\t\t\tif (typeof m === 'string') {\n\t\t\t\tmessage = m;\n\t\t\t} else if (typeof error === 'string') {\n\t\t\t\tmessage = error;\n\t\t\t} else if (error != null && typeof error === 'object') {\n\t\t\t\t// Some hosts nest it as `{ error: { message } }`; narrow the same way as the outer object.\n\t\t\t\tconst nested = (error as { message?: unknown }).message;\n\t\t\t\tif (typeof nested === 'string') {\n\t\t\t\t\tmessage = nested;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Not JSON — Bitbucket sends bare text for a throttled request, and any host can send an HTML error page.\n\t}\n\n\tmessage = (message ?? text).trim();\n\treturn message ? [{ message: message.slice(0, maxErrorBodyLength) }] : undefined;\n}\n\n/**\n * Whether a provider's error response denotes a rate limit rather than a permission failure. Kept here, in one\n * place, because the distinction is consequential: a rate limit is retryable, while a permission failure is\n * surfaced as `auth` and drives a reconnect prompt — misclassifying one as the other asks the user to\n * re-authenticate a perfectly healthy connection.\n *\n * Which status a throttled request arrives on varies by host, which is why this takes both:\n * - Azure DevOps and Bitbucket Cloud document 429 (learn.microsoft.com .../integrate/concepts/rate-limits).\n * - GitHub documents \"a `403` or `429` response\" for both its primary and secondary limits\n * (docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api).\n * - GitLab uses 403 for some throttles.\n * So 429 alone is decisive, and on 403 the message decides.\n *\n * NOTE the message must actually carry the host's body for the 403 path to work — see\n * {@link ProviderFetchError.fromResponse}. A `ProviderFetchError` built from the status line alone reads\n * \"(403) Forbidden.\" and can never match, which is what made this check dead code on the direct-fetch clients.\n */\nexport function isRateLimitResponse(ex: { status: number; message?: string }): boolean {\n\t// Matches the phrasing hosts actually use: GitHub/Bitbucket \"API rate limit exceeded\", GitLab \"rate limit\n\t// exceeded\", Azure \"Request was blocked due to exceeding usage of resource 'RateLimit'\" / \"TF400733: The\n\t// request has been canceled: Request was blocked due to exceeding usage\".\n\tif (ex.status === 429) return true;\n\n\tconst message = ex.message?.toLowerCase();\n\treturn message != null && (message.includes('rate limit') || message.includes('ratelimit'));\n}\n\n/**\n * A response's headers as either a `fetch` `Headers` instance or the plain object an SDK error carries. Read via\n * duck-typing on `get` rather than `instanceof Headers`, so this works in both the Node and webworker builds\n * without depending on the global being present.\n */\ntype ResponseHeaders = Pick<Headers, 'get'> | Record<string, unknown>;\n\n/**\n * Builds a {@link RequestRateLimitError} from a provider error response, reading the reset epoch from the\n * standard `x-ratelimit-reset` header when present. Accepts both header shapes in use: the `fetch` `Headers`\n * instance the direct clients get, and the plain object the SDK attaches to its errors.\n */\nexport function toRateLimitError(\n\tex: Error & { response?: { headers?: ResponseHeaders } },\n\ttoken: string | undefined,\n): RequestRateLimitError {\n\tconst headers = ex.response?.headers as { get?: unknown } & Record<string, unknown>;\n\tconst raw =\n\t\theaders == null\n\t\t\t? undefined\n\t\t\t: typeof headers.get === 'function'\n\t\t\t\t? (headers.get as (name: string) => string | null)('x-ratelimit-reset')\n\t\t\t\t: headers['x-ratelimit-reset'];\n\n\t// Only a header that actually came back as a string/number can be a reset epoch; anything else (a nested SDK\n\t// object, an array of values) would stringify to garbage and parse to NaN anyway.\n\tlet resetAt: number | undefined;\n\tif (typeof raw === 'string' || typeof raw === 'number') {\n\t\tresetAt = parseInt(String(raw), 10);\n\t\tif (Number.isNaN(resetAt)) {\n\t\t\tresetAt = undefined;\n\t\t}\n\t}\n\n\treturn new RequestRateLimitError(ex, token, resetAt);\n}\n\n/**\n * Normalizes a caught `unknown` into an `Error`. Result cores type their failure channel as `error: Error`,\n * but a `catch` binding is `unknown` and a provider (or a third-party SDK) can throw a non-Error value;\n * returning it raw would leak a non-Error through the public result surface and break downstream `instanceof`\n * classification. Passes an existing `Error` through unchanged and wraps anything else with `String(ex)`.\n */\nexport function toError(ex: unknown): Error {\n\treturn ex instanceof Error ? ex : new Error(String(ex));\n}\n"],"mappings":";;;;;;;;;AAkBA,IAAa,kCAAb,cAAqD,MAAM;CAC1D,YAAY,UAAkB,QAAgB;EAC7C,MAAM,GAAG,SAAS,qBAAqB,QAAQ;EAC/C,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;;;;AAKA,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAwB5B;CAvBjB,IAAI,SAAiB;EACpB,OAAO,KAAK,SAAS;CACtB;CAEA,IAAI,aAAqB;EACxB,OAAO,KAAK,SAAS;CACtB;;;;;;;;;;CAWA,aAAa,aAAa,UAAkB,UAAiD;EAC5F,OAAO,IAAI,mBAAmB,UAAU,UAAU,MAAM,qBAAqB,QAAQ,CAAC;CACvF;CAEA,YACC,UACA,UACA,QACC;EACD,MACC,GAAG,SAAS,mBAAmB,CAAC,SAAS,KAAK,IAAI,SAAS,OAAO,IAAI,SAAS,WAAW,MAAM,KAC/F,QAAQ,SAAS,OAAO,EAAE,CAAC,UAAU,IAEvC;EAPgB,KAAA,WAAA;EAShB,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;;AAGA,MAAM,qBAAqB;;;;;;;;;;AAW3B,eAAe,qBAAqB,UAAgE;CACnG,IAAI;CACJ,IAAI;EAGH,IAAI,SAAS,UAAU,OAAO,KAAA;EAE9B,QAAQ,MAAM,SAAS,KAAK,EAAA,EAAI,KAAK;CACtC,QAAQ;EACP;CACD;CACA,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,IAAI;CACJ,IAAI;EACH,MAAM,OAAgB,KAAK,MAAM,IAAI;EACrC,IAAI,QAAQ,QAAQ,OAAO,SAAS,UAAU;GAC7C,MAAM,EAAE,SAAS,GAAG,UAAU;GAC9B,IAAI,OAAO,MAAM,UAChB,UAAU;QACJ,IAAI,OAAO,UAAU,UAC3B,UAAU;QACJ,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;IAEtD,MAAM,SAAU,MAAgC;IAChD,IAAI,OAAO,WAAW,UACrB,UAAU;GAEZ;EACD;CACD,QAAQ,CAER;CAEA,WAAW,WAAW,KAAA,CAAM,KAAK;CACjC,OAAO,UAAU,CAAC,EAAE,SAAS,QAAQ,MAAM,GAAG,kBAAkB,EAAE,CAAC,IAAI,KAAA;AACxE;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,oBAAoB,IAAmD;CAItF,IAAI,GAAG,WAAW,KAAK,OAAO;CAE9B,MAAM,UAAU,GAAG,SAAS,YAAY;CACxC,OAAO,WAAW,SAAS,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,WAAW;AAC1F;;;;;;AAcA,SAAgB,iBACf,IACA,OACwB;CACxB,MAAM,UAAU,GAAG,UAAU;CAC7B,MAAM,MACL,WAAW,OACR,KAAA,IACA,OAAO,QAAQ,QAAQ,aACrB,QAAQ,IAAwC,mBAAmB,IACpE,QAAQ;CAIb,IAAI;CACJ,IAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;EACvD,UAAU,SAAS,OAAO,GAAG,GAAG,EAAE;EAClC,IAAI,OAAO,MAAM,OAAO,GACvB,UAAU,KAAA;CAEZ;CAEA,OAAO,IAAI,sBAAsB,IAAI,OAAO,OAAO;AACpD;;;;;;;AAQA,SAAgB,QAAQ,IAAoB;CAC3C,OAAO,cAAc,QAAQ,KAAK,IAAI,MAAM,OAAO,EAAE,CAAC;AACvD"}
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../../../plus/integrations/src/errors.ts"],"sourcesContent":["export type { AuthTokenInfo } from '@gitlens/git/errors.js';\nexport {\n\tAuthenticationError,\n\tAuthenticationErrorReason,\n\tRequestClientError,\n\tRequestNotFoundError,\n\tRequestRateLimitError,\n} from '@gitlens/git/errors.js';\n\nimport { RequestRateLimitError } from '@gitlens/git/errors.js';\n\n/**\n * Thrown by a provider read when it can't produce a result for a reason that is NOT \"the account is empty\":\n * a prerequisite is missing (e.g. Trello has no app key) or a required scope can't be resolved (e.g. the\n * Linear viewer id, needed to scope \"my issues\"). Returning an empty/undefined result in these cases would be\n * indistinguishable from a genuinely empty account; throwing this lets the result cores recover it into an\n * `{ error }` the facade surfaces as a warning + `fetchFailed`.\n */\nexport class IntegrationReadUnavailableError extends Error {\n\tconstructor(provider: string, reason: string) {\n\t\tsuper(`${provider} read unavailable: ${reason}`);\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n/**\n * Thrown by integration provider HTTP clients when an upstream request fails.\n */\nexport class ProviderFetchError extends Error {\n\tget status(): number {\n\t\treturn this.response.status;\n\t}\n\n\tget statusText(): string {\n\t\treturn this.response.statusText;\n\t}\n\n\t/**\n\t * Builds the error with the upstream body folded into the message, for clients that hold a `Response` whose\n\t * body has not been read (i.e. every non-`ok` path). Use this rather than the constructor whenever the body is\n\t * still available: the status line alone cannot distinguish a throttled request from a permission failure on\n\t * the statuses hosts overload (see {@link isRateLimitResponse}), and only the body says which one it is.\n\t *\n\t * Never throws: the body is best-effort, so an unreadable, empty, or already-consumed one simply yields the\n\t * status-line-only message the constructor would have produced.\n\t */\n\tstatic async fromResponse(provider: string, response: Response): Promise<ProviderFetchError> {\n\t\treturn new ProviderFetchError(provider, response, await readErrorBodyMessage(response));\n\t}\n\n\tconstructor(\n\t\tprovider: string,\n\t\tpublic readonly response: Response,\n\t\terrors?: { message: string }[],\n\t) {\n\t\tsuper(\n\t\t\t`${provider} request failed: ${!response.ok ? `(${response.status}) ${response.statusText}. ` : ''}${\n\t\t\t\terrors?.length ? errors[0].message : ''\n\t\t\t}`,\n\t\t);\n\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n/** Cap on the body text folded into an error message, so an HTML error page can't become the message. */\nconst maxErrorBodyLength = 500;\n\n/**\n * Best-effort human-readable message from an error response body, in the `errors` shape the\n * {@link ProviderFetchError} constructor takes. Tolerant by design — every host in use words its errors\n * differently and some do not send JSON at all:\n * - Azure DevOps — `{ message: \"TF400733: ...\" }`\n * - Bitbucket — `{ error: { message: \"...\" } }`, and bare text for a throttled request\n * - GitLab — `{ message: \"...\" }` or `{ error: \"...\" }`\n * Anything unrecognized falls back to the raw text, which is what the substring check wants anyway.\n */\nasync function readErrorBodyMessage(response: Response): Promise<{ message: string }[] | undefined> {\n\tlet text;\n\ttry {\n\t\t// `bodyUsed` is not a guarantee (a stream can fail mid-read), hence the catch — but it avoids the throw\n\t\t// entirely on the common path where something upstream already consumed the body.\n\t\tif (response.bodyUsed) return undefined;\n\n\t\ttext = (await response.text())?.trim();\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!text) return undefined;\n\n\tlet message: string | undefined;\n\ttry {\n\t\tconst body: unknown = JSON.parse(text);\n\t\tif (body != null && typeof body === 'object') {\n\t\t\tconst { message: m, error } = body as { message?: unknown; error?: unknown };\n\t\t\tif (typeof m === 'string') {\n\t\t\t\tmessage = m;\n\t\t\t} else if (typeof error === 'string') {\n\t\t\t\tmessage = error;\n\t\t\t} else if (error != null && typeof error === 'object') {\n\t\t\t\t// Some hosts nest it as `{ error: { message } }`; narrow the same way as the outer object.\n\t\t\t\tconst nested = (error as { message?: unknown }).message;\n\t\t\t\tif (typeof nested === 'string') {\n\t\t\t\t\tmessage = nested;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Not JSON — Bitbucket sends bare text for a throttled request, and any host can send an HTML error page.\n\t}\n\n\tmessage = (message ?? text).trim();\n\treturn message ? [{ message: message.slice(0, maxErrorBodyLength) }] : undefined;\n}\n\n/**\n * Whether a provider's error response denotes a rate limit rather than a permission failure. Kept here, in one\n * place, because the distinction is consequential: a rate limit is retryable, while a permission failure is\n * surfaced as `auth` and drives a reconnect prompt — misclassifying one as the other asks the user to\n * re-authenticate a perfectly healthy connection.\n *\n * Which status a throttled request arrives on varies by host, which is why this takes both:\n * - Azure DevOps and Bitbucket Cloud document 429 (learn.microsoft.com .../integrate/concepts/rate-limits).\n * - GitHub documents \"a `403` or `429` response\" for both its primary and secondary limits\n * (docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api).\n * - GitLab uses 403 for some throttles.\n * So 429 alone is decisive, and on 403 the message decides.\n *\n * NOTE the message must actually carry the host's body for the 403 path to work — see\n * {@link ProviderFetchError.fromResponse}. A `ProviderFetchError` built from the status line alone reads\n * \"(403) Forbidden.\" and can never match, which is what made this check dead code on the direct-fetch clients.\n */\nexport function isRateLimitResponse(ex: { status: number; message?: string }): boolean {\n\t// Matches the phrasing hosts actually use: GitHub/Bitbucket \"API rate limit exceeded\", GitLab \"rate limit\n\t// exceeded\", Azure \"Request was blocked due to exceeding usage of resource 'RateLimit'\" / \"TF400733: The\n\t// request has been canceled: Request was blocked due to exceeding usage\".\n\tif (ex.status === 429) return true;\n\n\tconst message = ex.message?.toLowerCase();\n\treturn message != null && (message.includes('rate limit') || message.includes('ratelimit'));\n}\n\n/**\n * A response's headers as either a `fetch` `Headers` instance or the plain object an SDK error carries. Read via\n * duck-typing on `get` rather than `instanceof Headers`, so this works in both the Node and webworker builds\n * without depending on the global being present.\n */\nexport type ResponseHeaders = Pick<Headers, 'get'> | Record<string, unknown>;\n\n/** Reads one header off either shape of {@link ResponseHeaders}; names are the lower-case ones both shapes use. */\nexport function getResponseHeader(headers: ResponseHeaders | undefined, name: string): unknown {\n\tif (headers == null) return undefined;\n\n\treturn typeof headers.get === 'function'\n\t\t? (headers.get as (name: string) => string | null)(name)\n\t\t: (headers as Record<string, unknown>)[name];\n}\n\n/**\n * Builds a {@link RequestRateLimitError} from a provider error response, reading the reset epoch from the\n * standard `x-ratelimit-reset` header when present. Accepts both header shapes in use: the `fetch` `Headers`\n * instance the direct clients get, and the plain object the SDK attaches to its errors.\n */\nexport function toRateLimitError(\n\tex: Error & { response?: { headers?: ResponseHeaders } },\n\ttoken: string | undefined,\n): RequestRateLimitError {\n\tconst raw = getResponseHeader(ex.response?.headers, 'x-ratelimit-reset');\n\n\t// Only a header that actually came back as a string/number can be a reset epoch; anything else (a nested SDK\n\t// object, an array of values) would stringify to garbage and parse to NaN anyway.\n\tlet resetAt: number | undefined;\n\tif (typeof raw === 'string' || typeof raw === 'number') {\n\t\tresetAt = parseInt(String(raw), 10);\n\t\tif (Number.isNaN(resetAt)) {\n\t\t\tresetAt = undefined;\n\t\t}\n\t}\n\n\treturn new RequestRateLimitError(ex, token, resetAt);\n}\n\n/**\n * Normalizes a caught `unknown` into an `Error`. Result cores type their failure channel as `error: Error`,\n * but a `catch` binding is `unknown` and a provider (or a third-party SDK) can throw a non-Error value;\n * returning it raw would leak a non-Error through the public result surface and break downstream `instanceof`\n * classification. Passes an existing `Error` through unchanged and wraps anything else with `String(ex)`.\n */\nexport function toError(ex: unknown): Error {\n\treturn ex instanceof Error ? ex : new Error(String(ex));\n}\n"],"mappings":";;;;;;;;;AAkBA,IAAa,kCAAb,cAAqD,MAAM;CAC1D,YAAY,UAAkB,QAAgB;EAC7C,MAAM,GAAG,SAAS,qBAAqB,QAAQ;EAC/C,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;;;;AAKA,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAwB5B;CAvBjB,IAAI,SAAiB;EACpB,OAAO,KAAK,SAAS;CACtB;CAEA,IAAI,aAAqB;EACxB,OAAO,KAAK,SAAS;CACtB;;;;;;;;;;CAWA,aAAa,aAAa,UAAkB,UAAiD;EAC5F,OAAO,IAAI,mBAAmB,UAAU,UAAU,MAAM,qBAAqB,QAAQ,CAAC;CACvF;CAEA,YACC,UACA,UACA,QACC;EACD,MACC,GAAG,SAAS,mBAAmB,CAAC,SAAS,KAAK,IAAI,SAAS,OAAO,IAAI,SAAS,WAAW,MAAM,KAC/F,QAAQ,SAAS,OAAO,EAAE,CAAC,UAAU,IAEvC;EAPgB,KAAA,WAAA;EAShB,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;;AAGA,MAAM,qBAAqB;;;;;;;;;;AAW3B,eAAe,qBAAqB,UAAgE;CACnG,IAAI;CACJ,IAAI;EAGH,IAAI,SAAS,UAAU,OAAO,KAAA;EAE9B,QAAQ,MAAM,SAAS,KAAK,EAAA,EAAI,KAAK;CACtC,QAAQ;EACP;CACD;CACA,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,IAAI;CACJ,IAAI;EACH,MAAM,OAAgB,KAAK,MAAM,IAAI;EACrC,IAAI,QAAQ,QAAQ,OAAO,SAAS,UAAU;GAC7C,MAAM,EAAE,SAAS,GAAG,UAAU;GAC9B,IAAI,OAAO,MAAM,UAChB,UAAU;QACJ,IAAI,OAAO,UAAU,UAC3B,UAAU;QACJ,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;IAEtD,MAAM,SAAU,MAAgC;IAChD,IAAI,OAAO,WAAW,UACrB,UAAU;GAEZ;EACD;CACD,QAAQ,CAER;CAEA,WAAW,WAAW,KAAA,CAAM,KAAK;CACjC,OAAO,UAAU,CAAC,EAAE,SAAS,QAAQ,MAAM,GAAG,kBAAkB,EAAE,CAAC,IAAI,KAAA;AACxE;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,oBAAoB,IAAmD;CAItF,IAAI,GAAG,WAAW,KAAK,OAAO;CAE9B,MAAM,UAAU,GAAG,SAAS,YAAY;CACxC,OAAO,WAAW,SAAS,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,WAAW;AAC1F;;AAUA,SAAgB,kBAAkB,SAAsC,MAAuB;CAC9F,IAAI,WAAW,MAAM,OAAO,KAAA;CAE5B,OAAO,OAAO,QAAQ,QAAQ,aAC1B,QAAQ,IAAwC,IAAI,IACpD,QAAoC;AACzC;;;;;;AAOA,SAAgB,iBACf,IACA,OACwB;CACxB,MAAM,MAAM,kBAAkB,GAAG,UAAU,SAAS,mBAAmB;CAIvE,IAAI;CACJ,IAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;EACvD,UAAU,SAAS,OAAO,GAAG,GAAG,EAAE;EAClC,IAAI,OAAO,MAAM,OAAO,GACvB,UAAU,KAAA;CAEZ;CAEA,OAAO,IAAI,sBAAsB,IAAI,OAAO,OAAO;AACpD;;;;;;;AAQA,SAAgB,QAAQ,IAAoB;CAC3C,OAAO,cAAc,QAAQ,KAAK,IAAI,MAAM,OAAO,EAAE,CAAC;AACvD"}
|
|
@@ -7,9 +7,12 @@ import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId, Integration
|
|
|
7
7
|
import { Source, Sources } from "./telemetry.js";
|
|
8
8
|
import { ConfiguredIntegrationsChangeEvent } from "./authentication/configuredIntegrationService.js";
|
|
9
9
|
import { IssueFilter } from "./providerFilters.js";
|
|
10
|
-
import { ConnectionStateChangeEvent, ProviderBroadenResult, ProviderOrganization, ProviderPageInfo, ProviderPagedResult, ProviderRepositoryShape, ProviderResult, ProviderSweepResult, ProviderWarning, ProviderWarningKind, ProviderWarningOmission, ProviderWarningOmissionKind, ProviderWarningOmissionRecovery, ProviderWarningOmissionScope, RepositoryIdentity, RepositoryResolution, RepositoryResolutionStatus, ResolveRepositoryResult } from "./results.js";
|
|
10
|
+
import { ConnectionStateChangeEvent, ProviderBroadenResult, ProviderOrganization, ProviderPageInfo, ProviderPagedResult, ProviderRepositoryShape, ProviderResult, ProviderSweepResult, ProviderWarning, ProviderWarningCause, ProviderWarningCauseReason, ProviderWarningKind, ProviderWarningOmission, ProviderWarningOmissionKind, ProviderWarningOmissionRecovery, ProviderWarningOmissionScope, ProviderWarningScope, RepositoryIdentity, RepositoryResolution, RepositoryResolutionStatus, ResolveRepositoryResult } from "./results.js";
|
|
11
11
|
import { IssueCountResult, IssueCountScope, PullRequestCountResult, PullRequestCountScope } from "./reads/counts.js";
|
|
12
|
-
import {
|
|
12
|
+
import { CurrentAccountResult } from "./reads/currentAccount.js";
|
|
13
|
+
import { IssueBatchResult, IssueBatchTarget } from "./reads/issueBatch.js";
|
|
14
|
+
import { PullRequestBatchResult, PullRequestBatchTarget } from "./reads/pullRequestBatch.js";
|
|
15
|
+
import { PullRequestBranchResult, PullRequestBranchTarget } from "./reads/pullRequestBranches.js";
|
|
13
16
|
import { ClosedPullRequestSweepOptions, IntegrationManager, ListOrgsOptions, ListProjectsOptions, ProviderBroadenOrg, ProviderRepositoriesInput, ProviderRepositoryInput, ProviderSweepTarget, ProviderSweepTargetEvent, PullRequestSweepOptions } from "./manager.js";
|
|
14
17
|
import { IntegrationAuthenticationProvider, IntegrationAuthenticationProviderDescriptor, IntegrationAuthenticationSessionDescriptor } from "./authentication/integrationAuthenticationProvider.js";
|
|
15
18
|
import { AccountProvider, AuthenticationSessionsChangeEvent, ConfigChangeEvent, ConfigProvider, HttpProvider, IntegrationServiceHooks, IntegrationStorageProvider, IntegrationsRemoteConfig, RepositoriesProvider } from "./context.js";
|
|
@@ -73,5 +76,5 @@ export interface IntegrationManagerContext {
|
|
|
73
76
|
*/
|
|
74
77
|
export declare function createIntegrationManager(ctx: IntegrationManagerContext): IntegrationManager;
|
|
75
78
|
//#endregion
|
|
76
|
-
export { type AccountProvider, type AuthenticationSessionLike, type AuthenticationSessionsChangeEvent, type ClosedPullRequestSweepOptions, type CloudIntegrationAuthType, type CloudIntegrationConnection, type CloudIntegrationType, type ConfigChangeEvent, type ConfigProvider, type ConfiguredIntegrationDescriptor, type ConfiguredIntegrationsChangeEvent, type ConnectionStateChangeEvent, GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId, type HttpProvider, type IntegrationAuthenticationProvider, type IntegrationAuthenticationProviderDescriptor, type IntegrationAuthenticationSessionDescriptor, type IntegrationIds, type IntegrationManager, type IntegrationServiceHooks, type IntegrationStorageProvider, type IntegrationsRemoteConfig, type IssueCountResult, type IssueCountScope, IssueFilter, type IssueSearchCapabilities, type IssueSearchCriteria, type IssueSearchRelationship, type IssueStateFilter, IssuesCloudHostIntegrationId, IssuesSelfManagedHostIntegrationId, type ListOrgsOptions, type ListProjectsOptions, type ManualTokenAuthProviderOptions, type ProviderAuthenticationSession, type ProviderBroadenOrg, type ProviderBroadenResult, type ProviderOrganization, type ProviderPageInfo, type ProviderPagedResult, type ProviderRepositoriesInput, type ProviderRepositoryInput, type ProviderRepositoryShape, type ProviderResult, type ProviderSweepResult, type ProviderSweepTarget, type ProviderSweepTargetEvent, type ProviderWarning, type ProviderWarningKind, type ProviderWarningOmission, type ProviderWarningOmissionKind, type ProviderWarningOmissionRecovery, type ProviderWarningOmissionScope, type PullRequestCountResult, type PullRequestCountScope, PullRequestFilter, type PullRequestSearchCapabilities, type PullRequestSearchCriteria, type PullRequestStateFilter, type PullRequestSweepOptions, type RepositoriesProvider, type RepositoryIdentity, type RepositoryResolution, type RepositoryResolutionStatus, type ResolveRepositoryResult, type Source, type Sources, type SupportedCloudIntegrationIds,
|
|
79
|
+
export { type Account, type AccountProvider, type AuthenticationSessionLike, type AuthenticationSessionsChangeEvent, type ClosedPullRequestSweepOptions, type CloudIntegrationAuthType, type CloudIntegrationConnection, type CloudIntegrationType, type ConfigChangeEvent, type ConfigProvider, type ConfiguredIntegrationDescriptor, type ConfiguredIntegrationsChangeEvent, type ConnectionStateChangeEvent, type CurrentAccountResult, GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId, type HttpProvider, type IntegrationAuthenticationProvider, type IntegrationAuthenticationProviderDescriptor, type IntegrationAuthenticationSessionDescriptor, type IntegrationIds, type IntegrationManager, type IntegrationServiceHooks, type IntegrationStorageProvider, type IntegrationsRemoteConfig, type IssueBatchResult, type IssueBatchTarget, type IssueCountResult, type IssueCountScope, IssueFilter, type IssueSearchCapabilities, type IssueSearchCriteria, type IssueSearchRelationship, type IssueStateFilter, IssuesCloudHostIntegrationId, IssuesSelfManagedHostIntegrationId, type ListOrgsOptions, type ListProjectsOptions, type ManualTokenAuthProviderOptions, type ProviderAuthenticationSession, type ProviderBroadenOrg, type ProviderBroadenResult, type ProviderOrganization, type ProviderPageInfo, type ProviderPagedResult, type ProviderRepositoriesInput, type ProviderRepositoryInput, type ProviderRepositoryShape, type ProviderResult, type ProviderSweepResult, type ProviderSweepTarget, type ProviderSweepTargetEvent, type ProviderWarning, type ProviderWarningCause, type ProviderWarningCauseReason, type ProviderWarningKind, type ProviderWarningOmission, type ProviderWarningOmissionKind, type ProviderWarningOmissionRecovery, type ProviderWarningOmissionScope, type ProviderWarningScope, type PullRequestBatchResult, type PullRequestBatchTarget, type PullRequestBranchResult, type PullRequestBranchTarget, type PullRequestCountResult, type PullRequestCountScope, PullRequestFilter, type PullRequestSearchCapabilities, type PullRequestSearchCriteria, type PullRequestStateFilter, type PullRequestSweepOptions, type RepositoriesProvider, type RepositoryIdentity, type RepositoryResolution, type RepositoryResolutionStatus, type ResolveRepositoryResult, type Source, type Sources, type SupportedCloudIntegrationIds, areDomainsOnSameHost, createManualTokenAuthProvider, hostFromDomain, isIntegrationId, isSupportedCloudIntegrationId, toCloudIntegrationType, toIntegrationId };
|
|
77
80
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../plus/integrations/src/index.ts"],"sourcesContent":["// Public facade for `@gitlens/integrations`.\n//\n// External consumers should import from this entry point only, not from the\n// package's internal subpaths, with one exception: the lightweight, token-scoped\n// read API is a supported public subpath (`./lite.js`). It's kept out of this\n// facade on purpose so importing the session-managed manager doesn't eagerly pull\n// in every provider API client. The internal classes (IntegrationService,\n// IntegrationAuthenticationService, etc.) are not part of the public API and\n// may be refactored without semver bumps.\n\nimport type { Account } from '@gitlens/git/models/author.js';\nimport { CacheController } from '@gitlens/utils/promiseCache.js';\nimport type { IntegrationIds } from './constants.js';\nimport type {\n\tAccountProvider,\n\tConfigProvider,\n\tHttpProvider,\n\tIntegrationCacheProvider,\n\tIntegrationServiceHooks,\n\tIntegrationStorageProvider,\n\tRepositoriesProvider,\n} from './context.js';\nimport { createIntegrationService } from './integrationService.js';\nimport type { IntegrationManager } from './manager.js';\n\n/** A cached provider value, which may still be resolving. */\nexport type IntegrationManagerCacheResult<T> = Promise<T | undefined> | T | undefined;\n\n/** Produces an account value on a cache miss. */\nexport type IntegrationManagerCacheLoader<T> = (cacheable: CacheController) => {\n\tvalue: IntegrationManagerCacheResult<T>;\n\texpiresAt?: number;\n};\n\n/** Stable integration identity supplied to the consumer-owned account cache. */\nexport interface IntegrationAccountCacheDescriptor {\n\treadonly id: IntegrationIds;\n\treadonly domain?: string;\n}\n\n/** Cache controls attached to a provider account lookup. */\nexport interface IntegrationManagerCacheOptions {\n\treadonly connectionId?: string;\n\treadonly etag?: string;\n\treadonly expiryOverride?: boolean | number;\n\treadonly expireOnError?: boolean;\n}\n\n/**\n * Optional consumer-owned cache for values reused by the public manager facade.\n *\n * The manager only needs cross-call caching for provider identity lookups. Other caches used by the GitLens\n * extension host are implementation details and deliberately stay out of this contract.\n */\nexport interface IntegrationManagerCacheProvider {\n\tgetCurrentAccount(\n\t\tintegration: IntegrationAccountCacheDescriptor,\n\t\tcacheable: IntegrationManagerCacheLoader<Account>,\n\t\toptions?: IntegrationManagerCacheOptions,\n\t): IntegrationManagerCacheResult<Account>;\n}\n\nfunction loadUncached<T>(loader: IntegrationManagerCacheLoader<T>): IntegrationManagerCacheResult<T> {\n\treturn loader(new CacheController()).value;\n}\n\nconst uncachedIntegrationCacheProvider: IntegrationCacheProvider = {\n\tgetRepositoryMetadata: (_repo, _integration, loader) => loadUncached(loader),\n\tgetRepositoryDefaultBranch: (_repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequestForSha: (_sha, _repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequestForBranch: (_branch, _repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequest: (_id, _resource, _integration, loader) => loadUncached(loader),\n\tgetIssueOrPullRequest: (_id, _type, _resource, _integration, loader) => loadUncached(loader),\n\tgetIssue: (_id, _resource, _integration, loader) => loadUncached(loader),\n\tgetCurrentAccount: (_integration, loader) => loadUncached(loader),\n\t// Nothing is cached, so there is nothing to evict.\n\tdeletePullRequests: () => {},\n};\n\nfunction toIntegrationCacheProvider(cache: IntegrationManagerCacheProvider | undefined): IntegrationCacheProvider {\n\tif (cache == null) return uncachedIntegrationCacheProvider;\n\n\treturn {\n\t\t...uncachedIntegrationCacheProvider,\n\t\tgetCurrentAccount: (integration, loader, options) =>\n\t\t\tcache.getCurrentAccount({ id: integration.id, domain: integration.domain }, loader, options),\n\t};\n}\n\n/**\n * Consumer-facing runtime for {@link createIntegrationManager}.\n *\n * External consumers may omit `cache`; reads then execute their loaders directly without cross-call caching.\n * The extension host's broader integration context remains private to the implementation.\n */\nexport interface IntegrationManagerContext {\n\treadonly storage: IntegrationStorageProvider;\n\treadonly account: AccountProvider;\n\treadonly config: ConfigProvider;\n\treadonly http: HttpProvider;\n\treadonly cache?: IntegrationManagerCacheProvider;\n\treadonly repositories: RepositoriesProvider;\n\treadonly hooks?: IntegrationServiceHooks;\n}\n\nexport type {\n\tClosedPullRequestSweepOptions,\n\tIntegrationManager,\n\tListOrgsOptions,\n\tListProjectsOptions,\n\t// Every option shape a caller has to BUILD is exported, not just the ones the manager returns:\n\t// `manager.js` is not a public subpath, so a type omitted here can't be named by a consumer at all\n\t// (`broadenIssues`' `orgs` needed `ProviderBroadenOrg` and had to be re-declared downstream).\n\tProviderBroadenOrg,\n\tProviderRepositoriesInput,\n\tProviderRepositoryInput,\n\tProviderSweepTarget,\n\tProviderSweepTargetEvent,\n\tPullRequestSweepOptions,\n} from './manager.js';\n\n/**\n * Construct an `@gitlens/integrations` manager bound to the supplied runtime.\n *\n * The runtime is the **single** cross-boundary contract — anything the\n * package needs (HTTP, storage, cache, auth, subscription, telemetry, UI,\n * configuration, environment) flows through it. The package never imports\n * `vscode`, `Container`, or any consumer-internal types.\n *\n * The returned manager owns its internal services; dispose it (or its\n * containing scope) to release every cached integration plus the runtime's\n * own VS Code subscriptions.\n */\nexport function createIntegrationManager(ctx: IntegrationManagerContext): IntegrationManager {\n\treturn createIntegrationService({\n\t\t...ctx,\n\t\tcache: toIntegrationCacheProvider(ctx.cache),\n\t});\n}\n\n// Re-exports for the public API surface.\nexport type {\n\tAccountProvider,\n\tAuthenticationSessionsChangeEvent,\n\tConfigChangeEvent,\n\tConfigProvider,\n\tRepositoriesProvider,\n\tHttpProvider,\n\tIntegrationsRemoteConfig,\n\tIntegrationServiceHooks,\n\tIntegrationStorageProvider,\n} from './context.js';\nexport type { Source, Sources } from './telemetry.js';\nexport type { IntegrationIds, SupportedCloudIntegrationIds } from './constants.js';\nexport type { ConfiguredIntegrationsChangeEvent } from './authentication/configuredIntegrationService.js';\n\n// Authentication contract — what `IntegrationServiceHooks.createAuthenticationProvider`\n// implementers return. Consumers can plug in any auth strategy (manual token,\n// OAuth, host-managed) by returning an object implementing this interface from\n// the hook.\nexport type {\n\tIntegrationAuthenticationProvider,\n\tIntegrationAuthenticationProviderDescriptor,\n\tIntegrationAuthenticationSessionDescriptor,\n} from './authentication/integrationAuthenticationProvider.js';\nexport type {\n\tAuthenticationSessionLike,\n\tCloudIntegrationAuthType,\n\tCloudIntegrationConnection,\n\tCloudIntegrationType,\n\tConfiguredIntegrationDescriptor,\n\tProviderAuthenticationSession,\n} from './authentication/models.js';\n// Provider-id mapping helpers for consumers bridging their own provider ids to `IntegrationIds`\n// (e.g. mapping multi-account connections from `getConfigured` back to a provider) and vice versa.\nexport { toCloudIntegrationType, toIntegrationId } from './authentication/models.js';\n// Domain normalization is part of connection selection and repository resolution; consumers should use the\n// same implementation rather than importing an internal utility subpath or maintaining a divergent copy.\nexport { areDomainsOnSameHost, hostFromDomain } from './utils/domain.utils.js';\n\n// Convenience: wrap a static access token (env var, CLI flag, secret manager)\n// as an `IntegrationAuthenticationProvider`. For OAuth/refresh flows, implement\n// the interface directly — this helper is for non-interactive consumers only.\nexport {\n\tcreateManualTokenAuthProvider,\n\ttype ManualTokenAuthProviderOptions,\n} from './authentication/manualTokenProvider.js';\n\nexport {\n\tGitCloudHostIntegrationId,\n\tGitSelfManagedHostIntegrationId,\n\tIssuesCloudHostIntegrationId,\n\tIssuesSelfManagedHostIntegrationId,\n\tisIntegrationId,\n\tisSupportedCloudIntegrationId,\n} from './constants.js';\n\n// Neutral pagination + warning result types the Kepler ProviderBackend adapter maps to its own DTOs.\n// These carry no `@gitkraken/provider-apis` types, so consumers depend only on `@gitkraken/core-gitlens`.\nexport type {\n\tConnectionStateChangeEvent,\n\tProviderBroadenResult,\n\tProviderPagedResult,\n\tProviderPageInfo,\n\tProviderResult,\n\tProviderSweepResult,\n\tProviderWarning,\n\tProviderWarningKind,\n\tProviderWarningOmission,\n\tProviderWarningOmissionKind,\n\tProviderWarningOmissionRecovery,\n\tProviderWarningOmissionScope,\n\tProviderOrganization,\n\tProviderRepositoryShape,\n\tRepositoryIdentity,\n\tRepositoryResolution,\n\tRepositoryResolutionStatus,\n\tResolveRepositoryResult,\n} from './results.js';\n// Runtime enums — re-exported as values (not `export type`) so consumers can read their members.\nexport { IssueFilter, PullRequestFilter } from './providerFilters.js';\n// The filtered issue search's criteria model and the capability table that says which of it a provider honors.\n// String unions and plain interfaces, so a consumer builds criteria without importing an internal subpath.\nexport type { IssueSearchCapabilities, IssueSearchCriteria, IssueSearchRelationship } from './providerFilters.js';\n// Account-wide pull-request search criteria and the per-provider capability table.\nexport type { PullRequestSearchCapabilities, PullRequestSearchCriteria } from './providerFilters.js';\n// The count-only issue and pull-request probes' input and result shapes.\nexport type {\n\tIssueCountResult,\n\tIssueCountScope,\n\tPullRequestCountResult,\n\tPullRequestCountScope,\n} from './reads/counts.js';\nexport type { TrackerIssueResult } from './reads/trackerIssue.js';\n// Cross-provider PR/issue state filters (string unions in the git models).\nexport type { PullRequestStateFilter } from '@gitlens/git/models/pullRequest.js';\nexport type { IssueStateFilter } from '@gitlens/git/models/issue.js';\n"],"mappings":";;;;;;;;;AA8DA,SAAS,aAAgB,QAA4E;CACpG,OAAO,OAAO,IAAI,gBAAgB,CAAC,CAAC,CAAC;AACtC;AAEA,MAAM,mCAA6D;CAClE,wBAAwB,OAAO,cAAc,WAAW,aAAa,MAAM;CAC3E,6BAA6B,OAAO,cAAc,WAAW,aAAa,MAAM;CAChF,uBAAuB,MAAM,OAAO,cAAc,WAAW,aAAa,MAAM;CAChF,0BAA0B,SAAS,OAAO,cAAc,WAAW,aAAa,MAAM;CACtF,iBAAiB,KAAK,WAAW,cAAc,WAAW,aAAa,MAAM;CAC7E,wBAAwB,KAAK,OAAO,WAAW,cAAc,WAAW,aAAa,MAAM;CAC3F,WAAW,KAAK,WAAW,cAAc,WAAW,aAAa,MAAM;CACvE,oBAAoB,cAAc,WAAW,aAAa,MAAM;CAEhE,0BAA0B,CAAC;AAC5B;AAEA,SAAS,2BAA2B,OAA8E;CACjH,IAAI,SAAS,MAAM,OAAO;CAE1B,OAAO;EACN,GAAG;EACH,oBAAoB,aAAa,QAAQ,YACxC,MAAM,kBAAkB;GAAE,IAAI,YAAY;GAAI,QAAQ,YAAY;EAAO,GAAG,QAAQ,OAAO;CAC7F;AACD;;;;;;;;;;;;;AA8CA,SAAgB,yBAAyB,KAAoD;CAC5F,OAAO,yBAAyB;EAC/B,GAAG;EACH,OAAO,2BAA2B,IAAI,KAAK;CAC5C,CAAC;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../plus/integrations/src/index.ts"],"sourcesContent":["// Public facade for `@gitlens/integrations`.\n//\n// External consumers should import from this entry point only, not from the\n// package's internal subpaths, with one exception: the lightweight, token-scoped\n// read API is a supported public subpath (`./lite.js`). It's kept out of this\n// facade on purpose so importing the session-managed manager doesn't eagerly pull\n// in every provider API client. The internal classes (IntegrationService,\n// IntegrationAuthenticationService, etc.) are not part of the public API and\n// may be refactored without semver bumps.\n\nimport type { Account } from '@gitlens/git/models/author.js';\nimport { CacheController } from '@gitlens/utils/promiseCache.js';\nimport type { IntegrationIds } from './constants.js';\nimport type {\n\tAccountProvider,\n\tConfigProvider,\n\tHttpProvider,\n\tIntegrationCacheProvider,\n\tIntegrationServiceHooks,\n\tIntegrationStorageProvider,\n\tRepositoriesProvider,\n} from './context.js';\nimport { createIntegrationService } from './integrationService.js';\nimport type { IntegrationManager } from './manager.js';\n\n/** A cached provider value, which may still be resolving. */\nexport type IntegrationManagerCacheResult<T> = Promise<T | undefined> | T | undefined;\n\n/** Produces an account value on a cache miss. */\nexport type IntegrationManagerCacheLoader<T> = (cacheable: CacheController) => {\n\tvalue: IntegrationManagerCacheResult<T>;\n\texpiresAt?: number;\n};\n\n/** Stable integration identity supplied to the consumer-owned account cache. */\nexport interface IntegrationAccountCacheDescriptor {\n\treadonly id: IntegrationIds;\n\treadonly domain?: string;\n}\n\n/** Cache controls attached to a provider account lookup. */\nexport interface IntegrationManagerCacheOptions {\n\treadonly connectionId?: string;\n\treadonly etag?: string;\n\treadonly expiryOverride?: boolean | number;\n\treadonly expireOnError?: boolean;\n}\n\n/**\n * Optional consumer-owned cache for values reused by the public manager facade.\n *\n * The manager only needs cross-call caching for provider identity lookups. Other caches used by the GitLens\n * extension host are implementation details and deliberately stay out of this contract.\n */\nexport interface IntegrationManagerCacheProvider {\n\tgetCurrentAccount(\n\t\tintegration: IntegrationAccountCacheDescriptor,\n\t\tcacheable: IntegrationManagerCacheLoader<Account>,\n\t\toptions?: IntegrationManagerCacheOptions,\n\t): IntegrationManagerCacheResult<Account>;\n}\n\nfunction loadUncached<T>(loader: IntegrationManagerCacheLoader<T>): IntegrationManagerCacheResult<T> {\n\treturn loader(new CacheController()).value;\n}\n\nconst uncachedIntegrationCacheProvider: IntegrationCacheProvider = {\n\tgetRepositoryMetadata: (_repo, _integration, loader) => loadUncached(loader),\n\tgetRepositoryDefaultBranch: (_repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequestForSha: (_sha, _repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequestForBranch: (_branch, _repo, _integration, loader) => loadUncached(loader),\n\tgetPullRequest: (_id, _resource, _integration, loader) => loadUncached(loader),\n\tgetIssueOrPullRequest: (_id, _type, _resource, _integration, loader) => loadUncached(loader),\n\tgetIssue: (_id, _resource, _integration, loader) => loadUncached(loader),\n\tgetCurrentAccount: (_integration, loader) => loadUncached(loader),\n\t// Nothing is cached, so there is nothing to evict.\n\tdeletePullRequests: () => {},\n};\n\nfunction toIntegrationCacheProvider(cache: IntegrationManagerCacheProvider | undefined): IntegrationCacheProvider {\n\tif (cache == null) return uncachedIntegrationCacheProvider;\n\n\treturn {\n\t\t...uncachedIntegrationCacheProvider,\n\t\tgetCurrentAccount: (integration, loader, options) =>\n\t\t\tcache.getCurrentAccount({ id: integration.id, domain: integration.domain }, loader, options),\n\t};\n}\n\n/**\n * Consumer-facing runtime for {@link createIntegrationManager}.\n *\n * External consumers may omit `cache`; reads then execute their loaders directly without cross-call caching.\n * The extension host's broader integration context remains private to the implementation.\n */\nexport interface IntegrationManagerContext {\n\treadonly storage: IntegrationStorageProvider;\n\treadonly account: AccountProvider;\n\treadonly config: ConfigProvider;\n\treadonly http: HttpProvider;\n\treadonly cache?: IntegrationManagerCacheProvider;\n\treadonly repositories: RepositoriesProvider;\n\treadonly hooks?: IntegrationServiceHooks;\n}\n\nexport type {\n\tClosedPullRequestSweepOptions,\n\tIntegrationManager,\n\tListOrgsOptions,\n\tListProjectsOptions,\n\t// Every option shape a caller has to BUILD is exported, not just the ones the manager returns:\n\t// `manager.js` is not a public subpath, so a type omitted here can't be named by a consumer at all\n\t// (`broadenIssues`' `orgs` needed `ProviderBroadenOrg` and had to be re-declared downstream).\n\tProviderBroadenOrg,\n\tProviderRepositoriesInput,\n\tProviderRepositoryInput,\n\tProviderSweepTarget,\n\tProviderSweepTargetEvent,\n\tPullRequestSweepOptions,\n} from './manager.js';\n\n/**\n * Construct an `@gitlens/integrations` manager bound to the supplied runtime.\n *\n * The runtime is the **single** cross-boundary contract — anything the\n * package needs (HTTP, storage, cache, auth, subscription, telemetry, UI,\n * configuration, environment) flows through it. The package never imports\n * `vscode`, `Container`, or any consumer-internal types.\n *\n * The returned manager owns its internal services; dispose it (or its\n * containing scope) to release every cached integration plus the runtime's\n * own VS Code subscriptions.\n */\nexport function createIntegrationManager(ctx: IntegrationManagerContext): IntegrationManager {\n\treturn createIntegrationService({\n\t\t...ctx,\n\t\tcache: toIntegrationCacheProvider(ctx.cache),\n\t});\n}\n\n// Re-exports for the public API surface.\nexport type {\n\tAccountProvider,\n\tAuthenticationSessionsChangeEvent,\n\tConfigChangeEvent,\n\tConfigProvider,\n\tRepositoriesProvider,\n\tHttpProvider,\n\tIntegrationsRemoteConfig,\n\tIntegrationServiceHooks,\n\tIntegrationStorageProvider,\n} from './context.js';\nexport type { Source, Sources } from './telemetry.js';\nexport type { IntegrationIds, SupportedCloudIntegrationIds } from './constants.js';\nexport type { ConfiguredIntegrationsChangeEvent } from './authentication/configuredIntegrationService.js';\n\n// Authentication contract — what `IntegrationServiceHooks.createAuthenticationProvider`\n// implementers return. Consumers can plug in any auth strategy (manual token,\n// OAuth, host-managed) by returning an object implementing this interface from\n// the hook.\nexport type {\n\tIntegrationAuthenticationProvider,\n\tIntegrationAuthenticationProviderDescriptor,\n\tIntegrationAuthenticationSessionDescriptor,\n} from './authentication/integrationAuthenticationProvider.js';\nexport type {\n\tAuthenticationSessionLike,\n\tCloudIntegrationAuthType,\n\tCloudIntegrationConnection,\n\tCloudIntegrationType,\n\tConfiguredIntegrationDescriptor,\n\tProviderAuthenticationSession,\n} from './authentication/models.js';\n// Provider-id mapping helpers for consumers bridging their own provider ids to `IntegrationIds`\n// (e.g. mapping multi-account connections from `getConfigured` back to a provider) and vice versa.\nexport { toCloudIntegrationType, toIntegrationId } from './authentication/models.js';\n// Domain normalization is part of connection selection and repository resolution; consumers should use the\n// same implementation rather than importing an internal utility subpath or maintaining a divergent copy.\nexport { areDomainsOnSameHost, hostFromDomain } from './utils/domain.utils.js';\n\n// Convenience: wrap a static access token (env var, CLI flag, secret manager)\n// as an `IntegrationAuthenticationProvider`. For OAuth/refresh flows, implement\n// the interface directly — this helper is for non-interactive consumers only.\nexport {\n\tcreateManualTokenAuthProvider,\n\ttype ManualTokenAuthProviderOptions,\n} from './authentication/manualTokenProvider.js';\n\nexport {\n\tGitCloudHostIntegrationId,\n\tGitSelfManagedHostIntegrationId,\n\tIssuesCloudHostIntegrationId,\n\tIssuesSelfManagedHostIntegrationId,\n\tisIntegrationId,\n\tisSupportedCloudIntegrationId,\n} from './constants.js';\n\n// Neutral pagination + warning result types the Kepler ProviderBackend adapter maps to its own DTOs.\n// These carry no `@gitkraken/provider-apis` types, so consumers depend only on `@gitkraken/core-gitlens`.\nexport type {\n\tConnectionStateChangeEvent,\n\tProviderBroadenResult,\n\tProviderPagedResult,\n\tProviderPageInfo,\n\tProviderResult,\n\tProviderSweepResult,\n\tProviderWarning,\n\tProviderWarningCause,\n\tProviderWarningCauseReason,\n\tProviderWarningKind,\n\tProviderWarningOmission,\n\tProviderWarningOmissionKind,\n\tProviderWarningOmissionRecovery,\n\tProviderWarningOmissionScope,\n\tProviderWarningScope,\n\tProviderOrganization,\n\tProviderRepositoryShape,\n\tRepositoryIdentity,\n\tRepositoryResolution,\n\tRepositoryResolutionStatus,\n\tResolveRepositoryResult,\n} from './results.js';\n// Runtime enums — re-exported as values (not `export type`) so consumers can read their members.\nexport { IssueFilter, PullRequestFilter } from './providerFilters.js';\n// The filtered issue search's criteria model and the capability table that says which of it a provider honors.\n// String unions and plain interfaces, so a consumer builds criteria without importing an internal subpath.\nexport type { IssueSearchCapabilities, IssueSearchCriteria, IssueSearchRelationship } from './providerFilters.js';\n// Account-wide pull-request search criteria and the per-provider capability table.\nexport type { PullRequestSearchCapabilities, PullRequestSearchCriteria } from './providerFilters.js';\n// The count-only issue and pull-request probes' input and result shapes.\nexport type {\n\tIssueCountResult,\n\tIssueCountScope,\n\tPullRequestCountResult,\n\tPullRequestCountScope,\n} from './reads/counts.js';\nexport type { IssueBatchResult, IssueBatchTarget } from './reads/issueBatch.js';\nexport type { PullRequestBatchResult, PullRequestBatchTarget } from './reads/pullRequestBatch.js';\nexport type { PullRequestBranchResult, PullRequestBranchTarget } from './reads/pullRequestBranches.js';\n// The current-account read's result, and the account shape every identity-bearing read already returns.\nexport type { CurrentAccountResult } from './reads/currentAccount.js';\nexport type { Account } from '@gitlens/git/models/author.js';\n// Cross-provider PR/issue state filters (string unions in the git models).\nexport type { PullRequestStateFilter } from '@gitlens/git/models/pullRequest.js';\nexport type { IssueStateFilter } from '@gitlens/git/models/issue.js';\n"],"mappings":";;;;;;;;;AA8DA,SAAS,aAAgB,QAA4E;CACpG,OAAO,OAAO,IAAI,gBAAgB,CAAC,CAAC,CAAC;AACtC;AAEA,MAAM,mCAA6D;CAClE,wBAAwB,OAAO,cAAc,WAAW,aAAa,MAAM;CAC3E,6BAA6B,OAAO,cAAc,WAAW,aAAa,MAAM;CAChF,uBAAuB,MAAM,OAAO,cAAc,WAAW,aAAa,MAAM;CAChF,0BAA0B,SAAS,OAAO,cAAc,WAAW,aAAa,MAAM;CACtF,iBAAiB,KAAK,WAAW,cAAc,WAAW,aAAa,MAAM;CAC7E,wBAAwB,KAAK,OAAO,WAAW,cAAc,WAAW,aAAa,MAAM;CAC3F,WAAW,KAAK,WAAW,cAAc,WAAW,aAAa,MAAM;CACvE,oBAAoB,cAAc,WAAW,aAAa,MAAM;CAEhE,0BAA0B,CAAC;AAC5B;AAEA,SAAS,2BAA2B,OAA8E;CACjH,IAAI,SAAS,MAAM,OAAO;CAE1B,OAAO;EACN,GAAG;EACH,oBAAoB,aAAa,QAAQ,YACxC,MAAM,kBAAkB;GAAE,IAAI,YAAY;GAAI,QAAQ,YAAY;EAAO,GAAG,QAAQ,OAAO;CAC7F;AACD;;;;;;;;;;;;;AA8CA,SAAgB,yBAAyB,KAAoD;CAC5F,OAAO,yBAAyB;EAC/B,GAAG;EACH,OAAO,2BAA2B,IAAI,KAAK;CAC5C,CAAC;AACF"}
|
|
@@ -11,16 +11,18 @@ import { CloudGitSelfManagedHostIntegrationIds, GitCloudHostIntegrationId, GitSe
|
|
|
11
11
|
import { Source } from "./telemetry.js";
|
|
12
12
|
import { ConfiguredIntegrationService, ConfiguredIntegrationsChangeEvent } from "./authentication/configuredIntegrationService.js";
|
|
13
13
|
import { IssueFilter } from "./providerFilters.js";
|
|
14
|
+
import { ConnectionStateChangeEvent, ProviderBroadenResult, ProviderOrganization, ProviderPagedResult, ProviderRepositoryShape, ProviderResult, ProviderSweepResult, ProviderWarning, ResolveRepositoryResult } from "./results.js";
|
|
14
15
|
import { GitHostIntegration, SearchMyPullRequestsOptions } from "./models/gitHostIntegration.js";
|
|
15
16
|
import { IssuesIntegration } from "./models/issuesIntegration.js";
|
|
16
17
|
import { Integration, IntegrationBase, IntegrationById, IntegrationResult } from "./models/integration.js";
|
|
17
|
-
import { ConnectionStateChangeEvent, ProviderBroadenResult, ProviderOrganization, ProviderPagedResult, ProviderRepositoryShape, ProviderResult, ProviderSweepResult, ProviderWarning, ResolveRepositoryResult } from "./results.js";
|
|
18
18
|
import { ProviderReposInput } from "./providers/models.js";
|
|
19
19
|
import { RepositoryResolutionContext } from "./reads/context.js";
|
|
20
20
|
import { IssueCountResult, IssueCountScope, PullRequestCountResult, PullRequestCountScope } from "./reads/counts.js";
|
|
21
|
+
import { CurrentAccountResult } from "./reads/currentAccount.js";
|
|
21
22
|
import { SupportedFilters } from "./reads/filters.js";
|
|
22
23
|
import { IssueBatchResult, IssueBatchTarget } from "./reads/issueBatch.js";
|
|
23
|
-
import {
|
|
24
|
+
import { PullRequestBatchResult, PullRequestBatchTarget } from "./reads/pullRequestBatch.js";
|
|
25
|
+
import { PullRequestBranchResult, PullRequestBranchTarget } from "./reads/pullRequestBranches.js";
|
|
24
26
|
import { ClosedPullRequestSweepOptions, ListOrgsOptions, ListProjectsOptions, ProviderBroadenOrg, PullRequestSweepOptions } from "./manager.js";
|
|
25
27
|
import "./providers/github/github.js";
|
|
26
28
|
import { ApiClients } from "./providers/apiClients.js";
|
|
@@ -319,22 +321,32 @@ export declare class IntegrationService implements Disposable, RepositoryResolut
|
|
|
319
321
|
connectionId?: string;
|
|
320
322
|
/**
|
|
321
323
|
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
322
|
-
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
324
|
+
* it must come from the trusted authentication configuration, not repository or remote data. Unlike the
|
|
325
|
+
* paged reads, a self-managed tracker does not fall back to the primary connection without one; see
|
|
326
|
+
* {@link IntegrationManager.getIssuesBatch}.
|
|
323
327
|
*/
|
|
324
328
|
domain?: string;
|
|
325
329
|
}): Promise<ProviderResult<IssueBatchResult>>;
|
|
326
|
-
|
|
330
|
+
getPullRequestsBatch(options: {
|
|
327
331
|
providerId: IntegrationIds;
|
|
328
|
-
|
|
329
|
-
resourceUrl?: string;
|
|
330
|
-
key: string;
|
|
332
|
+
targets: readonly PullRequestBatchTarget[];
|
|
331
333
|
connectionId?: string;
|
|
332
334
|
/**
|
|
333
|
-
* Explicit self-managed host domain.
|
|
334
|
-
*
|
|
335
|
+
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
336
|
+
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
335
337
|
*/
|
|
336
338
|
domain?: string;
|
|
337
|
-
}): Promise<ProviderResult<
|
|
339
|
+
}): Promise<ProviderResult<PullRequestBatchResult>>;
|
|
340
|
+
getPullRequestsForBranches(options: {
|
|
341
|
+
providerId: IntegrationIds;
|
|
342
|
+
targets: readonly PullRequestBranchTarget[];
|
|
343
|
+
connectionId?: string;
|
|
344
|
+
/**
|
|
345
|
+
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
346
|
+
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
347
|
+
*/
|
|
348
|
+
domain?: string;
|
|
349
|
+
}): Promise<ProviderResult<PullRequestBranchResult>>;
|
|
338
350
|
/**
|
|
339
351
|
* How many pull requests match each scope, without fetching any — the PR twin of {@link countIssues}. See
|
|
340
352
|
* {@link IntegrationManager.countPullRequests} for the cost model, the per-scope isolation rules, and why
|
|
@@ -439,6 +451,20 @@ export declare class IntegrationService implements Disposable, RepositoryResolut
|
|
|
439
451
|
*/
|
|
440
452
|
domain?: string;
|
|
441
453
|
}): Promise<ResolveRepositoryResult>;
|
|
454
|
+
/**
|
|
455
|
+
* Who the connection is signed in as — "who am I on this provider" — for a git host or issue tracker alike.
|
|
456
|
+
* Goes through {@link Integration.getCurrentAccount}'s own cache, so this and whatever else warms it (see
|
|
457
|
+
* `IntegrationManagerCacheProvider.getCurrentAccount`) stay one cache.
|
|
458
|
+
*/
|
|
459
|
+
getCurrentAccount(options: {
|
|
460
|
+
providerId: IntegrationIds;
|
|
461
|
+
connectionId?: string;
|
|
462
|
+
/**
|
|
463
|
+
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
464
|
+
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
465
|
+
*/
|
|
466
|
+
domain?: string;
|
|
467
|
+
}): Promise<CurrentAccountResult>;
|
|
442
468
|
/** {@link RepositoryResolutionContext} seam: the user's `remotes` configs, for the remote matcher. */
|
|
443
469
|
getRemoteConfigs(): readonly IntegrationsRemoteConfig[];
|
|
444
470
|
/** {@link RepositoryResolutionContext} seam: instance lookup by host, for the cloud-host resolution branch. */
|
|
@@ -20,16 +20,18 @@ import { noConnectionWarning } from "./reads/warnings.js";
|
|
|
20
20
|
import { getSupportedFilters } from "./reads/filters.js";
|
|
21
21
|
import { broadenIssues } from "./reads/broaden.js";
|
|
22
22
|
import { countIssues, countPullRequests } from "./reads/counts.js";
|
|
23
|
+
import { getCurrentAccount } from "./reads/currentAccount.js";
|
|
23
24
|
import { listOrgs, listProjects, listRepos } from "./reads/hierarchy.js";
|
|
24
25
|
import { getIssuesBatch } from "./reads/issueBatch.js";
|
|
25
26
|
import { listIssuesPage } from "./reads/issues.js";
|
|
26
27
|
import { listIssueTrackerIssuesPage } from "./reads/issueTracker.js";
|
|
28
|
+
import { getPullRequestsBatch } from "./reads/pullRequestBatch.js";
|
|
29
|
+
import { getPullRequestsForBranches } from "./reads/pullRequestBranches.js";
|
|
27
30
|
import { listPullRequestsPage } from "./reads/pullRequests.js";
|
|
28
31
|
import { resolveRepository } from "./reads/resolveRepository.js";
|
|
29
32
|
import { searchIssuesPage } from "./reads/searchIssues.js";
|
|
30
33
|
import { searchPullRequestsPage } from "./reads/searchPullRequests.js";
|
|
31
34
|
import { sweepClosedPullRequests, sweepPullRequests } from "./reads/sweeps.js";
|
|
32
|
-
import { getTrackerIssue } from "./reads/trackerIssue.js";
|
|
33
35
|
//#region ../plus/integrations/src/integrationService.ts
|
|
34
36
|
const maxSmallIntegerV8 = 2 ** 30 - 1;
|
|
35
37
|
var IntegrationService = class {
|
|
@@ -620,8 +622,11 @@ var IntegrationService = class {
|
|
|
620
622
|
async getIssuesBatch(options) {
|
|
621
623
|
return getIssuesBatch(this, options);
|
|
622
624
|
}
|
|
623
|
-
async
|
|
624
|
-
return
|
|
625
|
+
async getPullRequestsBatch(options) {
|
|
626
|
+
return getPullRequestsBatch(this, options);
|
|
627
|
+
}
|
|
628
|
+
async getPullRequestsForBranches(options) {
|
|
629
|
+
return getPullRequestsForBranches(this, options);
|
|
625
630
|
}
|
|
626
631
|
/**
|
|
627
632
|
* How many pull requests match each scope, without fetching any — the PR twin of {@link countIssues}. See
|
|
@@ -697,6 +702,14 @@ var IntegrationService = class {
|
|
|
697
702
|
async resolveRepository(options) {
|
|
698
703
|
return resolveRepository(this, options);
|
|
699
704
|
}
|
|
705
|
+
/**
|
|
706
|
+
* Who the connection is signed in as — "who am I on this provider" — for a git host or issue tracker alike.
|
|
707
|
+
* Goes through {@link Integration.getCurrentAccount}'s own cache, so this and whatever else warms it (see
|
|
708
|
+
* `IntegrationManagerCacheProvider.getCurrentAccount`) stay one cache.
|
|
709
|
+
*/
|
|
710
|
+
async getCurrentAccount(options) {
|
|
711
|
+
return getCurrentAccount(this, options);
|
|
712
|
+
}
|
|
700
713
|
/** {@link RepositoryResolutionContext} seam: the user's `remotes` configs, for the remote matcher. */
|
|
701
714
|
getRemoteConfigs() {
|
|
702
715
|
return this.ctx.config.getRemoteConfigs();
|