github-copilot-oauth 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +541 -26
- package/dist/index.js.map +1 -1
- package/dist/proxy.js +181 -13
- package/dist/proxy.js.map +1 -1
- package/package.json +1 -2
- package/dist/chunk-CUD4IYWR.js +0 -511
- package/dist/chunk-CUD4IYWR.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts"],"sourcesContent":["import { createOpenAI } from '@ai-sdk/openai';\r\nimport type { EmbeddingModelV3, ImageModelV3, LanguageModelV3, ProviderV3 } from '@ai-sdk/provider';\r\nimport { NoSuchModelError } from '@ai-sdk/provider';\r\nimport { copilotBase } from './enterprise';\r\nimport { createGitHubCopilotOAuthFetch, isCopilotResponsesModel } from './copilot-fetch';\r\nimport type { GitHubCopilotProviderSettings } from './types';\r\n\r\nexport type GitHubCopilotModelId = string;\r\n\r\n/** AI SDK provider for GitHub Copilot OAuth-backed language models. */\r\nexport interface GitHubCopilotProvider extends ProviderV3 {\r\n (modelId: GitHubCopilotModelId): LanguageModelV3;\r\n languageModel(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n chat(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n responses(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n embeddingModel(modelId: string): EmbeddingModelV3;\r\n imageModel(modelId: string): ImageModelV3;\r\n}\r\n\r\n/** Create a Vercel AI SDK provider backed by GitHub Copilot OAuth. */\r\nexport function createGitHubCopilot(settings: GitHubCopilotProviderSettings = {}): GitHubCopilotProvider {\r\n const providerName = settings.name ?? 'github-copilot';\r\n const fetch = createGitHubCopilotOAuthFetch(settings);\r\n const openai = createOpenAI({\r\n apiKey: 'oauth',\r\n baseURL: settings.baseURL ?? copilotBase(settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl, settings),\r\n name: providerName,\r\n fetch,\r\n });\r\n\r\n const createChatModel = (modelId: GitHubCopilotModelId) => openai.chat(modelId as never);\r\n const createResponsesModel = (modelId: GitHubCopilotModelId) => openai.responses(modelId as never);\r\n // Route GPT-5+ non-mini models to the Responses endpoint for multimodal capability.\r\n // Fall back to Chat Completions for older models.\r\n const createLanguageModel = (modelId: GitHubCopilotModelId) =>\r\n isCopilotResponsesModel(modelId) ? createResponsesModel(modelId) : createChatModel(modelId);\r\n const provider: GitHubCopilotProvider = Object.assign(\r\n (modelId: GitHubCopilotModelId) => createLanguageModel(modelId),\r\n {\r\n specificationVersion: 'v3' as const,\r\n languageModel: createLanguageModel,\r\n chat: createChatModel,\r\n responses: createResponsesModel,\r\n embeddingModel: (modelId: string) => {\r\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });\r\n },\r\n imageModel: (modelId: string) => {\r\n throw new NoSuchModelError({ modelId, modelType: 'imageModel' });\r\n },\r\n },\r\n );\r\n\r\n return provider;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,oBAAoB;AAE7B,SAAS,wBAAwB;AAkB1B,SAAS,oBAAoB,WAA0C,CAAC,GAA0B;AACvG,QAAM,eAAe,SAAS,QAAQ;AACtC,QAAM,QAAQ,8BAA8B,QAAQ;AACpD,QAAM,SAAS,aAAa;AAAA,IAC1B,QAAQ;AAAA,IACR,SAAS,SAAS,WAAW,YAAY,SAAS,iBAAiB,SAAS,QAAQ,eAAe,QAAQ;AAAA,IAC3G,MAAM;AAAA,IACN;AAAA,EACF,CAAC;AAED,QAAM,kBAAkB,CAAC,YAAkC,OAAO,KAAK,OAAgB;AACvF,QAAM,uBAAuB,CAAC,YAAkC,OAAO,UAAU,OAAgB;AAGjG,QAAM,sBAAsB,CAAC,YAC3B,wBAAwB,OAAO,IAAI,qBAAqB,OAAO,IAAI,gBAAgB,OAAO;AAC5F,QAAM,WAAkC,OAAO;AAAA,IAC7C,CAAC,YAAkC,oBAAoB,OAAO;AAAA,IAC9D;AAAA,MACE,sBAAsB;AAAA,MACtB,eAAe;AAAA,MACf,MAAM;AAAA,MACN,WAAW;AAAA,MACX,gBAAgB,CAAC,YAAoB;AACnC,cAAM,IAAI,iBAAiB,EAAE,SAAS,WAAW,iBAAiB,CAAC;AAAA,MACrE;AAAA,MACA,YAAY,CAAC,YAAoB;AAC/B,cAAM,IAAI,iBAAiB,EAAE,SAAS,WAAW,aAAa,CAAC;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/enterprise.ts","../src/headers.ts","../src/memory-token-store.ts","../src/token-exchange.ts","../src/copilot-fetch.ts","../src/device-flow.ts","../src/provider.ts"],"sourcesContent":["/**\r\n * GitHub Copilot OAuth integration for AI SDK and OpenAI-compatible clients.\r\n *\r\n * Provides OAuth-based authentication for GitHub Copilot's language models,\r\n * including device flow for CLI/headless sign-in, token exchange for API tokens,\r\n * and fetch wrappers for OpenAI-compatible endpoints.\r\n */\r\nexport { createGitHubCopilotOAuthFetch, createGitHubCopilotClient, hasVisionInput, isCopilotResponsesModel } from './copilot-fetch';\r\nexport { DEFAULT_GITHUB_COPILOT_CLIENT_ID, startGitHubCopilotDeviceFlow } from './device-flow';\r\nexport { copilotBase, copilotTokenExchangeUrl, githubOAuthUrls, normalizeEnterpriseDomain } from './enterprise';\r\nexport { COPILOT_HEADERS, copilotHeaders, copilotModelHeaders, copilotTokenExchangeHeaders } from './headers';\r\nexport { createMemoryTokenStore } from './memory-token-store';\r\nexport { createGitHubCopilot } from './provider';\r\nexport { exchangeGitHubCopilotToken } from './token-exchange';\r\nexport type { GitHubCopilotModelId, GitHubCopilotProvider } from './provider';\r\nexport type {\r\n CopilotInitiator,\r\n FetchLike,\r\n GitHubCopilotDeviceFlow,\r\n GitHubCopilotDeviceFlowOptions,\r\n GitHubCopilotOAuthSettings,\r\n GitHubCopilotOAuthTokens,\r\n GitHubCopilotProviderSettings,\r\n TokenStore,\r\n} from './types';\r\nexport { GitHubCopilotOAuthError } from './types';\r\n","export type FetchLike = typeof globalThis.fetch;\r\n\r\n/** GitHub OAuth credentials plus optional short-lived Copilot API token. Treat these as account credentials. */\r\nexport type GitHubCopilotOAuthTokens = {\r\n /** GitHub OAuth access token returned by the device flow. Used to mint Copilot API tokens. */\r\n githubToken: string;\r\n /** Short-lived token returned by GitHub's Copilot token exchange endpoint. */\r\n copilotToken?: string;\r\n /** Copilot API token expiry as epoch milliseconds. */\r\n copilotTokenExpiresAt?: number;\r\n /** Optional validated GitHub Enterprise hostname. Omitted for github.com. */\r\n enterpriseUrl?: string;\r\n};\r\n\r\n/** Async storage interface for loading and persisting GitHub Copilot OAuth credentials. */\r\nexport type TokenStore = {\r\n /** Load the latest credentials. Return `undefined` when the user is not signed in. */\r\n load(): Promise<GitHubCopilotOAuthTokens | undefined>;\r\n /** Persist credentials after sign-in or Copilot token exchange. */\r\n save(tokens: GitHubCopilotOAuthTokens): Promise<void>;\r\n};\r\n\r\n/** In-progress GitHub Copilot device authorization flow. */\r\nexport type GitHubCopilotDeviceFlow = {\r\n providerId: 'github-copilot';\r\n /** URL the user should open to authorize the device flow. */\r\n url: string;\r\n /** User code to enter on the authorization page. */\r\n code: string;\r\n /** Human-readable instruction string for command-line or app UI. */\r\n instructions: string;\r\n /** Poll until authorization completes and return GitHub OAuth credentials. */\r\n complete(): Promise<GitHubCopilotOAuthTokens>;\r\n};\r\n\r\n/** Options for starting GitHub Copilot's device OAuth flow. */\r\nexport type GitHubCopilotDeviceFlowOptions = {\r\n /** Custom fetch implementation, useful for tests and non-standard runtimes. */\r\n fetch?: FetchLike;\r\n /** Sleep override used between polling attempts. */\r\n sleep?: (ms: number) => Promise<void>;\r\n /** OAuth client id. Defaults to the GitHub Copilot Chat client id. */\r\n clientId?: string;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Optional store that receives credentials after successful authorization. */\r\n tokenStore?: TokenStore;\r\n};\r\n\r\n/** Shared settings for Copilot fetch and AI SDK provider creation. */\r\nexport type GitHubCopilotOAuthSettings = {\r\n /** Custom fetch implementation for both token exchange and Copilot API requests. */\r\n fetch?: FetchLike;\r\n /** Secure token storage used to load and save exchanged Copilot tokens. */\r\n tokenStore?: TokenStore;\r\n /** Inline tokens for scripts/tests. Prefer `tokenStore` for production apps. */\r\n tokens?: GitHubCopilotOAuthTokens;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Copilot API base URL override. Defaults to GitHub's public Copilot API. */\r\n baseURL?: string;\r\n /** Browser proxy base URL for Copilot API requests. Defaults to `/api/proxy/github-copilot` in browsers. Pass `false` to disable. */\r\n browserProxyBaseUrl?: string | false;\r\n /** Additional headers sent to the Copilot API before Copilot auth headers are applied. */\r\n headers?: Record<string, string>;\r\n /** `X-Initiator` header. Defaults to `user`. */\r\n initiator?: CopilotInitiator;\r\n /** Force `Copilot-Vision-Request` on or off. When omitted, image inputs are detected from JSON bodies. */\r\n vision?: boolean;\r\n /** Refresh Copilot API token this many milliseconds before expiry. */\r\n tokenRefreshMarginMs?: number;\r\n /** Allow fallback to the GitHub OAuth token if Copilot token exchange fails or gets 401/403. Defaults to true. */\r\n fallbackToGitHubToken?: boolean;\r\n /** Called after a successful Copilot token exchange. */\r\n onTokens?: (tokens: GitHubCopilotOAuthTokens) => void | Promise<void>;\r\n};\r\n\r\n/** Settings for the AI SDK provider factory. */\r\nexport type GitHubCopilotProviderSettings = GitHubCopilotOAuthSettings & {\r\n /** Provider name exposed to AI SDK telemetry and metadata. */\r\n name?: string;\r\n};\r\n\r\nexport type CopilotInitiator = 'user' | 'agent';\r\n\r\n/** Error class used for OAuth, token, and credential setup failures. */\r\nexport class GitHubCopilotOAuthError extends Error {\r\n readonly code: string;\r\n\r\n constructor(code: string, message: string, options?: ErrorOptions) {\r\n super(message, options);\r\n this.name = 'GitHubCopilotOAuthError';\r\n this.code = code;\r\n }\r\n}\r\n","import { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Normalize and validate a GitHub Enterprise hostname. Returns undefined for github.com. */\r\nexport function normalizeEnterpriseDomain(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string | undefined {\r\n const value = enterpriseUrl?.trim();\r\n if (!value) {\r\n return undefined;\r\n }\r\n\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(/^https?:\\/\\//i.test(value) ? value : `https://${value}`);\r\n } catch (error) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL.', { cause: error });\r\n }\r\n\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL protocol.');\r\n }\r\n\r\n if (parsed.username || parsed.password || parsed.port || parsed.pathname !== '/' || parsed.search || parsed.hash) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'GitHub Enterprise URL must be a hostname only.');\r\n }\r\n\r\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\r\n if (!hostname || isUnsafeEnterpriseHostname(hostname)) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Unsafe GitHub Enterprise hostname.');\r\n }\r\n\r\n if (hostname === 'github.com') {\r\n return undefined;\r\n }\r\n\r\n if (!options.allowEnterprise) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Custom GitHub Enterprise hosts are not enabled.');\r\n }\r\n\r\n return hostname;\r\n}\r\n\r\n// Blocks hostnames that could resolve to local development environments or be confused\r\n// with loopback addresses. Prevents SSRF and local network access attacks.\r\nfunction isUnsafeEnterpriseHostname(hostname: string): boolean {\r\n return (\r\n hostname === 'localhost' ||\r\n hostname.endsWith('.localhost') ||\r\n hostname.endsWith('.local') ||\r\n hostname.includes(':') ||\r\n /^\\d+(?:\\.\\d+){3}$/.test(hostname)\r\n );\r\n}\r\n\r\n/** Resolve the Copilot API base URL for github.com or a validated Enterprise hostname. */\r\nexport function copilotBase(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.githubcopilot.com';\r\n }\r\n\r\n return `https://copilot-api.${domain}`;\r\n}\r\n\r\n/** Resolve the GitHub endpoint used to exchange OAuth tokens for Copilot API tokens. */\r\nexport function copilotTokenExchangeUrl(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.github.com/copilot_internal/v2/token';\r\n }\r\n\r\n return `https://api.${domain}/copilot_internal/v2/token`;\r\n}\r\n\r\n/** Resolve the GitHub device OAuth endpoints for github.com or Enterprise. */\r\nexport function githubOAuthUrls(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}) {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options) ?? 'github.com';\r\n return {\r\n domain,\r\n code: `https://${domain}/login/device/code`,\r\n token: `https://${domain}/login/oauth/access_token`,\r\n };\r\n}\r\n","import type { CopilotInitiator } from './types';\r\n\r\nexport const COPILOT_HEADERS = {\r\n 'User-Agent': 'GitHubCopilotChat/0.35.0',\r\n 'Editor-Version': 'vscode/1.107.0',\r\n 'Editor-Plugin-Version': 'copilot-chat/0.35.0',\r\n 'Copilot-Integration-Id': 'vscode-chat',\r\n} as const;\r\n\r\n/** Build headers for Copilot chat/completions and responses requests. */\r\nexport function copilotHeaders(accessToken: string, options?: { vision?: boolean; initiator?: CopilotInitiator }) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n 'Openai-Intent': 'conversation-edits',\r\n 'X-Initiator': options?.initiator ?? 'user',\r\n ...(options?.vision ? { 'Copilot-Vision-Request': 'true' } : {}),\r\n };\r\n}\r\n\r\n/** Build headers for Copilot model-list requests. */\r\nexport function copilotModelHeaders(accessToken: string) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n };\r\n}\r\n\r\n/** Build headers for GitHub's Copilot token exchange endpoint. */\r\nexport function copilotTokenExchangeHeaders(githubToken: string) {\r\n return {\r\n Accept: 'application/json',\r\n Authorization: `Bearer ${githubToken}`,\r\n ...COPILOT_HEADERS,\r\n };\r\n}\r\n","import type { GitHubCopilotOAuthTokens, TokenStore } from './types';\r\n\r\n/**\r\n * Create an in-memory token store.\r\n *\r\n * This is useful for tests and short-lived scripts. It does not persist tokens\r\n * across process restarts.\r\n */\r\nexport function createMemoryTokenStore(initial?: GitHubCopilotOAuthTokens): TokenStore {\r\n let current = initial;\r\n\r\n return {\r\n async load() {\r\n return current;\r\n },\r\n async save(tokens) {\r\n current = tokens;\r\n },\r\n };\r\n}\r\n","import { copilotTokenExchangeUrl } from './enterprise';\r\nimport { copilotTokenExchangeHeaders } from './headers';\r\nimport type { FetchLike } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Exchange a GitHub OAuth token for a short-lived GitHub Copilot API token. */\r\nexport async function exchangeGitHubCopilotToken({\r\n fetch,\r\n githubToken,\r\n enterpriseUrl,\r\n allowEnterprise,\r\n}: {\r\n fetch: FetchLike;\r\n githubToken: string;\r\n enterpriseUrl?: string;\r\n allowEnterprise?: boolean;\r\n}): Promise<{ token: string; expiresAt: number }> {\r\n const response = await fetch(copilotTokenExchangeUrl(enterpriseUrl, { allowEnterprise }), {\r\n headers: copilotTokenExchangeHeaders(githubToken),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n `GitHub Copilot token exchange failed (${response.status}).`,\r\n );\r\n }\r\n\r\n const payload = (await response.json()) as {\r\n token?: number | string;\r\n expires_at?: number;\r\n };\r\n\r\n if (typeof payload.token !== 'string' || !payload.token.trim()) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot token exchange did not return a token.');\r\n }\r\n\r\n if (typeof payload.expires_at !== 'number' || !Number.isFinite(payload.expires_at) || payload.expires_at <= 0) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n 'GitHub Copilot token exchange did not return a valid expiration.',\r\n );\r\n }\r\n\r\n return {\r\n token: payload.token,\r\n expiresAt: payload.expires_at * 1000,\r\n };\r\n}\r\n","import { copilotBase } from './enterprise';\r\nimport { copilotHeaders, copilotModelHeaders } from './headers';\r\nimport { createMemoryTokenStore } from './memory-token-store';\r\nimport { exchangeGitHubCopilotToken } from './token-exchange';\r\nimport type { FetchLike, GitHubCopilotOAuthSettings, GitHubCopilotOAuthTokens, TokenStore } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nconst DEFAULT_REFRESH_MARGIN_MS = 60 * 1000;\r\nconst DEFAULT_BROWSER_PROXY_BASE_URL = '/api/proxy/github-copilot';\r\n\r\ntype RequestParts = {\r\n url: string;\r\n method?: string;\r\n headers: Headers;\r\n body?: BodyInit | null;\r\n signal?: AbortSignal | null;\r\n};\r\n\r\n// Resolves fetch with fallback: custom override > globalThis.fetch > error.\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\nfunction withoutTrailingSlash(value: string): string {\r\n return value.replace(/\\/$/, '');\r\n}\r\n\r\nfunction createStore(settings: GitHubCopilotOAuthSettings): TokenStore {\r\n if (settings.tokenStore) {\r\n return settings.tokenStore;\r\n }\r\n\r\n if (settings.tokens) {\r\n return createMemoryTokenStore(settings.tokens);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError(\r\n 'tokens_required',\r\n 'GitHub Copilot OAuth tokens are required. Pass `tokens` or `tokenStore`.',\r\n );\r\n}\r\n\r\nclass TokenManager {\r\n private inflight?: Promise<{ token: string; fromExchange: boolean }>;\r\n private current?: GitHubCopilotOAuthTokens;\r\n\r\n constructor(\r\n private readonly settings: GitHubCopilotOAuthSettings,\r\n private readonly store: TokenStore,\r\n private readonly fetch: FetchLike,\r\n ) {}\r\n\r\n async token(): Promise<{ token: string; fromExchange: boolean }> {\r\n if (this.inflight) {\r\n return this.inflight;\r\n }\r\n\r\n this.inflight = this.loadToken()\r\n .finally(() => {\r\n this.inflight = undefined;\r\n });\r\n return this.inflight;\r\n }\r\n\r\n async githubToken(): Promise<string> {\r\n const tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n return tokens.githubToken;\r\n }\r\n\r\n private async loadToken(): Promise<{ token: string; fromExchange: boolean }> {\r\n let tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n const margin = this.settings.tokenRefreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;\r\n const expiresAt = tokens.copilotTokenExpiresAt ?? 0;\r\n if (tokens.copilotToken && (expiresAt <= 0 || expiresAt > Date.now() + margin)) {\r\n return { token: tokens.copilotToken, fromExchange: true };\r\n }\r\n\r\n try {\r\n const exchanged = await exchangeGitHubCopilotToken({\r\n fetch: this.fetch,\r\n githubToken: tokens.githubToken,\r\n enterpriseUrl: this.settings.enterpriseUrl ?? tokens.enterpriseUrl,\r\n allowEnterprise: this.settings.allowEnterprise,\r\n });\r\n tokens = {\r\n ...tokens,\r\n copilotToken: exchanged.token,\r\n copilotTokenExpiresAt: exchanged.expiresAt,\r\n };\r\n this.current = tokens;\r\n await this.store.save(tokens);\r\n await this.settings.onTokens?.(tokens);\r\n return { token: exchanged.token, fromExchange: true };\r\n } catch (error) {\r\n if (this.settings.fallbackToGitHubToken === false) {\r\n throw error;\r\n }\r\n\r\n return { token: tokens.githubToken, fromExchange: false };\r\n }\r\n }\r\n}\r\n\r\nasync function readStoredTokens(settings: GitHubCopilotOAuthSettings): Promise<GitHubCopilotOAuthTokens | undefined> {\r\n if (settings.tokens) {\r\n return settings.tokens;\r\n }\r\n\r\n const tokenStore = settings.tokenStore as (TokenStore & {\r\n getTokens?: () => Promise<GitHubCopilotOAuthTokens | undefined>;\r\n }) | undefined;\r\n\r\n if (typeof tokenStore?.getTokens === 'function') {\r\n return tokenStore.getTokens();\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nasync function resolveBaseURL(settings: GitHubCopilotOAuthSettings): Promise<string> {\r\n if (settings.baseURL) {\r\n return withoutTrailingSlash(settings.baseURL);\r\n }\r\n\r\n const storedTokens = await readStoredTokens(settings);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl ?? storedTokens?.enterpriseUrl;\r\n\r\n return withoutTrailingSlash(copilotBase(enterpriseUrl, settings));\r\n}\r\n\r\n// Normalizes an incoming OpenAI-compatible URL against a base URL.\r\n// Strips /v1 prefix to map to Copilot API paths while preserving query strings.\r\nfunction resolveTargetUrl(input: string, baseURL: string): string {\r\n const base = new URL(baseURL);\r\n const parsed = /^https?:\\/\\//.test(input) ? new URL(input) : new URL(input, 'https://copilot.invalid');\r\n let pathname = parsed.pathname;\r\n const basePath = withoutTrailingSlash(base.pathname);\r\n\r\n if (basePath && pathname.startsWith(`${basePath}/`)) {\r\n pathname = pathname.slice(basePath.length);\r\n }\r\n\r\n if (pathname === '/v1') {\r\n pathname = '/';\r\n } else if (pathname.startsWith('/v1/')) {\r\n pathname = pathname.slice(3);\r\n }\r\n\r\n if (!pathname.startsWith('/')) {\r\n pathname = `/${pathname}`;\r\n }\r\n\r\n return `${base.origin}${basePath}${pathname}${parsed.search}`;\r\n}\r\n\r\nfunction browserOrigin(): string | undefined {\r\n const maybeWindow = (globalThis as { window?: { location?: { origin?: string } } }).window;\r\n return typeof maybeWindow?.location?.origin === 'string' ? maybeWindow.location.origin.replace(/\\/$/, '') : undefined;\r\n}\r\n\r\n// Resolves a browser proxy URL for Copilot API requests. Returns undefined in Node.js\r\n// or when browser proxy is disabled. Strips the upstream base path so proxy can route correctly.\r\nfunction resolveBrowserProxyUrl(target: URL, baseURL: string, settings: GitHubCopilotOAuthSettings): string | undefined {\r\n const origin = browserOrigin();\r\n if (!origin || settings.browserProxyBaseUrl === false) {\r\n return undefined;\r\n }\r\n\r\n const proxyBase = settings.browserProxyBaseUrl ?? DEFAULT_BROWSER_PROXY_BASE_URL;\r\n const absoluteProxyBase = /^https?:\\/\\//.test(proxyBase) ? proxyBase.replace(/\\/$/, '') : `${origin}${proxyBase.startsWith('/') ? '' : '/'}${proxyBase}`.replace(/\\/$/, '');\r\n const upstreamBasePath = withoutTrailingSlash(new URL(baseURL).pathname);\r\n let pathname = target.pathname;\r\n\r\n if (upstreamBasePath && pathname.startsWith(`${upstreamBasePath}/`)) {\r\n pathname = pathname.slice(upstreamBasePath.length);\r\n }\r\n\r\n return `${absoluteProxyBase}${pathname}${target.search}`;\r\n}\r\n\r\nasync function readRequestParts(input: Parameters<FetchLike>[0], init?: Parameters<FetchLike>[1]): Promise<RequestParts> {\r\n if (input instanceof Request) {\r\n const headers = new Headers(input.headers);\r\n if (init?.headers) {\r\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\r\n }\r\n\r\n return {\r\n url: input.url,\r\n method: init?.method ?? input.method,\r\n headers,\r\n body: init?.body ?? (input.body == null ? undefined : await input.clone().text()),\r\n signal: init?.signal ?? input.signal,\r\n };\r\n }\r\n\r\n return {\r\n url: String(input),\r\n method: init?.method,\r\n headers: new Headers(init?.headers),\r\n body: init?.body,\r\n signal: init?.signal,\r\n };\r\n}\r\n\r\nasync function bodyToText(body: BodyInit | null | undefined): Promise<string | undefined> {\r\n if (body == null) return undefined;\r\n if (typeof body === 'string') return body;\r\n if (body instanceof URLSearchParams) return body.toString();\r\n if (body instanceof FormData || body instanceof ReadableStream) return undefined;\r\n if (body instanceof Blob) return body.text();\r\n if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\r\n if (ArrayBuffer.isView(body)) return new TextDecoder().decode(body);\r\n return undefined;\r\n}\r\n\r\n/** Return true when a chat/completions or responses JSON body contains image input. */\r\nexport function hasVisionInput(body: string): boolean {\r\n if (!body.trim()) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(body) as {\r\n messages?: { content?: { type?: string }[] }[];\r\n input?: { content?: { type?: string }[] }[];\r\n };\r\n\r\n const chatVision = payload.messages?.some(\r\n (item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'image_url'),\r\n );\r\n if (chatVision) {\r\n return true;\r\n }\r\n\r\n return Boolean(\r\n payload.input?.some((item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'input_image')),\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Applies Copilot-specific headers. Detects vision capability from request body\r\n// unless explicitly configured. Uses model headers for /models, chat headers otherwise.\r\nfunction applyHeaders(headers: Headers, authToken: string, pathname: string, bodyText: string | undefined, settings: GitHubCopilotOAuthSettings) {\r\n const vision = settings.vision ?? (typeof bodyText === 'string' && hasVisionInput(bodyText));\r\n const authHeaders = pathname.endsWith('/models')\r\n ? copilotModelHeaders(authToken)\r\n : copilotHeaders(authToken, { vision, initiator: settings.initiator });\r\n\r\n headers.delete('authorization');\r\n for (const [key, value] of Object.entries(authHeaders)) {\r\n headers.set(key, value);\r\n }\r\n}\r\n\r\n/**\r\n * Create a fetch implementation that authenticates OpenAI-compatible requests\r\n * with GitHub Copilot OAuth credentials.\r\n */\r\nexport function createGitHubCopilotOAuthFetch(settings: GitHubCopilotOAuthSettings = {}): FetchLike {\r\n const fetch = pickFetch(settings.fetch);\r\n const store = createStore(settings);\r\n const manager = new TokenManager(settings, store, fetch);\r\n\r\n return async (input, init) => {\r\n const baseURL = await resolveBaseURL(settings);\r\n const request = await readRequestParts(input, init);\r\n const targetUrl = resolveTargetUrl(request.url, baseURL);\r\n const target = new URL(targetUrl);\r\n const bodyText = await bodyToText(request.body);\r\n const body = bodyText ?? request.body;\r\n const headers = new Headers(settings.headers);\r\n\r\n request.headers.forEach((value, key) => headers.set(key, value));\r\n const proxyUrl = resolveBrowserProxyUrl(target, baseURL, settings);\r\n if (proxyUrl) {\r\n headers.delete('authorization');\r\n headers.set('Authorization', `Bearer ${await manager.githubToken()}`);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl;\r\n if (enterpriseUrl) headers.set('x-copilot-enterprise-url', enterpriseUrl);\r\n return fetch(proxyUrl, {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n const token = await manager.token();\r\n applyHeaders(headers, token.token, target.pathname, bodyText, settings);\r\n\r\n const response = await fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n\r\n if (token.fromExchange && settings.fallbackToGitHubToken !== false && (response.status === 401 || response.status === 403)) {\r\n const fallbackHeaders = new Headers(headers);\r\n applyHeaders(fallbackHeaders, await manager.githubToken(), target.pathname, bodyText, settings);\r\n return fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers: fallbackHeaders,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n return response;\r\n };\r\n}\r\n\r\n/** Create a small Copilot client around `createGitHubCopilotOAuthFetch`. */\r\nexport async function createGitHubCopilotClient(settings: GitHubCopilotOAuthSettings = {}) {\r\n const baseURL = await resolveBaseURL(settings);\r\n const fetch = createGitHubCopilotOAuthFetch(settings);\r\n\r\n return {\r\n baseURL,\r\n fetch,\r\n request: (path: string, init?: RequestInit) => fetch(resolveTargetUrl(path, baseURL), init),\r\n };\r\n}\r\n\r\n/** Route GPT-5 non-mini models to Copilot's Responses endpoint. */\r\nexport function isCopilotResponsesModel(modelId: string): boolean {\r\n const normalized = modelId.toLowerCase();\r\n const match = /^gpt-(\\d+)/.exec(normalized);\r\n if (!match) {\r\n return false;\r\n }\r\n\r\n const generation = Number(match[1]);\r\n return generation >= 5 && !normalized.startsWith('gpt-5-mini');\r\n}\r\n","import { githubOAuthUrls } from './enterprise';\r\nimport type { FetchLike, GitHubCopilotDeviceFlow, GitHubCopilotDeviceFlowOptions, GitHubCopilotOAuthTokens } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nexport const DEFAULT_GITHUB_COPILOT_CLIENT_ID = 'Ov23li8tweQw6odWQebz';\r\n// Adds buffer to server-provided interval to avoid race condition on slow responses.\r\nconst POLL_BUFFER_MS = 3000;\r\n\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\n/**\r\n * Start GitHub Copilot's device OAuth flow.\r\n *\r\n * The returned flow contains a URL and user code for authorization. Call\r\n * `flow.complete()` after showing those values to poll for authorization and\r\n * return the GitHub OAuth token used to mint Copilot API tokens.\r\n */\r\nexport async function startGitHubCopilotDeviceFlow(\r\n options: GitHubCopilotDeviceFlowOptions = {},\r\n): Promise<GitHubCopilotDeviceFlow> {\r\n const fetch = pickFetch(options.fetch);\r\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\r\n const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;\r\n const urls = githubOAuthUrls(options.enterpriseUrl, { allowEnterprise: options.allowEnterprise });\r\n\r\n const codeResponse = await fetch(urls.code, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n scope: 'read:user',\r\n }),\r\n });\r\n\r\n if (!codeResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'Failed to initiate GitHub Copilot authorization.');\r\n }\r\n\r\n const code = (await codeResponse.json()) as {\r\n verification_uri?: string;\r\n user_code?: string;\r\n device_code?: string;\r\n interval?: number;\r\n };\r\n\r\n if (!code.verification_uri || !code.user_code || !code.device_code) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot authorization response did not include a device code.');\r\n }\r\n\r\n return {\r\n providerId: 'github-copilot',\r\n url: code.verification_uri,\r\n code: code.user_code,\r\n instructions: `Enter code: ${code.user_code}`,\r\n async complete() {\r\n while (true) {\r\n const tokenResponse = await fetch(urls.token, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n body: new URLSearchParams({\r\n client_id: clientId,\r\n device_code: code.device_code ?? '',\r\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\r\n }).toString(),\r\n });\r\n\r\n if (!tokenResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n\r\n const token = (await tokenResponse.json()) as {\r\n access_token?: string;\r\n error?: string;\r\n interval?: number;\r\n };\r\n\r\n if (token.access_token) {\r\n const result: GitHubCopilotOAuthTokens = {\r\n githubToken: token.access_token,\r\n ...(urls.domain === 'github.com' ? {} : { enterpriseUrl: urls.domain }),\r\n };\r\n await options.tokenStore?.save(result);\r\n return result;\r\n }\r\n\r\n if (token.error === 'authorization_pending') {\r\n await sleep((code.interval ?? 5) * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n if (token.error === 'slow_down') {\r\n const nextInterval = token.interval && token.interval > 0 ? token.interval : (code.interval ?? 5) + 5;\r\n await sleep(nextInterval * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n },\r\n };\r\n}\r\n","import { createOpenAI } from '@ai-sdk/openai';\r\nimport type { EmbeddingModelV3, ImageModelV3, LanguageModelV3, ProviderV3 } from '@ai-sdk/provider';\r\nimport { NoSuchModelError } from '@ai-sdk/provider';\r\nimport { copilotBase } from './enterprise';\r\nimport { createGitHubCopilotOAuthFetch, isCopilotResponsesModel } from './copilot-fetch';\r\nimport type { GitHubCopilotProviderSettings } from './types';\r\n\r\nexport type GitHubCopilotModelId = string;\r\n\r\n/** AI SDK provider for GitHub Copilot OAuth-backed language models. */\r\nexport interface GitHubCopilotProvider extends ProviderV3 {\r\n (modelId: GitHubCopilotModelId): LanguageModelV3;\r\n languageModel(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n chat(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n responses(modelId: GitHubCopilotModelId): LanguageModelV3;\r\n embeddingModel(modelId: string): EmbeddingModelV3;\r\n imageModel(modelId: string): ImageModelV3;\r\n}\r\n\r\n/** Create a Vercel AI SDK provider backed by GitHub Copilot OAuth. */\r\nexport function createGitHubCopilot(settings: GitHubCopilotProviderSettings = {}): GitHubCopilotProvider {\r\n const providerName = settings.name ?? 'github-copilot';\r\n const fetch = createGitHubCopilotOAuthFetch(settings);\r\n const openai = createOpenAI({\r\n apiKey: 'oauth',\r\n baseURL: settings.baseURL ?? copilotBase(settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl, settings),\r\n name: providerName,\r\n fetch,\r\n });\r\n\r\n const createChatModel = (modelId: GitHubCopilotModelId) => openai.chat(modelId as never);\r\n const createResponsesModel = (modelId: GitHubCopilotModelId) => openai.responses(modelId as never);\r\n // Route GPT-5+ non-mini models to the Responses endpoint for multimodal capability.\r\n // Fall back to Chat Completions for older models.\r\n const createLanguageModel = (modelId: GitHubCopilotModelId) =>\r\n isCopilotResponsesModel(modelId) ? createResponsesModel(modelId) : createChatModel(modelId);\r\n const provider: GitHubCopilotProvider = Object.assign(\r\n (modelId: GitHubCopilotModelId) => createLanguageModel(modelId),\r\n {\r\n specificationVersion: 'v3' as const,\r\n languageModel: createLanguageModel,\r\n chat: createChatModel,\r\n responses: createResponsesModel,\r\n embeddingModel: (modelId: string) => {\r\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });\r\n },\r\n imageModel: (modelId: string) => {\r\n throw new NoSuchModelError({ modelId, modelType: 'imageModel' });\r\n },\r\n },\r\n );\r\n\r\n return provider;\r\n}\r\n"],"mappings":"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","names":["pickFetch"]}
|
package/dist/proxy.js
CHANGED
|
@@ -1,14 +1,181 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/proxy.ts
|
|
21
|
+
var proxy_exports = {};
|
|
22
|
+
__export(proxy_exports, {
|
|
23
|
+
createGitHubCopilotProxy: () => createGitHubCopilotProxy
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(proxy_exports);
|
|
26
|
+
|
|
27
|
+
// src/types.ts
|
|
28
|
+
var GitHubCopilotOAuthError = class extends Error {
|
|
29
|
+
code;
|
|
30
|
+
constructor(code, message, options) {
|
|
31
|
+
super(message, options);
|
|
32
|
+
this.name = "GitHubCopilotOAuthError";
|
|
33
|
+
this.code = code;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/enterprise.ts
|
|
38
|
+
function normalizeEnterpriseDomain(enterpriseUrl, options = {}) {
|
|
39
|
+
const value = enterpriseUrl?.trim();
|
|
40
|
+
if (!value) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
let parsed;
|
|
44
|
+
try {
|
|
45
|
+
parsed = new URL(/^https?:\/\//i.test(value) ? value : `https://${value}`);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new GitHubCopilotOAuthError("unsupported", "Invalid GitHub Enterprise URL.", { cause: error });
|
|
48
|
+
}
|
|
49
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
50
|
+
throw new GitHubCopilotOAuthError("unsupported", "Invalid GitHub Enterprise URL protocol.");
|
|
51
|
+
}
|
|
52
|
+
if (parsed.username || parsed.password || parsed.port || parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
53
|
+
throw new GitHubCopilotOAuthError("unsupported", "GitHub Enterprise URL must be a hostname only.");
|
|
54
|
+
}
|
|
55
|
+
const hostname = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
56
|
+
if (!hostname || isUnsafeEnterpriseHostname(hostname)) {
|
|
57
|
+
throw new GitHubCopilotOAuthError("unsupported", "Unsafe GitHub Enterprise hostname.");
|
|
58
|
+
}
|
|
59
|
+
if (hostname === "github.com") {
|
|
60
|
+
return void 0;
|
|
61
|
+
}
|
|
62
|
+
if (!options.allowEnterprise) {
|
|
63
|
+
throw new GitHubCopilotOAuthError("unsupported", "Custom GitHub Enterprise hosts are not enabled.");
|
|
64
|
+
}
|
|
65
|
+
return hostname;
|
|
66
|
+
}
|
|
67
|
+
function isUnsafeEnterpriseHostname(hostname) {
|
|
68
|
+
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname.includes(":") || /^\d+(?:\.\d+){3}$/.test(hostname);
|
|
69
|
+
}
|
|
70
|
+
function copilotBase(enterpriseUrl, options = {}) {
|
|
71
|
+
const domain = normalizeEnterpriseDomain(enterpriseUrl, options);
|
|
72
|
+
if (!domain) {
|
|
73
|
+
return "https://api.githubcopilot.com";
|
|
74
|
+
}
|
|
75
|
+
return `https://copilot-api.${domain}`;
|
|
76
|
+
}
|
|
77
|
+
function copilotTokenExchangeUrl(enterpriseUrl, options = {}) {
|
|
78
|
+
const domain = normalizeEnterpriseDomain(enterpriseUrl, options);
|
|
79
|
+
if (!domain) {
|
|
80
|
+
return "https://api.github.com/copilot_internal/v2/token";
|
|
81
|
+
}
|
|
82
|
+
return `https://api.${domain}/copilot_internal/v2/token`;
|
|
83
|
+
}
|
|
84
|
+
function githubOAuthUrls(enterpriseUrl, options = {}) {
|
|
85
|
+
const domain = normalizeEnterpriseDomain(enterpriseUrl, options) ?? "github.com";
|
|
86
|
+
return {
|
|
87
|
+
domain,
|
|
88
|
+
code: `https://${domain}/login/device/code`,
|
|
89
|
+
token: `https://${domain}/login/oauth/access_token`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/headers.ts
|
|
94
|
+
var COPILOT_HEADERS = {
|
|
95
|
+
"User-Agent": "GitHubCopilotChat/0.35.0",
|
|
96
|
+
"Editor-Version": "vscode/1.107.0",
|
|
97
|
+
"Editor-Plugin-Version": "copilot-chat/0.35.0",
|
|
98
|
+
"Copilot-Integration-Id": "vscode-chat"
|
|
99
|
+
};
|
|
100
|
+
function copilotHeaders(accessToken, options) {
|
|
101
|
+
return {
|
|
102
|
+
...COPILOT_HEADERS,
|
|
103
|
+
Authorization: `Bearer ${accessToken}`,
|
|
104
|
+
"Openai-Intent": "conversation-edits",
|
|
105
|
+
"X-Initiator": options?.initiator ?? "user",
|
|
106
|
+
...options?.vision ? { "Copilot-Vision-Request": "true" } : {}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function copilotModelHeaders(accessToken) {
|
|
110
|
+
return {
|
|
111
|
+
...COPILOT_HEADERS,
|
|
112
|
+
Authorization: `Bearer ${accessToken}`
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function copilotTokenExchangeHeaders(githubToken) {
|
|
116
|
+
return {
|
|
117
|
+
Accept: "application/json",
|
|
118
|
+
Authorization: `Bearer ${githubToken}`,
|
|
119
|
+
...COPILOT_HEADERS
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/token-exchange.ts
|
|
124
|
+
async function exchangeGitHubCopilotToken({
|
|
125
|
+
fetch,
|
|
126
|
+
githubToken,
|
|
127
|
+
enterpriseUrl,
|
|
128
|
+
allowEnterprise
|
|
129
|
+
}) {
|
|
130
|
+
const response = await fetch(copilotTokenExchangeUrl(enterpriseUrl, { allowEnterprise }), {
|
|
131
|
+
headers: copilotTokenExchangeHeaders(githubToken)
|
|
132
|
+
});
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
throw new GitHubCopilotOAuthError(
|
|
135
|
+
"auth_failed",
|
|
136
|
+
`GitHub Copilot token exchange failed (${response.status}).`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const payload = await response.json();
|
|
140
|
+
if (typeof payload.token !== "string" || !payload.token.trim()) {
|
|
141
|
+
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot token exchange did not return a token.");
|
|
142
|
+
}
|
|
143
|
+
if (typeof payload.expires_at !== "number" || !Number.isFinite(payload.expires_at) || payload.expires_at <= 0) {
|
|
144
|
+
throw new GitHubCopilotOAuthError(
|
|
145
|
+
"auth_failed",
|
|
146
|
+
"GitHub Copilot token exchange did not return a valid expiration."
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
token: payload.token,
|
|
151
|
+
expiresAt: payload.expires_at * 1e3
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/device-flow.ts
|
|
156
|
+
var DEFAULT_GITHUB_COPILOT_CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
157
|
+
|
|
158
|
+
// src/copilot-fetch.ts
|
|
159
|
+
var DEFAULT_REFRESH_MARGIN_MS = 60 * 1e3;
|
|
160
|
+
function hasVisionInput(body) {
|
|
161
|
+
if (!body.trim()) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const payload = JSON.parse(body);
|
|
166
|
+
const chatVision = payload.messages?.some(
|
|
167
|
+
(item) => Array.isArray(item.content) && item.content.some((part) => part?.type === "image_url")
|
|
168
|
+
);
|
|
169
|
+
if (chatVision) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return Boolean(
|
|
173
|
+
payload.input?.some((item) => Array.isArray(item.content) && item.content.some((part) => part?.type === "input_image"))
|
|
174
|
+
);
|
|
175
|
+
} catch {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
12
179
|
|
|
13
180
|
// src/proxy.ts
|
|
14
181
|
function pickFetch(customFetch) {
|
|
@@ -171,7 +338,8 @@ function createGitHubCopilotProxy(options = {}) {
|
|
|
171
338
|
}
|
|
172
339
|
}
|
|
173
340
|
}
|
|
174
|
-
export
|
|
341
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
342
|
+
0 && (module.exports = {
|
|
175
343
|
createGitHubCopilotProxy
|
|
176
|
-
};
|
|
344
|
+
});
|
|
177
345
|
//# sourceMappingURL=proxy.js.map
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proxy.ts"],"sourcesContent":["import { githubOAuthUrls, normalizeEnterpriseDomain, copilotBase } from './enterprise';\r\nimport { copilotHeaders, copilotModelHeaders } from './headers';\r\nimport { exchangeGitHubCopilotToken } from './token-exchange';\r\nimport { DEFAULT_GITHUB_COPILOT_CLIENT_ID } from './device-flow';\r\nimport { GitHubCopilotOAuthError, type FetchLike } from './types';\r\nimport { hasVisionInput } from './copilot-fetch';\r\n\r\nexport type GitHubCopilotProxyOptions = {\r\n /** Custom fetch implementation. Defaults to global fetch. */\r\n fetch?: FetchLike;\r\n /** OAuth client id. Defaults to the GitHub Copilot Chat client id. */\r\n clientId?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n};\r\n\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') return customFetch;\r\n if (typeof globalThis.fetch === 'function') return globalThis.fetch.bind(globalThis);\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot proxy handlers.');\r\n}\r\n\r\nfunction jsonResponse(body: unknown, status: number): Response {\r\n return new Response(JSON.stringify(body), {\r\n status,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Cache-Control': 'no-store',\r\n },\r\n });\r\n}\r\n\r\nfunction passthroughJson(response: Response): Response {\r\n return new Response(response.body, {\r\n status: response.status,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Cache-Control': 'no-store',\r\n },\r\n });\r\n}\r\n\r\n// Extracts token from Authorization header. Rejects non-Bearer schemes.\r\nfunction parseBearer(value: string): string {\r\n const trimmed = value.trim();\r\n if (!trimmed) return '';\r\n const match = /^Bearer\\s+(.+)$/i.exec(trimmed);\r\n return match ? match[1].trim() : '';\r\n}\r\n\r\n// Extracts enterprise URL from request: header > query param > undefined.\r\nfunction enterpriseFromRequest(request: Request, options: GitHubCopilotProxyOptions): string | undefined {\r\n const fromHeader = request.headers.get('x-copilot-enterprise-url') ?? '';\r\n if (fromHeader.trim()) {\r\n return normalizeEnterpriseDomain(fromHeader, options);\r\n }\r\n\r\n const fromQuery = new URL(request.url).searchParams.get('enterpriseUrl') ?? '';\r\n if (fromQuery.trim()) {\r\n return normalizeEnterpriseDomain(fromQuery, options);\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nfunction errorResponse(error: unknown): Response {\r\n const status = error instanceof GitHubCopilotOAuthError\r\n ? error.code === 'unsupported'\r\n ? 400\r\n : error.code === 'auth_failed'\r\n ? 401\r\n : 502\r\n : 502;\r\n const message = error instanceof Error ? error.message : 'GitHub Copilot request failed.';\r\n return jsonResponse({ message }, status);\r\n}\r\n\r\n// Exchanges GitHub token for Copilot token, then calls `run`. Falls back to the\r\n// original GitHub token on 401/403 if exchange succeeded (allows Copilot API retry).\r\nasync function withCopilotToken(\r\n request: Request,\r\n options: GitHubCopilotProxyOptions,\r\n run: (input: { token: string; enterpriseUrl?: string }) => Promise<Response>,\r\n): Promise<Response> {\r\n const fetch = pickFetch(options.fetch);\r\n const refreshToken = parseBearer(request.headers.get('authorization') ?? '');\r\n if (!refreshToken) {\r\n return jsonResponse({ message: 'Missing GitHub Copilot OAuth token.' }, 401);\r\n }\r\n\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n let token = refreshToken;\r\n\r\n try {\r\n const exchanged = await exchangeGitHubCopilotToken({\r\n fetch,\r\n githubToken: refreshToken,\r\n enterpriseUrl,\r\n allowEnterprise: options.allowEnterprise,\r\n });\r\n token = exchanged.token;\r\n } catch {\r\n }\r\n\r\n const primary = await run({ token, enterpriseUrl });\r\n if (token !== refreshToken && (primary.status === 401 || primary.status === 403)) {\r\n return run({ token: refreshToken, enterpriseUrl });\r\n }\r\n\r\n return primary;\r\n}\r\n\r\n/** Create framework-agnostic fetch handlers for browser-safe OAuth/proxy routes. */\r\nexport function createGitHubCopilotProxy(options: GitHubCopilotProxyOptions = {}) {\r\n const fetch = pickFetch(options.fetch);\r\n const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;\r\n\r\n return {\r\n async deviceCode(request: Request): Promise<Response> {\r\n try {\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n const urls = githubOAuthUrls(enterpriseUrl, options);\r\n const response = await fetch(urls.code, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n scope: 'read:user',\r\n }),\r\n });\r\n return passthroughJson(response);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async deviceToken(request: Request): Promise<Response> {\r\n try {\r\n const payload = (await request.json().catch(() => ({}))) as { device_code?: string; grant_type?: string };\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n const urls = githubOAuthUrls(enterpriseUrl, options);\r\n const response = await fetch(urls.token, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n device_code: payload.device_code ?? '',\r\n grant_type: payload.grant_type ?? 'urn:ietf:params:oauth:grant-type:device_code',\r\n }),\r\n });\r\n return passthroughJson(response);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async models(request: Request): Promise<Response> {\r\n try {\r\n const upstream = await withCopilotToken(request, options, ({ token, enterpriseUrl }) =>\r\n fetch(`${copilotBase(enterpriseUrl, options)}/models`, {\r\n headers: copilotModelHeaders(token),\r\n }),\r\n );\r\n return passthroughJson(upstream);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async chatCompletions(request: Request): Promise<Response> {\r\n return proxyPost(request, 'chat/completions');\r\n },\r\n\r\n async responses(request: Request): Promise<Response> {\r\n return proxyPost(request, 'responses');\r\n },\r\n };\r\n\r\n async function proxyPost(request: Request, path: 'chat/completions' | 'responses'): Promise<Response> {\r\n const body = await request.text();\r\n try {\r\n const upstream = await withCopilotToken(request, options, ({ token, enterpriseUrl }) =>\r\n fetch(`${copilotBase(enterpriseUrl, options)}/${path}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...copilotHeaders(token, {\r\n vision: hasVisionInput(body),\r\n initiator: 'user',\r\n }),\r\n },\r\n body,\r\n }),\r\n );\r\n return passthroughJson(upstream);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/proxy.ts","../src/types.ts","../src/enterprise.ts","../src/headers.ts","../src/token-exchange.ts","../src/device-flow.ts","../src/copilot-fetch.ts"],"sourcesContent":["import { githubOAuthUrls, normalizeEnterpriseDomain, copilotBase } from './enterprise';\r\nimport { copilotHeaders, copilotModelHeaders } from './headers';\r\nimport { exchangeGitHubCopilotToken } from './token-exchange';\r\nimport { DEFAULT_GITHUB_COPILOT_CLIENT_ID } from './device-flow';\r\nimport { GitHubCopilotOAuthError, type FetchLike } from './types';\r\nimport { hasVisionInput } from './copilot-fetch';\r\n\r\nexport type GitHubCopilotProxyOptions = {\r\n /** Custom fetch implementation. Defaults to global fetch. */\r\n fetch?: FetchLike;\r\n /** OAuth client id. Defaults to the GitHub Copilot Chat client id. */\r\n clientId?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n};\r\n\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') return customFetch;\r\n if (typeof globalThis.fetch === 'function') return globalThis.fetch.bind(globalThis);\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot proxy handlers.');\r\n}\r\n\r\nfunction jsonResponse(body: unknown, status: number): Response {\r\n return new Response(JSON.stringify(body), {\r\n status,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Cache-Control': 'no-store',\r\n },\r\n });\r\n}\r\n\r\nfunction passthroughJson(response: Response): Response {\r\n return new Response(response.body, {\r\n status: response.status,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Cache-Control': 'no-store',\r\n },\r\n });\r\n}\r\n\r\n// Extracts token from Authorization header. Rejects non-Bearer schemes.\r\nfunction parseBearer(value: string): string {\r\n const trimmed = value.trim();\r\n if (!trimmed) return '';\r\n const match = /^Bearer\\s+(.+)$/i.exec(trimmed);\r\n return match ? match[1].trim() : '';\r\n}\r\n\r\n// Extracts enterprise URL from request: header > query param > undefined.\r\nfunction enterpriseFromRequest(request: Request, options: GitHubCopilotProxyOptions): string | undefined {\r\n const fromHeader = request.headers.get('x-copilot-enterprise-url') ?? '';\r\n if (fromHeader.trim()) {\r\n return normalizeEnterpriseDomain(fromHeader, options);\r\n }\r\n\r\n const fromQuery = new URL(request.url).searchParams.get('enterpriseUrl') ?? '';\r\n if (fromQuery.trim()) {\r\n return normalizeEnterpriseDomain(fromQuery, options);\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nfunction errorResponse(error: unknown): Response {\r\n const status = error instanceof GitHubCopilotOAuthError\r\n ? error.code === 'unsupported'\r\n ? 400\r\n : error.code === 'auth_failed'\r\n ? 401\r\n : 502\r\n : 502;\r\n const message = error instanceof Error ? error.message : 'GitHub Copilot request failed.';\r\n return jsonResponse({ message }, status);\r\n}\r\n\r\n// Exchanges GitHub token for Copilot token, then calls `run`. Falls back to the\r\n// original GitHub token on 401/403 if exchange succeeded (allows Copilot API retry).\r\nasync function withCopilotToken(\r\n request: Request,\r\n options: GitHubCopilotProxyOptions,\r\n run: (input: { token: string; enterpriseUrl?: string }) => Promise<Response>,\r\n): Promise<Response> {\r\n const fetch = pickFetch(options.fetch);\r\n const refreshToken = parseBearer(request.headers.get('authorization') ?? '');\r\n if (!refreshToken) {\r\n return jsonResponse({ message: 'Missing GitHub Copilot OAuth token.' }, 401);\r\n }\r\n\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n let token = refreshToken;\r\n\r\n try {\r\n const exchanged = await exchangeGitHubCopilotToken({\r\n fetch,\r\n githubToken: refreshToken,\r\n enterpriseUrl,\r\n allowEnterprise: options.allowEnterprise,\r\n });\r\n token = exchanged.token;\r\n } catch {\r\n }\r\n\r\n const primary = await run({ token, enterpriseUrl });\r\n if (token !== refreshToken && (primary.status === 401 || primary.status === 403)) {\r\n return run({ token: refreshToken, enterpriseUrl });\r\n }\r\n\r\n return primary;\r\n}\r\n\r\n/** Create framework-agnostic fetch handlers for browser-safe OAuth/proxy routes. */\r\nexport function createGitHubCopilotProxy(options: GitHubCopilotProxyOptions = {}) {\r\n const fetch = pickFetch(options.fetch);\r\n const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;\r\n\r\n return {\r\n async deviceCode(request: Request): Promise<Response> {\r\n try {\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n const urls = githubOAuthUrls(enterpriseUrl, options);\r\n const response = await fetch(urls.code, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n scope: 'read:user',\r\n }),\r\n });\r\n return passthroughJson(response);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async deviceToken(request: Request): Promise<Response> {\r\n try {\r\n const payload = (await request.json().catch(() => ({}))) as { device_code?: string; grant_type?: string };\r\n const enterpriseUrl = enterpriseFromRequest(request, options);\r\n const urls = githubOAuthUrls(enterpriseUrl, options);\r\n const response = await fetch(urls.token, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n device_code: payload.device_code ?? '',\r\n grant_type: payload.grant_type ?? 'urn:ietf:params:oauth:grant-type:device_code',\r\n }),\r\n });\r\n return passthroughJson(response);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async models(request: Request): Promise<Response> {\r\n try {\r\n const upstream = await withCopilotToken(request, options, ({ token, enterpriseUrl }) =>\r\n fetch(`${copilotBase(enterpriseUrl, options)}/models`, {\r\n headers: copilotModelHeaders(token),\r\n }),\r\n );\r\n return passthroughJson(upstream);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n },\r\n\r\n async chatCompletions(request: Request): Promise<Response> {\r\n return proxyPost(request, 'chat/completions');\r\n },\r\n\r\n async responses(request: Request): Promise<Response> {\r\n return proxyPost(request, 'responses');\r\n },\r\n };\r\n\r\n async function proxyPost(request: Request, path: 'chat/completions' | 'responses'): Promise<Response> {\r\n const body = await request.text();\r\n try {\r\n const upstream = await withCopilotToken(request, options, ({ token, enterpriseUrl }) =>\r\n fetch(`${copilotBase(enterpriseUrl, options)}/${path}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...copilotHeaders(token, {\r\n vision: hasVisionInput(body),\r\n initiator: 'user',\r\n }),\r\n },\r\n body,\r\n }),\r\n );\r\n return passthroughJson(upstream);\r\n } catch (error) {\r\n return errorResponse(error);\r\n }\r\n }\r\n}\r\n","export type FetchLike = typeof globalThis.fetch;\r\n\r\n/** GitHub OAuth credentials plus optional short-lived Copilot API token. Treat these as account credentials. */\r\nexport type GitHubCopilotOAuthTokens = {\r\n /** GitHub OAuth access token returned by the device flow. Used to mint Copilot API tokens. */\r\n githubToken: string;\r\n /** Short-lived token returned by GitHub's Copilot token exchange endpoint. */\r\n copilotToken?: string;\r\n /** Copilot API token expiry as epoch milliseconds. */\r\n copilotTokenExpiresAt?: number;\r\n /** Optional validated GitHub Enterprise hostname. Omitted for github.com. */\r\n enterpriseUrl?: string;\r\n};\r\n\r\n/** Async storage interface for loading and persisting GitHub Copilot OAuth credentials. */\r\nexport type TokenStore = {\r\n /** Load the latest credentials. Return `undefined` when the user is not signed in. */\r\n load(): Promise<GitHubCopilotOAuthTokens | undefined>;\r\n /** Persist credentials after sign-in or Copilot token exchange. */\r\n save(tokens: GitHubCopilotOAuthTokens): Promise<void>;\r\n};\r\n\r\n/** In-progress GitHub Copilot device authorization flow. */\r\nexport type GitHubCopilotDeviceFlow = {\r\n providerId: 'github-copilot';\r\n /** URL the user should open to authorize the device flow. */\r\n url: string;\r\n /** User code to enter on the authorization page. */\r\n code: string;\r\n /** Human-readable instruction string for command-line or app UI. */\r\n instructions: string;\r\n /** Poll until authorization completes and return GitHub OAuth credentials. */\r\n complete(): Promise<GitHubCopilotOAuthTokens>;\r\n};\r\n\r\n/** Options for starting GitHub Copilot's device OAuth flow. */\r\nexport type GitHubCopilotDeviceFlowOptions = {\r\n /** Custom fetch implementation, useful for tests and non-standard runtimes. */\r\n fetch?: FetchLike;\r\n /** Sleep override used between polling attempts. */\r\n sleep?: (ms: number) => Promise<void>;\r\n /** OAuth client id. Defaults to the GitHub Copilot Chat client id. */\r\n clientId?: string;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Optional store that receives credentials after successful authorization. */\r\n tokenStore?: TokenStore;\r\n};\r\n\r\n/** Shared settings for Copilot fetch and AI SDK provider creation. */\r\nexport type GitHubCopilotOAuthSettings = {\r\n /** Custom fetch implementation for both token exchange and Copilot API requests. */\r\n fetch?: FetchLike;\r\n /** Secure token storage used to load and save exchanged Copilot tokens. */\r\n tokenStore?: TokenStore;\r\n /** Inline tokens for scripts/tests. Prefer `tokenStore` for production apps. */\r\n tokens?: GitHubCopilotOAuthTokens;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Copilot API base URL override. Defaults to GitHub's public Copilot API. */\r\n baseURL?: string;\r\n /** Browser proxy base URL for Copilot API requests. Defaults to `/api/proxy/github-copilot` in browsers. Pass `false` to disable. */\r\n browserProxyBaseUrl?: string | false;\r\n /** Additional headers sent to the Copilot API before Copilot auth headers are applied. */\r\n headers?: Record<string, string>;\r\n /** `X-Initiator` header. Defaults to `user`. */\r\n initiator?: CopilotInitiator;\r\n /** Force `Copilot-Vision-Request` on or off. When omitted, image inputs are detected from JSON bodies. */\r\n vision?: boolean;\r\n /** Refresh Copilot API token this many milliseconds before expiry. */\r\n tokenRefreshMarginMs?: number;\r\n /** Allow fallback to the GitHub OAuth token if Copilot token exchange fails or gets 401/403. Defaults to true. */\r\n fallbackToGitHubToken?: boolean;\r\n /** Called after a successful Copilot token exchange. */\r\n onTokens?: (tokens: GitHubCopilotOAuthTokens) => void | Promise<void>;\r\n};\r\n\r\n/** Settings for the AI SDK provider factory. */\r\nexport type GitHubCopilotProviderSettings = GitHubCopilotOAuthSettings & {\r\n /** Provider name exposed to AI SDK telemetry and metadata. */\r\n name?: string;\r\n};\r\n\r\nexport type CopilotInitiator = 'user' | 'agent';\r\n\r\n/** Error class used for OAuth, token, and credential setup failures. */\r\nexport class GitHubCopilotOAuthError extends Error {\r\n readonly code: string;\r\n\r\n constructor(code: string, message: string, options?: ErrorOptions) {\r\n super(message, options);\r\n this.name = 'GitHubCopilotOAuthError';\r\n this.code = code;\r\n }\r\n}\r\n","import { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Normalize and validate a GitHub Enterprise hostname. Returns undefined for github.com. */\r\nexport function normalizeEnterpriseDomain(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string | undefined {\r\n const value = enterpriseUrl?.trim();\r\n if (!value) {\r\n return undefined;\r\n }\r\n\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(/^https?:\\/\\//i.test(value) ? value : `https://${value}`);\r\n } catch (error) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL.', { cause: error });\r\n }\r\n\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL protocol.');\r\n }\r\n\r\n if (parsed.username || parsed.password || parsed.port || parsed.pathname !== '/' || parsed.search || parsed.hash) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'GitHub Enterprise URL must be a hostname only.');\r\n }\r\n\r\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\r\n if (!hostname || isUnsafeEnterpriseHostname(hostname)) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Unsafe GitHub Enterprise hostname.');\r\n }\r\n\r\n if (hostname === 'github.com') {\r\n return undefined;\r\n }\r\n\r\n if (!options.allowEnterprise) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Custom GitHub Enterprise hosts are not enabled.');\r\n }\r\n\r\n return hostname;\r\n}\r\n\r\n// Blocks hostnames that could resolve to local development environments or be confused\r\n// with loopback addresses. Prevents SSRF and local network access attacks.\r\nfunction isUnsafeEnterpriseHostname(hostname: string): boolean {\r\n return (\r\n hostname === 'localhost' ||\r\n hostname.endsWith('.localhost') ||\r\n hostname.endsWith('.local') ||\r\n hostname.includes(':') ||\r\n /^\\d+(?:\\.\\d+){3}$/.test(hostname)\r\n );\r\n}\r\n\r\n/** Resolve the Copilot API base URL for github.com or a validated Enterprise hostname. */\r\nexport function copilotBase(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.githubcopilot.com';\r\n }\r\n\r\n return `https://copilot-api.${domain}`;\r\n}\r\n\r\n/** Resolve the GitHub endpoint used to exchange OAuth tokens for Copilot API tokens. */\r\nexport function copilotTokenExchangeUrl(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.github.com/copilot_internal/v2/token';\r\n }\r\n\r\n return `https://api.${domain}/copilot_internal/v2/token`;\r\n}\r\n\r\n/** Resolve the GitHub device OAuth endpoints for github.com or Enterprise. */\r\nexport function githubOAuthUrls(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}) {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options) ?? 'github.com';\r\n return {\r\n domain,\r\n code: `https://${domain}/login/device/code`,\r\n token: `https://${domain}/login/oauth/access_token`,\r\n };\r\n}\r\n","import type { CopilotInitiator } from './types';\r\n\r\nexport const COPILOT_HEADERS = {\r\n 'User-Agent': 'GitHubCopilotChat/0.35.0',\r\n 'Editor-Version': 'vscode/1.107.0',\r\n 'Editor-Plugin-Version': 'copilot-chat/0.35.0',\r\n 'Copilot-Integration-Id': 'vscode-chat',\r\n} as const;\r\n\r\n/** Build headers for Copilot chat/completions and responses requests. */\r\nexport function copilotHeaders(accessToken: string, options?: { vision?: boolean; initiator?: CopilotInitiator }) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n 'Openai-Intent': 'conversation-edits',\r\n 'X-Initiator': options?.initiator ?? 'user',\r\n ...(options?.vision ? { 'Copilot-Vision-Request': 'true' } : {}),\r\n };\r\n}\r\n\r\n/** Build headers for Copilot model-list requests. */\r\nexport function copilotModelHeaders(accessToken: string) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n };\r\n}\r\n\r\n/** Build headers for GitHub's Copilot token exchange endpoint. */\r\nexport function copilotTokenExchangeHeaders(githubToken: string) {\r\n return {\r\n Accept: 'application/json',\r\n Authorization: `Bearer ${githubToken}`,\r\n ...COPILOT_HEADERS,\r\n };\r\n}\r\n","import { copilotTokenExchangeUrl } from './enterprise';\r\nimport { copilotTokenExchangeHeaders } from './headers';\r\nimport type { FetchLike } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Exchange a GitHub OAuth token for a short-lived GitHub Copilot API token. */\r\nexport async function exchangeGitHubCopilotToken({\r\n fetch,\r\n githubToken,\r\n enterpriseUrl,\r\n allowEnterprise,\r\n}: {\r\n fetch: FetchLike;\r\n githubToken: string;\r\n enterpriseUrl?: string;\r\n allowEnterprise?: boolean;\r\n}): Promise<{ token: string; expiresAt: number }> {\r\n const response = await fetch(copilotTokenExchangeUrl(enterpriseUrl, { allowEnterprise }), {\r\n headers: copilotTokenExchangeHeaders(githubToken),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n `GitHub Copilot token exchange failed (${response.status}).`,\r\n );\r\n }\r\n\r\n const payload = (await response.json()) as {\r\n token?: number | string;\r\n expires_at?: number;\r\n };\r\n\r\n if (typeof payload.token !== 'string' || !payload.token.trim()) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot token exchange did not return a token.');\r\n }\r\n\r\n if (typeof payload.expires_at !== 'number' || !Number.isFinite(payload.expires_at) || payload.expires_at <= 0) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n 'GitHub Copilot token exchange did not return a valid expiration.',\r\n );\r\n }\r\n\r\n return {\r\n token: payload.token,\r\n expiresAt: payload.expires_at * 1000,\r\n };\r\n}\r\n","import { githubOAuthUrls } from './enterprise';\r\nimport type { FetchLike, GitHubCopilotDeviceFlow, GitHubCopilotDeviceFlowOptions, GitHubCopilotOAuthTokens } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nexport const DEFAULT_GITHUB_COPILOT_CLIENT_ID = 'Ov23li8tweQw6odWQebz';\r\n// Adds buffer to server-provided interval to avoid race condition on slow responses.\r\nconst POLL_BUFFER_MS = 3000;\r\n\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\n/**\r\n * Start GitHub Copilot's device OAuth flow.\r\n *\r\n * The returned flow contains a URL and user code for authorization. Call\r\n * `flow.complete()` after showing those values to poll for authorization and\r\n * return the GitHub OAuth token used to mint Copilot API tokens.\r\n */\r\nexport async function startGitHubCopilotDeviceFlow(\r\n options: GitHubCopilotDeviceFlowOptions = {},\r\n): Promise<GitHubCopilotDeviceFlow> {\r\n const fetch = pickFetch(options.fetch);\r\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\r\n const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;\r\n const urls = githubOAuthUrls(options.enterpriseUrl, { allowEnterprise: options.allowEnterprise });\r\n\r\n const codeResponse = await fetch(urls.code, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n scope: 'read:user',\r\n }),\r\n });\r\n\r\n if (!codeResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'Failed to initiate GitHub Copilot authorization.');\r\n }\r\n\r\n const code = (await codeResponse.json()) as {\r\n verification_uri?: string;\r\n user_code?: string;\r\n device_code?: string;\r\n interval?: number;\r\n };\r\n\r\n if (!code.verification_uri || !code.user_code || !code.device_code) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot authorization response did not include a device code.');\r\n }\r\n\r\n return {\r\n providerId: 'github-copilot',\r\n url: code.verification_uri,\r\n code: code.user_code,\r\n instructions: `Enter code: ${code.user_code}`,\r\n async complete() {\r\n while (true) {\r\n const tokenResponse = await fetch(urls.token, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n body: new URLSearchParams({\r\n client_id: clientId,\r\n device_code: code.device_code ?? '',\r\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\r\n }).toString(),\r\n });\r\n\r\n if (!tokenResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n\r\n const token = (await tokenResponse.json()) as {\r\n access_token?: string;\r\n error?: string;\r\n interval?: number;\r\n };\r\n\r\n if (token.access_token) {\r\n const result: GitHubCopilotOAuthTokens = {\r\n githubToken: token.access_token,\r\n ...(urls.domain === 'github.com' ? {} : { enterpriseUrl: urls.domain }),\r\n };\r\n await options.tokenStore?.save(result);\r\n return result;\r\n }\r\n\r\n if (token.error === 'authorization_pending') {\r\n await sleep((code.interval ?? 5) * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n if (token.error === 'slow_down') {\r\n const nextInterval = token.interval && token.interval > 0 ? token.interval : (code.interval ?? 5) + 5;\r\n await sleep(nextInterval * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n },\r\n };\r\n}\r\n","import { copilotBase } from './enterprise';\r\nimport { copilotHeaders, copilotModelHeaders } from './headers';\r\nimport { createMemoryTokenStore } from './memory-token-store';\r\nimport { exchangeGitHubCopilotToken } from './token-exchange';\r\nimport type { FetchLike, GitHubCopilotOAuthSettings, GitHubCopilotOAuthTokens, TokenStore } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nconst DEFAULT_REFRESH_MARGIN_MS = 60 * 1000;\r\nconst DEFAULT_BROWSER_PROXY_BASE_URL = '/api/proxy/github-copilot';\r\n\r\ntype RequestParts = {\r\n url: string;\r\n method?: string;\r\n headers: Headers;\r\n body?: BodyInit | null;\r\n signal?: AbortSignal | null;\r\n};\r\n\r\n// Resolves fetch with fallback: custom override > globalThis.fetch > error.\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\nfunction withoutTrailingSlash(value: string): string {\r\n return value.replace(/\\/$/, '');\r\n}\r\n\r\nfunction createStore(settings: GitHubCopilotOAuthSettings): TokenStore {\r\n if (settings.tokenStore) {\r\n return settings.tokenStore;\r\n }\r\n\r\n if (settings.tokens) {\r\n return createMemoryTokenStore(settings.tokens);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError(\r\n 'tokens_required',\r\n 'GitHub Copilot OAuth tokens are required. Pass `tokens` or `tokenStore`.',\r\n );\r\n}\r\n\r\nclass TokenManager {\r\n private inflight?: Promise<{ token: string; fromExchange: boolean }>;\r\n private current?: GitHubCopilotOAuthTokens;\r\n\r\n constructor(\r\n private readonly settings: GitHubCopilotOAuthSettings,\r\n private readonly store: TokenStore,\r\n private readonly fetch: FetchLike,\r\n ) {}\r\n\r\n async token(): Promise<{ token: string; fromExchange: boolean }> {\r\n if (this.inflight) {\r\n return this.inflight;\r\n }\r\n\r\n this.inflight = this.loadToken()\r\n .finally(() => {\r\n this.inflight = undefined;\r\n });\r\n return this.inflight;\r\n }\r\n\r\n async githubToken(): Promise<string> {\r\n const tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n return tokens.githubToken;\r\n }\r\n\r\n private async loadToken(): Promise<{ token: string; fromExchange: boolean }> {\r\n let tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n const margin = this.settings.tokenRefreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;\r\n const expiresAt = tokens.copilotTokenExpiresAt ?? 0;\r\n if (tokens.copilotToken && (expiresAt <= 0 || expiresAt > Date.now() + margin)) {\r\n return { token: tokens.copilotToken, fromExchange: true };\r\n }\r\n\r\n try {\r\n const exchanged = await exchangeGitHubCopilotToken({\r\n fetch: this.fetch,\r\n githubToken: tokens.githubToken,\r\n enterpriseUrl: this.settings.enterpriseUrl ?? tokens.enterpriseUrl,\r\n allowEnterprise: this.settings.allowEnterprise,\r\n });\r\n tokens = {\r\n ...tokens,\r\n copilotToken: exchanged.token,\r\n copilotTokenExpiresAt: exchanged.expiresAt,\r\n };\r\n this.current = tokens;\r\n await this.store.save(tokens);\r\n await this.settings.onTokens?.(tokens);\r\n return { token: exchanged.token, fromExchange: true };\r\n } catch (error) {\r\n if (this.settings.fallbackToGitHubToken === false) {\r\n throw error;\r\n }\r\n\r\n return { token: tokens.githubToken, fromExchange: false };\r\n }\r\n }\r\n}\r\n\r\nasync function readStoredTokens(settings: GitHubCopilotOAuthSettings): Promise<GitHubCopilotOAuthTokens | undefined> {\r\n if (settings.tokens) {\r\n return settings.tokens;\r\n }\r\n\r\n const tokenStore = settings.tokenStore as (TokenStore & {\r\n getTokens?: () => Promise<GitHubCopilotOAuthTokens | undefined>;\r\n }) | undefined;\r\n\r\n if (typeof tokenStore?.getTokens === 'function') {\r\n return tokenStore.getTokens();\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nasync function resolveBaseURL(settings: GitHubCopilotOAuthSettings): Promise<string> {\r\n if (settings.baseURL) {\r\n return withoutTrailingSlash(settings.baseURL);\r\n }\r\n\r\n const storedTokens = await readStoredTokens(settings);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl ?? storedTokens?.enterpriseUrl;\r\n\r\n return withoutTrailingSlash(copilotBase(enterpriseUrl, settings));\r\n}\r\n\r\n// Normalizes an incoming OpenAI-compatible URL against a base URL.\r\n// Strips /v1 prefix to map to Copilot API paths while preserving query strings.\r\nfunction resolveTargetUrl(input: string, baseURL: string): string {\r\n const base = new URL(baseURL);\r\n const parsed = /^https?:\\/\\//.test(input) ? new URL(input) : new URL(input, 'https://copilot.invalid');\r\n let pathname = parsed.pathname;\r\n const basePath = withoutTrailingSlash(base.pathname);\r\n\r\n if (basePath && pathname.startsWith(`${basePath}/`)) {\r\n pathname = pathname.slice(basePath.length);\r\n }\r\n\r\n if (pathname === '/v1') {\r\n pathname = '/';\r\n } else if (pathname.startsWith('/v1/')) {\r\n pathname = pathname.slice(3);\r\n }\r\n\r\n if (!pathname.startsWith('/')) {\r\n pathname = `/${pathname}`;\r\n }\r\n\r\n return `${base.origin}${basePath}${pathname}${parsed.search}`;\r\n}\r\n\r\nfunction browserOrigin(): string | undefined {\r\n const maybeWindow = (globalThis as { window?: { location?: { origin?: string } } }).window;\r\n return typeof maybeWindow?.location?.origin === 'string' ? maybeWindow.location.origin.replace(/\\/$/, '') : undefined;\r\n}\r\n\r\n// Resolves a browser proxy URL for Copilot API requests. Returns undefined in Node.js\r\n// or when browser proxy is disabled. Strips the upstream base path so proxy can route correctly.\r\nfunction resolveBrowserProxyUrl(target: URL, baseURL: string, settings: GitHubCopilotOAuthSettings): string | undefined {\r\n const origin = browserOrigin();\r\n if (!origin || settings.browserProxyBaseUrl === false) {\r\n return undefined;\r\n }\r\n\r\n const proxyBase = settings.browserProxyBaseUrl ?? DEFAULT_BROWSER_PROXY_BASE_URL;\r\n const absoluteProxyBase = /^https?:\\/\\//.test(proxyBase) ? proxyBase.replace(/\\/$/, '') : `${origin}${proxyBase.startsWith('/') ? '' : '/'}${proxyBase}`.replace(/\\/$/, '');\r\n const upstreamBasePath = withoutTrailingSlash(new URL(baseURL).pathname);\r\n let pathname = target.pathname;\r\n\r\n if (upstreamBasePath && pathname.startsWith(`${upstreamBasePath}/`)) {\r\n pathname = pathname.slice(upstreamBasePath.length);\r\n }\r\n\r\n return `${absoluteProxyBase}${pathname}${target.search}`;\r\n}\r\n\r\nasync function readRequestParts(input: Parameters<FetchLike>[0], init?: Parameters<FetchLike>[1]): Promise<RequestParts> {\r\n if (input instanceof Request) {\r\n const headers = new Headers(input.headers);\r\n if (init?.headers) {\r\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\r\n }\r\n\r\n return {\r\n url: input.url,\r\n method: init?.method ?? input.method,\r\n headers,\r\n body: init?.body ?? (input.body == null ? undefined : await input.clone().text()),\r\n signal: init?.signal ?? input.signal,\r\n };\r\n }\r\n\r\n return {\r\n url: String(input),\r\n method: init?.method,\r\n headers: new Headers(init?.headers),\r\n body: init?.body,\r\n signal: init?.signal,\r\n };\r\n}\r\n\r\nasync function bodyToText(body: BodyInit | null | undefined): Promise<string | undefined> {\r\n if (body == null) return undefined;\r\n if (typeof body === 'string') return body;\r\n if (body instanceof URLSearchParams) return body.toString();\r\n if (body instanceof FormData || body instanceof ReadableStream) return undefined;\r\n if (body instanceof Blob) return body.text();\r\n if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\r\n if (ArrayBuffer.isView(body)) return new TextDecoder().decode(body);\r\n return undefined;\r\n}\r\n\r\n/** Return true when a chat/completions or responses JSON body contains image input. */\r\nexport function hasVisionInput(body: string): boolean {\r\n if (!body.trim()) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(body) as {\r\n messages?: { content?: { type?: string }[] }[];\r\n input?: { content?: { type?: string }[] }[];\r\n };\r\n\r\n const chatVision = payload.messages?.some(\r\n (item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'image_url'),\r\n );\r\n if (chatVision) {\r\n return true;\r\n }\r\n\r\n return Boolean(\r\n payload.input?.some((item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'input_image')),\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Applies Copilot-specific headers. Detects vision capability from request body\r\n// unless explicitly configured. Uses model headers for /models, chat headers otherwise.\r\nfunction applyHeaders(headers: Headers, authToken: string, pathname: string, bodyText: string | undefined, settings: GitHubCopilotOAuthSettings) {\r\n const vision = settings.vision ?? (typeof bodyText === 'string' && hasVisionInput(bodyText));\r\n const authHeaders = pathname.endsWith('/models')\r\n ? copilotModelHeaders(authToken)\r\n : copilotHeaders(authToken, { vision, initiator: settings.initiator });\r\n\r\n headers.delete('authorization');\r\n for (const [key, value] of Object.entries(authHeaders)) {\r\n headers.set(key, value);\r\n }\r\n}\r\n\r\n/**\r\n * Create a fetch implementation that authenticates OpenAI-compatible requests\r\n * with GitHub Copilot OAuth credentials.\r\n */\r\nexport function createGitHubCopilotOAuthFetch(settings: GitHubCopilotOAuthSettings = {}): FetchLike {\r\n const fetch = pickFetch(settings.fetch);\r\n const store = createStore(settings);\r\n const manager = new TokenManager(settings, store, fetch);\r\n\r\n return async (input, init) => {\r\n const baseURL = await resolveBaseURL(settings);\r\n const request = await readRequestParts(input, init);\r\n const targetUrl = resolveTargetUrl(request.url, baseURL);\r\n const target = new URL(targetUrl);\r\n const bodyText = await bodyToText(request.body);\r\n const body = bodyText ?? request.body;\r\n const headers = new Headers(settings.headers);\r\n\r\n request.headers.forEach((value, key) => headers.set(key, value));\r\n const proxyUrl = resolveBrowserProxyUrl(target, baseURL, settings);\r\n if (proxyUrl) {\r\n headers.delete('authorization');\r\n headers.set('Authorization', `Bearer ${await manager.githubToken()}`);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl;\r\n if (enterpriseUrl) headers.set('x-copilot-enterprise-url', enterpriseUrl);\r\n return fetch(proxyUrl, {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n const token = await manager.token();\r\n applyHeaders(headers, token.token, target.pathname, bodyText, settings);\r\n\r\n const response = await fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n\r\n if (token.fromExchange && settings.fallbackToGitHubToken !== false && (response.status === 401 || response.status === 403)) {\r\n const fallbackHeaders = new Headers(headers);\r\n applyHeaders(fallbackHeaders, await manager.githubToken(), target.pathname, bodyText, settings);\r\n return fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers: fallbackHeaders,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n return response;\r\n };\r\n}\r\n\r\n/** Create a small Copilot client around `createGitHubCopilotOAuthFetch`. */\r\nexport async function createGitHubCopilotClient(settings: GitHubCopilotOAuthSettings = {}) {\r\n const baseURL = await resolveBaseURL(settings);\r\n const fetch = createGitHubCopilotOAuthFetch(settings);\r\n\r\n return {\r\n baseURL,\r\n fetch,\r\n request: (path: string, init?: RequestInit) => fetch(resolveTargetUrl(path, baseURL), init),\r\n };\r\n}\r\n\r\n/** Route GPT-5 non-mini models to Copilot's Responses endpoint. */\r\nexport function isCopilotResponsesModel(modelId: string): boolean {\r\n const normalized = modelId.toLowerCase();\r\n const match = /^gpt-(\\d+)/.exec(normalized);\r\n if (!match) {\r\n return false;\r\n }\r\n\r\n const generation = Number(match[1]);\r\n return generation >= 5 && !normalized.startsWith('gpt-5-mini');\r\n}\r\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-copilot-oauth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "GitHub Copilot OAuth provider and token helpers for the Vercel AI SDK.",
|
|
5
5
|
"author": "respectmathias",
|
|
6
|
-
"type": "module",
|
|
7
6
|
"license": "MIT",
|
|
8
7
|
"repository": {
|
|
9
8
|
"type": "git",
|