@layr-labs/ecloud-cli 0.4.3 → 0.5.0-dev.3
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/VERSION +2 -2
- package/dist/commands/auth/login.js +84 -54
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/auth/migrate.js +66 -30
- package/dist/commands/auth/migrate.js.map +1 -1
- package/dist/commands/auth/whoami.js +0 -1
- package/dist/commands/auth/whoami.js.map +1 -1
- package/dist/commands/billing/__tests__/status.test.js +11 -9
- package/dist/commands/billing/__tests__/status.test.js.map +1 -1
- package/dist/commands/billing/__tests__/subscribe.test.js +11 -9
- package/dist/commands/billing/__tests__/subscribe.test.js.map +1 -1
- package/dist/commands/billing/__tests__/top-up.test.js +11 -9
- package/dist/commands/billing/__tests__/top-up.test.js.map +1 -1
- package/dist/commands/billing/cancel.js +11 -9
- package/dist/commands/billing/cancel.js.map +1 -1
- package/dist/commands/billing/status.js +11 -9
- package/dist/commands/billing/status.js.map +1 -1
- package/dist/commands/billing/subscribe.js +11 -9
- package/dist/commands/billing/subscribe.js.map +1 -1
- package/dist/commands/billing/top-up.js +11 -9
- package/dist/commands/billing/top-up.js.map +1 -1
- package/dist/commands/compute/app/configure/tls.js +138 -50
- package/dist/commands/compute/app/configure/tls.js.map +1 -1
- package/dist/commands/compute/app/create.js +0 -1
- package/dist/commands/compute/app/create.js.map +1 -1
- package/dist/commands/compute/app/deploy.js +76 -29
- package/dist/commands/compute/app/deploy.js.map +1 -1
- package/dist/commands/compute/app/info.js +17 -17
- package/dist/commands/compute/app/info.js.map +1 -1
- package/dist/commands/compute/app/list.js +12 -10
- package/dist/commands/compute/app/list.js.map +1 -1
- package/dist/commands/compute/app/logs.js +17 -17
- package/dist/commands/compute/app/logs.js.map +1 -1
- package/dist/commands/compute/app/profile/set.js +18 -17
- package/dist/commands/compute/app/profile/set.js.map +1 -1
- package/dist/commands/compute/app/releases.js +17 -17
- package/dist/commands/compute/app/releases.js.map +1 -1
- package/dist/commands/compute/app/start.js +29 -20
- package/dist/commands/compute/app/start.js.map +1 -1
- package/dist/commands/compute/app/stop.js +29 -20
- package/dist/commands/compute/app/stop.js.map +1 -1
- package/dist/commands/compute/app/terminate.js +22 -17
- package/dist/commands/compute/app/terminate.js.map +1 -1
- package/dist/commands/compute/app/upgrade.js +115 -32
- package/dist/commands/compute/app/upgrade.js.map +1 -1
- package/dist/commands/compute/build/info.js +12 -10
- package/dist/commands/compute/build/info.js.map +1 -1
- package/dist/commands/compute/build/list.js +12 -10
- package/dist/commands/compute/build/list.js.map +1 -1
- package/dist/commands/compute/build/logs.js +12 -10
- package/dist/commands/compute/build/logs.js.map +1 -1
- package/dist/commands/compute/build/status.js +12 -10
- package/dist/commands/compute/build/status.js.map +1 -1
- package/dist/commands/compute/build/submit.js +13 -10
- package/dist/commands/compute/build/submit.js.map +1 -1
- package/dist/commands/compute/build/verify.js +12 -10
- package/dist/commands/compute/build/verify.js.map +1 -1
- package/dist/commands/compute/environment/set.js +12 -11
- package/dist/commands/compute/environment/set.js.map +1 -1
- package/dist/commands/compute/undelegate.js +12 -10
- package/dist/commands/compute/undelegate.js.map +1 -1
- package/dist/hooks/init/__tests__/version-check.test.js +1 -1
- package/dist/hooks/init/__tests__/version-check.test.js.map +1 -1
- package/dist/hooks/init/version-check.js +1 -1
- package/dist/hooks/init/version-check.js.map +1 -1
- package/package.json +26 -21
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/commands/compute/app/configure/tls.ts
|
|
4
|
-
import { Command } from "@oclif/core";
|
|
4
|
+
import { Command, Flags } from "@oclif/core";
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import chalk from "chalk";
|
|
8
|
+
import { input, confirm } from "@inquirer/prompts";
|
|
8
9
|
|
|
9
10
|
// src/templates/tls/Caddyfile.tmpl
|
|
10
11
|
var Caddyfile_default = `# Caddy configuration for automatic HTTPS
|
|
@@ -66,82 +67,169 @@ var Caddyfile_default = `# Caddy configuration for automatic HTTPS
|
|
|
66
67
|
function getCaddyfileTemplate() {
|
|
67
68
|
return Caddyfile_default;
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
APP_PORT=3000
|
|
77
|
-
|
|
78
|
-
# Enable Caddy debug logs
|
|
79
|
-
ENABLE_CADDY_LOGS=false
|
|
80
|
-
|
|
81
|
-
# Use Let's Encrypt staging environment (for testing)
|
|
82
|
-
# Set to true to avoid rate limits during development
|
|
83
|
-
ACME_STAGING=false
|
|
84
|
-
|
|
85
|
-
# Force certificate reissue even if a valid one exists
|
|
86
|
-
# Useful when you need to update SANs or force a renewal
|
|
70
|
+
function getTlsEnvBlock(vars) {
|
|
71
|
+
return `
|
|
72
|
+
# TLS Configuration
|
|
73
|
+
DOMAIN=${vars.domain}
|
|
74
|
+
APP_PORT=${vars.appPort}
|
|
75
|
+
ENABLE_CADDY_LOGS=${vars.enableCaddyLogs}
|
|
76
|
+
ACME_STAGING=${vars.acmeStaging}
|
|
87
77
|
ACME_FORCE_ISSUE=false
|
|
88
78
|
`;
|
|
79
|
+
}
|
|
80
|
+
var TLS_ENV_EXAMPLE_BLOCK = `
|
|
81
|
+
# TLS Configuration
|
|
82
|
+
# DOMAIN=yourdomain.com
|
|
83
|
+
# APP_PORT=3000
|
|
84
|
+
# ENABLE_CADDY_LOGS=false
|
|
85
|
+
# ACME_STAGING=false
|
|
86
|
+
# ACME_FORCE_ISSUE=false
|
|
87
|
+
`;
|
|
89
88
|
|
|
90
89
|
// src/commands/compute/app/configure/tls.ts
|
|
91
|
-
|
|
90
|
+
function envFileHasTlsConfig(filePath) {
|
|
91
|
+
if (!fs.existsSync(filePath)) return false;
|
|
92
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
93
|
+
return /^DOMAIN=/m.test(content);
|
|
94
|
+
}
|
|
95
|
+
function validateDomain(value) {
|
|
96
|
+
const trimmed = value.trim();
|
|
97
|
+
if (!trimmed) return "Domain is required";
|
|
98
|
+
if (trimmed.toLowerCase() === "localhost") return "Domain cannot be localhost";
|
|
99
|
+
if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}$/.test(trimmed))
|
|
100
|
+
return "Enter a valid domain (e.g. myapp.example.com)";
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
function validatePort(value) {
|
|
104
|
+
const num = Number(value.trim());
|
|
105
|
+
if (!Number.isInteger(num) || num < 1 || num > 65535) return "Enter a valid port (1-65535)";
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
var ConfigureTLS = class _ConfigureTLS extends Command {
|
|
92
109
|
static description = "Configure TLS for your application";
|
|
93
|
-
static summary = `
|
|
110
|
+
static summary = `Configures TLS for your EigenCloud application.
|
|
94
111
|
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
- .env
|
|
112
|
+
Prompts for domain and TLS settings (or accepts them via flags), then:
|
|
113
|
+
- Creates a Caddyfile for automatic HTTPS via Caddy reverse proxy
|
|
114
|
+
- Appends TLS variables to .env with your values
|
|
115
|
+
- Appends TLS placeholders to .env.example
|
|
98
116
|
|
|
99
117
|
TLS certificates are automatically obtained via Let's Encrypt using the tls-keygen tool.`;
|
|
118
|
+
static examples = [
|
|
119
|
+
"<%= config.bin %> compute app configure tls",
|
|
120
|
+
"<%= config.bin %> compute app configure tls --domain myapp.example.com",
|
|
121
|
+
"<%= config.bin %> compute app configure tls --domain myapp.example.com --app-port 8080",
|
|
122
|
+
"<%= config.bin %> compute app configure tls --domain myapp.example.com --no-acme-staging"
|
|
123
|
+
];
|
|
124
|
+
static flags = {
|
|
125
|
+
domain: Flags.string({
|
|
126
|
+
description: "Domain name for TLS certificate"
|
|
127
|
+
}),
|
|
128
|
+
"app-port": Flags.string({
|
|
129
|
+
description: "Port your application listens on",
|
|
130
|
+
default: "3000"
|
|
131
|
+
}),
|
|
132
|
+
"acme-staging": Flags.boolean({
|
|
133
|
+
description: "Use Let's Encrypt staging environment",
|
|
134
|
+
default: true,
|
|
135
|
+
allowNo: true
|
|
136
|
+
}),
|
|
137
|
+
"caddy-logs": Flags.boolean({
|
|
138
|
+
description: "Enable Caddy debug logs",
|
|
139
|
+
default: false,
|
|
140
|
+
allowNo: true
|
|
141
|
+
})
|
|
142
|
+
};
|
|
100
143
|
async run() {
|
|
144
|
+
const { flags } = await this.parse(_ConfigureTLS);
|
|
101
145
|
const cwd = process.cwd();
|
|
146
|
+
const envPath = path.join(cwd, ".env");
|
|
147
|
+
if (envFileHasTlsConfig(envPath)) {
|
|
148
|
+
this.warn("TLS is already configured in .env (DOMAIN is set). Skipping.");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
102
151
|
const caddyfilePath = path.join(cwd, "Caddyfile");
|
|
103
152
|
if (fs.existsSync(caddyfilePath)) {
|
|
104
|
-
this.
|
|
153
|
+
this.log("Caddyfile already exists, keeping existing file.");
|
|
105
154
|
} else {
|
|
106
155
|
const caddyfileContent = getCaddyfileTemplate();
|
|
107
156
|
fs.writeFileSync(caddyfilePath, caddyfileContent, { mode: 420 });
|
|
108
157
|
this.log("Created Caddyfile");
|
|
109
158
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
159
|
+
this.log("");
|
|
160
|
+
let domain = flags.domain;
|
|
161
|
+
if (!domain) {
|
|
162
|
+
domain = await input({
|
|
163
|
+
message: "Domain name:",
|
|
164
|
+
validate: validateDomain
|
|
165
|
+
});
|
|
113
166
|
} else {
|
|
114
|
-
|
|
115
|
-
this.
|
|
167
|
+
const result = validateDomain(domain);
|
|
168
|
+
if (result !== true) this.error(result);
|
|
116
169
|
}
|
|
170
|
+
let appPort = flags["app-port"];
|
|
171
|
+
const portResult = validatePort(appPort);
|
|
172
|
+
if (portResult !== true) this.error(portResult);
|
|
173
|
+
const acmeStaging = flags["acme-staging"] !== void 0 ? flags["acme-staging"] : await confirm({
|
|
174
|
+
message: "Use Let's Encrypt staging? (recommended for first deploy to avoid rate limits)",
|
|
175
|
+
default: true
|
|
176
|
+
});
|
|
177
|
+
const enableCaddyLogs = flags["caddy-logs"] !== void 0 ? flags["caddy-logs"] : await confirm({
|
|
178
|
+
message: "Enable Caddy debug logs?",
|
|
179
|
+
default: false
|
|
180
|
+
});
|
|
117
181
|
this.log("");
|
|
118
|
-
this.log(chalk.
|
|
119
|
-
this.log(
|
|
120
|
-
this.log(
|
|
121
|
-
this.log(
|
|
122
|
-
this.log(
|
|
182
|
+
this.log(chalk.bold("TLS Configuration:"));
|
|
183
|
+
this.log(` Domain: ${domain.trim()}`);
|
|
184
|
+
this.log(` App port: ${appPort.trim()}`);
|
|
185
|
+
this.log(` ACME staging: ${acmeStaging}`);
|
|
186
|
+
this.log(` Caddy logs: ${enableCaddyLogs}`);
|
|
123
187
|
this.log("");
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
188
|
+
if (!flags.domain) {
|
|
189
|
+
const confirmed = await confirm({
|
|
190
|
+
message: "Write these settings to .env?",
|
|
191
|
+
default: true
|
|
192
|
+
});
|
|
193
|
+
if (!confirmed) {
|
|
194
|
+
this.log("Cancelled.");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const vars = {
|
|
199
|
+
domain: domain.trim(),
|
|
200
|
+
appPort: appPort.trim(),
|
|
201
|
+
acmeStaging,
|
|
202
|
+
enableCaddyLogs
|
|
203
|
+
};
|
|
204
|
+
const envBlock = getTlsEnvBlock(vars);
|
|
205
|
+
fs.appendFileSync(envPath, envBlock, { mode: 420 });
|
|
206
|
+
this.log(`Updated .env`);
|
|
207
|
+
const envExamplePath = path.join(cwd, ".env.example");
|
|
208
|
+
if (!envFileHasTlsConfig(envExamplePath)) {
|
|
209
|
+
fs.appendFileSync(envExamplePath, TLS_ENV_EXAMPLE_BLOCK, { mode: 420 });
|
|
210
|
+
this.log(`Updated .env.example`);
|
|
211
|
+
}
|
|
128
212
|
this.log("");
|
|
129
|
-
this.log("
|
|
130
|
-
this.log(" DOMAIN=yourdomain.com");
|
|
213
|
+
this.log(chalk.green("TLS configured successfully"));
|
|
131
214
|
this.log("");
|
|
132
|
-
this.log("
|
|
133
|
-
this.log(" ENABLE_CADDY_LOGS=true");
|
|
134
|
-
this.log(" ACME_STAGING=true");
|
|
215
|
+
this.log("Next steps:");
|
|
135
216
|
this.log("");
|
|
136
|
-
this.log("
|
|
217
|
+
this.log("1. Set up DNS A record pointing to your instance IP");
|
|
137
218
|
this.log(" Run 'ecloud compute app list' to get IP address");
|
|
138
219
|
this.log("");
|
|
139
|
-
this.log("
|
|
140
|
-
this.log(" ecloud compute app
|
|
220
|
+
this.log("2. Deploy or upgrade:");
|
|
221
|
+
this.log(" ecloud compute app deploy # new app");
|
|
222
|
+
this.log(" ecloud compute app upgrade # existing app");
|
|
141
223
|
this.log("");
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
224
|
+
if (acmeStaging) {
|
|
225
|
+
this.log(chalk.yellow("Note: ACME_STAGING is enabled (recommended for first deploy)"));
|
|
226
|
+
this.log("Once verified, switch to production certs:");
|
|
227
|
+
this.log(" 1. Set ACME_STAGING=false in .env");
|
|
228
|
+
this.log(" 2. Set ACME_FORCE_ISSUE=true in .env (one-time)");
|
|
229
|
+
this.log(" 3. Run: ecloud compute app upgrade");
|
|
230
|
+
this.log("");
|
|
231
|
+
}
|
|
232
|
+
this.log("Let's Encrypt rate limit: 5 certificates/week per domain");
|
|
145
233
|
}
|
|
146
234
|
};
|
|
147
235
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/commands/compute/app/configure/tls.ts","../../../../../src/templates/tls/Caddyfile.tmpl","../../../../../src/templates/tls/templates.ts"],"sourcesContent":["import { Command } from \"@oclif/core\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport chalk from \"chalk\";\nimport { getCaddyfileTemplate, ENV_EXAMPLE_TLS } from \"../../../../templates/tls/templates.js\";\n\nexport default class ConfigureTLS extends Command {\n static description = \"Configure TLS for your application\";\n\n static summary = `Adds TLS configuration to your EigenCloud application.\n\nThis command creates:\n- Caddyfile: Reverse proxy configuration for automatic HTTPS\n- .env.example.tls: Example environment variables for TLS\n\nTLS certificates are automatically obtained via Let's Encrypt using the tls-keygen tool.`;\n\n async run() {\n const cwd = process.cwd();\n\n // Write Caddyfile\n const caddyfilePath = path.join(cwd, \"Caddyfile\");\n if (fs.existsSync(caddyfilePath)) {\n this.warn(\"Caddyfile already exists. Skipping...\");\n } else {\n const caddyfileContent = getCaddyfileTemplate();\n fs.writeFileSync(caddyfilePath, caddyfileContent, { mode: 0o644 });\n this.log(\"Created Caddyfile\");\n }\n\n // Write .env.example.tls\n const envTLSPath = path.join(cwd, \".env.example.tls\");\n if (fs.existsSync(envTLSPath)) {\n this.warn(\".env.example.tls already exists. Skipping...\");\n } else {\n fs.writeFileSync(envTLSPath, ENV_EXAMPLE_TLS, { mode: 0o644 });\n this.log(\"Created .env.example.tls\");\n }\n\n // Print success message and instructions\n this.log(\"\");\n this.log(chalk.green(\"TLS configuration added successfully\"));\n this.log(\"\");\n this.log(\"Created:\");\n this.log(\" - Caddyfile\");\n this.log(\" - .env.example.tls\");\n this.log(\"\");\n\n this.log(\"To enable TLS:\");\n this.log(\"\");\n this.log(\"1. Add TLS variables to .env:\");\n this.log(\" cat .env.example.tls >> .env\");\n this.log(\"\");\n\n this.log(\"2. Configure required variables:\");\n this.log(\" DOMAIN=yourdomain.com\");\n this.log(\"\");\n this.log(\" For first deployment (recommended):\");\n this.log(\" ENABLE_CADDY_LOGS=true\");\n this.log(\" ACME_STAGING=true\");\n this.log(\"\");\n\n this.log(\"3. Set up DNS A record pointing to instance IP\");\n this.log(\" Run 'ecloud compute app list' to get IP address\");\n this.log(\"\");\n\n this.log(\"4. Upgrade:\");\n this.log(\" ecloud compute app upgrade\");\n this.log(\"\");\n\n this.log(\"Note: Let's Encrypt rate limit is 5 certificates/week per domain\");\n this.log(\" To switch staging -> production: set ACME_STAGING=false\");\n this.log(\" If cert exists, use ACME_FORCE_ISSUE=true once to replace\");\n }\n}\n","# Caddy configuration for automatic HTTPS\n# The DOMAIN environment variable will be injected at runtime\n\n{$DOMAIN:localhost} {\n # TLS configuration - always use provided certificates generated by tls-keygen\n tls /run/tls/fullchain.pem /run/tls/privkey.pem\n\n # Reverse proxy to your Node.js application\n # Modify the port to match your application (default: 3000)\n reverse_proxy localhost:{$APP_PORT:3000} {\n # Health check configuration\n health_uri /health\n health_interval 30s\n health_timeout 5s\n health_status 200\n }\n\n # Custom headers\n header {\n # Security headers\n X-Content-Type-Options \"nosniff\"\n X-Frame-Options \"DENY\"\n X-XSS-Protection \"1; mode=block\"\n Referrer-Policy \"strict-origin-when-cross-origin\"\n\n # Remove server header\n -Server\n }\n\n # Logging\n log {\n output stdout\n format console\n level INFO\n }\n\n # Request size limits\n request_body {\n max_size 10MB\n }\n}\n\n# HTTP endpoint (optional, for health checks or redirects)\n:80 {\n # Redirect to HTTPS only when host isn't localhost\n @for_domain expression {host} != \"localhost\"\n redir @for_domain https://{host}{uri} permanent\n\n # Health check endpoint (always available via HTTP)\n handle /health {\n respond \"OK\" 200\n }\n}\n","/**\n * TLS configuration templates\n */\n\nimport caddyfileTemplate from \"./Caddyfile.tmpl\";\n\n/**\n * Get the Caddyfile template\n */\nexport function getCaddyfileTemplate(): string {\n return caddyfileTemplate;\n}\n\n/**\n * Embedded .env.example.tls content\n * (embedded directly since .env files are gitignored)\n */\nexport const ENV_EXAMPLE_TLS = `# TLS Configuration\n# Set these variables to enable TLS for your application\n\n# Your domain name (required for TLS)\nDOMAIN=yourdomain.com\n\n# Port your application listens on\nAPP_PORT=3000\n\n# Enable Caddy debug logs\nENABLE_CADDY_LOGS=false\n\n# Use Let's Encrypt staging environment (for testing)\n# Set to true to avoid rate limits during development\nACME_STAGING=false\n\n# Force certificate reissue even if a valid one exists\n# Useful when you need to update SANs or force a renewal\nACME_FORCE_ISSUE=false\n`;\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,OAAO,WAAW;;;ACHlB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSO,SAAS,uBAA+B;AAC7C,SAAO;AACT;AAMO,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AFX/B,IAAqB,eAArB,cAA0C,QAAQ;AAAA,EAChD,OAAO,cAAc;AAAA,EAErB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,MAAM,MAAM;AACV,UAAM,MAAM,QAAQ,IAAI;AAGxB,UAAM,gBAAqB,UAAK,KAAK,WAAW;AAChD,QAAO,cAAW,aAAa,GAAG;AAChC,WAAK,KAAK,uCAAuC;AAAA,IACnD,OAAO;AACL,YAAM,mBAAmB,qBAAqB;AAC9C,MAAG,iBAAc,eAAe,kBAAkB,EAAE,MAAM,IAAM,CAAC;AACjE,WAAK,IAAI,mBAAmB;AAAA,IAC9B;AAGA,UAAM,aAAkB,UAAK,KAAK,kBAAkB;AACpD,QAAO,cAAW,UAAU,GAAG;AAC7B,WAAK,KAAK,8CAA8C;AAAA,IAC1D,OAAO;AACL,MAAG,iBAAc,YAAY,iBAAiB,EAAE,MAAM,IAAM,CAAC;AAC7D,WAAK,IAAI,0BAA0B;AAAA,IACrC;AAGA,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,MAAM,MAAM,sCAAsC,CAAC;AAC5D,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,UAAU;AACnB,SAAK,IAAI,eAAe;AACxB,SAAK,IAAI,sBAAsB;AAC/B,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,gBAAgB;AACzB,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,+BAA+B;AACxC,SAAK,IAAI,iCAAiC;AAC1C,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,kCAAkC;AAC3C,SAAK,IAAI,0BAA0B;AACnC,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,wCAAwC;AACjD,SAAK,IAAI,2BAA2B;AACpC,SAAK,IAAI,sBAAsB;AAC/B,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,gDAAgD;AACzD,SAAK,IAAI,oDAAoD;AAC7D,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,aAAa;AACtB,SAAK,IAAI,+BAA+B;AACxC,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,kEAAkE;AAC3E,SAAK,IAAI,+DAA+D;AACxE,SAAK,IAAI,iEAAiE;AAAA,EAC5E;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/commands/compute/app/configure/tls.ts","../../../../../src/templates/tls/Caddyfile.tmpl","../../../../../src/templates/tls/templates.ts"],"sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport chalk from \"chalk\";\nimport { input, confirm } from \"@inquirer/prompts\";\nimport {\n getCaddyfileTemplate,\n getTlsEnvBlock,\n TLS_ENV_EXAMPLE_BLOCK,\n} from \"../../../../templates/tls/templates.js\";\n\nfunction envFileHasTlsConfig(filePath: string): boolean {\n if (!fs.existsSync(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return /^DOMAIN=/m.test(content);\n}\n\nfunction validateDomain(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) return \"Domain is required\";\n if (trimmed.toLowerCase() === \"localhost\") return \"Domain cannot be localhost\";\n if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*\\.)+[a-zA-Z]{2,}$/.test(trimmed))\n return \"Enter a valid domain (e.g. myapp.example.com)\";\n return true;\n}\n\nfunction validatePort(value: string): true | string {\n const num = Number(value.trim());\n if (!Number.isInteger(num) || num < 1 || num > 65535) return \"Enter a valid port (1-65535)\";\n return true;\n}\n\nexport default class ConfigureTLS extends Command {\n static description = \"Configure TLS for your application\";\n\n static summary = `Configures TLS for your EigenCloud application.\n\nPrompts for domain and TLS settings (or accepts them via flags), then:\n- Creates a Caddyfile for automatic HTTPS via Caddy reverse proxy\n- Appends TLS variables to .env with your values\n- Appends TLS placeholders to .env.example\n\nTLS certificates are automatically obtained via Let's Encrypt using the tls-keygen tool.`;\n\n static examples = [\n \"<%= config.bin %> compute app configure tls\",\n \"<%= config.bin %> compute app configure tls --domain myapp.example.com\",\n \"<%= config.bin %> compute app configure tls --domain myapp.example.com --app-port 8080\",\n \"<%= config.bin %> compute app configure tls --domain myapp.example.com --no-acme-staging\",\n ];\n\n static flags = {\n domain: Flags.string({\n description: \"Domain name for TLS certificate\",\n }),\n \"app-port\": Flags.string({\n description: \"Port your application listens on\",\n default: \"3000\",\n }),\n \"acme-staging\": Flags.boolean({\n description: \"Use Let's Encrypt staging environment\",\n default: true,\n allowNo: true,\n }),\n \"caddy-logs\": Flags.boolean({\n description: \"Enable Caddy debug logs\",\n default: false,\n allowNo: true,\n }),\n };\n\n async run() {\n const { flags } = await this.parse(ConfigureTLS);\n const cwd = process.cwd();\n\n // Check if TLS is already configured in .env\n const envPath = path.join(cwd, \".env\");\n if (envFileHasTlsConfig(envPath)) {\n this.warn(\"TLS is already configured in .env (DOMAIN is set). Skipping.\");\n return;\n }\n\n // Write Caddyfile\n const caddyfilePath = path.join(cwd, \"Caddyfile\");\n if (fs.existsSync(caddyfilePath)) {\n this.log(\"Caddyfile already exists, keeping existing file.\");\n } else {\n const caddyfileContent = getCaddyfileTemplate();\n fs.writeFileSync(caddyfilePath, caddyfileContent, { mode: 0o644 });\n this.log(\"Created Caddyfile\");\n }\n\n this.log(\"\");\n\n // Resolve values: use flags if provided, otherwise prompt\n let domain = flags.domain;\n if (!domain) {\n domain = await input({\n message: \"Domain name:\",\n validate: validateDomain,\n });\n } else {\n const result = validateDomain(domain);\n if (result !== true) this.error(result);\n }\n\n let appPort = flags[\"app-port\"];\n // Only prompt if the user didn't pass --app-port at all (default is \"3000\")\n // Since oclif always provides the default, we use the default directly\n const portResult = validatePort(appPort);\n if (portResult !== true) this.error(portResult);\n\n const acmeStaging =\n flags[\"acme-staging\"] !== undefined\n ? flags[\"acme-staging\"]\n : await confirm({\n message:\n \"Use Let's Encrypt staging? (recommended for first deploy to avoid rate limits)\",\n default: true,\n });\n\n const enableCaddyLogs =\n flags[\"caddy-logs\"] !== undefined\n ? flags[\"caddy-logs\"]\n : await confirm({\n message: \"Enable Caddy debug logs?\",\n default: false,\n });\n\n // Show summary\n this.log(\"\");\n this.log(chalk.bold(\"TLS Configuration:\"));\n this.log(` Domain: ${domain.trim()}`);\n this.log(` App port: ${appPort.trim()}`);\n this.log(` ACME staging: ${acmeStaging}`);\n this.log(` Caddy logs: ${enableCaddyLogs}`);\n this.log(\"\");\n\n // Only ask for confirmation in interactive mode (no --domain flag)\n if (!flags.domain) {\n const confirmed = await confirm({\n message: \"Write these settings to .env?\",\n default: true,\n });\n\n if (!confirmed) {\n this.log(\"Cancelled.\");\n return;\n }\n }\n\n const vars = {\n domain: domain.trim(),\n appPort: appPort.trim(),\n acmeStaging,\n enableCaddyLogs,\n };\n\n // Append to .env\n const envBlock = getTlsEnvBlock(vars);\n fs.appendFileSync(envPath, envBlock, { mode: 0o644 });\n this.log(`Updated .env`);\n\n // Append to .env.example (with placeholders, skip if already has DOMAIN)\n const envExamplePath = path.join(cwd, \".env.example\");\n if (!envFileHasTlsConfig(envExamplePath)) {\n fs.appendFileSync(envExamplePath, TLS_ENV_EXAMPLE_BLOCK, { mode: 0o644 });\n this.log(`Updated .env.example`);\n }\n\n // Print next steps\n this.log(\"\");\n this.log(chalk.green(\"TLS configured successfully\"));\n this.log(\"\");\n this.log(\"Next steps:\");\n this.log(\"\");\n this.log(\"1. Set up DNS A record pointing to your instance IP\");\n this.log(\" Run 'ecloud compute app list' to get IP address\");\n this.log(\"\");\n this.log(\"2. Deploy or upgrade:\");\n this.log(\" ecloud compute app deploy # new app\");\n this.log(\" ecloud compute app upgrade # existing app\");\n this.log(\"\");\n\n if (acmeStaging) {\n this.log(chalk.yellow(\"Note: ACME_STAGING is enabled (recommended for first deploy)\"));\n this.log(\"Once verified, switch to production certs:\");\n this.log(\" 1. Set ACME_STAGING=false in .env\");\n this.log(\" 2. Set ACME_FORCE_ISSUE=true in .env (one-time)\");\n this.log(\" 3. Run: ecloud compute app upgrade\");\n this.log(\"\");\n }\n\n this.log(\"Let's Encrypt rate limit: 5 certificates/week per domain\");\n }\n}\n","# Caddy configuration for automatic HTTPS\n# The DOMAIN environment variable will be injected at runtime\n\n{$DOMAIN:localhost} {\n # TLS configuration - always use provided certificates generated by tls-keygen\n tls /run/tls/fullchain.pem /run/tls/privkey.pem\n\n # Reverse proxy to your Node.js application\n # Modify the port to match your application (default: 3000)\n reverse_proxy localhost:{$APP_PORT:3000} {\n # Health check configuration\n health_uri /health\n health_interval 30s\n health_timeout 5s\n health_status 200\n }\n\n # Custom headers\n header {\n # Security headers\n X-Content-Type-Options \"nosniff\"\n X-Frame-Options \"DENY\"\n X-XSS-Protection \"1; mode=block\"\n Referrer-Policy \"strict-origin-when-cross-origin\"\n\n # Remove server header\n -Server\n }\n\n # Logging\n log {\n output stdout\n format console\n level INFO\n }\n\n # Request size limits\n request_body {\n max_size 10MB\n }\n}\n\n# HTTP endpoint (optional, for health checks or redirects)\n:80 {\n # Redirect to HTTPS only when host isn't localhost\n @for_domain expression {host} != \"localhost\"\n redir @for_domain https://{host}{uri} permanent\n\n # Health check endpoint (always available via HTTP)\n handle /health {\n respond \"OK\" 200\n }\n}\n","/**\n * TLS configuration templates\n */\n\nimport caddyfileTemplate from \"./Caddyfile.tmpl\";\n\n/**\n * Get the Caddyfile template\n */\nexport function getCaddyfileTemplate(): string {\n return caddyfileTemplate;\n}\n\nexport interface TlsEnvVars {\n domain: string;\n appPort: string;\n acmeStaging: boolean;\n enableCaddyLogs: boolean;\n}\n\n/**\n * Generate the TLS env block with user-provided values for .env\n */\nexport function getTlsEnvBlock(vars: TlsEnvVars): string {\n return `\n# TLS Configuration\nDOMAIN=${vars.domain}\nAPP_PORT=${vars.appPort}\nENABLE_CADDY_LOGS=${vars.enableCaddyLogs}\nACME_STAGING=${vars.acmeStaging}\nACME_FORCE_ISSUE=false\n`;\n}\n\n/**\n * Placeholder TLS block for .env.example\n */\nexport const TLS_ENV_EXAMPLE_BLOCK = `\n# TLS Configuration\n# DOMAIN=yourdomain.com\n# APP_PORT=3000\n# ENABLE_CADDY_LOGS=false\n# ACME_STAGING=false\n# ACME_FORCE_ISSUE=false\n`;\n"],"mappings":"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","names":[]}
|
|
@@ -15,7 +15,6 @@ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
|
15
15
|
import {
|
|
16
16
|
getEnvironmentConfig as getEnvironmentConfig2,
|
|
17
17
|
getAvailableEnvironments,
|
|
18
|
-
isEnvironmentAvailable,
|
|
19
18
|
getAllAppsByDeveloper as getAllAppsByDeveloper2,
|
|
20
19
|
getCategoryDescriptions,
|
|
21
20
|
fetchTemplateCatalog,
|