UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

514 lines (513 loc) 23.5 kB
import { A as resolveExpiresAtMsFromEpochSeconds, C as parseStrictNonNegativeInteger, o as asDateTimestampMs } from "./number-coercion-CLj0HTDM.js"; import { c as isRecord, t as asNonArrayRecord } from "./record-coerce-DItp3I4t.js"; import { a as resolveOsHomeRelativePath } from "./home-dir-BPhrG-aM.js"; import { w as resolveStateDir } from "./paths-D2sRr1a_.js"; import "./types.secrets-kC0nOetj.js"; import "./http-body-D3IMwTJJ.js"; import { t as cancelUnreadResponseBody } from "./http-response-body-CwT_cCNz.js"; import "./provider-env-vars-B8XgJCSL.js"; import { i as logWarn } from "./logger-DwECwNVZ.js"; import { m as readProviderJsonResponse } from "./provider-http-errors-U-nhuk_f.js"; import "./provider-openai-chatgpt-auth-BoLGEnud.js"; import "./persisted-B_qhhBlh.js"; import "./credential-state-N1MIGw99.js"; import { r as writeJsonTarget, t as loadJsonFileThroughSymlink } from "./json-file-CHTTn1IF.js"; import "./cli-credentials-CHuqM5pH.js"; import "./store-F1B2duCT.js"; import "./profiles-DOTqXcYA.js"; import "./repair-DXThsgJF.js"; import "./order-CC2RBzI5.js"; import "./model-auth-markers-jBKQn38x.js"; import "./model-auth-env-Dq9W4xg9.js"; import { i as COPILOT_INTEGRATION_ID, s as buildCopilotIdeHeaders } from "./copilot-dynamic-headers-C42FH9jo.js"; import "./provider-auth-availability-BUrlw84-.js"; import "./models-config.providers.secret-helpers-DC_SfKyR.js"; import "./provider-auth-write-compat-B_rokROR.js"; import "./provider-auth-input-B4MRIGbK.js"; import "./provider-auth-helpers-CaYTVMoC.js"; import "./provider-api-key-auth-mNtReYE0.js"; import "./secret-provider-alias-qpSlK0kh.js"; import "./provider-auth-result-BJQq6asp.js"; import fs from "node:fs"; import path from "node:path"; import { execSync } from "node:child_process"; import { userInfo } from "node:os"; import { createHash, randomBytes } from "node:crypto"; //#region src/plugin-sdk/github-copilot-domain.ts const DEFAULT_GITHUB_COPILOT_DOMAIN = "github.com"; const GHE_DATA_RESIDENCY_HOST = /^[a-z0-9-]+\.ghe\.com$/; /** * Whether a host may be templated into a Copilot endpoint: the public host or a * data-residency GHE tenant (`*.ghe.com`). An absent value counts as supported * because callers fall back to the public default. Anything else (a scheme, * path, credentials, or an off-allowlist host) is not, so a persisted or * injected origin can be rejected before any token is sent to it. */ function isSupportedGithubCopilotDomain(raw) { const trimmed = (raw ?? "").trim().toLowerCase(); if (!trimmed) return true; if (!/^[a-z0-9.-]+$/.test(trimmed)) return false; return trimmed === "github.com" || GHE_DATA_RESIDENCY_HOST.test(trimmed); } /** * Coerce a user/config-supplied GitHub host to a safe bare lowercase hostname. * * Fails closed to public `github.com`: only the public host and data-residency * GHE tenants (`*.ghe.com`) are trusted. Any other value falls back to the * default rather than being used verbatim, because the resolved host becomes the * `api.<host>` endpoint that receives the GitHub OAuth token during exchange — a * typo or injected value like `evil.com` must never redirect that token. * (Classic self-hosted GHE Server uses arbitrary hostnames but does not host * Copilot, so it is deliberately out of scope.) Config-supplied hosts coerce * rather than throw; persisted credential origins are rejected upstream with * `isSupportedGithubCopilotDomain` before reaching a token request. */ function normalizeGithubCopilotDomain(raw) { const trimmed = (raw ?? "").trim().toLowerCase(); if (trimmed && isSupportedGithubCopilotDomain(trimmed)) return trimmed; return DEFAULT_GITHUB_COPILOT_DOMAIN; } //#endregion //#region src/plugin-sdk/github-copilot-token-endpoint.ts function isSupportedGithubCopilotApiHost(host, enterpriseDomain) { if (host === "copilot-proxy.githubusercontent.com" || host.endsWith(".githubcopilot.com")) return true; if (!enterpriseDomain || !isSupportedGithubCopilotDomain(enterpriseDomain) || normalizeGithubCopilotDomain(enterpriseDomain) === "github.com") return false; const tenant = normalizeGithubCopilotDomain(enterpriseDomain); return host === tenant || host.endsWith(`.${tenant}`); } /** * Resolves the optional `proxy-ep` hint embedded in a Copilot API token. * The hint is untrusted credential data: only GitHub-owned Copilot hosts, or * service hosts below the credential's validated GHE.com tenant, may receive it. */ function resolveGithubCopilotTokenEndpoint(token, enterpriseDomain) { const proxyEndpoint = token.trim().match(/(?:^|;)\s*proxy-ep=([^;\s]+)/i)?.[1]?.trim(); if (!proxyEndpoint) return { hasProxyEndpoint: false, baseUrl: null }; const urlText = /^https?:\/\//i.test(proxyEndpoint) ? proxyEndpoint : `https://${proxyEndpoint}`; try { const url = new URL(urlText); if (url.protocol !== "http:" && url.protocol !== "https:") return { hasProxyEndpoint: true, baseUrl: null }; const apiHost = url.hostname.toLowerCase().replace(/^proxy\./, "api."); return { hasProxyEndpoint: true, baseUrl: isSupportedGithubCopilotApiHost(apiHost, enterpriseDomain) ? `https://${apiHost}` : null }; } catch { return { hasProxyEndpoint: true, baseUrl: null }; } } //#endregion //#region src/plugin-sdk/provider-auth-copilot-cache.ts const COPILOT_CACHE_NAMESPACE = "github-copilot-token"; const COPILOT_TOKEN_CACHE_MAX_ENTRIES = 8; function resolveLegacyCopilotTokenCachePath(env) { return path.join(resolveStateDir(env), "credentials", "github-copilot.token.json"); } function fingerprintCopilotSourceCredential(githubToken) { return createHash("sha256").update(githubToken).digest("hex"); } function isCopilotTokenUsable(params) { const expiresAt = asDateTimestampMs(params.cache.expiresAt); const cacheDomain = params.cache.domain ?? "github.com"; return params.cache.integrationId === "vscode-chat" && cacheDomain === params.domain && params.cache.sourceCredentialFingerprint === params.sourceCredentialFingerprint && expiresAt !== void 0 && expiresAt - (params.now ?? Date.now()) > 3e5; } async function resolveCopilotTokenCache(params) { if (params.cachePath !== void 0 || params.loadJsonFileImpl !== void 0 || params.saveJsonFileImpl !== void 0) { const cachePath = params.cachePath?.trim() || resolveLegacyCopilotTokenCachePath(params.env); const loadJsonFileFn = params.loadJsonFileImpl ?? loadJsonFileThroughSymlink; const saveJsonFileFn = params.saveJsonFileImpl ?? writeJsonTarget; return { path: cachePath, load: () => loadJsonFileFn(cachePath), save: (value) => saveJsonFileFn(cachePath, value) }; } const { createCorePluginStateSyncKeyedStore } = await import("./plugin-state-store-C4x5Ux-B.js"); const store = createCorePluginStateSyncKeyedStore({ ownerId: "core:provider-auth", namespace: COPILOT_CACHE_NAMESPACE, maxEntries: COPILOT_TOKEN_CACHE_MAX_ENTRIES, overflowPolicy: "evict-oldest", env: params.env }); const key = `${params.domain}:${params.sourceCredentialFingerprint}`; return { path: "plugin-state", load: () => store.lookup(key), save: (value) => store.register(key, value, { ttlMs: Math.max(1, value.expiresAt - Date.now()) }) }; } //#endregion //#region src/plugin-sdk/provider-auth-claude-compat.ts const CLAUDE_CLI_CREDENTIALS_FILE = ".credentials.json"; const CLAUDE_CLI_USER_SETTINGS_FILE = "settings.json"; const CLAUDE_CLI_KEYCHAIN_SERVICE = "Claude Code-credentials"; const CLAUDE_CLI_KEYCHAIN_TIMEOUT_MS = 2e3; const CLAUDE_CLI_KEYCHAIN_ACCOUNT_FALLBACK = "claude-code-user"; const MACOS_SECURITY_PATH = "/usr/bin/security"; const SAFE_KEYCHAIN_ACCOUNT_PATTERN = /^[a-zA-Z0-9._-]+$/u; let claudeCliCache = null; function resolveClaudeCliConfigDir(homeDir) { if (homeDir !== void 0) return path.join(resolveOsHomeRelativePath(homeDir), ".claude"); const configuredDir = process.env.CLAUDE_CONFIG_DIR; return configuredDir ? path.resolve(configuredDir) : path.join(resolveOsHomeRelativePath("~"), ".claude"); } function resolveClaudeCliPath(homeDir, fileName) { return path.join(resolveClaudeCliConfigDir(homeDir), fileName); } function resolveClaudeCliCredentialsPath(homeDir) { if (homeDir !== void 0) return path.join(resolveClaudeCliConfigDir(homeDir), CLAUDE_CLI_CREDENTIALS_FILE); const secureStorageDir = process.env.CLAUDE_SECURESTORAGE_CONFIG_DIR; if (secureStorageDir === void 0) return resolveClaudeCliPath(void 0, CLAUDE_CLI_CREDENTIALS_FILE); const credentialDir = secureStorageDir ? path.resolve(secureStorageDir) : path.join(resolveOsHomeRelativePath("~"), ".claude"); return path.join(credentialDir, CLAUDE_CLI_CREDENTIALS_FILE); } function resolveClaudeCliAccountPath(homeDir) { if (homeDir !== void 0) return path.join(resolveOsHomeRelativePath(homeDir), ".claude.json"); const configuredDir = process.env.CLAUDE_CONFIG_DIR; return configuredDir ? path.join(path.resolve(configuredDir), ".claude.json") : path.join(resolveOsHomeRelativePath("~"), ".claude.json"); } function resolveClaudeCliKeychainService(homeDir) { if (homeDir !== void 0) return CLAUDE_CLI_KEYCHAIN_SERVICE; const secureStorageDir = process.env.CLAUDE_SECURESTORAGE_CONFIG_DIR; const configDir = process.env.CLAUDE_CONFIG_DIR; const selectedDir = secureStorageDir !== void 0 ? secureStorageDir : configDir; if (!selectedDir) return CLAUDE_CLI_KEYCHAIN_SERVICE; const suffix = createHash("sha256").update(selectedDir.normalize("NFC")).digest("hex").slice(0, 8); return `${CLAUDE_CLI_KEYCHAIN_SERVICE}-${suffix}`; } function readFileMtimeMs(filePath) { try { return fs.statSync(filePath).mtimeMs; } catch { return null; } } function parseClaudeCliOauthCredential(value) { if (!value || typeof value !== "object") return null; const data = asNonArrayRecord(value); const accessToken = data.accessToken; const refreshToken = data.refreshToken; const expiresAt = data.expiresAt; if (typeof accessToken !== "string" || !accessToken || typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= 0) return null; const subscriptionType = typeof data.subscriptionType === "string" && data.subscriptionType.trim() ? data.subscriptionType.trim() : void 0; const rateLimitTier = typeof data.rateLimitTier === "string" && data.rateLimitTier.trim() ? data.rateLimitTier.trim() : void 0; const plan = { ...subscriptionType ? { subscriptionType } : {}, ...rateLimitTier ? { rateLimitTier } : {} }; return typeof refreshToken === "string" && refreshToken ? { type: "oauth", provider: "anthropic", access: accessToken, refresh: refreshToken, expires: expiresAt, ...plan } : { type: "token", provider: "anthropic", token: accessToken, expires: expiresAt, ...plan }; } function readClaudeAccountEmail(homeDir) { const raw = loadJsonFileThroughSymlink(resolveClaudeCliAccountPath(homeDir)); const account = asNonArrayRecord(raw).oauthAccount; const email = asNonArrayRecord(account).emailAddress; return typeof email === "string" && email.trim() ? email.trim() : void 0; } function withClaudeAccountEmail(credential, homeDir) { if (!credential || credential.type === "api_key_helper") return credential; if (path.dirname(resolveClaudeCliCredentialsPath(homeDir)) !== resolveClaudeCliConfigDir(homeDir)) return credential; const email = readClaudeAccountEmail(homeDir); return email ? { ...credential, email } : credential; } function readClaudeApiKeyHelper(homeDir) { const raw = loadJsonFileThroughSymlink(resolveClaudeCliPath(homeDir, CLAUDE_CLI_USER_SETTINGS_FILE)); const helper = asNonArrayRecord(raw).apiKeyHelper; return typeof helper === "string" && helper.trim() ? { type: "api_key_helper", provider: "anthropic", helperHash: createHash("sha256").update(helper.trim()).digest("hex") } : null; } function readClaudeKeychain(execSyncImpl, timeout, service) { try { const account = resolveClaudeCliKeychainAccount(); const result = execSyncImpl(`${MACOS_SECURITY_PATH} find-generic-password -a "${account}" -w -s "${service}"`, { encoding: "utf8", stdio: [ "pipe", "pipe", "pipe" ], ...timeout === void 0 ? {} : { timeout } }); const parsed = JSON.parse(result.trim()); return isRecord(parsed) ? parsed : null; } catch { return null; } } function hasClaudeKeychainItem(execSyncImpl, service) { try { const account = resolveClaudeCliKeychainAccount(); execSyncImpl(`${MACOS_SECURITY_PATH} find-generic-password -a "${account}" -s "${service}"`, { encoding: "utf8", timeout: CLAUDE_CLI_KEYCHAIN_TIMEOUT_MS, stdio: [ "pipe", "pipe", "pipe" ] }); return true; } catch { return false; } } function resolveClaudeCliKeychainAccount() { let account; try { account = process.env.USER || userInfo().username; } catch { account = void 0; } return account && SAFE_KEYCHAIN_ACCOUNT_PATTERN.test(account) ? account : CLAUDE_CLI_KEYCHAIN_ACCOUNT_FALLBACK; } function readClaudeCliCredentials(options) { const helper = readClaudeApiKeyHelper(options.homeDir); if (helper) return helper; const platform = options.platform ?? process.platform; const execSyncImpl = options.execSync ?? execSync; const keychainService = resolveClaudeCliKeychainService(options.homeDir); if (platform === "darwin" && options.allowKeychainPrompt !== false) { const credential = parseClaudeCliOauthCredential(readClaudeKeychain(execSyncImpl, options.tryKeychainWithoutPrompt ? CLAUDE_CLI_KEYCHAIN_TIMEOUT_MS : void 0, keychainService)?.claudeAiOauth); if (credential) return withClaudeAccountEmail(credential, options.homeDir); } const credentialsPath = resolveClaudeCliCredentialsPath(options.homeDir); const raw = loadJsonFileThroughSymlink(credentialsPath); const credential = withClaudeAccountEmail(parseClaudeCliOauthCredential(asNonArrayRecord(raw).claudeAiOauth), options.homeDir); if (credential) return credential; if (options.onStoredCredentialUnreadable && options.tryKeychainWithoutPrompt && (fs.existsSync(credentialsPath) || platform === "darwin" && hasClaudeKeychainItem(execSyncImpl, keychainService))) options.onStoredCredentialUnreadable(); return null; } /** * @deprecated Claude CLI owns native login. Kept functional for shipped Plugin SDK callers only. * Scheduled for removal after v2026.10. */ function readClaudeCliCredentialsCached(options = {}) { const platform = options.platform ?? process.platform; const ttlMs = options.ttlMs ?? 0; const credentialsPath = resolveClaudeCliCredentialsPath(options.homeDir); const settingsPath = resolveClaudeCliPath(options.homeDir, CLAUDE_CLI_USER_SETTINGS_FILE); const accountPath = resolveClaudeCliAccountPath(options.homeDir); const keychainService = resolveClaudeCliKeychainService(options.homeDir); const cacheKey = `${credentialsPath}:${settingsPath}:${accountPath}:${platform !== "darwin" ? "file" : options.allowKeychainPrompt === false ? options.tryKeychainWithoutPrompt ? "keychain-presence" : "file" : options.tryKeychainWithoutPrompt ? "keychain-bounded" : "keychain"}:${keychainService}:${options.onStoredCredentialUnreadable && options.tryKeychainWithoutPrompt ? "notify" : "silent"}`; const sourceFingerprint = `${readFileMtimeMs(credentialsPath) ?? "missing"}:${readFileMtimeMs(settingsPath) ?? "missing"}:${readFileMtimeMs(accountPath) ?? "missing"}`; const now = Date.now(); if (ttlMs > 0 && claudeCliCache?.cacheKey === cacheKey && claudeCliCache.sourceFingerprint === sourceFingerprint && now - claudeCliCache.readAt < ttlMs) return claudeCliCache.value; const value = readClaudeCliCredentials({ ...options, platform }); const nextFingerprint = `${readFileMtimeMs(credentialsPath) ?? "missing"}:${readFileMtimeMs(settingsPath) ?? "missing"}:${readFileMtimeMs(accountPath) ?? "missing"}`; claudeCliCache = ttlMs > 0 && nextFingerprint === sourceFingerprint ? { value, readAt: now, cacheKey, sourceFingerprint: nextFingerprint } : null; return value; } //#endregion //#region src/plugin-sdk/oauth-utils.ts /** * Encode a flat object as application/x-www-form-urlencoded form data. * * @deprecated OAuth provider-owned helper; keep this local to provider plugins instead. */ function toFormUrlEncoded(data) { return Object.entries(data).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&"); } /** * Generate a PKCE verifier/challenge pair suitable for OAuth authorization flows. * * @deprecated OAuth provider-owned helper; keep this local to provider plugins instead. */ function generatePkceVerifierChallenge() { const verifier = randomBytes(32).toString("base64url"); return { verifier, challenge: createHash("sha256").update(verifier).digest("base64url") }; } /** Generate a PKCE verifier/challenge pair with a 64-character hex verifier. */ function generateHexPkceVerifierChallenge() { const verifier = randomBytes(32).toString("hex"); return { verifier, challenge: createHash("sha256").update(verifier).digest("base64url") }; } //#endregion //#region src/plugin-sdk/provider-auth.ts /** @deprecated GitHub Copilot provider-owned helper; do not use from third-party plugins. */ const DEFAULT_COPILOT_API_BASE_URL = "https://api.individual.githubcopilot.com"; /** * Data-residency GitHub Enterprise (`*.ghe.com`) support. * * Copilot on a data-residency GHE tenant lives at `<domain>` / `api.<domain>` / * `copilot-api.<domain>` rather than the public github.com endpoints. The host * is resolved (in priority order) from the `COPILOT_GITHUB_DOMAIN` env override, * the persisted `models.providers.github-copilot.params.githubDomain` config, and * finally public `github.com`. */ const COPILOT_PROVIDER_ID = "github-copilot"; const COPILOT_TOKEN_EXCHANGE_TIMEOUT_MS = 3e4; function readGithubCopilotDomainFromConfig(config) { const params = config?.models?.providers?.[COPILOT_PROVIDER_ID]?.params; const value = params && typeof params === "object" ? params.githubDomain : void 0; if (typeof value !== "string" || value.trim().length === 0) return; const trimmed = value.trim(); warnOnceOnRejectedConfigDomain(trimmed); return trimmed; } const warnedRejectedConfigDomains = /* @__PURE__ */ new Set(); function warnOnceOnRejectedConfigDomain(configured) { const lowered = configured.toLowerCase(); if (lowered === "github.com") return; if (normalizeGithubCopilotDomain(configured) !== "github.com") return; if (warnedRejectedConfigDomains.has(lowered)) return; warnedRejectedConfigDomains.add(lowered); logWarn(`Ignoring configured GitHub Copilot domain "${configured}": only github.com and *.ghe.com tenants are accepted. Falling back to github.com.`); } function resolveGithubCopilotDomain(params) { const fromEnv = (params?.env ?? process.env).COPILOT_GITHUB_DOMAIN?.trim(); if (fromEnv) return normalizeGithubCopilotDomain(fromEnv); if (params?.explicit) return normalizeGithubCopilotDomain(params.explicit); return normalizeGithubCopilotDomain(readGithubCopilotDomainFromConfig(params?.config)); } /** * Data-residency GHE Copilot tokens carry no `proxy-ep`, so the completions base * URL cannot be derived from the token. Point it at the tenant Copilot proxy * (`copilot-api.<domain>`) instead of the public individual endpoint. */ function copilotTokenUrl(domain) { return `https://api.${domain}/copilot_internal/v2/token`; } function copilotApiBaseFallback(domain) { return domain === "github.com" ? DEFAULT_COPILOT_API_BASE_URL : `https://copilot-api.${domain}`; } function resolveCopilotTokenExpiresAtMs(expiresAt) { const parsed = typeof expiresAt === "number" && Number.isFinite(expiresAt) ? expiresAt : typeof expiresAt === "string" && expiresAt.trim().length > 0 ? parseStrictNonNegativeInteger(expiresAt) : void 0; if (parsed === void 0) return; return parsed < 1e11 ? resolveExpiresAtMsFromEpochSeconds(parsed) : asDateTimestampMs(parsed); } function parseCopilotTokenResponse(value) { if (!value || typeof value !== "object") throw new Error("Unexpected response from GitHub Copilot token endpoint"); const asRecord = value; const token = asRecord.token; const expiresAt = asRecord.expires_at; if (typeof token !== "string" || token.trim().length === 0) throw new Error("Copilot token response missing token"); const expiresAtMs = resolveCopilotTokenExpiresAtMs(expiresAt); if (expiresAt === void 0 || expiresAt === null || typeof expiresAt === "string" && expiresAt.trim().length === 0) throw new Error("Copilot token response missing expires_at"); if (expiresAtMs === void 0) throw new Error("Copilot token response has invalid expires_at"); return { token, expiresAt: expiresAtMs }; } /** @deprecated GitHub Copilot provider-owned helper; do not use from third-party plugins. */ function deriveCopilotApiBaseUrlFromToken(token) { return resolveGithubCopilotTokenEndpoint(token).baseUrl; } /** * @deprecated GitHub Copilot provider-owned helper; do not use from third-party plugins. */ async function resolveCopilotApiToken(params) { const env = params.env ?? process.env; const domain = resolveGithubCopilotDomain({ env, explicit: params.githubDomain, config: params.config }); const tokenUrl = copilotTokenUrl(domain); const apiBaseFallback = copilotApiBaseFallback(domain); const sourceCredentialFingerprint = fingerprintCopilotSourceCredential(params.githubToken); const cache = await resolveCopilotTokenCache({ env, domain, sourceCredentialFingerprint, ...params.cachePath !== void 0 ? { cachePath: params.cachePath } : {}, ...params.loadJsonFileImpl ? { loadJsonFileImpl: params.loadJsonFileImpl } : {}, ...params.saveJsonFileImpl ? { saveJsonFileImpl: params.saveJsonFileImpl } : {} }); const cachePath = cache.path; const cached = cache.load(); if (cached && typeof cached.token === "string" && typeof cached.expiresAt === "number") { if (isCopilotTokenUsable({ cache: cached, domain, sourceCredentialFingerprint })) return { token: cached.token, expiresAt: cached.expiresAt, source: `cache:${cachePath}`, baseUrl: deriveCopilotApiBaseUrlFromToken(cached.token) ?? apiBaseFallback }; } const fetchImpl = params.fetchImpl ?? fetch; const signal = AbortSignal.timeout(COPILOT_TOKEN_EXCHANGE_TIMEOUT_MS); let json; try { const res = await fetchImpl(tokenUrl, { method: "GET", headers: { Accept: "application/json", Authorization: `Bearer ${params.githubToken}`, "Copilot-Integration-Id": COPILOT_INTEGRATION_ID, ...buildCopilotIdeHeaders({ includeApiVersion: true }) }, signal }); if (!res.ok) { await cancelUnreadResponseBody(res); throw new Error(`Copilot token exchange failed: HTTP ${res.status}`); } json = parseCopilotTokenResponse(await readProviderJsonResponse(res, "github-copilot.token")); } catch (error) { if (signal.aborted && error === signal.reason) throw new Error(`Copilot token exchange failed: timed out after ${COPILOT_TOKEN_EXCHANGE_TIMEOUT_MS}ms`, { cause: error }); throw error; } const payload = { token: json.token, expiresAt: json.expiresAt, updatedAt: Date.now(), integrationId: COPILOT_INTEGRATION_ID, sourceCredentialFingerprint, domain }; cache.save(payload); return { token: payload.token, expiresAt: payload.expiresAt, source: `fetched:${tokenUrl}`, baseUrl: deriveCopilotApiBaseUrlFromToken(payload.token) ?? apiBaseFallback }; } //#endregion export { generatePkceVerifierChallenge as a, normalizeGithubCopilotDomain as c, generateHexPkceVerifierChallenge as i, deriveCopilotApiBaseUrlFromToken as n, toFormUrlEncoded as o, resolveCopilotApiToken as r, readClaudeCliCredentialsCached as s, DEFAULT_COPILOT_API_BASE_URL as t };