rushdeploy 1.0.5 → 1.0.7

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 (2) hide show
  1. package/bin/index.js +152 -31
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -92,8 +92,8 @@ const ui = {
92
92
  },
93
93
 
94
94
  box(fields, options = {}) {
95
- const fieldPairs = Array.isArray(fields)
96
- ? fields
95
+ const fieldPairs = Array.isArray(fields)
96
+ ? fields
97
97
  : Object.entries(fields).map(([label, value]) => ({ label, value }));
98
98
 
99
99
  const labelWidth = 14;
@@ -110,7 +110,7 @@ const ui = {
110
110
  const innerWidth = Math.max(options.minWidth || 66, leftIndent + labelWidth + gap + maxValLen + rightMargin);
111
111
 
112
112
  const topBorder = `┌${'─'.repeat(innerWidth)}┐`;
113
- const emptyRow = `│${' '.repeat(innerWidth)}│`;
113
+ const emptyRow = `│${' '.repeat(innerWidth)}│`;
114
114
  const bottomBorder = `└${'─'.repeat(innerWidth)}┘`;
115
115
 
116
116
  console.log(`\n${colors.gray}${topBorder}${colors.reset}`);
@@ -255,7 +255,7 @@ function makeRequest(apiPath, method = 'GET', data = null) {
255
255
  } else if (jsonResponse && jsonResponse.detail) {
256
256
  errorMsg = typeof jsonResponse.detail === 'object' ? jsonResponse.detail.message : jsonResponse.detail;
257
257
  }
258
-
258
+
259
259
  if (res.statusCode === 401) {
260
260
  ui.stepError(`Unauthorized (401). Your token may have expired or been revoked.`);
261
261
  console.log(` Please log in again using: ${colors.green}rushdeploy login <token>${colors.reset}`);
@@ -345,16 +345,16 @@ function extractRepoName(url) {
345
345
  async function cmdLogin(token, serverArg) {
346
346
  const server = serverArg || getServerUrl();
347
347
  ui.stepInfo(`Connecting to ${colors.brightWhite}${server}${colors.reset}...`);
348
-
348
+
349
349
  saveConfig(server, token);
350
-
350
+
351
351
  try {
352
352
  ui.stepInfo(`Validating authentication token...`);
353
353
  const res = await makeRequest('/auth/me');
354
354
  if (res.success) {
355
355
  const user = res.user;
356
356
  ui.step(`Authentication successful!`);
357
-
357
+
358
358
  ui.box([
359
359
  { label: 'Account', value: `${colors.bold}${user.name}${colors.reset} (${colors.gray}${user.email}${colors.reset})` },
360
360
  { label: 'Role', value: user.role.toUpperCase() },
@@ -421,7 +421,7 @@ async function cmdPlans() {
421
421
  function drawCards(cards, cardsPerRow = 2) {
422
422
  const cardWidth = 34;
423
423
  const rows = [];
424
-
424
+
425
425
  for (let i = 0; i < cards.length; i += cardsPerRow) {
426
426
  rows.push(cards.slice(i, i + cardsPerRow));
427
427
  }
@@ -440,19 +440,19 @@ function drawCards(cards, cardsPerRow = 2) {
440
440
 
441
441
  const label = card.label || '';
442
442
  let value = card.value !== undefined ? String(card.value) : '';
443
-
443
+
444
444
  let valColor = colors.bold;
445
445
  if (card.status === 'online') valColor = colors.green + colors.bold;
446
446
  else if (card.status === 'offline') valColor = colors.red + colors.bold;
447
447
  else if (card.status === 'warn') valColor = colors.yellow + colors.bold;
448
-
448
+
449
449
  const valStr = `${valColor}${value}${colors.reset}`;
450
450
  const rawVal = stripAnsi(value);
451
-
451
+
452
452
  const textLen = label.length + rawVal.length;
453
453
  const padLen = cardWidth - 6 - textLen;
454
454
  const pad = ' '.repeat(Math.max(1, padLen));
455
-
455
+
456
456
  labelValLine += space + `${colors.gray}│${colors.reset} ${colors.brightCyan}${label}${colors.reset}${pad}${valStr} ${colors.gray}│${colors.reset}`;
457
457
  sepLine += space + colors.gray + '├' + '─'.repeat(cardWidth - 2) + '┤' + colors.reset;
458
458
 
@@ -460,7 +460,7 @@ function drawCards(cards, cardsPerRow = 2) {
460
460
  const rawHint = stripAnsi(hint);
461
461
  const hintPadLen = cardWidth - 6 - rawHint.length;
462
462
  const hintPad = ' '.repeat(Math.max(0, hintPadLen));
463
-
463
+
464
464
  hintLine += space + `${colors.gray}│${colors.reset} ${colors.gray}${hint}${colors.reset}${hintPad} ${colors.gray}│${colors.reset}`;
465
465
  bottomBorder += space + colors.gray + '└' + '─'.repeat(cardWidth - 2) + '┘' + colors.reset;
466
466
  });
@@ -499,7 +499,7 @@ async function cmdStatus() {
499
499
  const byStatus = stats.projects_by_status || {};
500
500
  const celery = stats.celery || {};
501
501
  const workerOnline = (celery.workers ?? 0) > 0;
502
-
502
+
503
503
  const activeBuildingProjects = (byStatus.building || byStatus.BUILDING || 0) + (byStatus.pending || byStatus.PENDING || 0);
504
504
  const activeTasksCount = (celery.active && celery.active > 0) ? celery.active : activeBuildingProjects;
505
505
  const pendingInQueue = stats.redis_queue_len ?? celery.queued ?? 0;
@@ -517,23 +517,23 @@ async function cmdStatus() {
517
517
  const adminCards = [
518
518
  { label: 'Users', value: stats.users ?? 0, hint: 'Total registered users' },
519
519
  { label: 'Databases', value: stats.databases ?? 0, hint: 'Total workspace databases' },
520
- {
521
- label: 'Projects',
522
- value: stats.projects ?? 0,
523
- hint: `${colors.green}${runCount} run${colors.reset} · ${colors.yellow}${buildCount} build${colors.reset} · ${colors.red}${failCount} fail${colors.reset}`
520
+ {
521
+ label: 'Projects',
522
+ value: stats.projects ?? 0,
523
+ hint: `${colors.green}${runCount} run${colors.reset} · ${colors.yellow}${buildCount} build${colors.reset} · ${colors.red}${failCount} fail${colors.reset}`
524
524
  },
525
- {
526
- label: 'App Containers',
527
- value: stats.running_containers ?? 0,
525
+ {
526
+ label: 'App Containers',
527
+ value: stats.running_containers ?? 0,
528
528
  status: stats.docker_available ? 'online' : 'offline',
529
529
  hint: stats.docker_available ? 'Active running containers' : 'Engine offline'
530
530
  },
531
531
  { label: 'CPU Usage', value: cpuVal, hint: 'Host CPU load' },
532
532
  { label: 'RAM Usage', value: ramVal, hint: 'Host memory allocation' },
533
533
  { label: 'Disk Usage', value: diskVal, hint: 'Host storage capacity' },
534
- {
535
- label: 'Task Queue',
536
- value: workerOnline ? 'Online' : 'Offline',
534
+ {
535
+ label: 'Task Queue',
536
+ value: workerOnline ? 'Online' : 'Offline',
537
537
  status: workerOnline ? 'online' : 'offline',
538
538
  hint: `${activeTasksCount} active · ${pendingInQueue} pending`
539
539
  }
@@ -773,28 +773,80 @@ async function cmdDeploy(type, args) {
773
773
  ]);
774
774
  }
775
775
 
776
+ } else if (type === 'n8n') {
777
+ const name = args[0];
778
+ if (!name) {
779
+ ui.stepError(`Please specify the n8n project name.`);
780
+ console.log(` Usage: ${colors.green}rushdeploy deploy n8n <name> [--key <encryption_key>] [--auth-user <user>] [--auth-pass <pass>]${colors.reset}`);
781
+ process.exit(1);
782
+ }
783
+
784
+ let encryptionKey = null;
785
+ const keyIdx = args.indexOf('--key');
786
+ if (keyIdx !== -1 && args[keyIdx + 1]) encryptionKey = args[keyIdx + 1];
787
+
788
+ let basicAuthActive = false;
789
+ let basicAuthUser = 'admin';
790
+ let basicAuthPass = null;
791
+
792
+ const authUserIdx = args.indexOf('--auth-user');
793
+ if (authUserIdx !== -1 && args[authUserIdx + 1]) {
794
+ basicAuthActive = true;
795
+ basicAuthUser = args[authUserIdx + 1];
796
+ }
797
+ const authPassIdx = args.indexOf('--auth-pass');
798
+ if (authPassIdx !== -1 && args[authPassIdx + 1]) {
799
+ basicAuthActive = true;
800
+ basicAuthPass = args[authPassIdx + 1];
801
+ }
802
+
803
+ ui.step(`Preparing n8n autonomous workflow environment for ${name}`);
804
+ ui.step(`Configuring persistent volume storage and container security`);
805
+ ui.step(`Queueing 1-click n8n instance deployment`);
806
+
807
+ const res = await makeRequest('/projects/n8n', 'POST', {
808
+ name,
809
+ encryption_key: encryptionKey,
810
+ basic_auth_active: basicAuthActive,
811
+ basic_auth_user: basicAuthUser,
812
+ basic_auth_password: basicAuthPass
813
+ });
814
+
815
+ if (res.success) {
816
+ ui.step(`n8n deployment queued successfully!`);
817
+ ui.box([
818
+ { label: 'Site Name', value: colors.bold + name + colors.reset },
819
+ { label: 'State', value: ui.badge('QUEUED') },
820
+ { label: 'Project ID', value: String(res.project_id) },
821
+ { label: 'Deployment ID', value: String(res.deployment_id) },
822
+ { label: 'Public URL', value: colors.brightCyan + colors.bold + res.url + colors.reset }
823
+ ]);
824
+ }
825
+
776
826
  } else {
777
- ui.stepError(`Invalid deployment source type. Must be 'git', 'repo', or 'wordpress'.`);
827
+ ui.stepError(`Invalid deployment source type. Must be 'git', 'repo', 'wordpress', or 'n8n'.`);
778
828
  console.log(`\nUsage:`);
779
829
  console.log(` rushdeploy deploy git <repo_url> [options]`);
780
830
  console.log(` rushdeploy deploy repo <owner/repo> [options]`);
781
831
  console.log(` rushdeploy deploy wordpress <name> --email <email> [options]`);
832
+ console.log(` rushdeploy deploy n8n <name> [options]`);
782
833
  process.exit(1);
783
834
  }
784
835
  }
785
836
 
837
+
786
838
  async function resolveProjectId(idOrSlug) {
787
839
  if (/^\d+$/.test(idOrSlug)) {
788
840
  return parseInt(idOrSlug, 10);
789
841
  }
790
-
842
+
791
843
  const res = await makeRequest('/projects/');
792
844
  const projects = res.projects || [];
793
845
  const matched = projects.find(p => p.slug === idOrSlug || p.name.toLowerCase() === idOrSlug.toLowerCase());
794
846
  if (matched) {
795
847
  return matched.id;
796
848
  }
797
-
849
+
798
850
  ui.stepError(`No project found matching name or slug "${idOrSlug}".`);
799
851
  process.exit(1);
800
852
  }
@@ -864,7 +916,7 @@ async function cmdProject(idOrSlug, subcommand, subArgs) {
864
916
  const stats = statsRes.stats;
865
917
 
866
918
  ui.stepInfo(`Resource metrics for Project ${id}`);
867
-
919
+
868
920
  const fields = [
869
921
  { label: 'Current Status', value: ui.badge(info.status) }
870
922
  ];
@@ -1145,7 +1197,7 @@ async function cmdWorkspace() {
1145
1197
 
1146
1198
  function printHelp() {
1147
1199
  console.log(`
1148
- ${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.4${colors.reset} - Modern PaaS Command Line Interface
1200
+ ${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.7${colors.reset} - Modern PaaS Command Line Interface
1149
1201
 
1150
1202
  ${colors.bold}USAGE:${colors.reset}
1151
1203
  ${colors.brightCyan}rushdeploy${colors.reset} <command> [arguments] [options]
@@ -1199,6 +1251,11 @@ async function main() {
1199
1251
  process.exit(0);
1200
1252
  }
1201
1253
 
1254
+ if (command === 'version' || command === '-v' || command === '--version') {
1255
+ console.log(`${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.7${colors.reset}`);
1256
+ process.exit(0);
1257
+ }
1258
+
1202
1259
  switch (command) {
1203
1260
  case 'login': {
1204
1261
  const token = args[1];
@@ -1207,13 +1264,13 @@ async function main() {
1207
1264
  console.log(` Usage: ${colors.green}rushdeploy login <token> [--server <url>]${colors.reset}`);
1208
1265
  process.exit(1);
1209
1266
  }
1210
-
1267
+
1211
1268
  let server = null;
1212
1269
  const serverIndex = args.indexOf('--server');
1213
1270
  if (serverIndex !== -1 && args[serverIndex + 1]) {
1214
1271
  server = args[serverIndex + 1];
1215
1272
  }
1216
-
1273
+
1217
1274
  await cmdLogin(token, server);
1218
1275
  break;
1219
1276
  }
@@ -1230,6 +1287,7 @@ async function main() {
1230
1287
  await cmdStatus();
1231
1288
  break;
1232
1289
  case 'projects':
1290
+ case 'ls':
1233
1291
  await cmdProjects();
1234
1292
  break;
1235
1293
  case 'repos':
@@ -1241,6 +1299,68 @@ async function main() {
1241
1299
  await cmdDeploy(type, deployArgs);
1242
1300
  break;
1243
1301
  }
1302
+ case 'open':
1303
+ case 'visit': {
1304
+ const target = args[1];
1305
+ if (!target) {
1306
+ ui.stepError(`Usage: rushdeploy open <slug|id>`);
1307
+ process.exit(1);
1308
+ }
1309
+ await cmdProject(target, 'visit', []);
1310
+ break;
1311
+ }
1312
+ case 'logs': {
1313
+ const target = args[1];
1314
+ if (!target) {
1315
+ ui.stepError(`Usage: rushdeploy logs <slug|id> [--lines <N>]`);
1316
+ process.exit(1);
1317
+ }
1318
+ await cmdProject(target, 'logs', args.slice(2));
1319
+ break;
1320
+ }
1321
+ case 'start': {
1322
+ const target = args[1];
1323
+ if (!target) {
1324
+ ui.stepError(`Usage: rushdeploy start <slug|id>`);
1325
+ process.exit(1);
1326
+ }
1327
+ await cmdProject(target, 'start', []);
1328
+ break;
1329
+ }
1330
+ case 'stop': {
1331
+ const target = args[1];
1332
+ if (!target) {
1333
+ ui.stepError(`Usage: rushdeploy stop <slug|id>`);
1334
+ process.exit(1);
1335
+ }
1336
+ await cmdProject(target, 'stop', []);
1337
+ break;
1338
+ }
1339
+ case 'restart':
1340
+ case 'redeploy': {
1341
+ const target = args[1];
1342
+ if (!target) {
1343
+ ui.stepError(`Usage: rushdeploy restart <slug|id>`);
1344
+ process.exit(1);
1345
+ }
1346
+ await cmdProject(target, 'redeploy', []);
1347
+ break;
1348
+ }
1349
+ case 'delete':
1350
+ case 'remove': {
1351
+ const target = args[1];
1352
+ if (!target) {
1353
+ ui.stepError(`Usage: rushdeploy delete <slug|id>`);
1354
+ process.exit(1);
1355
+ }
1356
+ const id = await resolveProjectId(target);
1357
+ ui.stepInfo(`Deleting project ${id}...`);
1358
+ const res = await makeRequest(`/projects/${id}`, 'DELETE');
1359
+ if (res.success) {
1360
+ ui.step(`Project deleted successfully.`);
1361
+ }
1362
+ break;
1363
+ }
1244
1364
  case 'project': {
1245
1365
  const idOrSlug = args[1];
1246
1366
  if (!idOrSlug) {
@@ -1263,6 +1383,7 @@ async function main() {
1263
1383
  }
1264
1384
  }
1265
1385
 
1386
+
1266
1387
  main().catch(err => {
1267
1388
  ui.stepError(`Fatal Error: ${err.message}`);
1268
1389
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rushdeploy",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "CLI tool to manage your self-hosted RushDeploy PaaS account.",
5
5
  "main": "bin/index.js",
6
6
  "bin": {