@@ -71,6 +71,27 @@ function resolveCopilotAuthToken(env = process.env) {
7171 return resolveApiKey ( env ) || stripBearerPrefix ( env . COPILOT_GITHUB_TOKEN ) ;
7272}
7373
74+ /**
75+ * Classify GITHUB_SERVER_URL by host type for auth-routing derivation logic.
76+ *
77+ * @param {Record<string, string|undefined> } env - Environment variables
78+ * @returns {{kind: 'missing'|'invalid'|'github'|'ghec'|'ghes', subdomain?: string} }
79+ */
80+ function classifyGithubServerHost ( env = process . env ) {
81+ const serverUrl = env . GITHUB_SERVER_URL ;
82+ if ( ! serverUrl ) return { kind : 'missing' } ;
83+ try {
84+ const hostname = new URL ( serverUrl ) . hostname ;
85+ if ( hostname === 'github.com' ) return { kind : 'github' } ;
86+ if ( hostname . endsWith ( '.ghe.com' ) ) {
87+ return { kind : 'ghec' , subdomain : hostname . slice ( 0 , - 8 ) } ;
88+ }
89+ return { kind : 'ghes' } ;
90+ } catch {
91+ return { kind : 'invalid' } ;
92+ }
93+ }
94+
7495/**
7596 * Derive the Copilot API target hostname from environment variables.
7697 *
@@ -91,21 +112,9 @@ function deriveCopilotApiTarget(env = process.env) {
91112 // fall through to auto-derivation when the value is malformed.
92113 if ( target ) return target ;
93114 }
94- const serverUrl = env . GITHUB_SERVER_URL ;
95- if ( serverUrl ) {
96- try {
97- const hostname = new URL ( serverUrl ) . hostname ;
98- if ( hostname !== 'github.com' ) {
99- if ( hostname . endsWith ( '.ghe.com' ) ) {
100- const subdomain = hostname . slice ( 0 , - 8 ) ; // Remove '.ghe.com'
101- return `copilot-api.${ subdomain } .ghe.com` ;
102- }
103- return 'api.enterprise.githubcopilot.com' ;
104- }
105- } catch {
106- // Invalid URL — fall through to default
107- }
108- }
115+ const serverHost = classifyGithubServerHost ( env ) ;
116+ if ( serverHost . kind === 'ghec' ) return `copilot-api.${ serverHost . subdomain } .ghe.com` ;
117+ if ( serverHost . kind === 'ghes' ) return 'api.enterprise.githubcopilot.com' ;
109118 return 'api.githubcopilot.com' ;
110119}
111120
@@ -125,18 +134,8 @@ function deriveGitHubApiTarget(env = process.env) {
125134 const target = normalizeApiTarget ( env . GITHUB_API_URL ) ;
126135 if ( target ) return target ;
127136 }
128- const serverUrl = env . GITHUB_SERVER_URL ;
129- if ( serverUrl ) {
130- try {
131- const hostname = new URL ( serverUrl ) . hostname ;
132- if ( hostname !== 'github.com' && hostname . endsWith ( '.ghe.com' ) ) {
133- const subdomain = hostname . slice ( 0 , - 8 ) ;
134- return `api.${ subdomain } .ghe.com` ;
135- }
136- } catch {
137- // Invalid URL — fall through to default
138- }
139- }
137+ const serverHost = classifyGithubServerHost ( env ) ;
138+ if ( serverHost . kind === 'ghec' ) return `api.${ serverHost . subdomain } .ghe.com` ;
140139 return 'api.github.com' ;
141140}
142141
@@ -228,15 +227,7 @@ function isGhesInstance(resolvedTarget, env = process.env) {
228227 if ( env . AWF_PLATFORM_TYPE && env . AWF_PLATFORM_TYPE !== 'ghes' ) return false ;
229228
230229 if ( resolvedTarget === 'api.enterprise.githubcopilot.com' ) return true ;
231-
232- const serverUrl = env . GITHUB_SERVER_URL ;
233- if ( ! serverUrl ) return false ;
234- try {
235- const hostname = new URL ( serverUrl ) . hostname ;
236- return hostname !== 'github.com' && ! hostname . endsWith ( '.ghe.com' ) ;
237- } catch {
238- return false ;
239- }
230+ return classifyGithubServerHost ( env ) . kind === 'ghes' ;
240231}
241232
242233/**
@@ -303,6 +294,7 @@ module.exports = {
303294 deriveGitHubApiBasePath,
304295 isGithubCopilotCatalogTarget,
305296 isGhesInstance,
297+ classifyGithubServerHost,
306298 copilotTargetRequiresGitHubTokenPrefix,
307299 getCopilotModelFallbackPolicy,
308300 // Exported for unit-test access only; not part of the public API.
@@ -315,6 +307,7 @@ module.exports = {
315307 deriveGitHubApiBasePath,
316308 isGithubCopilotCatalogTarget,
317309 isGhesInstance,
310+ classifyGithubServerHost,
318311 copilotTargetRequiresGitHubTokenPrefix,
319312 getCopilotModelFallbackPolicy,
320313 } ,
0 commit comments