@lead-routing/cli 0.1.10 → 0.1.12

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 +41 -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
 
@@ -385,6 +369,7 @@ function renderEnvWeb(c) {
385
369
  ``,
386
370
  `# Engine`,
387
371
  `ENGINE_URL=${c.engineUrl}`,
372
+ `PUBLIC_ENGINE_URL=${c.publicEngineUrl}`,
388
373
  `ENGINE_WEBHOOK_SECRET=${c.engineWebhookSecret}`,
389
374
  ``,
390
375
  `# Database`,
@@ -489,9 +474,9 @@ function renderCaddyfile(appUrl, engineUrl) {
489
474
 
490
475
  // src/utils/config.ts
491
476
  import { readFileSync, writeFileSync, existsSync as existsSync2 } from "fs";
492
- import { join as join2 } from "path";
477
+ import { join } from "path";
493
478
  function getConfigPath(dir) {
494
- return join2(dir, "lead-routing.json");
479
+ return join(dir, "lead-routing.json");
495
480
  }
496
481
  function readConfig(dir) {
497
482
  const path2 = getConfigPath(dir);
@@ -506,10 +491,10 @@ function writeConfig(dir, config2) {
506
491
  writeFileSync(getConfigPath(dir), JSON.stringify(config2, null, 2), "utf8");
507
492
  }
508
493
  function findInstallDir(startDir = process.cwd()) {
509
- const candidate = join2(startDir, "lead-routing.json");
494
+ const candidate = join(startDir, "lead-routing.json");
510
495
  if (existsSync2(candidate)) return startDir;
511
- const nested = join2(startDir, "lead-routing", "lead-routing.json");
512
- if (existsSync2(nested)) return join2(startDir, "lead-routing");
496
+ const nested = join(startDir, "lead-routing", "lead-routing.json");
497
+ if (existsSync2(nested)) return join(startDir, "lead-routing");
513
498
  return null;
514
499
  }
515
500
 
@@ -517,14 +502,14 @@ function findInstallDir(startDir = process.cwd()) {
517
502
  var __dirname = dirname(fileURLToPath(import.meta.url));
518
503
  function getCliVersion() {
519
504
  try {
520
- const pkg = JSON.parse(readFileSync2(join3(__dirname, "../../package.json"), "utf8"));
505
+ const pkg = JSON.parse(readFileSync2(join2(__dirname, "../../package.json"), "utf8"));
521
506
  return pkg.version ?? "0.1.0";
522
507
  } catch {
523
508
  return "0.1.0";
524
509
  }
525
510
  }
526
511
  function generateFiles(cfg, sshCfg) {
527
- const dir = join3(process.cwd(), "lead-routing");
512
+ const dir = join2(process.cwd(), "lead-routing");
528
513
  mkdirSync(dir, { recursive: true });
529
514
  const dockerEngineUrl = `http://engine:3001`;
530
515
  const composeContent = renderDockerCompose({
@@ -532,15 +517,16 @@ function generateFiles(cfg, sshCfg) {
532
517
  managedRedis: cfg.managedRedis,
533
518
  dbPassword: cfg.dbPassword
534
519
  });
535
- const composeFile = join3(dir, "docker-compose.yml");
520
+ const composeFile = join2(dir, "docker-compose.yml");
536
521
  writeFileSync2(composeFile, composeContent, "utf8");
537
522
  log3.success("Generated docker-compose.yml");
538
523
  const caddyfileContent = renderCaddyfile(cfg.appUrl, cfg.engineUrl);
539
- writeFileSync2(join3(dir, "Caddyfile"), caddyfileContent, "utf8");
524
+ writeFileSync2(join2(dir, "Caddyfile"), caddyfileContent, "utf8");
540
525
  log3.success("Generated Caddyfile");
541
526
  const envWebContent = renderEnvWeb({
542
527
  appUrl: cfg.appUrl,
543
528
  engineUrl: dockerEngineUrl,
529
+ publicEngineUrl: cfg.engineUrl,
544
530
  databaseUrl: cfg.databaseUrl,
545
531
  redisUrl: cfg.redisUrl,
546
532
  sfdcClientId: cfg.sfdcClientId,
@@ -552,7 +538,7 @@ function generateFiles(cfg, sshCfg) {
552
538
  resendApiKey: cfg.resendApiKey || void 0,
553
539
  feedbackToEmail: cfg.feedbackToEmail || void 0
554
540
  });
555
- const envWeb = join3(dir, ".env.web");
541
+ const envWeb = join2(dir, ".env.web");
556
542
  writeFileSync2(envWeb, envWebContent, "utf8");
557
543
  log3.success("Generated .env.web");
558
544
  const envEngineContent = renderEnvEngine({
@@ -563,7 +549,7 @@ function generateFiles(cfg, sshCfg) {
563
549
  sfdcLoginUrl: cfg.sfdcLoginUrl,
564
550
  engineWebhookSecret: cfg.engineWebhookSecret
565
551
  });
566
- const envEngine = join3(dir, ".env.engine");
552
+ const envEngine = join2(dir, ".env.engine");
567
553
  writeFileSync2(envEngine, envEngineContent, "utf8");
568
554
  log3.success("Generated .env.engine");
569
555
  writeConfig(dir, {
@@ -732,7 +718,7 @@ async function checkRemotePort(ssh, port) {
732
718
  }
733
719
 
734
720
  // src/steps/upload-files.ts
735
- import { join as join4 } from "path";
721
+ import { join as join3 } from "path";
736
722
  import { spinner as spinner3 } from "@clack/prompts";
737
723
  async function uploadFiles(ssh, localDir, remoteDir) {
738
724
  const s = spinner3();
@@ -748,7 +734,7 @@ async function uploadFiles(ssh, localDir, remoteDir) {
748
734
  ];
749
735
  await ssh.upload(
750
736
  filenames.map((f) => ({
751
- local: join4(localDir, f),
737
+ local: join3(localDir, f),
752
738
  remote: `${remoteDir}/${f}`
753
739
  }))
754
740
  );
@@ -1039,7 +1025,7 @@ function sleep2(ms) {
1039
1025
 
1040
1026
  // src/steps/sfdc-deploy-inline.ts
1041
1027
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, cpSync, rmSync } from "fs";
1042
- import { join as join6, dirname as dirname3 } from "path";
1028
+ import { join as join5, dirname as dirname3 } from "path";
1043
1029
  import { tmpdir } from "os";
1044
1030
  import { fileURLToPath as fileURLToPath3 } from "url";
1045
1031
  import { spinner as spinner7, log as log7 } from "@clack/prompts";
@@ -1070,10 +1056,10 @@ async function sfdcDeployInline(params) {
1070
1056
  }
1071
1057
  }
1072
1058
  s.start("Copying Salesforce package\u2026");
1073
- const inDist = join6(__dirname3, "sfdc-package");
1074
- const nextToDist = join6(__dirname3, "..", "sfdc-package");
1059
+ const inDist = join5(__dirname3, "sfdc-package");
1060
+ const nextToDist = join5(__dirname3, "..", "sfdc-package");
1075
1061
  const bundledPkg = existsSync4(inDist) ? inDist : nextToDist;
1076
- const destPkg = join6(installDir ?? tmpdir(), "lead-routing-sfdc-package");
1062
+ const destPkg = join5(installDir ?? tmpdir(), "lead-routing-sfdc-package");
1077
1063
  if (!existsSync4(bundledPkg)) {
1078
1064
  s.stop("sfdc-package not found in CLI bundle");
1079
1065
  throw new Error(
@@ -1084,7 +1070,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1084
1070
  if (existsSync4(destPkg)) rmSync(destPkg, { recursive: true, force: true });
1085
1071
  cpSync(bundledPkg, destPkg, { recursive: true });
1086
1072
  s.stop("Package copied");
1087
- const ncPath = join6(
1073
+ const ncPath = join5(
1088
1074
  destPkg,
1089
1075
  "force-app",
1090
1076
  "main",
@@ -1096,7 +1082,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1096
1082
  const nc = patchXml(readFileSync4(ncPath, "utf8"), "endpoint", engineUrl);
1097
1083
  writeFileSync3(ncPath, nc, "utf8");
1098
1084
  }
1099
- const rssEnginePath = join6(
1085
+ const rssEnginePath = join5(
1100
1086
  destPkg,
1101
1087
  "force-app",
1102
1088
  "main",
@@ -1109,7 +1095,7 @@ The CLI may need to be reinstalled: npm i -g @lead-routing/cli`
1109
1095
  rss = patchXml(rss, "description", "Lead Router Engine endpoint");
1110
1096
  writeFileSync3(rssEnginePath, rss, "utf8");
1111
1097
  }
1112
- const rssAppPath = join6(
1098
+ const rssAppPath = join5(
1113
1099
  destPkg,
1114
1100
  "force-app",
1115
1101
  "main",
@@ -1541,7 +1527,7 @@ async function runInit(options = {}) {
1541
1527
  log9.step("Step 1/9 Checking local prerequisites");
1542
1528
  await checkPrerequisites();
1543
1529
  log9.step("Step 2/9 SSH connection");
1544
- let sshCfg = await collectSshConfig({
1530
+ const sshCfg = await collectSshConfig({
1545
1531
  sshPort: options.sshPort,
1546
1532
  sshUser: options.sshUser,
1547
1533
  sshKey: options.sshKey,
@@ -1552,31 +1538,9 @@ async function runInit(options = {}) {
1552
1538
  await ssh.connect(sshCfg);
1553
1539
  log9.success(`Connected to ${sshCfg.host}`);
1554
1540
  } 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
- }
1541
+ log9.error(`SSH connection failed: ${String(err)}`);
1542
+ log9.info("Check your password and re-run `lead-routing init`.");
1543
+ process.exit(1);
1580
1544
  }
1581
1545
  }
1582
1546
  log9.step("Step 3/9 Configuration");
@@ -1650,7 +1614,7 @@ Files created: docker-compose.yml, Caddyfile, .env.web, .env.engine, lead-routin
1650
1614
 
1651
1615
  // src/commands/deploy.ts
1652
1616
  import { writeFileSync as writeFileSync4, unlinkSync } from "fs";
1653
- import { join as join7 } from "path";
1617
+ import { join as join6 } from "path";
1654
1618
  import { tmpdir as tmpdir2 } from "os";
1655
1619
  import { intro as intro2, outro as outro2, log as log10, password as promptPassword2 } from "@clack/prompts";
1656
1620
  import chalk3 from "chalk";
@@ -1692,7 +1656,7 @@ async function runDeploy() {
1692
1656
  const remoteDir = await ssh.resolveHome(cfg.remoteDir);
1693
1657
  log10.step("Syncing Caddyfile");
1694
1658
  const caddyContent = renderCaddyfile(cfg.appUrl, cfg.engineUrl);
1695
- const tmpCaddy = join7(tmpdir2(), "lead-routing-Caddyfile");
1659
+ const tmpCaddy = join6(tmpdir2(), "lead-routing-Caddyfile");
1696
1660
  writeFileSync4(tmpCaddy, caddyContent, "utf8");
1697
1661
  await ssh.upload([{ local: tmpCaddy, remote: `${remoteDir}/Caddyfile` }]);
1698
1662
  unlinkSync(tmpCaddy);
@@ -1858,7 +1822,7 @@ async function runStatus() {
1858
1822
 
1859
1823
  // src/commands/config.ts
1860
1824
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "fs";
1861
- import { join as join8 } from "path";
1825
+ import { join as join7 } from "path";
1862
1826
  import { intro as intro4, outro as outro4, text as text3, password as password3, spinner as spinner8, log as log14 } from "@clack/prompts";
1863
1827
  import chalk5 from "chalk";
1864
1828
  import { execa as execa7 } from "execa";
@@ -1902,8 +1866,8 @@ async function runConfigSfdc() {
1902
1866
  log14.info("Run `lead-routing init` first, or cd into your installation directory.");
1903
1867
  process.exit(1);
1904
1868
  }
1905
- const envWeb = join8(dir, ".env.web");
1906
- const envEngine = join8(dir, ".env.engine");
1869
+ const envWeb = join7(dir, ".env.web");
1870
+ const envEngine = join7(dir, ".env.engine");
1907
1871
  const currentWeb = parseEnv(envWeb);
1908
1872
  const currentClientId = currentWeb.get("SFDC_CLIENT_ID") ?? "";
1909
1873
  const currentLoginUrl = currentWeb.get("SFDC_LOGIN_URL") ?? "https://login.salesforce.com";
@@ -1956,7 +1920,7 @@ function runConfigShow() {
1956
1920
  console.error("No lead-routing installation found in the current directory.");
1957
1921
  process.exit(1);
1958
1922
  }
1959
- const envWeb = join8(dir, ".env.web");
1923
+ const envWeb = join7(dir, ".env.web");
1960
1924
  const cfg = parseEnv(envWeb);
1961
1925
  const adminSecret = cfg.get("ADMIN_SECRET") ?? "(not found)";
1962
1926
  const appUrl = cfg.get("APP_URL") ?? "(not found)";
@@ -2043,7 +2007,7 @@ async function runSfdcDeploy() {
2043
2007
 
2044
2008
  // src/index.ts
2045
2009
  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");
2010
+ program.name("lead-routing").description("Self-hosted Lead Routing \u2014 scaffold, deploy, and manage your installation").version("0.1.12");
2047
2011
  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
2012
  dryRun: opts.dryRun,
2049
2013
  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.12",
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"],