@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.
- package/dist/index.js +92 -10
- 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 {
|
|
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
|
|
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
|
|
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.
|
|
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"],
|