@lead-routing/cli 0.6.2 → 0.6.4
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 +135 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "
|
|
|
9
9
|
import { exec } from "child_process";
|
|
10
10
|
import { platform } from "os";
|
|
11
11
|
import { join as join5 } from "path";
|
|
12
|
-
import { intro, outro, note as note3, log as log7, confirm, cancel as cancel3, isCancel as isCancel3, password as promptPassword } from "@clack/prompts";
|
|
12
|
+
import { intro, outro, note as note3, log as log7, confirm, cancel as cancel3, isCancel as isCancel3, password as promptPassword, select, text as text3 } from "@clack/prompts";
|
|
13
13
|
import chalk2 from "chalk";
|
|
14
14
|
|
|
15
15
|
// src/steps/prerequisites.ts
|
|
@@ -1208,16 +1208,108 @@ async function runInit(options = {}) {
|
|
|
1208
1208
|
let auth;
|
|
1209
1209
|
try {
|
|
1210
1210
|
auth = await requireAuth();
|
|
1211
|
-
} catch
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
)
|
|
1220
|
-
|
|
1211
|
+
} catch {
|
|
1212
|
+
const action = await select({
|
|
1213
|
+
message: "You need an account to continue. What would you like to do?",
|
|
1214
|
+
options: [
|
|
1215
|
+
{ value: "signup", label: "Create a new account" },
|
|
1216
|
+
{ value: "login", label: "Log in to existing account" }
|
|
1217
|
+
]
|
|
1218
|
+
});
|
|
1219
|
+
if (isCancel3(action)) {
|
|
1220
|
+
cancel3("Setup cancelled.");
|
|
1221
|
+
process.exit(0);
|
|
1222
|
+
}
|
|
1223
|
+
if (action === "signup") {
|
|
1224
|
+
const firstName = await text3({ message: "First name", placeholder: "John", validate: (v) => v.trim() ? void 0 : "Required" });
|
|
1225
|
+
if (isCancel3(firstName)) {
|
|
1226
|
+
cancel3("Setup cancelled.");
|
|
1227
|
+
process.exit(0);
|
|
1228
|
+
}
|
|
1229
|
+
const lastName = await text3({ message: "Last name", placeholder: "Smith", validate: (v) => v.trim() ? void 0 : "Required" });
|
|
1230
|
+
if (isCancel3(lastName)) {
|
|
1231
|
+
cancel3("Setup cancelled.");
|
|
1232
|
+
process.exit(0);
|
|
1233
|
+
}
|
|
1234
|
+
const signupEmail = await text3({ message: "Email", placeholder: "john@acme.com", validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()) ? void 0 : "Invalid email" });
|
|
1235
|
+
if (isCancel3(signupEmail)) {
|
|
1236
|
+
cancel3("Setup cancelled.");
|
|
1237
|
+
process.exit(0);
|
|
1238
|
+
}
|
|
1239
|
+
const signupPw = await promptPassword({ message: "Password (min 8 characters)", validate: (v) => v.length >= 8 ? void 0 : "Must be at least 8 characters" });
|
|
1240
|
+
if (isCancel3(signupPw)) {
|
|
1241
|
+
cancel3("Setup cancelled.");
|
|
1242
|
+
process.exit(0);
|
|
1243
|
+
}
|
|
1244
|
+
const confirmPw = await promptPassword({ message: "Confirm password", validate: (v) => v === signupPw ? void 0 : "Passwords do not match" });
|
|
1245
|
+
if (isCancel3(confirmPw)) {
|
|
1246
|
+
cancel3("Setup cancelled.");
|
|
1247
|
+
process.exit(0);
|
|
1248
|
+
}
|
|
1249
|
+
log7.step("Creating account...");
|
|
1250
|
+
try {
|
|
1251
|
+
await apiSignup({ firstName: firstName.trim(), lastName: lastName.trim(), email: signupEmail.trim(), password: signupPw });
|
|
1252
|
+
log7.success("Account created!");
|
|
1253
|
+
} catch (err) {
|
|
1254
|
+
log7.error(err instanceof Error ? err.message : "Signup failed");
|
|
1255
|
+
process.exit(1);
|
|
1256
|
+
}
|
|
1257
|
+
note3(
|
|
1258
|
+
`Check your email (${signupEmail.trim()}) for a verification link.
|
|
1259
|
+
After verifying, press Enter to continue.`,
|
|
1260
|
+
"Verify Email"
|
|
1261
|
+
);
|
|
1262
|
+
await text3({ message: "Press Enter once you've verified your email...", defaultValue: "" });
|
|
1263
|
+
log7.step("Logging in...");
|
|
1264
|
+
try {
|
|
1265
|
+
const { token, customer } = await apiLogin(signupEmail.trim(), signupPw);
|
|
1266
|
+
if (!customer.emailVerified) {
|
|
1267
|
+
log7.warn("Email not verified yet.");
|
|
1268
|
+
const resend = await confirm({ message: "Resend verification email?" });
|
|
1269
|
+
if (resend && !isCancel3(resend)) {
|
|
1270
|
+
await apiResendVerification(token).catch(() => {
|
|
1271
|
+
});
|
|
1272
|
+
log7.info("Verification email sent. Verify and re-run `lead-routing init`.");
|
|
1273
|
+
}
|
|
1274
|
+
process.exit(1);
|
|
1275
|
+
}
|
|
1276
|
+
saveCredentials({ token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1277
|
+
auth = { token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
log7.error(err instanceof Error ? err.message : "Login failed");
|
|
1280
|
+
process.exit(1);
|
|
1281
|
+
}
|
|
1282
|
+
} else {
|
|
1283
|
+
const loginEmail = await text3({ message: "Email", placeholder: "john@acme.com" });
|
|
1284
|
+
if (isCancel3(loginEmail)) {
|
|
1285
|
+
cancel3("Setup cancelled.");
|
|
1286
|
+
process.exit(0);
|
|
1287
|
+
}
|
|
1288
|
+
const loginPw = await promptPassword({ message: "Password" });
|
|
1289
|
+
if (isCancel3(loginPw)) {
|
|
1290
|
+
cancel3("Setup cancelled.");
|
|
1291
|
+
process.exit(0);
|
|
1292
|
+
}
|
|
1293
|
+
log7.step("Authenticating...");
|
|
1294
|
+
try {
|
|
1295
|
+
const { token, customer } = await apiLogin(loginEmail.trim(), loginPw);
|
|
1296
|
+
if (!customer.emailVerified) {
|
|
1297
|
+
log7.warn("Email not verified yet.");
|
|
1298
|
+
const resend = await confirm({ message: "Resend verification email?" });
|
|
1299
|
+
if (resend && !isCancel3(resend)) {
|
|
1300
|
+
await apiResendVerification(token).catch(() => {
|
|
1301
|
+
});
|
|
1302
|
+
log7.info("Verification email sent. Verify and re-run `lead-routing init`.");
|
|
1303
|
+
}
|
|
1304
|
+
process.exit(1);
|
|
1305
|
+
}
|
|
1306
|
+
saveCredentials({ token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1307
|
+
auth = { token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1308
|
+
} catch (err) {
|
|
1309
|
+
log7.error(err instanceof Error ? err.message : "Login failed");
|
|
1310
|
+
process.exit(1);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1221
1313
|
}
|
|
1222
1314
|
log7.success(`Logged in as ${auth.customer.firstName} ${auth.customer.lastName} \u2014 ${formatTierBadge(auth.customer.tier)}`);
|
|
1223
1315
|
try {
|
|
@@ -1313,6 +1405,24 @@ Files created: docker-compose.yml, Caddyfile, .env.web, .env.engine, lead-routin
|
|
|
1313
1405
|
The managed package is already installed \u2014 just click "Connect Salesforce" to authorize.`,
|
|
1314
1406
|
"Next: Connect Salesforce"
|
|
1315
1407
|
);
|
|
1408
|
+
let webhookSecret = "";
|
|
1409
|
+
try {
|
|
1410
|
+
const envEngineContent = readFileSync4(join5(dir, ".env.engine"), "utf-8");
|
|
1411
|
+
const match = envEngineContent.match(/^WEBHOOK_SECRET=(.+)$/m);
|
|
1412
|
+
if (match) webhookSecret = match[1].trim();
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
if (webhookSecret) {
|
|
1416
|
+
const mcpCmd = `claude mcp add lead-routing \\
|
|
1417
|
+
-e APP_URL=${cfg.appUrl} \\
|
|
1418
|
+
-e ENGINE_URL=${cfg.engineUrl} \\
|
|
1419
|
+
-e WEBHOOK_SECRET=${webhookSecret} \\
|
|
1420
|
+
-- npx -y @lead-routing/mcp`;
|
|
1421
|
+
note3(
|
|
1422
|
+
"Paste this command in your terminal to connect Lead Routing to Claude Code:\n\n" + chalk2.cyan(mcpCmd),
|
|
1423
|
+
"Claude Code MCP"
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1316
1426
|
outro(
|
|
1317
1427
|
chalk2.green("\u2714 You're live!") + `
|
|
1318
1428
|
|
|
@@ -1591,7 +1701,7 @@ function runConfigShow() {
|
|
|
1591
1701
|
}
|
|
1592
1702
|
|
|
1593
1703
|
// src/commands/sfdc.ts
|
|
1594
|
-
import { intro as intro5, outro as outro5, text as
|
|
1704
|
+
import { intro as intro5, outro as outro5, text as text4, note as note4, confirm as confirm2, log as log14, isCancel as isCancel4, cancel as cancel4 } from "@clack/prompts";
|
|
1595
1705
|
import chalk6 from "chalk";
|
|
1596
1706
|
import { exec as exec2 } from "child_process";
|
|
1597
1707
|
import { platform as platform2 } from "os";
|
|
@@ -1723,9 +1833,9 @@ Content-Type: application/zip\r
|
|
|
1723
1833
|
body
|
|
1724
1834
|
});
|
|
1725
1835
|
if (!res.ok) {
|
|
1726
|
-
const
|
|
1836
|
+
const text8 = await res.text();
|
|
1727
1837
|
throw new Error(
|
|
1728
|
-
`Metadata deploy request failed (${res.status}): ${
|
|
1838
|
+
`Metadata deploy request failed (${res.status}): ${text8}`
|
|
1729
1839
|
);
|
|
1730
1840
|
}
|
|
1731
1841
|
const result = await res.json();
|
|
@@ -1742,9 +1852,9 @@ Content-Type: application/zip\r
|
|
|
1742
1852
|
const url = `${this.baseUrl}/metadata/deployRequest/${deployId}?includeDetails=true`;
|
|
1743
1853
|
const res = await fetch(url, { headers: this.headers() });
|
|
1744
1854
|
if (!res.ok) {
|
|
1745
|
-
const
|
|
1855
|
+
const text8 = await res.text();
|
|
1746
1856
|
throw new Error(
|
|
1747
|
-
`Deploy status check failed (${res.status}): ${
|
|
1857
|
+
`Deploy status check failed (${res.status}): ${text8}`
|
|
1748
1858
|
);
|
|
1749
1859
|
}
|
|
1750
1860
|
const data = await res.json();
|
|
@@ -2112,13 +2222,13 @@ async function runSfdcDeploy() {
|
|
|
2112
2222
|
log14.info(`Using config from ${dir}/lead-routing.json`);
|
|
2113
2223
|
} else {
|
|
2114
2224
|
log14.warn("No lead-routing.json found \u2014 enter the URLs from your installation.");
|
|
2115
|
-
const rawApp = await
|
|
2225
|
+
const rawApp = await text4({
|
|
2116
2226
|
message: "App URL (e.g. https://leads.acme.com)",
|
|
2117
2227
|
validate: (v) => !v ? "Required" : void 0
|
|
2118
2228
|
});
|
|
2119
2229
|
if (typeof rawApp === "symbol") process.exit(0);
|
|
2120
2230
|
appUrl = rawApp.trim();
|
|
2121
|
-
const rawEngine = await
|
|
2231
|
+
const rawEngine = await text4({
|
|
2122
2232
|
message: "Engine URL (e.g. https://engine.acme.com or https://acme.com:3001)",
|
|
2123
2233
|
validate: (v) => !v ? "Required" : void 0
|
|
2124
2234
|
});
|
|
@@ -2148,7 +2258,7 @@ Install URL: ${chalk6.cyan(MANAGED_PACKAGE_INSTALL_URL2)}`,
|
|
|
2148
2258
|
} else {
|
|
2149
2259
|
log14.success("Salesforce package installed");
|
|
2150
2260
|
}
|
|
2151
|
-
const alias = await
|
|
2261
|
+
const alias = await text4({
|
|
2152
2262
|
message: "Salesforce org alias (used to log in)",
|
|
2153
2263
|
placeholder: "lead-routing",
|
|
2154
2264
|
initialValue: "lead-routing",
|
|
@@ -2351,7 +2461,7 @@ import {
|
|
|
2351
2461
|
intro as intro9,
|
|
2352
2462
|
outro as outro9,
|
|
2353
2463
|
spinner as spinner8,
|
|
2354
|
-
text as
|
|
2464
|
+
text as text7,
|
|
2355
2465
|
password as promptPassword4,
|
|
2356
2466
|
note as note7,
|
|
2357
2467
|
log as log18,
|
|
@@ -2470,7 +2580,7 @@ async function runDev(opts = {}) {
|
|
|
2470
2580
|
"You need a Salesforce Connected App with callback URL:\n http://localhost:3000/api/auth/sfdc/callback",
|
|
2471
2581
|
"Before you begin"
|
|
2472
2582
|
);
|
|
2473
|
-
const clientId = await
|
|
2583
|
+
const clientId = await text7({
|
|
2474
2584
|
message: "Consumer Key (Client ID)",
|
|
2475
2585
|
validate: (v) => !v ? "Required" : void 0
|
|
2476
2586
|
});
|
|
@@ -2483,7 +2593,7 @@ async function runDev(opts = {}) {
|
|
|
2483
2593
|
cancel5("Cancelled.");
|
|
2484
2594
|
process.exit(0);
|
|
2485
2595
|
}
|
|
2486
|
-
const loginUrl = await
|
|
2596
|
+
const loginUrl = await text7({
|
|
2487
2597
|
message: "Login URL",
|
|
2488
2598
|
initialValue: "https://login.salesforce.com",
|
|
2489
2599
|
validate: (v) => !v ? "Required" : void 0
|
|
@@ -2582,7 +2692,7 @@ async function runDev(opts = {}) {
|
|
|
2582
2692
|
"Sets up a full Lead Routing stack locally using Docker.\nNo SSH, no VPS, no manual steps.",
|
|
2583
2693
|
"First-time setup"
|
|
2584
2694
|
);
|
|
2585
|
-
const adminEmail = await
|
|
2695
|
+
const adminEmail = await text7({
|
|
2586
2696
|
message: "Admin email",
|
|
2587
2697
|
placeholder: "you@company.com",
|
|
2588
2698
|
validate: (v) => {
|
|
@@ -2604,7 +2714,7 @@ async function runDev(opts = {}) {
|
|
|
2604
2714
|
"Optional \u2014 needed to connect Salesforce.\nPress Enter to skip; add credentials later via `lead-routing config sfdc`.",
|
|
2605
2715
|
"Salesforce Connected App"
|
|
2606
2716
|
);
|
|
2607
|
-
const sfdcClientId = await
|
|
2717
|
+
const sfdcClientId = await text7({
|
|
2608
2718
|
message: "Consumer Key (Client ID)",
|
|
2609
2719
|
placeholder: "Leave blank to skip"
|
|
2610
2720
|
});
|
|
@@ -2615,7 +2725,7 @@ async function runDev(opts = {}) {
|
|
|
2615
2725
|
if (isCancel8(s)) bail3(s);
|
|
2616
2726
|
sfdcClientSecret = s.trim();
|
|
2617
2727
|
}
|
|
2618
|
-
const tunnelUrl = await
|
|
2728
|
+
const tunnelUrl = await text7({
|
|
2619
2729
|
message: "Engine tunnel URL (for Salesforce webhooks)",
|
|
2620
2730
|
placeholder: "Leave blank \u2014 use `ssh -R 80:localhost:3001 localhost.run` to get one"
|
|
2621
2731
|
});
|