1- import { writeFile , readFile as readFileNode } from 'node:fs/promises' ;
1+ import { writeFile , readFile as readFileNode , chmod } from 'node:fs/promises' ;
22import { ensureDir , pathExists } from 'fs-extra' ;
33import { resolve } from 'path' ;
44import { createInterface } from 'readline' ;
55import { detectFramework , detectPkgManager } from '../../domain/framework/detector.js' ;
66import { isValidIpOrHostname , isValidPort } from '../../domain/validation/ip.js' ;
77import { ORM_PATTERNS } from '../../shared/constants.js' ;
88import { ui } from '../ui.js' ;
9+ import type { DatabaseType } from '../../shared/types.js' ;
910
1011const rl = createInterface ( { input : process . stdin , output : process . stdout } ) ;
1112
@@ -83,6 +84,12 @@ export async function cmdInit(cwd: string, options: { nonInteractive?: boolean;
8384 let domain = '' ;
8485 let zeroDowntime = true ;
8586 let healthCheckPath = '/health' ;
87+ let dbType : DatabaseType | undefined ;
88+ let dbHost : string | undefined ;
89+ let dbPort : number | undefined ;
90+ let dbName : string | undefined ;
91+ let dbUser : string | undefined ;
92+ let dbPassword : string | undefined ;
8693
8794 if ( appType === 'backend' ) {
8895 pm2Name = await ask ( 'PM2 app name' , appName ) ;
@@ -93,6 +100,25 @@ export async function cmdInit(cwd: string, options: { nonInteractive?: boolean;
93100 if ( zeroDowntime ) {
94101 healthCheckPath = await ask ( 'Health check path' , '/health' ) ;
95102 }
103+
104+ const hasDb = ( await ask ( 'Configure a database?' , 'no' ) ) . toLowerCase ( ) . startsWith ( 'y' ) ;
105+ if ( hasDb ) {
106+ const dbTypeRaw = await ask ( 'Database type (postgres/mysql/sqlite/mongodb)' , 'postgres' ) ;
107+ dbType = ( [ 'postgres' , 'mysql' , 'sqlite' , 'mongodb' ] . includes ( dbTypeRaw )
108+ ? dbTypeRaw
109+ : 'postgres' ) as DatabaseType ;
110+
111+ if ( dbType !== 'sqlite' ) {
112+ dbHost = await ask ( 'Database host' , 'localhost' ) ;
113+ const defaultDbPort = dbType === 'postgres' ? '5432' : dbType === 'mysql' ? '3306' : '27017' ;
114+ dbPort = parseInt ( await ask ( 'Database port' , defaultDbPort ) , 10 ) ;
115+ dbName = await ask ( 'Database name' , appName ) ;
116+ dbUser = await ask ( 'Database user' , appName ) ;
117+ dbPassword = await ask ( 'Database password (optional)' , '' ) ;
118+ } else {
119+ dbName = await ask ( 'SQLite file path' , './data.db' ) ;
120+ }
121+ }
96122 } else {
97123 domain = await ask ( 'Domain (optional)' , '' ) ;
98124 }
@@ -112,6 +138,12 @@ export async function cmdInit(cwd: string, options: { nonInteractive?: boolean;
112138 zeroDowntime,
113139 healthCheckPath,
114140 pkgManager : pkgManager ?? undefined ,
141+ dbType,
142+ dbHost,
143+ dbPort,
144+ dbName,
145+ dbUser,
146+ dbPassword : dbPassword || undefined ,
115147 } ) ;
116148
117149 const configPath = resolve ( cwd , 'shipnode.config.ts' ) ;
@@ -154,6 +186,12 @@ interface ConfigOptions {
154186 zeroDowntime ?: boolean ;
155187 healthCheckPath ?: string ;
156188 pkgManager ?: string ;
189+ dbType ?: DatabaseType ;
190+ dbHost ?: string ;
191+ dbPort ?: number ;
192+ dbName ?: string ;
193+ dbUser ?: string ;
194+ dbPassword ?: string ;
157195}
158196
159197async function generateShipnodeDir ( cwd : string , detectedOrm ?: string ) : Promise < void > {
@@ -166,12 +204,12 @@ async function generateShipnodeDir(cwd: string, detectedOrm?: string): Promise<v
166204
167205 if ( ! ( await pathExists ( preDeployPath ) ) ) {
168206 await writeFile ( preDeployPath , generatePreDeployHook ( detectedOrm ) , 'utf-8' ) ;
169- await import ( 'fs/promises' ) . then ( ( fs ) => fs . chmod ( preDeployPath , 0o755 ) ) ;
207+ await chmod ( preDeployPath , 0o755 ) ;
170208 }
171209
172210 if ( ! ( await pathExists ( postDeployPath ) ) ) {
173211 await writeFile ( postDeployPath , generatePostDeployHook ( ) , 'utf-8' ) ;
174- await import ( 'fs/promises' ) . then ( ( fs ) => fs . chmod ( postDeployPath , 0o755 ) ) ;
212+ await chmod ( postDeployPath , 0o755 ) ;
175213 }
176214
177215 if ( ! ( await pathExists ( ignorePath ) ) ) {
@@ -293,6 +331,22 @@ function generateConfig(opts: ConfigOptions): string {
293331 lines . push ( ` .pkgManager('${ opts . pkgManager } ')` ) ;
294332 }
295333
334+ if ( opts . dbType ) {
335+ if ( opts . dbType === 'sqlite' ) {
336+ lines . push ( ` .database({ type: 'sqlite', host: 'localhost', port: 0, name: '${ opts . dbName ?? './data.db' } ', user: '' })` ) ;
337+ } else {
338+ const dbOpts = [
339+ `type: '${ opts . dbType } '` ,
340+ `host: '${ opts . dbHost ?? 'localhost' } '` ,
341+ `port: ${ opts . dbPort ?? 5432 } ` ,
342+ `name: '${ opts . dbName ?? '' } '` ,
343+ `user: '${ opts . dbUser ?? '' } '` ,
344+ ...( opts . dbPassword ? [ `password: process.env.DB_PASSWORD ?? '${ opts . dbPassword } '` ] : [ `// password: process.env.DB_PASSWORD` ] ) ,
345+ ] ;
346+ lines . push ( ` .database({ ${ dbOpts . join ( ', ' ) } })` ) ;
347+ }
348+ }
349+
296350 lines . push ( ' .build();' ) ;
297351 lines . push ( '' ) ;
298352 return lines . join ( '\n' ) ;
0 commit comments