suthep 0.1.0 ā 0.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -71
- package/dist/commands/deploy.js +251 -37
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/down.js +179 -0
- package/dist/commands/down.js.map +1 -0
- package/dist/commands/redeploy.js +59 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/up.js +213 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/index.js +36 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/certbot.js +40 -3
- package/dist/utils/certbot.js.map +1 -1
- package/dist/utils/config-loader.js +30 -0
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/deployment.js +49 -16
- package/dist/utils/deployment.js.map +1 -1
- package/dist/utils/docker.js +396 -25
- package/dist/utils/docker.js.map +1 -1
- package/dist/utils/nginx.js +167 -8
- package/dist/utils/nginx.js.map +1 -1
- package/docs/README.md +25 -49
- package/docs/english/01-introduction.md +84 -0
- package/docs/english/02-installation.md +200 -0
- package/docs/english/03-quick-start.md +256 -0
- package/docs/english/04-configuration.md +358 -0
- package/docs/english/05-commands.md +363 -0
- package/docs/english/06-examples.md +456 -0
- package/docs/english/07-troubleshooting.md +417 -0
- package/docs/english/08-advanced.md +411 -0
- package/docs/english/README.md +48 -0
- package/docs/thai/01-introduction.md +84 -0
- package/docs/thai/02-installation.md +200 -0
- package/docs/thai/03-quick-start.md +256 -0
- package/docs/thai/04-configuration.md +358 -0
- package/docs/thai/05-commands.md +363 -0
- package/docs/thai/06-examples.md +456 -0
- package/docs/thai/07-troubleshooting.md +417 -0
- package/docs/thai/08-advanced.md +411 -0
- package/docs/thai/README.md +48 -0
- package/example/README.md +286 -53
- package/example/suthep-complete.yml +103 -0
- package/example/suthep-docker-only.yml +71 -0
- package/example/suthep-no-docker.yml +51 -0
- package/example/suthep-path-routing.yml +62 -0
- package/example/suthep.example.yml +89 -0
- package/package.json +1 -1
- package/src/commands/deploy.ts +322 -50
- package/src/commands/down.ts +240 -0
- package/src/commands/redeploy.ts +78 -0
- package/src/commands/up.ts +271 -0
- package/src/index.ts +62 -1
- package/src/types/config.ts +25 -24
- package/src/utils/certbot.ts +68 -6
- package/src/utils/config-loader.ts +40 -0
- package/src/utils/deployment.ts +61 -36
- package/src/utils/docker.ts +634 -30
- package/src/utils/nginx.ts +187 -4
- package/suthep-0.1.0-beta.1.tgz +0 -0
- package/suthep-0.1.1.tgz +0 -0
- package/suthep.example.yml +34 -0
- package/suthep.yml +39 -0
- package/test +0 -0
- package/docs/api-reference.md +0 -545
- package/docs/architecture.md +0 -367
- package/docs/commands.md +0 -273
- package/docs/configuration.md +0 -347
- package/docs/examples.md +0 -537
- package/docs/getting-started.md +0 -197
- package/docs/troubleshooting.md +0 -441
- package/example/docker-compose.yml +0 -72
- package/example/suthep.yml +0 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.js","sources":["../../src/commands/deploy.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport path from 'path'\nimport { requestCertificate } from '../utils/certbot'\nimport { loadConfig } from '../utils/config-loader'\nimport { deployService, performHealthCheck } from '../utils/deployment'\nimport { startDockerContainer } from '../utils/docker'\nimport { enableSite, generateNginxConfig, reloadNginx } from '../utils/nginx'\n\ninterface DeployOptions {\n file: string\n https: boolean\n nginx: boolean\n}\n\nexport async function deployCommand(options: DeployOptions): Promise<void> {\n console.log(chalk.blue.bold('\\nš Deploying Services\\n'))\n\n try {\n // Load configuration\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n console.log(chalk.cyan(`š Loading configuration from ${options.file}...`))\n const config = await loadConfig(options.file)\n\n console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`))\n console.log(chalk.dim(` Services: ${config.services.map((s) => s.name).join(', ')}\\n`))\n\n // Deploy each service\n for (const service of config.services) {\n console.log(chalk.cyan(`\\nš¦ Deploying service: ${service.name}`))\n\n try {\n // Start Docker container if configured\n if (service.docker) {\n console.log(chalk.dim(' š³ Managing Docker container...'))\n await startDockerContainer(service)\n }\n\n // Deploy the service\n await deployService(service, config.deployment)\n\n // Generate and configure Nginx\n if (options.nginx) {\n console.log(chalk.dim(' āļø Configuring Nginx reverse proxy...'))\n const nginxConfigContent = generateNginxConfig(service, false)\n const nginxConfigPath = path.join(config.nginx.configPath, `${service.name}.conf`)\n\n await fs.writeFile(nginxConfigPath, nginxConfigContent)\n await enableSite(service.name, config.nginx.configPath)\n\n console.log(chalk.green(` ā
Nginx configured for ${service.domains.join(', ')}`))\n }\n\n // Setup HTTPS with Certbot\n if (options.https && service.domains.length > 0) {\n console.log(chalk.dim(' š Setting up HTTPS certificates...'))\n\n for (const domain of service.domains) {\n try {\n await requestCertificate(domain, config.certbot.email, config.certbot.staging)\n console.log(chalk.green(` ā
SSL certificate obtained for ${domain}`))\n } catch (error) {\n console.log(\n chalk.yellow(\n ` ā ļø Failed to obtain SSL for ${domain}: ${\n error instanceof Error ? error.message : error\n }`\n )\n )\n }\n }\n\n // Update Nginx config with HTTPS\n if (options.nginx) {\n const nginxConfigContent = generateNginxConfig(service, true)\n const nginxConfigPath = path.join(config.nginx.configPath, `${service.name}.conf`)\n await fs.writeFile(nginxConfigPath, nginxConfigContent)\n }\n }\n\n // Reload Nginx after all configurations\n if (options.nginx) {\n console.log(chalk.dim(' š Reloading Nginx...'))\n await reloadNginx(config.nginx.reloadCommand)\n }\n\n // Perform health check\n if (service.healthCheck) {\n console.log(chalk.dim(` š„ Performing health check...`))\n const isHealthy = await performHealthCheck(\n `http://localhost:${service.port}${service.healthCheck.path}`,\n config.deployment.healthCheckTimeout\n )\n\n if (isHealthy) {\n console.log(chalk.green(` ā
Service ${service.name} is healthy`))\n } else {\n throw new Error(`Health check failed for service ${service.name}`)\n }\n }\n\n console.log(chalk.green.bold(`\\n⨠Service ${service.name} deployed successfully!`))\n } catch (error) {\n console.error(\n chalk.red(`\\nā Failed to deploy service ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n console.log(chalk.green.bold('\\nš All services deployed successfully!\\n'))\n\n // Print service URLs\n console.log(chalk.cyan('š Service URLs:'))\n for (const service of config.services) {\n for (const domain of service.domains) {\n const protocol = options.https ? 'https' : 'http'\n console.log(chalk.dim(` ${service.name}: ${protocol}://${domain}`))\n }\n }\n console.log()\n } catch (error) {\n console.error(\n chalk.red('\\nā Deployment failed:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":";;;;;;;;AAeA,eAAsB,cAAc,SAAuC;AACzE,UAAQ,IAAI,MAAM,KAAK,KAAK,2BAA2B,CAAC;AAExD,MAAI;AAEF,QAAI,CAAE,MAAM,GAAG,WAAW,QAAQ,IAAI,GAAI;AACxC,YAAM,IAAI,MAAM,iCAAiC,QAAQ,IAAI,EAAE;AAAA,IACjE;AAEA,YAAQ,IAAI,MAAM,KAAK,iCAAiC,QAAQ,IAAI,KAAK,CAAC;AAC1E,UAAM,SAAS,MAAM,WAAW,QAAQ,IAAI;AAE5C,YAAQ,IAAI,MAAM,MAAM,uCAAuC,OAAO,QAAQ,IAAI,EAAE,CAAC;AACrF,YAAQ,IAAI,MAAM,IAAI,gBAAgB,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,CAAI,CAAC;AAGxF,eAAW,WAAW,OAAO,UAAU;AACrC,cAAQ,IAAI,MAAM,KAAK;AAAA,wBAA2B,QAAQ,IAAI,EAAE,CAAC;AAEjE,UAAI;AAEF,YAAI,QAAQ,QAAQ;AAClB,kBAAQ,IAAI,MAAM,IAAI,mCAAmC,CAAC;AAC1D,gBAAM,qBAAqB,OAAO;AAAA,QACpC;AAGA,cAAM,cAAc,SAAS,OAAO,UAAU;AAG9C,YAAI,QAAQ,OAAO;AACjB,kBAAQ,IAAI,MAAM,IAAI,0CAA0C,CAAC;AACjE,gBAAM,qBAAqB,oBAAoB,SAAS,KAAK;AAC7D,gBAAM,kBAAkB,KAAK,KAAK,OAAO,MAAM,YAAY,GAAG,QAAQ,IAAI,OAAO;AAEjF,gBAAM,GAAG,UAAU,iBAAiB,kBAAkB;AACtD,gBAAM,WAAW,QAAQ,MAAM,OAAO,MAAM,UAAU;AAEtD,kBAAQ,IAAI,MAAM,MAAM,4BAA4B,QAAQ,QAAQ,KAAK,IAAI,CAAC,EAAE,CAAC;AAAA,QACnF;AAGA,YAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,GAAG;AAC/C,kBAAQ,IAAI,MAAM,IAAI,uCAAuC,CAAC;AAE9D,qBAAW,UAAU,QAAQ,SAAS;AACpC,gBAAI;AACF,oBAAM,mBAAmB,QAAQ,OAAO,QAAQ,OAAO,OAAO,QAAQ,OAAO;AAC7E,sBAAQ,IAAI,MAAM,MAAM,oCAAoC,MAAM,EAAE,CAAC;AAAA,YACvE,SAAS,OAAO;AACd,sBAAQ;AAAA,gBACN,MAAM;AAAA,kBACJ,kCAAkC,MAAM,KACtC,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,gBAAA;AAAA,cACF;AAAA,YAEJ;AAAA,UACF;AAGA,cAAI,QAAQ,OAAO;AACjB,kBAAM,qBAAqB,oBAAoB,SAAS,IAAI;AAC5D,kBAAM,kBAAkB,KAAK,KAAK,OAAO,MAAM,YAAY,GAAG,QAAQ,IAAI,OAAO;AACjF,kBAAM,GAAG,UAAU,iBAAiB,kBAAkB;AAAA,UACxD;AAAA,QACF;AAGA,YAAI,QAAQ,OAAO;AACjB,kBAAQ,IAAI,MAAM,IAAI,yBAAyB,CAAC;AAChD,gBAAM,YAAY,OAAO,MAAM,aAAa;AAAA,QAC9C;AAGA,YAAI,QAAQ,aAAa;AACvB,kBAAQ,IAAI,MAAM,IAAI,iCAAiC,CAAC;AACxD,gBAAM,YAAY,MAAM;AAAA,YACtB,oBAAoB,QAAQ,IAAI,GAAG,QAAQ,YAAY,IAAI;AAAA,YAC3D,OAAO,WAAW;AAAA,UAAA;AAGpB,cAAI,WAAW;AACb,oBAAQ,IAAI,MAAM,MAAM,eAAe,QAAQ,IAAI,aAAa,CAAC;AAAA,UACnE,OAAO;AACL,kBAAM,IAAI,MAAM,mCAAmC,QAAQ,IAAI,EAAE;AAAA,UACnE;AAAA,QACF;AAEA,gBAAQ,IAAI,MAAM,MAAM,KAAK;AAAA,YAAe,QAAQ,IAAI,yBAAyB,CAAC;AAAA,MACpF,SAAS,OAAO;AACd,gBAAQ;AAAA,UACN,MAAM,IAAI;AAAA,6BAAgC,QAAQ,IAAI,GAAG;AAAA,UACzD,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAAA;AAE3C,cAAM;AAAA,MACR;AAAA,IACF;AAEA,YAAQ,IAAI,MAAM,MAAM,KAAK,4CAA4C,CAAC;AAG1E,YAAQ,IAAI,MAAM,KAAK,kBAAkB,CAAC;AAC1C,eAAW,WAAW,OAAO,UAAU;AACrC,iBAAW,UAAU,QAAQ,SAAS;AACpC,cAAM,WAAW,QAAQ,QAAQ,UAAU;AAC3C,gBAAQ,IAAI,MAAM,IAAI,MAAM,QAAQ,IAAI,KAAK,QAAQ,MAAM,MAAM,EAAE,CAAC;AAAA,MACtE;AAAA,IACF;AACA,YAAQ,IAAA;AAAA,EACV,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,MAAM,IAAI,wBAAwB;AAAA,MAClC,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAAA;AAE3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;"}
|
|
1
|
+
{"version":3,"file":"deploy.js","sources":["../../src/commands/deploy.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { certificateExists, requestCertificate } from '../utils/certbot'\nimport { loadConfig } from '../utils/config-loader'\nimport { deployService, performHealthCheck } from '../utils/deployment'\nimport {\n cleanupTempContainer,\n startDockerContainer,\n startDockerContainerZeroDowntime,\n swapContainersForZeroDowntime,\n type ZeroDowntimeContainerInfo,\n} from '../utils/docker'\nimport {\n enableSite,\n generateMultiServiceNginxConfig,\n generateNginxConfig,\n reloadNginx,\n writeNginxConfig,\n} from '../utils/nginx'\n\ninterface DeployOptions {\n file: string\n https: boolean\n nginx: boolean\n}\n\nexport async function deployCommand(options: DeployOptions): Promise<void> {\n console.log(chalk.blue.bold('\\nš Deploying Services\\n'))\n\n try {\n // Load configuration\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n console.log(chalk.cyan(`š Loading configuration from ${options.file}...`))\n const config = await loadConfig(options.file)\n\n console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`))\n console.log(chalk.dim(` Services: ${config.services.map((s) => s.name).join(', ')}\\n`))\n\n // Group services by domain\n const domainToServices = new Map<string, ServiceConfig[]>()\n const allDomains = new Set<string>()\n\n for (const service of config.services) {\n for (const domain of service.domains) {\n allDomains.add(domain)\n if (!domainToServices.has(domain)) {\n domainToServices.set(domain, [])\n }\n domainToServices.get(domain)!.push(service)\n }\n }\n\n // Deploy each service (Docker, health checks, etc.)\n // Track zero-downtime info for services that need it\n const serviceTempInfo = new Map<string, ZeroDowntimeContainerInfo | null>()\n\n for (const service of config.services) {\n console.log(chalk.cyan(`\\nš¦ Deploying service: ${service.name}`))\n\n try {\n // Start Docker container if configured\n if (service.docker) {\n console.log(chalk.dim(' š³ Managing Docker container...'))\n\n // Use zero-downtime deployment if strategy is blue-green or rolling\n if (\n config.deployment.strategy === 'blue-green' ||\n config.deployment.strategy === 'rolling'\n ) {\n const tempInfo = await startDockerContainerZeroDowntime(service)\n serviceTempInfo.set(service.name, tempInfo)\n\n if (tempInfo && tempInfo.oldContainerExists) {\n console.log(\n chalk.cyan(\n ` š Zero-downtime deployment: new container on port ${tempInfo.tempPort}`\n )\n )\n }\n } else {\n // Fallback to regular deployment\n await startDockerContainer(service)\n serviceTempInfo.set(service.name, null)\n }\n } else {\n serviceTempInfo.set(service.name, null)\n }\n\n // Deploy the service (with temp info for zero-downtime)\n const tempInfo = serviceTempInfo.get(service.name) || null\n await deployService(service, config.deployment, tempInfo)\n\n // Perform health check on appropriate port\n if (service.healthCheck) {\n console.log(chalk.dim(` š„ Performing health check...`))\n const checkPort =\n tempInfo && tempInfo.oldContainerExists ? tempInfo.tempPort : service.port\n const isHealthy = await performHealthCheck(\n `http://localhost:${checkPort}${service.healthCheck.path}`,\n config.deployment.healthCheckTimeout\n )\n\n if (isHealthy) {\n console.log(chalk.green(` ā
Service ${service.name} is healthy`))\n } else {\n throw new Error(`Health check failed for service ${service.name}`)\n }\n }\n\n console.log(chalk.green.bold(`⨠Service ${service.name} deployed successfully!`))\n } catch (error) {\n console.error(\n chalk.red(`\\nā Failed to deploy service ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Helper function to generate nginx configs with optional port overrides\n const generateNginxConfigsForDomain = (\n domain: string,\n withHttps: boolean,\n portOverrides?: Map<string, number>\n ): string => {\n const servicesForDomain = domainToServices.get(domain)!\n if (servicesForDomain.length === 1) {\n const service = servicesForDomain[0]\n const portOverride = portOverrides?.get(service.name)\n return generateNginxConfig(service, withHttps, portOverride)\n } else {\n return generateMultiServiceNginxConfig(servicesForDomain, domain, withHttps, portOverrides)\n }\n }\n\n // Check if we need zero-downtime nginx updates (any service has temp container)\n const needsZeroDowntimeNginx = Array.from(serviceTempInfo.values()).some(\n (info) => info !== null && info.oldContainerExists\n )\n\n // Configure Nginx per domain\n if (options.nginx) {\n // If zero-downtime, first update nginx to point to temp ports\n if (needsZeroDowntimeNginx) {\n console.log(chalk.cyan(`\\nāļø Updating Nginx for zero-downtime deployment...`))\n\n // Build port override map for temp ports\n const tempPortOverrides = new Map<string, number>()\n for (const service of config.services) {\n const tempInfo = serviceTempInfo.get(service.name)\n if (tempInfo && tempInfo.oldContainerExists) {\n tempPortOverrides.set(service.name, tempInfo.tempPort)\n }\n }\n\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n try {\n const nginxConfigContent = generateNginxConfigsForDomain(\n domain,\n false,\n tempPortOverrides\n )\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n await enableSite(configName, config.nginx.configPath)\n console.log(chalk.green(` ā
Nginx updated for ${domain} (temporary ports)`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to update Nginx for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Reload nginx to switch to temp ports (graceful reload, no connection drops)\n console.log(chalk.cyan(`\\nš Reloading Nginx to switch to new containers...`))\n await reloadNginx(config.nginx.reloadCommand)\n console.log(chalk.green(` ā
Nginx reloaded, traffic now routed to new containers`))\n\n // Now swap containers (stop old, promote new)\n console.log(chalk.cyan(`\\nš Swapping containers for zero-downtime...`))\n for (const service of config.services) {\n const tempInfo = serviceTempInfo.get(service.name)\n if (tempInfo && tempInfo.oldContainerExists && service.docker) {\n try {\n await swapContainersForZeroDowntime(service, tempInfo)\n console.log(chalk.green(` ā
Container swapped for ${service.name}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to swap container for ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n\n // Update nginx back to original ports (before stopping temp containers)\n console.log(chalk.cyan(`\\nāļø Updating Nginx back to production ports...`))\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n try {\n const nginxConfigContent = generateNginxConfigsForDomain(domain, false)\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n await enableSite(configName, config.nginx.configPath)\n console.log(chalk.green(` ā
Nginx updated for ${domain} (production ports)`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to update Nginx for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Reload nginx to switch to production ports (graceful reload)\n console.log(chalk.cyan(`\\nš Reloading Nginx to switch to production ports...`))\n await reloadNginx(config.nginx.reloadCommand)\n console.log(chalk.green(` ā
Nginx reloaded, traffic now routed to production containers`))\n\n // Clean up temp containers (nginx already pointing to production, so safe to remove)\n console.log(chalk.cyan(`\\nš§¹ Cleaning up temporary containers...`))\n for (const service of config.services) {\n const tempInfo = serviceTempInfo.get(service.name)\n if (tempInfo && tempInfo.oldContainerExists) {\n await cleanupTempContainer(tempInfo.tempContainerName)\n }\n }\n } else {\n // Regular nginx configuration (no zero-downtime needed)\n console.log(chalk.cyan(`\\nāļø Configuring Nginx reverse proxy...`))\n\n for (const domain of allDomains) {\n const servicesForDomain = domainToServices.get(domain)!\n const configName = domain.replace(/\\./g, '_')\n\n try {\n // Log domain and services configuration\n if (servicesForDomain.length > 1) {\n console.log(\n chalk.cyan(\n ` š Configuring ${domain} with ${\n servicesForDomain.length\n } services: ${servicesForDomain.map((s) => s.name).join(', ')}`\n )\n )\n console.log(\n chalk.dim(\n ` All services will share the same nginx config file: ${configName}.conf`\n )\n )\n }\n\n // Generate Nginx config\n const nginxConfigContent = generateNginxConfigsForDomain(domain, false)\n\n // Check if config file already exists and write/override it\n const wasOverridden = await writeNginxConfig(\n configName,\n config.nginx.configPath,\n nginxConfigContent\n )\n\n if (wasOverridden) {\n console.log(\n chalk.yellow(\n ` š Nginx config \"${configName}.conf\" already exists, deleting and recreating with new configuration...`\n )\n )\n }\n\n await enableSite(configName, config.nginx.configPath)\n\n console.log(chalk.green(` ā
Nginx configured for ${domain}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to configure Nginx for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n }\n\n // Setup HTTPS with Certbot (per domain, not per service)\n if (options.https && allDomains.size > 0) {\n console.log(chalk.cyan(`\\nš Setting up HTTPS certificates...`))\n\n for (const domain of allDomains) {\n try {\n // Check if certificate already exists\n const exists = await certificateExists(domain)\n if (exists) {\n console.log(\n chalk.green(\n ` ā
SSL certificate already exists for ${domain}, skipping certificate creation`\n )\n )\n console.log(\n chalk.dim(` Using existing certificate from /etc/letsencrypt/live/${domain}/`)\n )\n } else {\n // Request new certificate\n console.log(chalk.cyan(` š Requesting SSL certificate for ${domain}...`))\n try {\n await requestCertificate(domain, config.certbot.email, config.certbot.staging)\n console.log(chalk.green(` ā
SSL certificate obtained for ${domain}`))\n } catch (error: any) {\n // Check if error is because certificate already exists (race condition or check missed it)\n const errorMessage = error?.message || String(error) || ''\n if (\n errorMessage.includes('already exists') ||\n errorMessage.includes('Skipping certificate creation')\n ) {\n console.log(\n chalk.green(\n ` ā
SSL certificate already exists for ${domain} (detected during request), skipping...`\n )\n )\n } else {\n throw error // Re-throw if it's a different error\n }\n }\n }\n } catch (error) {\n console.log(\n chalk.yellow(\n ` ā ļø Failed to obtain SSL for ${domain}: ${\n error instanceof Error ? error.message : error\n }`\n )\n )\n }\n }\n\n // Update Nginx configs with HTTPS\n if (options.nginx) {\n console.log(chalk.cyan(`\\nš Updating Nginx configs with HTTPS...`))\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n\n try {\n const nginxConfigContent = generateNginxConfigsForDomain(domain, true)\n const wasOverridden = await writeNginxConfig(\n configName,\n config.nginx.configPath,\n nginxConfigContent\n )\n\n if (wasOverridden) {\n console.log(\n chalk.yellow(\n ` š Nginx config \"${configName}.conf\" already exists, deleting and recreating with new HTTPS configuration...`\n )\n )\n }\n console.log(chalk.green(` ā
HTTPS config updated for ${domain}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to update HTTPS config for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n }\n\n // Final reload Nginx after all configurations (only if we didn't already reload for zero-downtime)\n if (options.nginx && !needsZeroDowntimeNginx) {\n console.log(chalk.cyan(`\\nš Reloading Nginx...`))\n await reloadNginx(config.nginx.reloadCommand)\n } else if (options.nginx && needsZeroDowntimeNginx) {\n // Final reload after HTTPS update\n console.log(chalk.cyan(`\\nš Final Nginx reload with HTTPS...`))\n await reloadNginx(config.nginx.reloadCommand)\n }\n\n console.log(chalk.green.bold('\\nš All services deployed successfully!\\n'))\n\n // Print service URLs\n console.log(chalk.cyan('š Service URLs:'))\n for (const service of config.services) {\n for (const domain of service.domains) {\n const protocol = options.https ? 'https' : 'http'\n const servicePath = service.path || '/'\n const fullPath = servicePath === '/' ? '' : servicePath\n console.log(chalk.dim(` ${service.name}: ${protocol}://${domain}${fullPath}`))\n }\n }\n console.log()\n } catch (error) {\n console.error(\n chalk.red('\\nā Deployment failed:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":["tempInfo"],"mappings":"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"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { loadConfig } from "../utils/config-loader.js";
|
|
4
|
+
import { stopDockerContainer, removeDockerContainer, isContainerRunning } from "../utils/docker.js";
|
|
5
|
+
import { disableSite, generateNginxConfig, generateMultiServiceNginxConfig, writeNginxConfig, enableSite, reloadNginx } from "../utils/nginx.js";
|
|
6
|
+
async function downCommand(options) {
|
|
7
|
+
console.log(chalk.blue.bold("\nš Bringing Down Services\n"));
|
|
8
|
+
try {
|
|
9
|
+
if (!await fs.pathExists(options.file)) {
|
|
10
|
+
throw new Error(`Configuration file not found: ${options.file}`);
|
|
11
|
+
}
|
|
12
|
+
console.log(chalk.cyan(`š Loading configuration from ${options.file}...`));
|
|
13
|
+
const config = await loadConfig(options.file);
|
|
14
|
+
console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`));
|
|
15
|
+
let servicesToDown = [];
|
|
16
|
+
if (options.all) {
|
|
17
|
+
servicesToDown = config.services;
|
|
18
|
+
console.log(
|
|
19
|
+
chalk.cyan(
|
|
20
|
+
`š Bringing down all services: ${servicesToDown.map((s) => s.name).join(", ")}
|
|
21
|
+
`
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
} else if (options.serviceName) {
|
|
25
|
+
const service = config.services.find((s) => s.name === options.serviceName);
|
|
26
|
+
if (!service) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Service "${options.serviceName}" not found in configuration. Available services: ${config.services.map((s) => s.name).join(", ")}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
servicesToDown = [service];
|
|
32
|
+
console.log(chalk.cyan(`š Bringing down service: ${options.serviceName}
|
|
33
|
+
`));
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error("Either specify a service name or use --all flag");
|
|
36
|
+
}
|
|
37
|
+
const domainToServices = /* @__PURE__ */ new Map();
|
|
38
|
+
const allDomains = /* @__PURE__ */ new Set();
|
|
39
|
+
for (const service of servicesToDown) {
|
|
40
|
+
for (const domain of service.domains) {
|
|
41
|
+
allDomains.add(domain);
|
|
42
|
+
if (!domainToServices.has(domain)) {
|
|
43
|
+
domainToServices.set(domain, []);
|
|
44
|
+
}
|
|
45
|
+
domainToServices.get(domain).push(service);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const service of servicesToDown) {
|
|
49
|
+
if (service.docker) {
|
|
50
|
+
console.log(chalk.cyan(`
|
|
51
|
+
š³ Stopping Docker container for service: ${service.name}`));
|
|
52
|
+
try {
|
|
53
|
+
const containerName = service.docker.container;
|
|
54
|
+
try {
|
|
55
|
+
await stopDockerContainer(containerName);
|
|
56
|
+
console.log(chalk.green(` ā
Stopped container: ${containerName}`));
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const errorMessage = error?.message || String(error) || "Unknown error";
|
|
59
|
+
if (errorMessage.toLowerCase().includes("no such container") || errorMessage.toLowerCase().includes("container not found")) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.yellow(` ā ļø Container ${containerName} not found (already stopped)`)
|
|
62
|
+
);
|
|
63
|
+
} else {
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
await removeDockerContainer(containerName);
|
|
69
|
+
console.log(chalk.green(` ā
Removed container: ${containerName}`));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const errorMessage = error?.message || String(error) || "Unknown error";
|
|
72
|
+
if (errorMessage.toLowerCase().includes("no such container") || errorMessage.toLowerCase().includes("container not found")) {
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.yellow(` ā ļø Container ${containerName} not found (already removed)`)
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(
|
|
82
|
+
chalk.red(` ā Failed to stop/remove container for service ${service.name}:`),
|
|
83
|
+
error instanceof Error ? error.message : error
|
|
84
|
+
);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (allDomains.size > 0) {
|
|
90
|
+
console.log(chalk.cyan(`
|
|
91
|
+
āļø Updating Nginx configurations...`));
|
|
92
|
+
const servicesBeingDowned = new Set(servicesToDown.map((s) => s.name));
|
|
93
|
+
for (const domain of allDomains) {
|
|
94
|
+
const configName = domain.replace(/\./g, "_");
|
|
95
|
+
const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain));
|
|
96
|
+
const remainingServices = allServicesForDomain.filter(
|
|
97
|
+
(s) => !servicesBeingDowned.has(s.name)
|
|
98
|
+
);
|
|
99
|
+
const activeServices = [];
|
|
100
|
+
for (const service of remainingServices) {
|
|
101
|
+
if (service.docker) {
|
|
102
|
+
const isRunning = await isContainerRunning(service.docker.container);
|
|
103
|
+
if (isRunning) {
|
|
104
|
+
activeServices.push(service);
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
activeServices.push(service);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
if (activeServices.length === 0) {
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.cyan(` š No active services on ${domain}, disabling Nginx config...`)
|
|
114
|
+
);
|
|
115
|
+
await disableSite(configName, config.nginx.configPath);
|
|
116
|
+
console.log(chalk.green(` ā
Disabled Nginx config for ${domain}`));
|
|
117
|
+
} else {
|
|
118
|
+
console.log(
|
|
119
|
+
chalk.cyan(
|
|
120
|
+
` š Regenerating Nginx config for ${domain} with ${activeServices.length} active service(s): ${activeServices.map((s) => s.name).join(", ")}`
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
let nginxConfigContent;
|
|
124
|
+
if (activeServices.length === 1) {
|
|
125
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], false);
|
|
126
|
+
} else {
|
|
127
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false);
|
|
128
|
+
}
|
|
129
|
+
const { certificateExists } = await import("../utils/certbot.js");
|
|
130
|
+
const hasHttps = await certificateExists(domain);
|
|
131
|
+
if (hasHttps) {
|
|
132
|
+
if (activeServices.length === 1) {
|
|
133
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], true);
|
|
134
|
+
} else {
|
|
135
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent);
|
|
139
|
+
await enableSite(configName, config.nginx.configPath);
|
|
140
|
+
console.log(
|
|
141
|
+
chalk.green(
|
|
142
|
+
` ā
Updated Nginx config for ${domain} (${activeServices.length} service(s) active)`
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error(
|
|
148
|
+
chalk.red(` ā Failed to update Nginx config for ${domain}:`),
|
|
149
|
+
error instanceof Error ? error.message : error
|
|
150
|
+
);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
console.log(chalk.cyan(`
|
|
155
|
+
š Reloading Nginx...`));
|
|
156
|
+
try {
|
|
157
|
+
await reloadNginx(config.nginx.reloadCommand);
|
|
158
|
+
console.log(chalk.green(` ā
Nginx reloaded`));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(
|
|
161
|
+
chalk.red(` ā Failed to reload Nginx:`),
|
|
162
|
+
error instanceof Error ? error.message : error
|
|
163
|
+
);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
console.log(chalk.green.bold("\nā
Services brought down successfully!\n"));
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error(
|
|
170
|
+
chalk.red("\nā Failed to bring down services:"),
|
|
171
|
+
error instanceof Error ? error.message : error
|
|
172
|
+
);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
downCommand
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=down.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"down.js","sources":["../../src/commands/down.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { loadConfig } from '../utils/config-loader'\nimport { isContainerRunning, removeDockerContainer, stopDockerContainer } from '../utils/docker'\nimport {\n disableSite,\n enableSite,\n generateMultiServiceNginxConfig,\n generateNginxConfig,\n reloadNginx,\n writeNginxConfig,\n} from '../utils/nginx'\n\ninterface DownOptions {\n file: string\n all: boolean\n serviceName?: string\n}\n\nexport async function downCommand(options: DownOptions): Promise<void> {\n console.log(chalk.blue.bold('\\nš Bringing Down Services\\n'))\n\n try {\n // Load configuration\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n console.log(chalk.cyan(`š Loading configuration from ${options.file}...`))\n const config = await loadConfig(options.file)\n\n console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`))\n\n // Determine which services to bring down\n let servicesToDown: ServiceConfig[] = []\n\n if (options.all) {\n servicesToDown = config.services\n console.log(\n chalk.cyan(\n `š Bringing down all services: ${servicesToDown.map((s) => s.name).join(', ')}\\n`\n )\n )\n } else if (options.serviceName) {\n const service = config.services.find((s) => s.name === options.serviceName)\n if (!service) {\n throw new Error(\n `Service \"${\n options.serviceName\n }\" not found in configuration. Available services: ${config.services\n .map((s) => s.name)\n .join(', ')}`\n )\n }\n servicesToDown = [service]\n console.log(chalk.cyan(`š Bringing down service: ${options.serviceName}\\n`))\n } else {\n throw new Error('Either specify a service name or use --all flag')\n }\n\n // Group services by domain for nginx config management\n const domainToServices = new Map<string, ServiceConfig[]>()\n const allDomains = new Set<string>()\n\n for (const service of servicesToDown) {\n for (const domain of service.domains) {\n allDomains.add(domain)\n if (!domainToServices.has(domain)) {\n domainToServices.set(domain, [])\n }\n domainToServices.get(domain)!.push(service)\n }\n }\n\n // Stop and remove Docker containers\n for (const service of servicesToDown) {\n if (service.docker) {\n console.log(chalk.cyan(`\\nš³ Stopping Docker container for service: ${service.name}`))\n try {\n const containerName = service.docker.container\n\n // Stop container\n try {\n await stopDockerContainer(containerName)\n console.log(chalk.green(` ā
Stopped container: ${containerName}`))\n } catch (error: any) {\n const errorMessage = error?.message || String(error) || 'Unknown error'\n if (\n errorMessage.toLowerCase().includes('no such container') ||\n errorMessage.toLowerCase().includes('container not found')\n ) {\n console.log(\n chalk.yellow(` ā ļø Container ${containerName} not found (already stopped)`)\n )\n } else {\n throw error\n }\n }\n\n // Remove container\n try {\n await removeDockerContainer(containerName)\n console.log(chalk.green(` ā
Removed container: ${containerName}`))\n } catch (error: any) {\n const errorMessage = error?.message || String(error) || 'Unknown error'\n if (\n errorMessage.toLowerCase().includes('no such container') ||\n errorMessage.toLowerCase().includes('container not found')\n ) {\n console.log(\n chalk.yellow(` ā ļø Container ${containerName} not found (already removed)`)\n )\n } else {\n throw error\n }\n }\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to stop/remove container for service ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n\n // Handle Nginx configs by domain\n // Check which services remain active for each domain\n if (allDomains.size > 0) {\n console.log(chalk.cyan(`\\nāļø Updating Nginx configurations...`))\n\n // Create a set of service names being brought down for quick lookup\n const servicesBeingDowned = new Set(servicesToDown.map((s) => s.name))\n\n // For each domain, find all services that use it (from all config services)\n // and determine which ones remain active\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n\n // Find all services that use this domain (from entire config)\n const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain))\n\n // Filter out services being brought down\n const remainingServices = allServicesForDomain.filter(\n (s) => !servicesBeingDowned.has(s.name)\n )\n\n // Check if remaining services are actually running (have active containers)\n const activeServices: ServiceConfig[] = []\n for (const service of remainingServices) {\n if (service.docker) {\n const isRunning = await isContainerRunning(service.docker.container)\n if (isRunning) {\n activeServices.push(service)\n }\n } else {\n // Service without docker - assume it's running if not being brought down\n activeServices.push(service)\n }\n }\n\n try {\n if (activeServices.length === 0) {\n // No active services on this domain, disable the config\n console.log(\n chalk.cyan(` š No active services on ${domain}, disabling Nginx config...`)\n )\n await disableSite(configName, config.nginx.configPath)\n console.log(chalk.green(` ā
Disabled Nginx config for ${domain}`))\n } else {\n // Regenerate config with remaining active services\n console.log(\n chalk.cyan(\n ` š Regenerating Nginx config for ${domain} with ${\n activeServices.length\n } active service(s): ${activeServices.map((s) => s.name).join(', ')}`\n )\n )\n\n // Generate config for remaining services\n let nginxConfigContent: string\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], false)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false)\n }\n\n // Check if HTTPS is enabled (check if certificate exists)\n const { certificateExists } = await import('../utils/certbot')\n const hasHttps = await certificateExists(domain)\n if (hasHttps) {\n // Regenerate with HTTPS\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], true)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true)\n }\n }\n\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n await enableSite(configName, config.nginx.configPath)\n console.log(\n chalk.green(\n ` ā
Updated Nginx config for ${domain} (${activeServices.length} service(s) active)`\n )\n )\n }\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to update Nginx config for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Reload Nginx to apply changes\n console.log(chalk.cyan(`\\nš Reloading Nginx...`))\n try {\n await reloadNginx(config.nginx.reloadCommand)\n console.log(chalk.green(` ā
Nginx reloaded`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to reload Nginx:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n console.log(chalk.green.bold('\\nā
Services brought down successfully!\\n'))\n } catch (error) {\n console.error(\n chalk.red('\\nā Failed to bring down services:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { loadConfig } from "../utils/config-loader.js";
|
|
4
|
+
import { deployCommand } from "./deploy.js";
|
|
5
|
+
import { downCommand } from "./down.js";
|
|
6
|
+
async function redeployCommand(options) {
|
|
7
|
+
console.log(chalk.blue.bold("\nš Redeploying Services\n"));
|
|
8
|
+
try {
|
|
9
|
+
if (!await fs.pathExists(options.file)) {
|
|
10
|
+
throw new Error(`Configuration file not found: ${options.file}`);
|
|
11
|
+
}
|
|
12
|
+
const config = await loadConfig(options.file);
|
|
13
|
+
let servicesToRedeploy = [];
|
|
14
|
+
if (options.all) {
|
|
15
|
+
servicesToRedeploy = config.services;
|
|
16
|
+
console.log(
|
|
17
|
+
chalk.cyan(
|
|
18
|
+
`š Redeploying all services: ${servicesToRedeploy.map((s) => s.name).join(", ")}
|
|
19
|
+
`
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
} else if (options.serviceName) {
|
|
23
|
+
const service = config.services.find((s) => s.name === options.serviceName);
|
|
24
|
+
if (!service) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Service "${options.serviceName}" not found in configuration. Available services: ${config.services.map((s) => s.name).join(", ")}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
servicesToRedeploy = [service];
|
|
30
|
+
console.log(chalk.cyan(`š Redeploying service: ${options.serviceName}
|
|
31
|
+
`));
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error("Either specify a service name or use --all flag");
|
|
34
|
+
}
|
|
35
|
+
console.log(chalk.yellow("Step 1: Bringing down services...\n"));
|
|
36
|
+
await downCommand({
|
|
37
|
+
file: options.file,
|
|
38
|
+
all: options.all,
|
|
39
|
+
serviceName: options.serviceName
|
|
40
|
+
});
|
|
41
|
+
console.log(chalk.yellow("\nStep 2: Deploying services...\n"));
|
|
42
|
+
await deployCommand({
|
|
43
|
+
file: options.file,
|
|
44
|
+
https: options.https,
|
|
45
|
+
nginx: options.nginx
|
|
46
|
+
});
|
|
47
|
+
console.log(chalk.green.bold("\nā
Services redeployed successfully!\n"));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(
|
|
50
|
+
chalk.red("\nā Failed to redeploy services:"),
|
|
51
|
+
error instanceof Error ? error.message : error
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
redeployCommand
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=redeploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redeploy.js","sources":["../../src/commands/redeploy.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { loadConfig } from '../utils/config-loader'\nimport { deployCommand } from './deploy'\nimport { downCommand } from './down'\n\ninterface RedeployOptions {\n file: string\n all: boolean\n serviceName?: string\n https: boolean\n nginx: boolean\n}\n\nexport async function redeployCommand(options: RedeployOptions): Promise<void> {\n console.log(chalk.blue.bold('\\nš Redeploying Services\\n'))\n\n try {\n // Load configuration to validate service names\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n const config = await loadConfig(options.file)\n\n // Determine which services to redeploy\n let servicesToRedeploy: ServiceConfig[] = []\n\n if (options.all) {\n servicesToRedeploy = config.services\n console.log(\n chalk.cyan(\n `š Redeploying all services: ${servicesToRedeploy.map((s) => s.name).join(', ')}\\n`\n )\n )\n } else if (options.serviceName) {\n const service = config.services.find((s) => s.name === options.serviceName)\n if (!service) {\n throw new Error(\n `Service \"${\n options.serviceName\n }\" not found in configuration. Available services: ${config.services\n .map((s) => s.name)\n .join(', ')}`\n )\n }\n servicesToRedeploy = [service]\n console.log(chalk.cyan(`š Redeploying service: ${options.serviceName}\\n`))\n } else {\n throw new Error('Either specify a service name or use --all flag')\n }\n\n // Step 1: Bring down the services\n console.log(chalk.yellow('Step 1: Bringing down services...\\n'))\n await downCommand({\n file: options.file,\n all: options.all,\n serviceName: options.serviceName,\n })\n\n // Step 2: Deploy the services (which will bring them back up)\n console.log(chalk.yellow('\\nStep 2: Deploying services...\\n'))\n await deployCommand({\n file: options.file,\n https: options.https,\n nginx: options.nginx,\n })\n\n console.log(chalk.green.bold('\\nā
Services redeployed successfully!\\n'))\n } catch (error) {\n console.error(\n chalk.red('\\nā Failed to redeploy services:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":";;;;;AAeA,eAAsB,gBAAgB,SAAyC;AAC7E,UAAQ,IAAI,MAAM,KAAK,KAAK,6BAA6B,CAAC;AAE1D,MAAI;AAEF,QAAI,CAAE,MAAM,GAAG,WAAW,QAAQ,IAAI,GAAI;AACxC,YAAM,IAAI,MAAM,iCAAiC,QAAQ,IAAI,EAAE;AAAA,IACjE;AAEA,UAAM,SAAS,MAAM,WAAW,QAAQ,IAAI;AAG5C,QAAI,qBAAsC,CAAA;AAE1C,QAAI,QAAQ,KAAK;AACf,2BAAqB,OAAO;AAC5B,cAAQ;AAAA,QACN,MAAM;AAAA,UACJ,gCAAgC,mBAAmB,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,QAAA;AAAA,MAClF;AAAA,IAEJ,WAAW,QAAQ,aAAa;AAC9B,YAAM,UAAU,OAAO,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,WAAW;AAC1E,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,YACE,QAAQ,WACV,qDAAqD,OAAO,SACzD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI,CAAC;AAAA,QAAA;AAAA,MAEjB;AACA,2BAAqB,CAAC,OAAO;AAC7B,cAAQ,IAAI,MAAM,KAAK,2BAA2B,QAAQ,WAAW;AAAA,CAAI,CAAC;AAAA,IAC5E,OAAO;AACL,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,YAAQ,IAAI,MAAM,OAAO,qCAAqC,CAAC;AAC/D,UAAM,YAAY;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,aAAa,QAAQ;AAAA,IAAA,CACtB;AAGD,YAAQ,IAAI,MAAM,OAAO,mCAAmC,CAAC;AAC7D,UAAM,cAAc;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,IAAA,CAChB;AAED,YAAQ,IAAI,MAAM,MAAM,KAAK,yCAAyC,CAAC;AAAA,EACzE,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,MAAM,IAAI,kCAAkC;AAAA,MAC5C,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAAA;AAE3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { loadConfig } from "../utils/config-loader.js";
|
|
4
|
+
import { waitForService } from "../utils/deployment.js";
|
|
5
|
+
import { startDockerContainer, isContainerRunning } from "../utils/docker.js";
|
|
6
|
+
import { generateNginxConfig, generateMultiServiceNginxConfig, writeNginxConfig, enableSite, reloadNginx } from "../utils/nginx.js";
|
|
7
|
+
async function upCommand(options) {
|
|
8
|
+
console.log(chalk.blue.bold("\nš Bringing Up Services\n"));
|
|
9
|
+
try {
|
|
10
|
+
if (!await fs.pathExists(options.file)) {
|
|
11
|
+
throw new Error(`Configuration file not found: ${options.file}`);
|
|
12
|
+
}
|
|
13
|
+
console.log(chalk.cyan(`š Loading configuration from ${options.file}...`));
|
|
14
|
+
const config = await loadConfig(options.file);
|
|
15
|
+
console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`));
|
|
16
|
+
let servicesToUp = [];
|
|
17
|
+
if (options.all) {
|
|
18
|
+
servicesToUp = config.services;
|
|
19
|
+
console.log(
|
|
20
|
+
chalk.cyan(`š Bringing up all services: ${servicesToUp.map((s) => s.name).join(", ")}
|
|
21
|
+
`)
|
|
22
|
+
);
|
|
23
|
+
} else if (options.serviceName) {
|
|
24
|
+
const service = config.services.find((s) => s.name === options.serviceName);
|
|
25
|
+
if (!service) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Service "${options.serviceName}" not found in configuration. Available services: ${config.services.map((s) => s.name).join(", ")}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
servicesToUp = [service];
|
|
31
|
+
console.log(chalk.cyan(`š Bringing up service: ${options.serviceName}
|
|
32
|
+
`));
|
|
33
|
+
} else {
|
|
34
|
+
throw new Error("Either specify a service name or use --all flag");
|
|
35
|
+
}
|
|
36
|
+
const domainToServices = /* @__PURE__ */ new Map();
|
|
37
|
+
const allDomains = /* @__PURE__ */ new Set();
|
|
38
|
+
for (const service of servicesToUp) {
|
|
39
|
+
for (const domain of service.domains) {
|
|
40
|
+
allDomains.add(domain);
|
|
41
|
+
if (!domainToServices.has(domain)) {
|
|
42
|
+
domainToServices.set(domain, []);
|
|
43
|
+
}
|
|
44
|
+
domainToServices.get(domain).push(service);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const service of servicesToUp) {
|
|
48
|
+
if (service.docker) {
|
|
49
|
+
console.log(chalk.cyan(`
|
|
50
|
+
š³ Starting Docker container for service: ${service.name}`));
|
|
51
|
+
try {
|
|
52
|
+
await startDockerContainer(service);
|
|
53
|
+
console.log(chalk.green(` ā
Container started for service: ${service.name}`));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(
|
|
56
|
+
chalk.red(` ā Failed to start container for service ${service.name}:`),
|
|
57
|
+
error instanceof Error ? error.message : error
|
|
58
|
+
);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const service of servicesToUp) {
|
|
64
|
+
if (service.healthCheck) {
|
|
65
|
+
console.log(chalk.cyan(`
|
|
66
|
+
š„ Waiting for service ${service.name} to be healthy...`));
|
|
67
|
+
const isHealthy = await waitForService(service, config.deployment.healthCheckTimeout);
|
|
68
|
+
if (isHealthy) {
|
|
69
|
+
console.log(chalk.green(` ā
Service ${service.name} is healthy`));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(
|
|
72
|
+
chalk.yellow(` ā ļø Service ${service.name} health check timeout, continuing anyway...`)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (options.nginx && allDomains.size > 0) {
|
|
78
|
+
console.log(chalk.cyan(`
|
|
79
|
+
āļø Configuring Nginx reverse proxy...`));
|
|
80
|
+
const servicesBeingUpped = new Set(servicesToUp.map((s) => s.name));
|
|
81
|
+
for (const domain of allDomains) {
|
|
82
|
+
const configName = domain.replace(/\./g, "_");
|
|
83
|
+
const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain));
|
|
84
|
+
const activeServices = [];
|
|
85
|
+
for (const service of allServicesForDomain) {
|
|
86
|
+
if (service.docker) {
|
|
87
|
+
const isRunning = await isContainerRunning(service.docker.container);
|
|
88
|
+
if (isRunning) {
|
|
89
|
+
activeServices.push(service);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (servicesBeingUpped.has(service.name)) {
|
|
93
|
+
activeServices.push(service);
|
|
94
|
+
} else {
|
|
95
|
+
activeServices.push(service);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (activeServices.length === 0) {
|
|
100
|
+
console.log(
|
|
101
|
+
chalk.yellow(` ā ļø No active services found for ${domain}, skipping Nginx config`)
|
|
102
|
+
);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
if (activeServices.length > 1) {
|
|
107
|
+
console.log(
|
|
108
|
+
chalk.cyan(
|
|
109
|
+
` š Configuring ${domain} with ${activeServices.length} active service(s): ${activeServices.map((s) => s.name).join(", ")}`
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
console.log(
|
|
114
|
+
chalk.cyan(` š Configuring ${domain} for service: ${activeServices[0].name}`)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
let nginxConfigContent;
|
|
118
|
+
if (activeServices.length === 1) {
|
|
119
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], false);
|
|
120
|
+
} else {
|
|
121
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false);
|
|
122
|
+
}
|
|
123
|
+
await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent);
|
|
124
|
+
await enableSite(configName, config.nginx.configPath);
|
|
125
|
+
console.log(chalk.green(` ā
Nginx configured for ${domain}`));
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error(
|
|
128
|
+
chalk.red(` ā Failed to configure Nginx for ${domain}:`),
|
|
129
|
+
error instanceof Error ? error.message : error
|
|
130
|
+
);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (options.https) {
|
|
135
|
+
console.log(chalk.cyan(`
|
|
136
|
+
š Updating Nginx configs with HTTPS...`));
|
|
137
|
+
for (const domain of allDomains) {
|
|
138
|
+
const configName = domain.replace(/\./g, "_");
|
|
139
|
+
const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain));
|
|
140
|
+
const activeServices = [];
|
|
141
|
+
for (const service of allServicesForDomain) {
|
|
142
|
+
if (service.docker) {
|
|
143
|
+
const isRunning = await isContainerRunning(service.docker.container);
|
|
144
|
+
if (isRunning) {
|
|
145
|
+
activeServices.push(service);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
if (servicesBeingUpped.has(service.name)) {
|
|
149
|
+
activeServices.push(service);
|
|
150
|
+
} else {
|
|
151
|
+
activeServices.push(service);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (activeServices.length === 0) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
let nginxConfigContent;
|
|
160
|
+
if (activeServices.length === 1) {
|
|
161
|
+
nginxConfigContent = generateNginxConfig(activeServices[0], true);
|
|
162
|
+
} else {
|
|
163
|
+
nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true);
|
|
164
|
+
}
|
|
165
|
+
await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent);
|
|
166
|
+
console.log(chalk.green(` ā
HTTPS config updated for ${domain}`));
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(
|
|
169
|
+
chalk.red(` ā Failed to update HTTPS config for ${domain}:`),
|
|
170
|
+
error instanceof Error ? error.message : error
|
|
171
|
+
);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
console.log(chalk.cyan(`
|
|
177
|
+
š Reloading Nginx...`));
|
|
178
|
+
try {
|
|
179
|
+
await reloadNginx(config.nginx.reloadCommand);
|
|
180
|
+
console.log(chalk.green(` ā
Nginx reloaded`));
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(
|
|
183
|
+
chalk.red(` ā Failed to reload Nginx:`),
|
|
184
|
+
error instanceof Error ? error.message : error
|
|
185
|
+
);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
console.log(chalk.green.bold("\nā
Services brought up successfully!\n"));
|
|
190
|
+
if (allDomains.size > 0) {
|
|
191
|
+
console.log(chalk.cyan("š Service URLs:"));
|
|
192
|
+
for (const service of servicesToUp) {
|
|
193
|
+
for (const domain of service.domains) {
|
|
194
|
+
const protocol = options.https ? "https" : "http";
|
|
195
|
+
const servicePath = service.path || "/";
|
|
196
|
+
const fullPath = servicePath === "/" ? "" : servicePath;
|
|
197
|
+
console.log(chalk.dim(` ${service.name}: ${protocol}://${domain}${fullPath}`));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error(
|
|
204
|
+
chalk.red("\nā Failed to bring up services:"),
|
|
205
|
+
error instanceof Error ? error.message : error
|
|
206
|
+
);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
upCommand
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.js","sources":["../../src/commands/up.ts"],"sourcesContent":["import chalk from 'chalk'\nimport fs from 'fs-extra'\nimport type { ServiceConfig } from '../types/config'\nimport { loadConfig } from '../utils/config-loader'\nimport { waitForService } from '../utils/deployment'\nimport { isContainerRunning, startDockerContainer } from '../utils/docker'\nimport {\n enableSite,\n generateMultiServiceNginxConfig,\n generateNginxConfig,\n reloadNginx,\n writeNginxConfig,\n} from '../utils/nginx'\n\ninterface UpOptions {\n file: string\n all: boolean\n serviceName?: string\n https: boolean\n nginx: boolean\n}\n\nexport async function upCommand(options: UpOptions): Promise<void> {\n console.log(chalk.blue.bold('\\nš Bringing Up Services\\n'))\n\n try {\n // Load configuration\n if (!(await fs.pathExists(options.file))) {\n throw new Error(`Configuration file not found: ${options.file}`)\n }\n\n console.log(chalk.cyan(`š Loading configuration from ${options.file}...`))\n const config = await loadConfig(options.file)\n\n console.log(chalk.green(`ā
Configuration loaded for project: ${config.project.name}`))\n\n // Determine which services to bring up\n let servicesToUp: ServiceConfig[] = []\n\n if (options.all) {\n servicesToUp = config.services\n console.log(\n chalk.cyan(`š Bringing up all services: ${servicesToUp.map((s) => s.name).join(', ')}\\n`)\n )\n } else if (options.serviceName) {\n const service = config.services.find((s) => s.name === options.serviceName)\n if (!service) {\n throw new Error(\n `Service \"${\n options.serviceName\n }\" not found in configuration. Available services: ${config.services\n .map((s) => s.name)\n .join(', ')}`\n )\n }\n servicesToUp = [service]\n console.log(chalk.cyan(`š Bringing up service: ${options.serviceName}\\n`))\n } else {\n throw new Error('Either specify a service name or use --all flag')\n }\n\n // Group services by domain for nginx config management\n const domainToServices = new Map<string, ServiceConfig[]>()\n const allDomains = new Set<string>()\n\n for (const service of servicesToUp) {\n for (const domain of service.domains) {\n allDomains.add(domain)\n if (!domainToServices.has(domain)) {\n domainToServices.set(domain, [])\n }\n domainToServices.get(domain)!.push(service)\n }\n }\n\n // Start Docker containers\n for (const service of servicesToUp) {\n if (service.docker) {\n console.log(chalk.cyan(`\\nš³ Starting Docker container for service: ${service.name}`))\n try {\n await startDockerContainer(service)\n console.log(chalk.green(` ā
Container started for service: ${service.name}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to start container for service ${service.name}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n\n // Wait for services to be healthy\n for (const service of servicesToUp) {\n if (service.healthCheck) {\n console.log(chalk.cyan(`\\nš„ Waiting for service ${service.name} to be healthy...`))\n const isHealthy = await waitForService(service, config.deployment.healthCheckTimeout)\n if (isHealthy) {\n console.log(chalk.green(` ā
Service ${service.name} is healthy`))\n } else {\n console.log(\n chalk.yellow(` ā ļø Service ${service.name} health check timeout, continuing anyway...`)\n )\n }\n }\n }\n\n // Configure Nginx\n if (options.nginx && allDomains.size > 0) {\n console.log(chalk.cyan(`\\nāļø Configuring Nginx reverse proxy...`))\n\n // Create a set of service names being brought up for quick lookup\n const servicesBeingUpped = new Set(servicesToUp.map((s) => s.name))\n\n // For each domain, find all services that use it (from all config services)\n // and include all active services (both newly brought up and already running)\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n\n // Find all services that use this domain (from entire config)\n const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain))\n\n // Check which services are actually running (have active containers)\n const activeServices: ServiceConfig[] = []\n for (const service of allServicesForDomain) {\n if (service.docker) {\n const isRunning = await isContainerRunning(service.docker.container)\n if (isRunning) {\n activeServices.push(service)\n }\n } else {\n // Service without docker - include if it's being brought up or assume it's running\n if (servicesBeingUpped.has(service.name)) {\n activeServices.push(service)\n } else {\n // For non-docker services, assume they're running if not explicitly being brought up\n // This is a best-effort approach\n activeServices.push(service)\n }\n }\n }\n\n if (activeServices.length === 0) {\n console.log(\n chalk.yellow(` ā ļø No active services found for ${domain}, skipping Nginx config`)\n )\n continue\n }\n\n try {\n // Log domain and services configuration\n if (activeServices.length > 1) {\n console.log(\n chalk.cyan(\n ` š Configuring ${domain} with ${\n activeServices.length\n } active service(s): ${activeServices.map((s) => s.name).join(', ')}`\n )\n )\n } else {\n console.log(\n chalk.cyan(` š Configuring ${domain} for service: ${activeServices[0].name}`)\n )\n }\n\n // Generate Nginx config for all active services on this domain\n let nginxConfigContent: string\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], false)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, false)\n }\n\n // Write config file\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n await enableSite(configName, config.nginx.configPath)\n\n console.log(chalk.green(` ā
Nginx configured for ${domain}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to configure Nginx for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n // Update with HTTPS if enabled\n if (options.https) {\n console.log(chalk.cyan(`\\nš Updating Nginx configs with HTTPS...`))\n for (const domain of allDomains) {\n const configName = domain.replace(/\\./g, '_')\n\n // Find all active services for this domain again\n const allServicesForDomain = config.services.filter((s) => s.domains.includes(domain))\n const activeServices: ServiceConfig[] = []\n for (const service of allServicesForDomain) {\n if (service.docker) {\n const isRunning = await isContainerRunning(service.docker.container)\n if (isRunning) {\n activeServices.push(service)\n }\n } else {\n if (servicesBeingUpped.has(service.name)) {\n activeServices.push(service)\n } else {\n activeServices.push(service)\n }\n }\n }\n\n if (activeServices.length === 0) {\n continue\n }\n\n try {\n let nginxConfigContent: string\n if (activeServices.length === 1) {\n nginxConfigContent = generateNginxConfig(activeServices[0], true)\n } else {\n nginxConfigContent = generateMultiServiceNginxConfig(activeServices, domain, true)\n }\n await writeNginxConfig(configName, config.nginx.configPath, nginxConfigContent)\n console.log(chalk.green(` ā
HTTPS config updated for ${domain}`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to update HTTPS config for ${domain}:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n }\n\n // Reload Nginx\n console.log(chalk.cyan(`\\nš Reloading Nginx...`))\n try {\n await reloadNginx(config.nginx.reloadCommand)\n console.log(chalk.green(` ā
Nginx reloaded`))\n } catch (error) {\n console.error(\n chalk.red(` ā Failed to reload Nginx:`),\n error instanceof Error ? error.message : error\n )\n throw error\n }\n }\n\n console.log(chalk.green.bold('\\nā
Services brought up successfully!\\n'))\n\n // Print service URLs\n if (allDomains.size > 0) {\n console.log(chalk.cyan('š Service URLs:'))\n for (const service of servicesToUp) {\n for (const domain of service.domains) {\n const protocol = options.https ? 'https' : 'http'\n const servicePath = service.path || '/'\n const fullPath = servicePath === '/' ? '' : servicePath\n console.log(chalk.dim(` ${service.name}: ${protocol}://${domain}${fullPath}`))\n }\n }\n console.log()\n }\n } catch (error) {\n console.error(\n chalk.red('\\nā Failed to bring up services:'),\n error instanceof Error ? error.message : error\n )\n process.exit(1)\n }\n}\n"],"names":[],"mappings":"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"}
|