@lead-routing/cli 0.1.4 → 0.1.5

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 +92 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,8 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
- import { intro, outro, note as note4, log as log8 } from "@clack/prompts";
7
+ import { promises as dns } from "dns";
8
+ import { intro, outro, note as note4, log as log8, confirm as confirm3, cancel as cancel3, isCancel as isCancel4, password as promptPassword } from "@clack/prompts";
8
9
  import chalk2 from "chalk";
9
10
 
10
11
  // src/steps/prerequisites.ts
@@ -1507,13 +1508,97 @@ ${result.stderr || result.stdout}`
1507
1508
  };
1508
1509
 
1509
1510
  // src/commands/init.ts
1511
+ async function checkDnsResolvable(appUrl, engineUrl) {
1512
+ let hosts;
1513
+ try {
1514
+ hosts = [.../* @__PURE__ */ new Set([new URL(appUrl).hostname, new URL(engineUrl).hostname])];
1515
+ } catch {
1516
+ return;
1517
+ }
1518
+ for (const host of hosts) {
1519
+ try {
1520
+ await dns.lookup(host);
1521
+ } catch {
1522
+ log8.warn(
1523
+ `${chalk2.yellow(host)} does not resolve in DNS yet.
1524
+ Check for typos \u2014 a bad domain will cause a 2-minute timeout at step 8.`
1525
+ );
1526
+ const go = await confirm3({ message: "Continue anyway?", initialValue: true });
1527
+ if (isCancel4(go) || !go) {
1528
+ cancel3("Setup cancelled.");
1529
+ process.exit(0);
1530
+ }
1531
+ }
1532
+ }
1533
+ }
1510
1534
  async function runInit(options = {}) {
1511
1535
  const dryRun = options.dryRun ?? false;
1536
+ const resume = options.resume ?? false;
1512
1537
  console.log();
1513
1538
  intro(
1514
- chalk2.bold.cyan("Lead Routing \u2014 Self-Hosted Setup") + (dryRun ? chalk2.yellow(" [dry run]") : "")
1539
+ chalk2.bold.cyan("Lead Routing \u2014 Self-Hosted Setup") + (dryRun ? chalk2.yellow(" [dry run]") : "") + (resume ? chalk2.yellow(" [resume]") : "")
1515
1540
  );
1516
1541
  const ssh = new SshConnection();
1542
+ if (resume) {
1543
+ try {
1544
+ const dir = findInstallDir();
1545
+ if (!dir) {
1546
+ log8.error("No lead-routing.json found \u2014 run `lead-routing init` first.");
1547
+ process.exit(1);
1548
+ }
1549
+ const saved = readConfig(dir);
1550
+ let sshPassword;
1551
+ if (!saved.ssh.privateKeyPath) {
1552
+ const pw = await promptPassword({
1553
+ message: `SSH password for ${saved.ssh.username}@${saved.ssh.host}`
1554
+ });
1555
+ if (typeof pw === "symbol") process.exit(0);
1556
+ sshPassword = pw;
1557
+ }
1558
+ log8.step("Connecting to server");
1559
+ await ssh.connect({
1560
+ host: saved.ssh.host,
1561
+ port: saved.ssh.port,
1562
+ username: saved.ssh.username,
1563
+ privateKeyPath: saved.ssh.privateKeyPath,
1564
+ password: sshPassword,
1565
+ remoteDir: saved.remoteDir
1566
+ });
1567
+ log8.success(`Connected to ${saved.ssh.host}`);
1568
+ const remoteDir = await ssh.resolveHome(saved.remoteDir);
1569
+ log8.step("Step 8/9 Verifying health");
1570
+ await verifyHealth(saved.appUrl, saved.engineUrl, ssh, remoteDir);
1571
+ log8.step("Step 9/9 Deploying Salesforce package");
1572
+ await sfdcDeployInline({
1573
+ appUrl: saved.appUrl,
1574
+ engineUrl: saved.engineUrl,
1575
+ orgAlias: "lead-routing",
1576
+ sfdcClientId: saved.sfdcClientId ?? "",
1577
+ sfdcLoginUrl: saved.sfdcLoginUrl ?? "https://login.salesforce.com",
1578
+ installDir: dir
1579
+ });
1580
+ await guideAppLauncherSetup(saved.appUrl);
1581
+ outro(
1582
+ chalk2.green("\u2714 You're live!") + `
1583
+
1584
+ Dashboard: ${chalk2.cyan(saved.appUrl)}
1585
+ Routing engine: ${chalk2.cyan(saved.engineUrl)}
1586
+
1587
+ ` + chalk2.bold(" Next steps:\n") + ` ${chalk2.cyan("1.")} Open ${chalk2.cyan(saved.appUrl)} and log in
1588
+ ${chalk2.cyan("2.")} Create your first routing rule to start routing leads
1589
+
1590
+ Run ${chalk2.cyan("lead-routing doctor")} to check service health at any time.
1591
+ Run ${chalk2.cyan("lead-routing deploy")} to update to a new version.`
1592
+ );
1593
+ } catch (err) {
1594
+ const message = err instanceof Error ? err.message : String(err);
1595
+ log8.error(`Resume failed: ${message}`);
1596
+ process.exit(1);
1597
+ } finally {
1598
+ await ssh.disconnect();
1599
+ }
1600
+ return;
1601
+ }
1517
1602
  try {
1518
1603
  log8.step("Step 1/9 Checking local prerequisites");
1519
1604
  await checkPrerequisites();
@@ -1521,6 +1606,7 @@ async function runInit(options = {}) {
1521
1606
  const sshCfg = await collectSshConfig();
1522
1607
  log8.step("Step 3/9 Configuration");
1523
1608
  const cfg = await collectConfig();
1609
+ await checkDnsResolvable(cfg.appUrl, cfg.engineUrl);
1524
1610
  log8.step("Step 4/9 Generating config files");
1525
1611
  const { dir, adminSecret } = generateFiles(cfg, sshCfg);
1526
1612
  note4(
@@ -1588,7 +1674,7 @@ Files created: docker-compose.yml, Caddyfile, .env.web, .env.engine, lead-routin
1588
1674
  import { writeFileSync as writeFileSync4, unlinkSync } from "fs";
1589
1675
  import { join as join6 } from "path";
1590
1676
  import { tmpdir as tmpdir2 } from "os";
1591
- import { intro as intro2, outro as outro2, log as log9, password as promptPassword } from "@clack/prompts";
1677
+ import { intro as intro2, outro as outro2, log as log9, password as promptPassword2 } from "@clack/prompts";
1592
1678
  import chalk3 from "chalk";
1593
1679
  async function runDeploy() {
1594
1680
  console.log();
@@ -1604,7 +1690,7 @@ async function runDeploy() {
1604
1690
  const ssh = new SshConnection();
1605
1691
  let sshPassword;
1606
1692
  if (!cfg.ssh.privateKeyPath) {
1607
- const pw = await promptPassword({
1693
+ const pw = await promptPassword2({
1608
1694
  message: `SSH password for ${cfg.ssh.username}@${cfg.ssh.host}`
1609
1695
  });
1610
1696
  if (typeof pw === "symbol") process.exit(0);
@@ -1969,14 +2055,10 @@ async function runSfdcDeploy() {
1969
2055
  log14.error(err instanceof Error ? err.message : String(err));
1970
2056
  process.exit(1);
1971
2057
  }
2058
+ await guideAppLauncherSetup(appUrl);
1972
2059
  outro5(
1973
2060
  chalk6.green("\u2714 Salesforce package deployed!") + `
