@@ -267,8 +267,107 @@ export async function env(
267267
268268 ctx . debug && ctx . logger . debug ( `Database Token: ${ dbToken } ` ) ;
269269
270- envBuilderOpts . astroDbRemoteUrl = dbURL ;
271- envBuilderOpts . astroDbToken = dbToken ;
270+ // Validate URL and token
271+ if ( ! dbURL || ! dbURL . startsWith ( 'libsql://' ) ) {
272+ tursoSetup . stop (
273+ `${ label ( 'Turso' , TursoColorway , color . black ) } Failed to retrieve a valid database URL.`
274+ ) ;
275+ ctx . prompt . log . error ( StudioCMSColorwayError ( `Invalid database URL: ${ dbURL || 'undefined' } ` ) ) ;
276+
277+ const manualURL = await ctx . prompt . text ( {
278+ message : 'Enter your Turso database URL manually' ,
279+ placeholder : 'libsql://your-database.turso.io' ,
280+ } ) ;
281+
282+ if ( typeof manualURL === 'symbol' ) {
283+ ctx . promptCancel ( manualURL ) ;
284+ } else {
285+ envBuilderOpts . astroDbRemoteUrl = manualURL || '' ;
286+ }
287+ } else {
288+ envBuilderOpts . astroDbRemoteUrl = dbURL ;
289+ }
290+
291+ if ( ! dbToken || dbToken . length < 10 ) {
292+ tursoSetup . stop (
293+ `${ label ( 'Turso' , TursoColorway , color . black ) } Failed to retrieve a valid token.`
294+ ) ;
295+ ctx . prompt . log . error ( StudioCMSColorwayError ( `Invalid database token: ${ dbToken ? 'too short' : 'undefined' } ` ) ) ;
296+
297+ const manualToken = await ctx . prompt . text ( {
298+ message : 'Enter your Turso database token manually' ,
299+ placeholder : 'eyJh...Nzc2' ,
300+ } ) ;
301+
302+ if ( typeof manualToken === 'symbol' ) {
303+ ctx . promptCancel ( manualToken ) ;
304+ } else {
305+ envBuilderOpts . astroDbToken = manualToken || '' ;
306+ }
307+ } else {
308+ envBuilderOpts . astroDbToken = dbToken ;
309+ }
310+
311+ // Verify credentials with a simple test connection
312+ if ( envBuilderOpts . astroDbRemoteUrl && envBuilderOpts . astroDbToken ) {
313+ tursoSetup . message (
314+ `${ label ( 'Turso' , TursoColorway , color . black ) } Verifying database connection...`
315+ ) ;
316+
317+ try {
318+ // Test connection using curl (doesn't require additional dependencies)
319+ const connectionTest = await runShellCommand (
320+ `curl -s -o /dev/null -w "%{http_code}" ${ envBuilderOpts . astroDbRemoteUrl } /health -H "Authorization: Bearer ${ envBuilderOpts . astroDbToken } "`
321+ ) ;
322+
323+ const statusCode = Number . parseInt ( connectionTest . trim ( ) , 10 ) ;
324+
325+ if ( statusCode >= 200 && statusCode < 300 ) {
326+ ctx . debug && ctx . logger . debug ( `Database connection successful: ${ statusCode } ` ) ;
327+ } else {
328+ ctx . debug && ctx . logger . debug ( `Database connection failed: ${ statusCode } ` ) ;
329+ ctx . prompt . log . warn (
330+ `${ label ( 'Warning' , StudioCMSColorwayWarnBg , color . black ) } Could not verify database connection. Status: ${ statusCode } `
331+ ) ;
332+
333+ const confirmContinue = await ctx . prompt . confirm ( {
334+ message : 'Continue with these credentials anyway?' ,
335+ initialValue : true ,
336+ } ) ;
337+
338+ if ( typeof confirmContinue === 'symbol' ) {
339+ ctx . promptCancel ( confirmContinue ) ;
340+ } else if ( ! confirmContinue ) {
341+ // If user doesn't want to continue with unverified credentials, ask for new ones
342+ const newCredentials = await ctx . prompt . group (
343+ {
344+ astroDbRemoteUrl : ( ) =>
345+ ctx . prompt . text ( {
346+ message : 'Remote URL for AstroDB' ,
347+ initialValue : envBuilderOpts . astroDbRemoteUrl || 'libsql://your-database.turso.io' ,
348+ } ) ,
349+ astroDbToken : ( ) =>
350+ ctx . prompt . text ( {
351+ message : 'AstroDB Token' ,
352+ initialValue : '' ,
353+ } ) ,
354+ } ,
355+ {
356+ onCancel : ( ) => ctx . promptOnCancel ( ) ,
357+ }
358+ ) ;
359+
360+ envBuilderOpts . astroDbRemoteUrl = newCredentials . astroDbRemoteUrl || '' ;
361+ envBuilderOpts . astroDbToken = newCredentials . astroDbToken || '' ;
362+ }
363+ }
364+ } catch ( error ) {
365+ ctx . debug && ctx . logger . debug ( `Database connection test error: ${ error instanceof Error ? error . message : 'unknown error' } ` ) ;
366+ ctx . prompt . log . warn (
367+ `${ label ( 'Warning' , StudioCMSColorwayWarnBg , color . black ) } Could not verify database connection due to an error.`
368+ ) ;
369+ }
370+ }
272371
273372 tursoSetup . stop (
274373 `${ label ( 'Turso' , TursoColorway , color . black ) } Database setup complete. New Database: ${ dbFinalName } `
@@ -312,7 +411,100 @@ export async function env(
312411
313412 ctx . debug && ctx . logger . debug ( `AstroDB setup: ${ envBuilderStep_AstroDB } ` ) ;
314413
315- envBuilderOpts = { ...envBuilderStep_AstroDB } ;
414+ // Validate the manually entered credentials
415+ let dbUrl = envBuilderStep_AstroDB . astroDbRemoteUrl || '' ;
416+ let dbToken = envBuilderStep_AstroDB . astroDbToken || '' ;
417+
418+ // Check URL format
419+ if ( ! dbUrl . startsWith ( 'libsql://' ) && dbUrl !== '' ) {
420+ ctx . prompt . log . warn (
421+ `${ label ( 'Warning' , StudioCMSColorwayWarnBg , color . black ) } The database URL should start with 'libsql://'.`
422+ ) ;
423+
424+ const fixUrl = await ctx . prompt . confirm ( {
425+ message : 'Would you like to prepend "libsql://" to your URL?' ,
426+ initialValue : true ,
427+ } ) ;
428+
429+ if ( typeof fixUrl === 'symbol' ) {
430+ ctx . promptCancel ( fixUrl ) ;
431+ } else if ( fixUrl ) {
432+ dbUrl = `libsql://${ dbUrl } ` ;
433+ }
434+ }
435+
436+ // Verify the credentials with a connection test
437+ if ( dbUrl && dbToken && dbToken !== 'your-astrodb-token' ) {
438+ const verifyConnection = await ctx . prompt . confirm ( {
439+ message : 'Would you like to verify these credentials?' ,
440+ initialValue : true ,
441+ } ) ;
442+
443+ if ( typeof verifyConnection === 'symbol' ) {
444+ ctx . promptCancel ( verifyConnection ) ;
445+ } else if ( verifyConnection ) {
446+ const connectionTestSpinner = ctx . prompt . spinner ( ) ;
447+ connectionTestSpinner . start ( `${ label ( 'Turso' , TursoColorway , color . black ) } Verifying database connection...` ) ;
448+
449+ try {
450+ // Test connection using curl (doesn't require additional dependencies)
451+ const connectionTest = await runShellCommand (
452+ `curl -s -o /dev/null -w "%{http_code}" ${ dbUrl } /health -H "Authorization: Bearer ${ dbToken } "`
453+ ) ;
454+
455+ const statusCode = Number . parseInt ( connectionTest . trim ( ) , 10 ) ;
456+
457+ if ( statusCode >= 200 && statusCode < 300 ) {
458+ connectionTestSpinner . stop ( `${ label ( 'Turso' , TursoColorway , color . black ) } Connection successful!` ) ;
459+ } else {
460+ connectionTestSpinner . stop ( `${ label ( 'Turso' , TursoColorway , color . black ) } Connection failed (${ statusCode } ).` ) ;
461+ ctx . prompt . log . warn (
462+ `${ label ( 'Warning' , StudioCMSColorwayWarnBg , color . black ) } Could not verify database connection. Status: ${ statusCode } `
463+ ) ;
464+
465+ const retryCredentials = await ctx . prompt . confirm ( {
466+ message : 'Would you like to enter different credentials?' ,
467+ initialValue : true ,
468+ } ) ;
469+
470+ if ( typeof retryCredentials === 'symbol' ) {
471+ ctx . promptCancel ( retryCredentials ) ;
472+ } else if ( retryCredentials ) {
473+ const newCredentials = await ctx . prompt . group (
474+ {
475+ astroDbRemoteUrl : ( ) =>
476+ ctx . prompt . text ( {
477+ message : 'Remote URL for AstroDB' ,
478+ initialValue : dbUrl ,
479+ } ) ,
480+ astroDbToken : ( ) =>
481+ ctx . prompt . text ( {
482+ message : 'AstroDB Token' ,
483+ initialValue : '' ,
484+ } ) ,
485+ } ,
486+ {
487+ onCancel : ( ) => ctx . promptOnCancel ( ) ,
488+ }
489+ ) ;
490+
491+ dbUrl = newCredentials . astroDbRemoteUrl || '' ;
492+ dbToken = newCredentials . astroDbToken || '' ;
493+ }
494+ }
495+ } catch ( error ) {
496+ connectionTestSpinner . stop ( `${ label ( 'Turso' , TursoColorway , color . black ) } Connection test failed.` ) ;
497+ ctx . debug && ctx . logger . debug ( `Database connection test error: ${ error instanceof Error ? error . message : 'unknown error' } ` ) ;
498+ ctx . prompt . log . warn (
499+ `${ label ( 'Warning' , StudioCMSColorwayWarnBg , color . black ) } Could not verify database connection due to an error.`
500+ ) ;
501+ }
502+ }
503+ }
504+
505+ // Save the validated credentials
506+ envBuilderOpts . astroDbRemoteUrl = dbUrl ;
507+ envBuilderOpts . astroDbToken = dbToken ;
316508 }
317509 }
318510
@@ -344,7 +536,18 @@ export async function env(
344536
345537 ctx . debug && ctx . logger . debug ( `Environment Builder Step 1: ${ envBuilderStep1 } ` ) ;
346538
347- envBuilderOpts = { ...envBuilderStep1 } ;
539+ // Preserve AstroDB URL and token while merging
540+ const previousDbValues = {
541+ astroDbRemoteUrl : envBuilderOpts . astroDbRemoteUrl ,
542+ astroDbToken : envBuilderOpts . astroDbToken
543+ } ;
544+
545+ envBuilderOpts = {
546+ ...envBuilderOpts ,
547+ ...envBuilderStep1 ,
548+ astroDbRemoteUrl : previousDbValues . astroDbRemoteUrl || '' ,
549+ astroDbToken : previousDbValues . astroDbToken || ''
550+ } ;
348551
349552 if ( envBuilderStep1 . oAuthOptions . includes ( 'github' ) ) {
350553 const githubOAuth = await ctx . prompt . group (
0 commit comments