@@ -137,13 +137,25 @@ const parseUrlString = (value: string | undefined): URL | null => {
137137 }
138138} ;
139139
140- const assertExplicitUrl = (
140+ const URL_SCHEME_PREFIX = / ^ [ A - Z a - z ] [ A - Z a - z \d + \- . ] * : \/ \/ / ;
141+
142+ const coerceConfiguredUrl = (
141143 value : string | undefined ,
142144 fieldName : string ,
143- allowedSchemes ?: string [ ] ,
144- ) : void => {
145- if ( value === undefined ) return ;
146- const url = parseUrlString ( value ) ;
145+ options : {
146+ allowedSchemes ?: string [ ] ;
147+ defaultScheme : string ;
148+ defaultPort ?: string ;
149+ } ,
150+ ) : string | undefined => {
151+ if ( value === undefined ) return undefined ;
152+
153+ const hasExplicitScheme = URL_SCHEME_PREFIX . test ( value ) ;
154+ const candidate = hasExplicitScheme
155+ ? value
156+ : `${ options . defaultScheme } ://${ value . replace ( / ^ \/ \/ / , "" ) } ` ;
157+
158+ const url = parseUrlString ( candidate ) ;
147159 if ( ! url ) {
148160 throw new ConfigLoadError (
149161 `Invalid config value for ${ fieldName } : expected a valid URL, received ${
@@ -153,30 +165,62 @@ const assertExplicitUrl = (
153165 ) ;
154166 }
155167 if (
156- ! allowedSchemes ||
157- allowedSchemes . includes ( url . protocol . slice ( 0 , - 1 ) )
168+ ! options . allowedSchemes ||
169+ options . allowedSchemes . includes ( url . protocol . slice ( 0 , - 1 ) )
158170 ) {
159- return ;
171+ if ( ! hasExplicitScheme && options . defaultPort && ! url . port ) {
172+ url . port = options . defaultPort ;
173+ }
174+ return url . toString ( ) ;
160175 }
176+
161177 throw new ConfigLoadError (
162178 `Invalid config value for ${ fieldName } : expected URL scheme ${
163- allowedSchemes . map ( ( scheme ) => JSON . stringify ( scheme ) ) . join ( " or " )
179+ options . allowedSchemes . map ( ( scheme ) => JSON . stringify ( scheme ) ) . join (
180+ " or " ,
181+ )
164182 } , received ${ JSON . stringify ( redactEndpointUserInfo ( value ) ) } `,
165183 { code : "config-invalid" } ,
166184 ) ;
167185} ;
168186
169- const validateExplicitConfig = ( value : RawGraphitiConfig | null ) : void => {
170- if ( ! value ) return ;
171- assertExplicitUrl ( value . endpoint , "endpoint" , [ "http" , "https" ] ) ;
172- assertExplicitUrl ( value . graphiti ?. endpoint , "graphiti.endpoint" , [
173- "http" ,
174- "https" ,
175- ] ) ;
176- assertExplicitUrl ( value . redis ?. endpoint , "redis.endpoint" , [
177- "redis" ,
178- "rediss" ,
179- ] ) ;
187+ const normalizeConfiguredEndpoints = (
188+ value : RawGraphitiConfig | null ,
189+ ) : RawGraphitiConfig | null => {
190+ if ( ! value ) return value ;
191+
192+ return {
193+ ...value ,
194+ endpoint : coerceConfiguredUrl ( value . endpoint , "endpoint" , {
195+ allowedSchemes : [ "http" , "https" ] ,
196+ defaultScheme : "http" ,
197+ defaultPort : "8000" ,
198+ } ) ,
199+ graphiti : value . graphiti
200+ ? {
201+ ...value . graphiti ,
202+ endpoint : coerceConfiguredUrl (
203+ value . graphiti . endpoint ,
204+ "graphiti.endpoint" ,
205+ {
206+ allowedSchemes : [ "http" , "https" ] ,
207+ defaultScheme : "http" ,
208+ defaultPort : "8000" ,
209+ } ,
210+ ) ,
211+ }
212+ : value . graphiti ,
213+ redis : value . redis
214+ ? {
215+ ...value . redis ,
216+ endpoint : coerceConfiguredUrl ( value . redis . endpoint , "redis.endpoint" , {
217+ allowedSchemes : [ "redis" , "rediss" ] ,
218+ defaultScheme : "redis" ,
219+ defaultPort : "6379" ,
220+ } ) ,
221+ }
222+ : value . redis ,
223+ } ;
180224} ;
181225
182226const resolveNumber = (
@@ -288,8 +332,9 @@ const loadConfigFile = (
288332) : RawGraphitiConfig | null => {
289333 try {
290334 const loaded = adapter ?. load ( filePath ) ;
291- const normalized = loaded ? normalizeConfig ( loaded . config ) : null ;
292- validateExplicitConfig ( normalized ) ;
335+ const normalized = loaded
336+ ? normalizeConfiguredEndpoints ( normalizeConfig ( loaded . config ) )
337+ : null ;
293338 return normalized ;
294339 } catch ( err ) {
295340 if ( err instanceof ConfigLoadError ) throw err ;
@@ -314,8 +359,9 @@ const searchConfig = (
314359) : RawGraphitiConfig | null => {
315360 try {
316361 const loaded = adapter . search ( directory ) ;
317- const normalized = loaded ? normalizeConfig ( loaded . config ) : null ;
318- validateExplicitConfig ( normalized ) ;
362+ const normalized = loaded
363+ ? normalizeConfiguredEndpoints ( normalizeConfig ( loaded . config ) )
364+ : null ;
319365 return normalized ;
320366 } catch ( err ) {
321367 if ( err instanceof ConfigLoadError ) throw err ;
@@ -349,7 +395,6 @@ export function loadConfig(directory?: string): GraphitiConfig {
349395 const adapter = getConfigExplorerAdapter ( ) ;
350396 const loaded = searchConfig ( adapter , directory ) ;
351397 const resolved = loaded ?? loadLegacyConfig ( adapter ) ;
352- validateExplicitConfig ( resolved ) ;
353398 return resolveConfig ( resolved ) ;
354399 } catch ( error ) {
355400 if (
0 commit comments