1974
2061
 
1975
- Next steps:
1976
- 1. In Salesforce, open App Launcher \u2192 search "Lead Router Setup"
1977
- 2. Click "Connect to Lead Router" to authorise the OAuth connection
1978
- 3. Follow the 4-step wizard to activate triggers and sync field schema
1979
-
1980
2062
  Your Lead Router dashboard: ${chalk6.cyan(appUrl)}`
1981
2063
  );
1982
2064
  }
@@ -1984,7 +2066,7 @@ async function runSfdcDeploy() {
1984
2066
  // src/index.ts
1985
2067
  var program = new Command();
1986
2068
  program.name("lead-routing").description("Self-hosted Lead Routing \u2014 scaffold, deploy, and manage your installation").version("0.1.0");
1987
- program.command("init").description("Interactive setup wizard \u2014 configure and deploy the full Lead Routing stack").option("--dry-run", "Run the wizard and generate config files without starting Docker services").action((opts) => runInit({ dryRun: opts.dryRun }));
2069
+ program.command("init").description("Interactive setup wizard \u2014 configure and deploy the full Lead Routing stack").option("--dry-run", "Run the wizard and generate config files without starting Docker services").option("--resume", "Skip steps 1-7 and resume from health check using existing lead-routing.json").action((opts) => runInit({ dryRun: opts.dryRun, resume: opts.resume }));
1988
2070
  program.command("deploy").description("Pull latest images, restart services, and run any pending migrations").action(runDeploy);
1989
2071
  program.command("doctor").description("Check the health of all services in your installation").action(runDoctor);
1990
2072
  program.command("logs [service]").description("Stream logs from a service (web, engine, postgres, redis). Defaults to engine.").action((service) => runLogs(service));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lead-routing/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
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"],