@expressots/cli 3.0.0-beta.4 → 4.0.0-preview.2

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.
Files changed (180) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +126 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +345 -0
  6. package/bin/cicd/generators/azure-devops.d.ts +2 -0
  7. package/bin/cicd/generators/azure-devops.js +370 -0
  8. package/bin/cicd/generators/bitbucket.d.ts +2 -0
  9. package/bin/cicd/generators/bitbucket.js +217 -0
  10. package/bin/cicd/generators/circleci.d.ts +2 -0
  11. package/bin/cicd/generators/circleci.js +274 -0
  12. package/bin/cicd/generators/github-actions.d.ts +14 -0
  13. package/bin/cicd/generators/github-actions.js +426 -0
  14. package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
  15. package/bin/cicd/generators/gitlab-ci.js +237 -0
  16. package/bin/cicd/generators/index.d.ts +6 -0
  17. package/bin/cicd/generators/index.js +15 -0
  18. package/bin/cicd/generators/jenkins.d.ts +2 -0
  19. package/bin/cicd/generators/jenkins.js +248 -0
  20. package/bin/cicd/generators/template-loader.d.ts +17 -0
  21. package/bin/cicd/generators/template-loader.js +128 -0
  22. package/bin/cicd/index.d.ts +1 -0
  23. package/bin/cicd/index.js +5 -0
  24. package/bin/cli.d.ts +1 -1
  25. package/bin/cli.js +18 -3
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +390 -61
  28. package/bin/config/index.d.ts +5 -0
  29. package/bin/config/index.js +10 -0
  30. package/bin/config/manager.d.ts +98 -0
  31. package/bin/config/manager.js +222 -0
  32. package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
  33. package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
  34. package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
  35. package/bin/containerize/analyzers/project-analyzer.js +150 -0
  36. package/bin/containerize/cli.d.ts +4 -0
  37. package/bin/containerize/cli.js +113 -0
  38. package/bin/containerize/form.d.ts +15 -0
  39. package/bin/containerize/form.js +154 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +936 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +186 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +635 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +133 -0
  48. package/bin/containerize/generators/template-loader.d.ts +36 -0
  49. package/bin/containerize/generators/template-loader.js +129 -0
  50. package/bin/containerize/index.d.ts +4 -0
  51. package/bin/containerize/index.js +13 -0
  52. package/bin/containerize/presets/preset-registry.d.ts +20 -0
  53. package/bin/containerize/presets/preset-registry.js +102 -0
  54. package/bin/costs/cli.d.ts +5 -0
  55. package/bin/costs/cli.js +183 -0
  56. package/bin/costs/form.d.ts +44 -0
  57. package/bin/costs/form.js +412 -0
  58. package/bin/costs/index.d.ts +4 -0
  59. package/bin/costs/index.js +25 -0
  60. package/bin/costs/pricing-manager.d.ts +84 -0
  61. package/bin/costs/pricing-manager.js +342 -0
  62. package/bin/costs/providers/index.d.ts +32 -0
  63. package/bin/costs/providers/index.js +153 -0
  64. package/bin/costs/sources/api-source.d.ts +10 -0
  65. package/bin/costs/sources/api-source.js +32 -0
  66. package/bin/costs/sources/index.d.ts +6 -0
  67. package/bin/costs/sources/index.js +15 -0
  68. package/bin/costs/sources/local-json-source.d.ts +23 -0
  69. package/bin/costs/sources/local-json-source.js +59 -0
  70. package/bin/costs/sources/remote-json-source.d.ts +11 -0
  71. package/bin/costs/sources/remote-json-source.js +53 -0
  72. package/bin/costs/types.d.ts +53 -0
  73. package/bin/costs/types.js +5 -0
  74. package/bin/dev/cli.d.ts +4 -0
  75. package/bin/dev/cli.js +134 -0
  76. package/bin/dev/form.d.ts +36 -0
  77. package/bin/dev/form.js +254 -0
  78. package/bin/dev/index.d.ts +1 -0
  79. package/bin/dev/index.js +5 -0
  80. package/bin/generate/cli.js +29 -2
  81. package/bin/generate/form.d.ts +5 -1
  82. package/bin/generate/form.js +3 -3
  83. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  84. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  85. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  86. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  87. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  88. package/bin/generate/templates/opinionated/config.tpl +47 -0
  89. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  90. package/bin/generate/templates/opinionated/event.tpl +15 -0
  91. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  92. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  93. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  94. package/bin/generate/utils/command-utils.d.ts +7 -3
  95. package/bin/generate/utils/command-utils.js +95 -31
  96. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  97. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  98. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  99. package/bin/generate/utils/opinionated-cmd.js +112 -7
  100. package/bin/generate/utils/string-utils.d.ts +6 -0
  101. package/bin/generate/utils/string-utils.js +13 -1
  102. package/bin/help/form.js +11 -3
  103. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  104. package/bin/migrate/analyzers/platform-detector.js +116 -0
  105. package/bin/migrate/cli.d.ts +6 -0
  106. package/bin/migrate/cli.js +96 -0
  107. package/bin/migrate/form.d.ts +25 -0
  108. package/bin/migrate/form.js +347 -0
  109. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  110. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  111. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  112. package/bin/migrate/generators/compose-to-railway.js +138 -0
  113. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  114. package/bin/migrate/generators/compose-to-render.js +148 -0
  115. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  116. package/bin/migrate/generators/generic-migration.js +221 -0
  117. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  118. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  119. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  120. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  121. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  122. package/bin/migrate/generators/heroku-to-render.js +148 -0
  123. package/bin/migrate/generators/index.d.ts +7 -0
  124. package/bin/migrate/generators/index.js +17 -0
  125. package/bin/migrate/generators/template-loader.d.ts +21 -0
  126. package/bin/migrate/generators/template-loader.js +59 -0
  127. package/bin/migrate/index.d.ts +1 -0
  128. package/bin/migrate/index.js +5 -0
  129. package/bin/new/cli.js +21 -6
  130. package/bin/new/form.d.ts +25 -4
  131. package/bin/new/form.js +285 -70
  132. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  133. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  134. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  135. package/bin/profile/analyzers/image-analyzer.js +85 -0
  136. package/bin/profile/cli.d.ts +4 -0
  137. package/bin/profile/cli.js +92 -0
  138. package/bin/profile/form.d.ts +56 -0
  139. package/bin/profile/form.js +400 -0
  140. package/bin/profile/index.d.ts +1 -0
  141. package/bin/profile/index.js +5 -0
  142. package/bin/profile/optimizers/index.d.ts +19 -0
  143. package/bin/profile/optimizers/index.js +137 -0
  144. package/bin/providers/add/form.d.ts +1 -1
  145. package/bin/providers/add/form.js +27 -6
  146. package/bin/providers/create/form.js +2 -1
  147. package/bin/scripts/form.js +27 -5
  148. package/bin/studio/cli.d.ts +15 -0
  149. package/bin/studio/cli.js +166 -0
  150. package/bin/studio/index.d.ts +5 -0
  151. package/bin/studio/index.js +9 -0
  152. package/bin/templates/cache.d.ts +54 -0
  153. package/bin/templates/cache.js +180 -0
  154. package/bin/templates/cli.d.ts +8 -0
  155. package/bin/templates/cli.js +292 -0
  156. package/bin/templates/fetcher.d.ts +49 -0
  157. package/bin/templates/fetcher.js +208 -0
  158. package/bin/templates/index.d.ts +11 -0
  159. package/bin/templates/index.js +37 -0
  160. package/bin/templates/manager.d.ts +116 -0
  161. package/bin/templates/manager.js +323 -0
  162. package/bin/templates/renderer.d.ts +49 -0
  163. package/bin/templates/renderer.js +204 -0
  164. package/bin/templates/types.d.ts +51 -0
  165. package/bin/templates/types.js +5 -0
  166. package/bin/utils/add-module-to-container.d.ts +2 -2
  167. package/bin/utils/add-module-to-container.js +15 -5
  168. package/bin/utils/cli-ui.d.ts +30 -3
  169. package/bin/utils/cli-ui.js +95 -13
  170. package/bin/utils/index.d.ts +4 -0
  171. package/bin/utils/index.js +4 -0
  172. package/bin/utils/input-validation.d.ts +50 -0
  173. package/bin/utils/input-validation.js +143 -0
  174. package/bin/utils/package-manager-commands.d.ts +24 -0
  175. package/bin/utils/package-manager-commands.js +50 -0
  176. package/bin/utils/safe-spawn.d.ts +35 -0
  177. package/bin/utils/safe-spawn.js +51 -0
  178. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  179. package/bin/utils/update-tsconfig-paths.js +286 -0
  180. package/package.json +154 -154
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateHerokuToFly = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const template_loader_1 = require("./template-loader");
11
+ async function generateHerokuToFly(outputDir, options) {
12
+ console.log(chalk_1.default.yellow(" Generating Heroku → Fly.io migration..."));
13
+ const vars = (0, template_loader_1.buildMigrationVars)(options);
14
+ // Generate fly.toml
15
+ const flyConfig = `# Fly.io Configuration
16
+ # Generated by ExpressoTS CLI
17
+
18
+ app = "expressots-app"
19
+ primary_region = "iad"
20
+ kill_signal = "SIGINT"
21
+ kill_timeout = "5s"
22
+
23
+ [experimental]
24
+ auto_rollback = true
25
+
26
+ [build]
27
+ # Uses Dockerfile by default
28
+ # Or use Nixpacks:
29
+ # builder = "nixpacks"
30
+
31
+ [env]
32
+ NODE_ENV = "production"
33
+ PORT = "3000"
34
+
35
+ [http_service]
36
+ internal_port = 3000
37
+ force_https = true
38
+ auto_stop_machines = true
39
+ auto_start_machines = true
40
+ min_machines_running = 0
41
+ processes = ["app"]
42
+
43
+ [[services]]
44
+ protocol = "tcp"
45
+ internal_port = 3000
46
+ processes = ["app"]
47
+
48
+ [[services.ports]]
49
+ port = 80
50
+ handlers = ["http"]
51
+ force_https = true
52
+
53
+ [[services.ports]]
54
+ port = 443
55
+ handlers = ["tls", "http"]
56
+
57
+ [services.concurrency]
58
+ type = "connections"
59
+ hard_limit = 25
60
+ soft_limit = 20
61
+
62
+ [[services.tcp_checks]]
63
+ interval = "15s"
64
+ timeout = "2s"
65
+ grace_period = "1s"
66
+
67
+ [[services.http_checks]]
68
+ interval = "10s"
69
+ timeout = "2s"
70
+ grace_period = "5s"
71
+ method = "GET"
72
+ path = "/health"
73
+ protocol = "http"
74
+ `;
75
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "fly.toml"), flyConfig, "utf-8");
76
+ console.log(chalk_1.default.green(" āœ“ Created fly.toml"));
77
+ // Generate migration checklist
78
+ const checklist = generateFlyChecklist();
79
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "MIGRATION_CHECKLIST.md"), checklist, "utf-8");
80
+ console.log(chalk_1.default.green(" āœ“ Created MIGRATION_CHECKLIST.md"));
81
+ // Generate migration scripts (cross-platform)
82
+ const nodeScript = generateFlyMigrationScriptNode();
83
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "migrate.js"), nodeScript, "utf-8");
84
+ console.log(chalk_1.default.green(" āœ“ Created migrate.js (cross-platform)"));
85
+ // Also generate bash script for Unix users
86
+ const bashScript = generateFlyMigrationScriptBash();
87
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "migrate.sh"), bashScript, "utf-8");
88
+ console.log(chalk_1.default.green(" āœ“ Created migrate.sh (Unix/Mac)"));
89
+ }
90
+ exports.generateHerokuToFly = generateHerokuToFly;
91
+ function generateFlyChecklist() {
92
+ return `# Migration Checklist: Heroku → Fly.io
93
+
94
+ ## Pre-Migration
95
+
96
+ Install Fly CLI:
97
+ - **Windows**: \`powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"\`
98
+ - **Mac/Linux**: \`curl -L https://fly.io/install.sh | sh\`
99
+
100
+ - [ ] Create account: \`fly auth signup\` or \`fly auth login\`
101
+ - [ ] Export Heroku config: \`heroku config --app your-app\`
102
+
103
+ ## Automated Migration Script
104
+
105
+ \`\`\`bash
106
+ # Set your app name
107
+ export HEROKU_APP_NAME=your-app # Mac/Linux
108
+ set HEROKU_APP_NAME=your-app # Windows CMD
109
+ $env:HEROKU_APP_NAME="your-app" # Windows PowerShell
110
+
111
+ # Run migration
112
+ node migrate.js
113
+ \`\`\`
114
+
115
+ ## Fly.io Setup
116
+
117
+ - [ ] Copy \`fly.toml\` to project root
118
+ - [ ] Create app: \`fly apps create expressots-app\`
119
+ - [ ] Set secrets: \`fly secrets set KEY=value\`
120
+
121
+ ## Database (if using PostgreSQL)
122
+
123
+ - [ ] Create Fly Postgres: \`fly postgres create\`
124
+ - [ ] Attach to app: \`fly postgres attach --app expressots-app\`
125
+ - [ ] Export Heroku data and import to Fly Postgres
126
+
127
+ ## Deployment
128
+
129
+ - [ ] Deploy: \`fly deploy\`
130
+ - [ ] Check status: \`fly status\`
131
+ - [ ] View logs: \`fly logs\`
132
+
133
+ ## Custom Domain
134
+
135
+ - [ ] Add certificate: \`fly certs add your-domain.com\`
136
+ - [ ] Update DNS to point to Fly
137
+
138
+ ## Scaling
139
+
140
+ - [ ] Adjust scaling: \`fly scale count 2\`
141
+ - [ ] Set memory: \`fly scale memory 512\`
142
+
143
+ ## Post-Migration
144
+
145
+ - [ ] Verify endpoints
146
+ - [ ] Monitor metrics: \`fly dashboard\`
147
+ - [ ] Disable Heroku after verification
148
+ `;
149
+ }
150
+ function generateFlyMigrationScriptNode() {
151
+ return `#!/usr/bin/env node
152
+ /**
153
+ * Migration Script: Heroku → Fly.io
154
+ * Generated by ExpressoTS CLI
155
+ * Cross-platform (Windows, macOS, Linux)
156
+ */
157
+
158
+ const { execSync } = require('child_process');
159
+ const fs = require('fs');
160
+
161
+ const HEROKU_APP = process.env.HEROKU_APP_NAME || 'your-app';
162
+ const FLY_APP = process.env.FLY_APP_NAME || 'expressots-app';
163
+
164
+ function run(cmd, options = {}) {
165
+ console.log(\` Running: \${cmd}\`);
166
+ try {
167
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'inherit', ...options });
168
+ } catch (error) {
169
+ if (!options.ignoreError) {
170
+ console.error(\` Error: \${error.message}\`);
171
+ process.exit(1);
172
+ }
173
+ }
174
+ }
175
+
176
+ function checkCommand(cmd) {
177
+ try {
178
+ execSync(\`\${cmd} version\`, { stdio: 'pipe' });
179
+ return true;
180
+ } catch {
181
+ try {
182
+ execSync(\`\${cmd} --version\`, { stdio: 'pipe' });
183
+ return true;
184
+ } catch {
185
+ return false;
186
+ }
187
+ }
188
+ }
189
+
190
+ async function main() {
191
+ console.log('\\n🪰 Starting Heroku → Fly.io Migration\\n');
192
+
193
+ // Check prerequisites
194
+ if (!checkCommand('fly') && !checkCommand('flyctl')) {
195
+ console.error('āŒ Fly CLI required.');
196
+ console.error(' Windows: powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"');
197
+ console.error(' Mac/Linux: curl -L https://fly.io/install.sh | sh');
198
+ process.exit(1);
199
+ }
200
+
201
+ const flyCmd = checkCommand('flyctl') ? 'flyctl' : 'fly';
202
+
203
+ // Export Heroku config (if available)
204
+ if (checkCommand('heroku')) {
205
+ console.log('šŸ“¦ Exporting Heroku configuration...');
206
+ try {
207
+ const config = execSync(\`heroku config --app \${HEROKU_APP} --shell\`, { encoding: 'utf-8' });
208
+ fs.writeFileSync('.env.heroku', config);
209
+ console.log(' āœ“ Exported to .env.heroku');
210
+ } catch {
211
+ console.log(' ⚠ Could not export. Set HEROKU_APP_NAME env var.');
212
+ }
213
+ }
214
+
215
+ // Create Fly app
216
+ console.log('\\n🪰 Creating Fly app...');
217
+ run(\`\${flyCmd} apps create \${FLY_APP}\`, { ignoreError: true });
218
+
219
+ // Import secrets
220
+ if (fs.existsSync('.env.heroku')) {
221
+ console.log('\\nšŸ” Setting secrets...');
222
+ const envContent = fs.readFileSync('.env.heroku', 'utf-8');
223
+ const lines = envContent.split('\\n');
224
+
225
+ for (const line of lines) {
226
+ const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
227
+ if (match) {
228
+ const [, key, value] = match;
229
+ console.log(\` Setting \${key}...\`);
230
+ run(\`\${flyCmd} secrets set "\${key}=\${value}" --app \${FLY_APP}\`, { ignoreError: true });
231
+ }
232
+ }
233
+ }
234
+
235
+ // Deploy
236
+ console.log('\\nšŸš€ Deploying to Fly.io...');
237
+ run(\`\${flyCmd} deploy\`);
238
+
239
+ console.log('\\nāœ… Migration complete!');
240
+ console.log(\` Dashboard: \${flyCmd} dashboard\`);
241
+ console.log(\` Logs: \${flyCmd} logs\\n\`);
242
+ }
243
+
244
+ main().catch(console.error);
245
+ `;
246
+ }
247
+ function generateFlyMigrationScriptBash() {
248
+ return `#!/bin/bash
249
+ # Migration Script: Heroku → Fly.io
250
+ # Generated by ExpressoTS CLI
251
+ # For Unix/macOS - Windows users: use migrate.js instead
252
+
253
+ set -e
254
+
255
+ echo "🪰 Starting Heroku → Fly.io Migration"
256
+
257
+ # Check prerequisites
258
+ command -v fly >/dev/null 2>&1 || command -v flyctl >/dev/null 2>&1 || {
259
+ echo "Fly CLI required. Install: curl -L https://fly.io/install.sh | sh"
260
+ exit 1
261
+ }
262
+
263
+ FLY_CMD="fly"
264
+ command -v flyctl >/dev/null 2>&1 && FLY_CMD="flyctl"
265
+
266
+ # Export Heroku config
267
+ echo "šŸ“¦ Exporting Heroku configuration..."
268
+ heroku config --app \${HEROKU_APP_NAME:-your-app} --shell > .env.heroku
269
+
270
+ # Create Fly app
271
+ echo "🪰 Creating Fly app..."
272
+ $FLY_CMD apps create \${FLY_APP_NAME:-expressots-app} || echo "App may already exist"
273
+
274
+ # Set secrets from Heroku config
275
+ echo "šŸ” Setting secrets..."
276
+ while IFS='=' read -r key value; do
277
+ if [[ ! -z "$key" && ! "$key" =~ ^# ]]; then
278
+ echo " Setting $key..."
279
+ $FLY_CMD secrets set "$key=$value" --app \${FLY_APP_NAME:-expressots-app}
280
+ fi
281
+ done < .env.heroku
282
+
283
+ # Deploy
284
+ echo "šŸš€ Deploying to Fly.io..."
285
+ $FLY_CMD deploy
286
+
287
+ echo "āœ… Migration complete!"
288
+ echo " Dashboard: $FLY_CMD dashboard"
289
+ echo " Logs: $FLY_CMD logs"
290
+ `;
291
+ }
@@ -0,0 +1,2 @@
1
+ import type { MigrationOptions } from "../form";
2
+ export declare function generateHerokuToRailway(outputDir: string, options: MigrationOptions): Promise<void>;
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateHerokuToRailway = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const template_loader_1 = require("./template-loader");
11
+ async function generateHerokuToRailway(outputDir, options) {
12
+ console.log(chalk_1.default.yellow(" Generating Heroku → Railway migration..."));
13
+ const vars = (0, template_loader_1.buildMigrationVars)(options);
14
+ // Generate railway.json
15
+ const railwayConfig = {
16
+ $schema: "https://railway.app/railway.schema.json",
17
+ build: {
18
+ builder: "NIXPACKS",
19
+ },
20
+ deploy: {
21
+ startCommand: "npm start",
22
+ healthcheckPath: "/health",
23
+ healthcheckTimeout: 300,
24
+ restartPolicyType: "ON_FAILURE",
25
+ restartPolicyMaxRetries: 10,
26
+ },
27
+ };
28
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "railway.json"), JSON.stringify(railwayConfig, null, 2), "utf-8");
29
+ console.log(chalk_1.default.green(" āœ“ Created railway.json"));
30
+ // Generate environment variable mapping
31
+ if (options.includeSecrets) {
32
+ const envMapping = generateEnvMapping();
33
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "env-mapping.md"), envMapping, "utf-8");
34
+ console.log(chalk_1.default.green(" āœ“ Created env-mapping.md"));
35
+ }
36
+ // Generate migration checklist (try remote template first)
37
+ const checklistResult = await (0, template_loader_1.loadMigrationTemplate)("heroku", "railway", "checklist", vars, () => generateChecklist(options));
38
+ (0, template_loader_1.logTemplateSource)("MIGRATION_CHECKLIST.md", checklistResult.source);
39
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "MIGRATION_CHECKLIST.md"), checklistResult.content, "utf-8");
40
+ console.log(chalk_1.default.green(" āœ“ Created MIGRATION_CHECKLIST.md"));
41
+ // Generate migration scripts (cross-platform)
42
+ const nodeScript = generateMigrationScriptNode();
43
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "migrate.js"), nodeScript, "utf-8");
44
+ console.log(chalk_1.default.green(" āœ“ Created migrate.js (cross-platform)"));
45
+ // Also generate bash script for Unix users
46
+ const bashScript = generateMigrationScriptBash();
47
+ fs_1.default.writeFileSync(path_1.default.join(outputDir, "migrate.sh"), bashScript, "utf-8");
48
+ console.log(chalk_1.default.green(" āœ“ Created migrate.sh (Unix/Mac)"));
49
+ }
50
+ exports.generateHerokuToRailway = generateHerokuToRailway;
51
+ function generateEnvMapping() {
52
+ return `# Environment Variable Mapping: Heroku → Railway
53
+
54
+ ## Common Variable Translations
55
+
56
+ | Heroku Variable | Railway Variable | Notes |
57
+ |-----------------|------------------|-------|
58
+ | \`DATABASE_URL\` | \`DATABASE_URL\` | Same format, Railway provides PostgreSQL |
59
+ | \`REDIS_URL\` | \`REDIS_URL\` | Same format |
60
+ | \`PORT\` | \`PORT\` | Railway sets this automatically |
61
+ | \`NODE_ENV\` | \`NODE_ENV\` | Set to \`production\` |
62
+ | \`HEROKU_APP_NAME\` | \`RAILWAY_SERVICE_NAME\` | Service name |
63
+
64
+ ## Database Migration
65
+
66
+ If using Heroku Postgres:
67
+ 1. Export data: \`heroku pg:backups:capture --app your-app\`
68
+ 2. Download: \`heroku pg:backups:download --app your-app\`
69
+ 3. Import to Railway PostgreSQL instance
70
+
71
+ ## Steps to Set Environment Variables
72
+
73
+ \`\`\`bash
74
+ # List Heroku config vars
75
+ heroku config --app your-app
76
+
77
+ # Set Railway variables via CLI
78
+ railway variables set KEY=value
79
+
80
+ # Or use Railway dashboard
81
+ # https://railway.app/project/[project-id]/settings
82
+ \`\`\`
83
+ `;
84
+ }
85
+ function generateChecklist(options) {
86
+ return `# Migration Checklist: Heroku → Railway
87
+
88
+ ## Pre-Migration
89
+
90
+ - [ ] Export Heroku environment variables: \`heroku config --app your-app > .env.heroku\`
91
+ - [ ] Backup database if applicable
92
+ - [ ] Document current Heroku add-ons
93
+ - [ ] Note current dyno configuration
94
+
95
+ ## Automated Migration Script
96
+
97
+ Run the cross-platform migration script:
98
+ \`\`\`bash
99
+ # Set your app name
100
+ export HEROKU_APP_NAME=your-app # Mac/Linux
101
+ set HEROKU_APP_NAME=your-app # Windows CMD
102
+ $env:HEROKU_APP_NAME="your-app" # Windows PowerShell
103
+
104
+ # Run migration
105
+ node migrate.js
106
+ \`\`\`
107
+
108
+ ## Railway Setup (Manual)
109
+
110
+ - [ ] Create Railway account at https://railway.app
111
+ - [ ] Install Railway CLI: \`npm install -g @railway/cli\`
112
+ - [ ] Login: \`railway login\`
113
+ - [ ] Create new project: \`railway init\`
114
+
115
+ ## Configuration
116
+
117
+ - [ ] Copy \`railway.json\` to your project root
118
+ - [ ] Set environment variables in Railway dashboard
119
+ - [ ] Configure custom domain (if needed)
120
+
121
+ ## Database Migration
122
+
123
+ - [ ] Provision PostgreSQL on Railway
124
+ - [ ] Export Heroku database
125
+ - [ ] Import to Railway PostgreSQL
126
+ - [ ] Update \`DATABASE_URL\`
127
+
128
+ ## Deployment
129
+
130
+ - [ ] Deploy: \`railway up\`
131
+ - [ ] Verify deployment in Railway dashboard
132
+ - [ ] Test application endpoints
133
+ - [ ] Monitor logs: \`railway logs\`
134
+
135
+ ## DNS & Domain
136
+
137
+ - [ ] Add custom domain in Railway
138
+ - [ ] Update DNS records
139
+ - [ ] Verify SSL certificate
140
+
141
+ ## Post-Migration
142
+
143
+ - [ ] Monitor for 24-48 hours
144
+ - [ ] Disable Heroku app
145
+ - [ ] Delete Heroku resources after verification
146
+
147
+ ## Rollback Plan
148
+
149
+ If issues occur:
150
+ 1. Re-enable Heroku app
151
+ 2. Point DNS back to Heroku
152
+ 3. Investigate and fix Railway deployment
153
+ `;
154
+ }
155
+ function generateMigrationScriptNode() {
156
+ return `#!/usr/bin/env node
157
+ /**
158
+ * Migration Script: Heroku → Railway
159
+ * Generated by ExpressoTS CLI
160
+ * Cross-platform (Windows, macOS, Linux)
161
+ */
162
+
163
+ const { execSync, spawnSync } = require('child_process');
164
+ const fs = require('fs');
165
+ const path = require('path');
166
+
167
+ const HEROKU_APP = process.env.HEROKU_APP_NAME || 'your-app';
168
+
169
+ function run(cmd, options = {}) {
170
+ console.log(\` Running: \${cmd}\`);
171
+ try {
172
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'inherit', ...options });
173
+ } catch (error) {
174
+ if (!options.ignoreError) {
175
+ console.error(\` Error: \${error.message}\`);
176
+ process.exit(1);
177
+ }
178
+ }
179
+ }
180
+
181
+ function checkCommand(cmd) {
182
+ try {
183
+ execSync(\`\${cmd} --version\`, { stdio: 'pipe' });
184
+ return true;
185
+ } catch {
186
+ return false;
187
+ }
188
+ }
189
+
190
+ async function main() {
191
+ console.log('\\nšŸš€ Starting Heroku → Railway Migration\\n');
192
+
193
+ // Check prerequisites
194
+ if (!checkCommand('railway')) {
195
+ console.error('āŒ Railway CLI required. Install: npm i -g @railway/cli');
196
+ process.exit(1);
197
+ }
198
+
199
+ // Export Heroku config (if heroku CLI available)
200
+ if (checkCommand('heroku')) {
201
+ console.log('šŸ“¦ Exporting Heroku configuration...');
202
+ try {
203
+ const config = execSync(\`heroku config --app \${HEROKU_APP} --shell\`, { encoding: 'utf-8' });
204
+ fs.writeFileSync('.env.heroku', config);
205
+ console.log(' āœ“ Exported to .env.heroku');
206
+ } catch {
207
+ console.log(' ⚠ Could not export Heroku config. Set HEROKU_APP_NAME env var.');
208
+ }
209
+ } else {
210
+ console.log('⚠ Heroku CLI not found. Skipping config export.');
211
+ console.log(' Manually export your environment variables.');
212
+ }
213
+
214
+ // Initialize Railway project
215
+ console.log('\\nšŸš‚ Initializing Railway project...');
216
+ run('railway init', { ignoreError: true });
217
+
218
+ // Import environment variables
219
+ if (fs.existsSync('.env.heroku')) {
220
+ console.log('\\nšŸ” Setting up environment variables...');
221
+ const envContent = fs.readFileSync('.env.heroku', 'utf-8');
222
+ const lines = envContent.split('\\n');
223
+
224
+ for (const line of lines) {
225
+ const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
226
+ if (match) {
227
+ const [, key, value] = match;
228
+ console.log(\` Setting \${key}...\`);
229
+ run(\`railway variables set "\${key}=\${value}"\`, { ignoreError: true });
230
+ }
231
+ }
232
+ }
233
+
234
+ // Deploy
235
+ console.log('\\nšŸš€ Deploying to Railway...');
236
+ run('railway up');
237
+
238
+ console.log('\\nāœ… Migration complete!');
239
+ console.log(' Check your deployment at: https://railway.app/dashboard\\n');
240
+ }
241
+
242
+ main().catch(console.error);
243
+ `;
244
+ }
245
+ function generateMigrationScriptBash() {
246
+ return `#!/bin/bash
247
+ # Migration Script: Heroku → Railway
248
+ # Generated by ExpressoTS CLI
249
+ # For Unix/macOS - Windows users: use migrate.js instead
250
+
251
+ set -e
252
+
253
+ echo "šŸš€ Starting Heroku → Railway Migration"
254
+
255
+ # Check prerequisites
256
+ command -v railway >/dev/null 2>&1 || { echo "Railway CLI required. Install: npm i -g @railway/cli"; exit 1; }
257
+ command -v heroku >/dev/null 2>&1 || { echo "Heroku CLI required."; exit 1; }
258
+
259
+ # Export Heroku config
260
+ echo "šŸ“¦ Exporting Heroku configuration..."
261
+ heroku config --app \${HEROKU_APP_NAME:-your-app} --shell > .env.heroku
262
+
263
+ # Initialize Railway project
264
+ echo "šŸš‚ Initializing Railway project..."
265
+ railway init
266
+
267
+ # Copy environment variables
268
+ echo "šŸ” Setting up environment variables..."
269
+ while IFS='=' read -r key value; do
270
+ if [[ ! -z "$key" && ! "$key" =~ ^# ]]; then
271
+ echo " Setting $key..."
272
+ railway variables set "$key=$value"
273
+ fi
274
+ done < .env.heroku
275
+
276
+ # Deploy
277
+ echo "šŸš€ Deploying to Railway..."
278
+ railway up
279
+
280
+ echo "āœ… Migration complete!"
281
+ echo " Check your deployment at: https://railway.app/dashboard"
282
+ `;
283
+ }
@@ -0,0 +1,2 @@
1
+ import type { MigrationOptions } from "../form";
2
+ export declare function generateHerokuToRender(outputDir: string, options: MigrationOptions): Promise<void>;