@lead-routing/cli 0.1.10 → 0.1.11

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/dist/index.js +39 -77
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -69,16 +69,7 @@ async function checkSalesforceCLI() {
69
69
  // src/steps/collect-ssh-config.ts
70
70
  import { existsSync } from "fs";
71
71
  import { homedir } from "os";
72
- import { join } from "path";
73
72
  import { text, password, note, log as log2, cancel, isCancel } from "@clack/prompts";
74
- var DEFAULT_KEYS = [
75
- join(homedir(), ".ssh", "id_ed25519"),
76
- join(homedir(), ".ssh", "id_rsa"),
77
- join(homedir(), ".ssh", "id_ecdsa")
78
- ];
79
- function detectDefaultKey() {
80
- return DEFAULT_KEYS.find(existsSync);
81
- }
82
73
  function bail(value) {
83
74
  if (isCancel(value)) {
84
75
  cancel("Setup cancelled.");
@@ -88,7 +79,7 @@ function bail(value) {
88
79
  }
89
80
  async function collectSshConfig(opts = {}) {
90
81
  note(
91
- "The CLI will SSH into your server to deploy the full stack.\nYou will need:\n \u2022 Server hostname or IP address\n \u2022 SSH access (key auto-detected, or password)\n \u2022 Docker 24+ already installed on the server",
82
+ "The CLI will SSH into your server to deploy the full stack.\nYou will need:\n \u2022 Server hostname or IP address\n \u2022 SSH password for your server (root access)\n \u2022 A fresh Linux VPS (Ubuntu/Debian/CentOS) \u2014 Docker installed automatically",
92
83
  "Server connection"
93
84
  );
94
85
  const host = await text({
@@ -108,19 +99,12 @@ async function collectSshConfig(opts = {}) {
108
99
  privateKeyPath = resolved;
109
100
  log2.info(`Using SSH key: ${opts.sshKey}`);
110
101
  } else {
111
- const detected = detectDefaultKey();
112
- if (detected) {
113
- privateKeyPath = detected;
114
- log2.info(`Using SSH key: ${detected.replace(homedir(), "~")}`);
115
- } else {
116
- log2.warn("No SSH key found at ~/.ssh/id_ed25519, ~/.ssh/id_rsa, or ~/.ssh/id_ecdsa");
117
- const p = await password({
118
- message: `SSH password for ${opts.sshUser ?? "root"}@${host}`,
119
- validate: (v) => !v ? "Required" : void 0
120
- });
121
- if (isCancel(p)) bail(p);
122
- pwd = p;
123
- }
102
+ const p = await password({
103
+ message: `SSH password for ${opts.sshUser ?? "root"}@${host}`,
104
+ validate: (v) => !v ? "Required" : void 0
105
+ });
106
+ if (isCancel(p)) bail(p);
107
+ pwd = p;
124
108
  }
125
109
  return {
126
110
  host,
@@ -258,7 +242,7 @@ async function collectConfig(opts = {}) {
258
242
 
259
243
  // src/steps/generate-files.ts
260
244
  import { mkdirSync, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
261
- import { join as join3, dirname } from "path";
245
+ import { join as join2, dirname } from "path";
262
246
  import { fileURLToPath } from "url";
263
247
  import { log as log3 } from "@clack/prompts";
264
248
 
@@ -489,9 +473,9 @@ function renderCaddyfile(appUrl, engineUrl) {
489
473
 
490
474
  // src/utils/config.ts
491
475
  import { readFileSync, writeFileSync, existsSync as existsSync2 } from "fs";
492
- import { join as join2 } from "path";
476
+ import { join } from "path";
493
477
  function getConfigPath(dir) {
494
- return join2(dir, "lead-routing.json");
478
+ return join(dir, "lead-routing.json");
495
479
  }
496
480
  function readConfig(dir) {
497
481
  const path2 = getConfigPath(dir);
@@ -506,10 +490,10 @@ function writeConfig(dir, config2) {
506
490
  writeFileSync(getConfigPath(dir), JSON.stringify(config2, null, 2), "utf8");
507
491
  }
508
492
  function findInstallDir(startDir = process.cwd()) {
509
- const candidate = join2(startDir, "lead-routing.json");
493
+ const candidate = join(startDir, "lead-routing.json");
510
494
  if (existsSync2(candidate)) return startDir;
511
- const nested = join2(startDir, "lead-routing", "lead-routing.json");
512
- if (existsSync2(nested)) return join2(startDir, "lead-routing");
495
+ const nested = join(startDir, "lead-routing", "lead-routing.json");
496
+ if (existsSync2(nested)) return join(startDir, "lead-routing");
513
497
  return null;
514
498
  }
515
499
 
@@ -517,14 +501,14 @@ function findInstallDir(startDir = process.cwd()) {
517
501
  var __dirname = dirname(fileURLToPath(import.meta.url));
518
502
  function getCliVersion() {
519
503
  try {
520
- const pkg = JSON.parse(readFileSync2(join3(__dirname, "../../package.json"), "utf8"));
504
+ const pkg = JSON.parse(readFileSync2(join2(__dirname, "../../package.json"), "utf8"));
521
505
  return pkg.version ?? "0.1.0";
522
506
  } catch {
523
507
  return "0.1.0";
524
508
  }
525
509
  }
526
510
  function generateFiles(cfg, sshCfg) {
527
- const dir = join3(process.cwd(), "lead-routing");
511
+ const dir = join2(process.cwd(), "lead-routing");
528
512
  mkdirSync(dir, { recursive: true });
529
513
  const dockerEngineUrl = `http://engine:3001`;
530
514
  const composeContent = renderDockerCompose({
@@ -532,11 +516,11 @@ function generateFiles(cfg, sshCfg) {
532
516
  managedRedis: cfg.managedRedis,
533
517
  dbPassword: cfg.dbPassword
534
518
  });
535
- const composeFile = join3(dir, "docker-compose.yml");
519
+ const composeFile = join2(dir, "docker-compose.yml");
536
520
  writeFileSync2(composeFile, composeContent, "utf8");
537
521
  log3.success("Generated docker-compose.yml");
538
522
  const caddyfileContent = renderCaddyfile(cfg.appUrl, cfg.engineUrl);
539
- writeFileSync2(join3(dir, "Caddyfile"), caddyfileContent, "utf8");
523
+ writeFileSync2(join2(dir, "Caddyfile"), caddyfileContent, "utf8");
540
524
  log3.success("Generated Caddyfile");
541
525
  const envWebContent = renderEnvWeb({
542
526
  appUrl: cfg.appUrl,
@@ -552,7 +536,7 @@ function generateFiles(cfg, sshCfg) {
552
536
  resendApiKey: cfg.resendApiKey || void 0,
553
537
  feedbackToEmail: cfg.feedbackToEmail || void 0
554
538
  });
555
- const envWeb = join3(dir, ".env.web");
539
+ const envWeb = join2(dir, ".env.web");
556
540
  writeFileSync2(envWeb, envWebContent, "utf8");
557
541
  log3.success("Generated .env.web");
558
542
  const envEngineContent = renderEnvEngine({
@@ -563,7 +547,7 @@ function generateFiles(cfg, sshCfg) {
563
547
  sfdcLoginUrl: cfg.sfdcLoginUrl,
564
548
  engineWebhookSecret: cfg.engineWebhookSecret
565
549
  });
566
- const envEngine = join3(dir, ".env.engine");
550
+ const envEngine = join2(dir, ".env.engine");
567
551
  writeFileSync2(envEngine, envEngineContent, "utf8");
568
552
  log3.success("Generated .env.engine");
569
553
  writeConfig(dir, {
@@ -732,7 +716,7 @@ async function checkRemotePort(ssh, port) {
732
716
  }
733
717
 
734
718
  // src/steps/upload-files.ts
735
- import { join as join4 } from "path";
719
+ import { join as join3 } from "path";
736
720
  import { spinner as spinner3 } from "@clack/prompts";
737
721
  async function uploadFiles(ssh, localDir, remoteDir) {
738
722
  const s = spinner3();
@@ -748,7 +732,7 @@ async function uploadFiles(ssh, localDir, remoteDir) {
748
732
  ];
749
733
  await ssh.upload(
750
734
  filenames.map((f) => ({
751
- local: join4(localDir, f),
735
+ local: join3(localDir, f),
752
736
  remote: `${remoteDir}/${f}`
753
737
  }))
754
738
  );
@@ -1039,7 +1023,7 @@ function sleep2(ms) {
1039
1023
 
1040
1024
  // src/steps/sfdc-deploy-inline.ts
1041
1025
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, cpSync, rmSync } from "fs";
1042
- import { join as join6, dirname as dirname3 } from "path";
1026
+ import { join as join5, dirname as dirname3 } from "path";
1043
1027
  import { tmpdir } from "os";
1044
1028
  import { fileURLToPath as fileURLToPath3 } from "url";
1045
1029
  import { spinner as spinner7, log as log7 } from "@clack/prompts";
@@ -1070,10 +1054,10 @@ async function sfdcDeployInline(params) {
1070
1054
  }
1071
1055
  }
1072
1056
  s.start("Copying Salesforce package\u2026");
1073
- const inDist = join6(__dirname3, "sfdc-package");
1074
- const nextToDist = join6(__dirname3, "..", "sfdc-package");
1057
+ const inDist = join5(__dirname3, "sfdc-package");
1058
+ const nextToDist = join5(__dirname3, "..", "sfdc-package");
1075
1059
  const bundledPkg = existsSync4(inDist) ? inDist : nextToDist;
1076
- const destPkg = join6(installDir ?? tmpdir(), "lead-routing-sfdc-package");
1060
+ const destPkg = join5(installDir ?? tmpdir(), "lead-routing-sfdc-package");
1077
1061
  if (!existsSync4(bundledPkg)) {
1078
1062
  s.stop("sfdc-package not found in CLI bundle");
1079
1063
  throw new Error(
@@ -1084,7 +1068,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1084
1068
  if (existsSync4(destPkg)) rmSync(destPkg, { recursive: true, force: true });
1085
1069
  cpSync(bundledPkg, destPkg, { recursive: true });
1086
1070
  s.stop("Package copied");
1087
- const ncPath = join6(
1071
+ const ncPath = join5(
1088
1072
  destPkg,
1089
1073
  "force-app",
1090
1074
  "main",
@@ -1096,7 +1080,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1096
1080
  const nc = patchXml(readFileSync4(ncPath, "utf8"), "endpoint", engineUrl);
1097
1081
  writeFileSync3(ncPath, nc, "utf8");
1098
1082
  }
1099
- const rssEnginePath = join6(
1083
+ const rssEnginePath = join5(
1100
1084
  destPkg,
1101
1085
  "force-app",
1102
1086
  "main",
@@ -1109,7 +1093,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1109
1093
  rss = patchXml(rss, "description", "Lead Router Engine endpoint");
1110
1094
  writeFileSync3(rssEnginePath, rss, "utf8");
1111
1095
  }
1112
- const rssAppPath = join6(
1096
+ const rssAppPath = join5(
1113
1097
  destPkg,
1114
1098
  "force-app",
1115
1099
  "main",
@@ -1541,7 +1525,7 @@ async function runInit(options = {}) {
1541
1525
  log9.step("Step 1/9 Checking local prerequisites");
1542
1526
  await checkPrerequisites();
1543
1527
  log9.step("Step 2/9 SSH connection");
1544
- let sshCfg = await collectSshConfig({
1528
+ const sshCfg = await collectSshConfig({
1545
1529
  sshPort: options.sshPort,
1546
1530
  sshUser: options.sshUser,
1547
1531
  sshKey: options.sshKey,
@@ -1552,31 +1536,9 @@ async function runInit(options = {}) {
1552
1536
  await ssh.connect(sshCfg);
1553
1537
  log9.success(`Connected to ${sshCfg.host}`);
1554
1538
  } catch (err) {
1555
- if (sshCfg.privateKeyPath && !sshCfg.password) {
1556
- log9.warn(`Key auth failed \u2014 the server rejected the SSH key`);
1557
- log9.info("Falling back to password auth\u2026");
1558
- const pw = await promptPassword({
1559
- message: `SSH password for ${sshCfg.username}@${sshCfg.host}`,
1560
- validate: (v) => !v ? "Required" : void 0
1561
- });
1562
- if (isCancel4(pw)) {
1563
- cancel3("Setup cancelled.");
1564
- process.exit(0);
1565
- }
1566
- sshCfg = { ...sshCfg, privateKeyPath: void 0, password: pw };
1567
- try {
1568
- await ssh.connect(sshCfg);
1569
- log9.success(`Connected to ${sshCfg.host}`);
1570
- } catch (err2) {
1571
- log9.error(`SSH connection failed: ${String(err2)}`);
1572
- log9.info("Fix your SSH credentials and re-run `lead-routing init`.");
1573
- process.exit(1);
1574
- }
1575
- } else {
1576
- log9.error(`SSH connection failed: ${String(err)}`);
1577
- log9.info("Fix your SSH credentials and re-run `lead-routing init`.");
1578
- process.exit(1);
1579
- }
1539
+ log9.error(`SSH connection failed: ${String(err)}`);
1540
+ log9.info("Check your password and re-run `lead-routing init`.");
1541
+ process.exit(1);
1580
1542
  }
1581
1543
  }
1582
1544
  log9.step("Step 3/9 Configuration");
@@ -1650,7 +1612,7 @@ Files created: docker-compose.yml, Caddyfile, .env.web, .env.engine, lead-routin
1650
1612
 
1651
1613
  // src/commands/deploy.ts
1652
1614
  import { writeFileSync as writeFileSync4, unlinkSync } from "fs";
1653
- import { join as join7 } from "path";
1615
+ import { join as join6 } from "path";
1654
1616
  import { tmpdir as tmpdir2 } from "os";
1655
1617
  import { intro as intro2, outro as outro2, log as log10, password as promptPassword2 } from "@clack/prompts";
1656
1618
  import chalk3 from "chalk";
@@ -1692,7 +1654,7 @@ async function runDeploy() {
1692
1654
  const remoteDir = await ssh.resolveHome(cfg.remoteDir);
1693
1655
  log10.step("Syncing Caddyfile");
1694
1656
  const caddyContent = renderCaddyfile(cfg.appUrl, cfg.engineUrl);
1695
- const tmpCaddy = join7(tmpdir2(), "lead-routing-Caddyfile");
1657
+ const tmpCaddy = join6(tmpdir2(), "lead-routing-Caddyfile");
1696
1658
  writeFileSync4(tmpCaddy, caddyContent, "utf8");
1697
1659
  await ssh.upload([{ local: tmpCaddy, remote: `${remoteDir}/Caddyfile` }]);
1698
1660
  unlinkSync(tmpCaddy);
@@ -1858,7 +1820,7 @@ async function runStatus() {
1858
1820
 
1859
1821
  // src/commands/config.ts
1860
1822
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "fs";
1861
- import { join as join8 } from "path";
1823
+ import { join as join7 } from "path";
1862
1824
  import { intro as intro4, outro as outro4, text as text3, password as password3, spinner as spinner8, log as log14 } from "@clack/prompts";
1863
1825
  import chalk5 from "chalk";
1864
1826
  import { execa as execa7 } from "execa";
@@ -1902,8 +1864,8 @@ async function runConfigSfdc() {
1902
1864
  log14.info("Run `lead-routing init` first, or cd into your installation directory.");
1903
1865
  process.exit(1);
1904
1866
  }
1905
- const envWeb = join8(dir, ".env.web");
1906
- const envEngine = join8(dir, ".env.engine");
1867
+ const envWeb = join7(dir, ".env.web");
1868
+ const envEngine = join7(dir, ".env.engine");
1907
1869
  const currentWeb = parseEnv(envWeb);
1908
1870
  const currentClientId = currentWeb.get("SFDC_CLIENT_ID") ?? "";
1909
1871
  const currentLoginUrl = currentWeb.get("SFDC_LOGIN_URL") ?? "https://login.salesforce.com";
@@ -1956,7 +1918,7 @@ function runConfigShow() {
1956
1918
  console.error("No lead-routing installation found in the current directory.");
1957
1919
  process.exit(1);
1958
1920
  }
1959
- const envWeb = join8(dir, ".env.web");
1921
+ const envWeb = join7(dir, ".env.web");
1960
1922
  const cfg = parseEnv(envWeb);
1961
1923
  const adminSecret = cfg.get("ADMIN_SECRET") ?? "(not found)";
1962
1924
  const appUrl = cfg.get("APP_URL") ?? "(not found)";
@@ -2043,7 +2005,7 @@ async function runSfdcDeploy() {
2043
2005
 
2044
2006
  // src/index.ts
2045
2007
  var program = new Command();
2046
- program.name("lead-routing").description("Self-hosted Lead Routing \u2014 scaffold, deploy, and manage your installation").version("0.1.10");
2008
+ program.name("lead-routing").description("Self-hosted Lead Routing \u2014 scaffold, deploy, and manage your installation").version("0.1.11");
2047
2009
  program.command("init").description("Interactive setup wizard \u2014 configure and deploy the full Lead Routing stack").option("--dry-run", "Generate config files without connecting or deploying").option("--resume", "Skip to health check using existing lead-routing.json (post-timeout recovery)").option("--sandbox", "Use Salesforce sandbox (test.salesforce.com) instead of production").option("--ssh-port <port>", "SSH port (default: 22)", parseInt).option("--ssh-user <user>", "SSH username (default: root)").option("--ssh-key <path>", "Path to SSH private key (overrides auto-detection)").option("--remote-dir <path>", "Remote install directory (default: ~/lead-routing)").option("--external-db <url>", "Use external PostgreSQL URL instead of managed Docker container").option("--external-redis <url>", "Use external Redis URL instead of managed Docker container").action((opts) => runInit({
2048
2010
  dryRun: opts.dryRun,
2049
2011
  resume: opts.resume,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lead-routing/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Self-hosted deployment CLI for Lead Routing",
5
5
  "homepage": "https://github.com/lead-routing/lead-routing",
6
6
  "keywords": ["salesforce", "lead-routing", "self-hosted", "deployment", "cli"],