@@ -48,7 +48,7 @@ import {
4848import { computed , ref , watch } from 'vue'
4949import { useI18n } from 'vue-i18n'
5050
51- import { isAbsoluteUrl } from '../utils/string '
51+ import { isUrl } from '../utils/url '
5252import { models as elevenLabsModels } from './providers/elevenlabs/list-models'
5353
5454export interface ProviderMetadata {
@@ -160,11 +160,29 @@ export interface VoiceInfo {
160160export const useProvidersStore = defineStore ( 'providers' , ( ) => {
161161 const providerCredentials = useLocalStorage < Record < string , Record < string , unknown > > > ( 'settings/credentials/providers' , { } )
162162 const { t } = useI18n ( )
163- const notBaseUrlError = computed ( ( ) => ( {
164- errors : [ new Error ( 'Base URL is not absolute' ) ] ,
165- reason : 'Base URL is not absolute. Check your input.' ,
166- valid : false ,
167- } ) )
163+ const baseUrlValidator = computed ( ( ) => ( baseUrl : unknown ) => {
164+ let msg = ''
165+ if ( ! baseUrl ) {
166+ msg = 'Base URL is required.'
167+ }
168+ else if ( typeof baseUrl !== 'string' ) {
169+ msg = 'Base URL must be a string.'
170+ }
171+ else if ( ! isUrl ( baseUrl ) || new URL ( baseUrl ) . host . length === 0 ) {
172+ msg = 'Base URL is not absolute. Try to include a scheme (http:// or https://).'
173+ }
174+ else if ( ! baseUrl . endsWith ( '/' ) ) {
175+ msg = 'Base URL must end with a trailing slash (/).'
176+ }
177+ if ( msg ) {
178+ return {
179+ errors : [ new Error ( msg ) ] ,
180+ reason : msg ,
181+ valid : false ,
182+ }
183+ }
184+ return null
185+ } )
168186
169187 // Helper function to fetch OpenRouter models manually
170188 async function fetchOpenRouterModels ( config : Record < string , unknown > ) : Promise < ModelInfo [ ] > {
@@ -223,8 +241,9 @@ export const useProvidersStore = defineStore('providers', () => {
223241 ! config . baseUrl && new Error ( 'Base URL is required' ) ,
224242 ] . filter ( Boolean )
225243
226- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
227- return notBaseUrlError . value
244+ const res = baseUrlValidator . value ( config . baseUrl )
245+ if ( res ) {
246+ return res
228247 }
229248
230249 return {
@@ -504,8 +523,9 @@ export const useProvidersStore = defineStore('providers', () => {
504523 }
505524 }
506525
507- if ( ! isAbsoluteUrl ( config . baseUrl as string ) ) {
508- return notBaseUrlError . value
526+ const res = baseUrlValidator . value ( config . baseUrl )
527+ if ( res ) {
528+ return res
509529 }
510530
511531 // Check if the Ollama server is reachable
@@ -570,8 +590,9 @@ export const useProvidersStore = defineStore('providers', () => {
570590 }
571591 }
572592
573- if ( ! isAbsoluteUrl ( config . baseUrl as string ) ) {
574- return notBaseUrlError . value
593+ const res = baseUrlValidator . value ( config . baseUrl )
594+ if ( res ) {
595+ return res
575596 }
576597
577598 // Check if the Ollama server is reachable
@@ -665,8 +686,9 @@ export const useProvidersStore = defineStore('providers', () => {
665686 }
666687 }
667688
668- if ( ! isAbsoluteUrl ( config . baseUrl as string ) ) {
669- return notBaseUrlError . value
689+ const res = baseUrlValidator . value ( config . baseUrl )
690+ if ( res ) {
691+ return res
670692 }
671693
672694 // Check if the vLLM is reachable
@@ -742,6 +764,11 @@ export const useProvidersStore = defineStore('providers', () => {
742764 }
743765 }
744766
767+ const res = baseUrlValidator . value ( config . baseUrl )
768+ if ( res ) {
769+ return res
770+ }
771+
745772 // Check if the LM Studio server is reachable
746773 return fetch ( `${ ( config . baseUrl as string ) . trim ( ) } models` , { headers : ( config . headers as HeadersInit ) || undefined } )
747774 . then ( ( response ) => {
@@ -800,8 +827,9 @@ export const useProvidersStore = defineStore('providers', () => {
800827 ! config . baseUrl && new Error ( 'Base URL is required. Default to https://api.openai.com/v1/ for official OpenAI API.' ) ,
801828 ] . filter ( Boolean )
802829
803- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
804- return notBaseUrlError . value
830+ const res = baseUrlValidator . value ( config . baseUrl )
831+ if ( res ) {
832+ return res
805833 }
806834
807835 return {
@@ -848,8 +876,9 @@ export const useProvidersStore = defineStore('providers', () => {
848876 ! config . baseUrl && new Error ( 'Base URL is required' ) ,
849877 ] . filter ( Boolean )
850878
851- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
852- return notBaseUrlError . value
879+ const res = baseUrlValidator . value ( config . baseUrl )
880+ if ( res ) {
881+ return res
853882 }
854883
855884 return {
@@ -965,8 +994,9 @@ export const useProvidersStore = defineStore('providers', () => {
965994 ! config . baseUrl && new Error ( 'Base URL is required. Default to https://api.openai.com/v1/ for official OpenAI API.' ) ,
966995 ] . filter ( Boolean )
967996
968- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
969- return notBaseUrlError . value
997+ const res = baseUrlValidator . value ( config . baseUrl )
998+ if ( res ) {
999+ return res
9701000 }
9711001
9721002 return {
@@ -1016,8 +1046,9 @@ export const useProvidersStore = defineStore('providers', () => {
10161046 ! config . baseUrl && new Error ( 'Base URL is required' ) ,
10171047 ] . filter ( Boolean )
10181048
1019- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1020- return notBaseUrlError . value
1049+ const res = baseUrlValidator . value ( config . baseUrl )
1050+ if ( res ) {
1051+ return res
10211052 }
10221053
10231054 return {
@@ -1063,8 +1094,9 @@ export const useProvidersStore = defineStore('providers', () => {
10631094 ! config . baseUrl && new Error ( 'Base URL is required. Default to https://api.openai.com/v1/ for official OpenAI API.' ) ,
10641095 ] . filter ( Boolean )
10651096
1066- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1067- return notBaseUrlError . value
1097+ const res = baseUrlValidator . value ( config . baseUrl )
1098+ if ( res ) {
1099+ return res
10681100 }
10691101
10701102 return {
@@ -1111,8 +1143,9 @@ export const useProvidersStore = defineStore('providers', () => {
11111143 ! config . baseUrl && new Error ( 'Base URL is required' ) ,
11121144 ] . filter ( Boolean )
11131145
1114- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1115- return notBaseUrlError . value
1146+ const res = baseUrlValidator . value ( config . baseUrl )
1147+ if ( res ) {
1148+ return res
11161149 }
11171150
11181151 return {
@@ -1246,8 +1279,9 @@ export const useProvidersStore = defineStore('providers', () => {
12461279 ! config . baseUrl && new Error ( 'Base URL is required. Default to https://api.anthropic.com/v1/ for official Claude API with OpenAI compatibility.' ) ,
12471280 ] . filter ( Boolean )
12481281
1249- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1250- return notBaseUrlError . value
1282+ const res = baseUrlValidator . value ( config . baseUrl )
1283+ if ( res ) {
1284+ return res
12511285 }
12521286
12531287 return {
@@ -1294,8 +1328,9 @@ export const useProvidersStore = defineStore('providers', () => {
12941328 ! config . baseUrl && new Error ( 'Base URL is required. Default to https://generativelanguage.googleapis.com/v1beta/openai/ for official Google Gemini API with OpenAI compatibility.' ) ,
12951329 ] . filter ( Boolean )
12961330
1297- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1298- return notBaseUrlError . value
1331+ const res = baseUrlValidator . value ( config . baseUrl )
1332+ if ( res ) {
1333+ return res
12991334 }
13001335
13011336 return {
@@ -1383,8 +1418,9 @@ export const useProvidersStore = defineStore('providers', () => {
13831418 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
13841419 ] . filter ( Boolean )
13851420
1386- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1387- return notBaseUrlError . value
1421+ const res = baseUrlValidator . value ( config . baseUrl )
1422+ if ( res ) {
1423+ return res
13881424 }
13891425
13901426 return {
@@ -1467,8 +1503,9 @@ export const useProvidersStore = defineStore('providers', () => {
14671503 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
14681504 ] . filter ( Boolean )
14691505
1470- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1471- return notBaseUrlError . value
1506+ const res = baseUrlValidator . value ( config . baseUrl )
1507+ if ( res ) {
1508+ return res
14721509 }
14731510
14741511 return {
@@ -1531,8 +1568,9 @@ export const useProvidersStore = defineStore('providers', () => {
15311568 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
15321569 ] . filter ( Boolean )
15331570
1534- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1535- return notBaseUrlError . value
1571+ const res = baseUrlValidator . value ( config . baseUrl )
1572+ if ( res ) {
1573+ return res
15361574 }
15371575
15381576 return {
@@ -1592,8 +1630,9 @@ export const useProvidersStore = defineStore('providers', () => {
15921630 ! config . baseUrl && new Error ( 'Base URL is required. Default to http://localhost:11996/tts for Index-TTS.' ) ,
15931631 ] . filter ( Boolean )
15941632
1595- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1596- return notBaseUrlError . value
1633+ const res = baseUrlValidator . value ( config . baseUrl )
1634+ if ( res ) {
1635+ return res
15971636 }
15981637
15991638 return {
@@ -1664,8 +1703,9 @@ export const useProvidersStore = defineStore('providers', () => {
16641703 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
16651704 ] . filter ( Boolean )
16661705
1667- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1668- return notBaseUrlError . value
1706+ const res = baseUrlValidator . value ( config . baseUrl )
1707+ if ( res ) {
1708+ return res
16691709 }
16701710
16711711 return {
@@ -1729,8 +1769,9 @@ export const useProvidersStore = defineStore('providers', () => {
17291769 ! ( ( config . app as any ) ?. appId ) && new Error ( 'App ID is required.' ) ,
17301770 ] . filter ( Boolean )
17311771
1732- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1733- return notBaseUrlError . value
1772+ const res = baseUrlValidator . value ( config . baseUrl )
1773+ if ( res ) {
1774+ return res
17341775 }
17351776
17361777 return {
@@ -1900,8 +1941,9 @@ export const useProvidersStore = defineStore('providers', () => {
19001941 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
19011942 ] . filter ( Boolean )
19021943
1903- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
1904- return notBaseUrlError . value
1944+ const res = baseUrlValidator . value ( config . baseUrl )
1945+ if ( res ) {
1946+ return res
19051947 }
19061948
19071949 return {
@@ -2003,8 +2045,9 @@ export const useProvidersStore = defineStore('providers', () => {
20032045 ! config . baseUrl && new Error ( 'Base URL is required.' ) ,
20042046 ] . filter ( Boolean )
20052047
2006- if ( ! ! config . baseUrl && ! isAbsoluteUrl ( config . baseUrl as string ) ) {
2007- return notBaseUrlError . value
2048+ const res = baseUrlValidator . value ( config . baseUrl )
2049+ if ( res ) {
2050+ return res
20082051 }
20092052
20102053 return {
@@ -2131,12 +2174,13 @@ export const useProvidersStore = defineStore('providers', () => {
21312174 }
21322175 }
21332176
2134- if ( ! isAbsoluteUrl ( config . baseUrl as string ) ) {
2135- return notBaseUrlError . value
2177+ const res = baseUrlValidator . value ( config . baseUrl )
2178+ if ( res ) {
2179+ return res
21362180 }
21372181
21382182 // Check if the local running Player 2 is reachable
2139- return await fetch ( `${ ( config . baseUrl as string ) . endsWith ( '/' ) ? ( config . baseUrl as string ) . slice ( 0 , - 1 ) : config . baseUrl } / health` , {
2183+ return await fetch ( `${ config . baseUrl } health` , {
21402184 method : 'GET' ,
21412185 headers : {
21422186 'player2-game-key' : 'airi' ,
@@ -2241,8 +2285,9 @@ export const useProvidersStore = defineStore('providers', () => {
22412285 }
22422286 }
22432287
2244- if ( ! isAbsoluteUrl ( config . baseUrl as string ) ) {
2245- return notBaseUrlError . value
2288+ const res = baseUrlValidator . value ( config . baseUrl )
2289+ if ( res ) {
2290+ return res
22462291 }
22472292
22482293 return {
0 commit comments