@ascendkit/cli 0.3.0 → 0.3.2
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/api/client.js +5 -1
- package/dist/cli.js +327 -139
- package/dist/commands/platform.js +8 -2
- package/dist/utils/correlation.d.ts +11 -0
- package/dist/utils/correlation.js +67 -0
- package/dist/utils/exit.d.ts +23 -0
- package/dist/utils/exit.js +64 -0
- package/dist/utils/redaction.d.ts +16 -0
- package/dist/utils/redaction.js +114 -0
- package/dist/utils/telemetry.d.ts +32 -0
- package/dist/utils/telemetry.js +47 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,11 @@ import * as webhooks from "./commands/webhooks.js";
|
|
|
14
14
|
import * as campaigns from "./commands/campaigns.js";
|
|
15
15
|
import * as importCmd from "./commands/import.js";
|
|
16
16
|
import { parseDelay } from "./utils/duration.js";
|
|
17
|
+
import { exitCli, installGlobalHandlers, onExit } from "./utils/exit.js";
|
|
18
|
+
import { getInvocationId, getMachineId } from "./utils/correlation.js";
|
|
19
|
+
import { redactArgs } from "./utils/redaction.js";
|
|
20
|
+
import { captureTelemetry } from "./utils/telemetry.js";
|
|
21
|
+
import { hostname as osHostname, platform as osPlatform } from "node:os";
|
|
17
22
|
import { formatJourneyAnalytics, formatJourneyWithGuidance, formatNodeList, formatSingleNode, formatSingleTransition, formatTransitionList, } from "./utils/journey-format.js";
|
|
18
23
|
const require = createRequire(import.meta.url);
|
|
19
24
|
const { version: CLI_VERSION } = require("../package.json");
|
|
@@ -217,7 +222,8 @@ function getClient() {
|
|
|
217
222
|
// Require auth unless env var provides the public key (CI/CD escape hatch)
|
|
218
223
|
if (!auth?.token && !publicKey) {
|
|
219
224
|
console.error("Not initialized. Run: ascendkit init");
|
|
220
|
-
|
|
225
|
+
exitCli(1);
|
|
226
|
+
throw new Error("unreachable");
|
|
221
227
|
}
|
|
222
228
|
if (!publicKey && env?.publicKey) {
|
|
223
229
|
publicKey = env.publicKey;
|
|
@@ -227,7 +233,8 @@ function getClient() {
|
|
|
227
233
|
}
|
|
228
234
|
if (!publicKey) {
|
|
229
235
|
console.error("No environment set. Run: ascendkit set-env <public-key>");
|
|
230
|
-
|
|
236
|
+
exitCli(1);
|
|
237
|
+
throw new Error("unreachable");
|
|
231
238
|
}
|
|
232
239
|
const client = new AscendKitClient({
|
|
233
240
|
apiUrl: apiUrl ?? DEFAULT_API_URL,
|
|
@@ -280,7 +287,7 @@ function printAuthSettingsSummary(data) {
|
|
|
280
287
|
console.log(`Session: ${data.sessionDuration}`);
|
|
281
288
|
}
|
|
282
289
|
}
|
|
283
|
-
function printTemplateSummary(data) {
|
|
290
|
+
function printTemplateSummary(data, opts) {
|
|
284
291
|
console.log(`Template: ${data.name} (${data.id})`);
|
|
285
292
|
if (data.slug)
|
|
286
293
|
console.log(`Slug: ${data.slug}`);
|
|
@@ -290,6 +297,35 @@ function printTemplateSummary(data) {
|
|
|
290
297
|
if (Array.isArray(data.variables) && data.variables.length > 0) {
|
|
291
298
|
console.log(`Variables: ${data.variables.join(", ")}`);
|
|
292
299
|
}
|
|
300
|
+
if (Array.isArray(data.unconfiguredVariables) && data.unconfiguredVariables.length > 0) {
|
|
301
|
+
console.log(`\n⚠ Unconfigured variables: ${data.unconfiguredVariables.join(", ")}`);
|
|
302
|
+
console.log(` Set values with: ascendkit keystore set <key> <value>`);
|
|
303
|
+
}
|
|
304
|
+
if (Array.isArray(data.relatedJourneys) && data.relatedJourneys.length > 0) {
|
|
305
|
+
const refs = data.relatedJourneys.map((j) => `${j.name} (${j.id})`).join(", ");
|
|
306
|
+
console.log(`Used in journeys: ${refs}`);
|
|
307
|
+
}
|
|
308
|
+
// Show body content on show/get (verbose) but not on create/update summaries
|
|
309
|
+
if (opts?.verbose) {
|
|
310
|
+
if (data.bodyHtml) {
|
|
311
|
+
console.log(`\n--- HTML Body ---\n${data.bodyHtml}`);
|
|
312
|
+
}
|
|
313
|
+
if (data.bodyText) {
|
|
314
|
+
console.log(`\n--- Plain Text Body ---\n${data.bodyText}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Always show warnings and variable diffs (relevant on update responses)
|
|
318
|
+
if (Array.isArray(data.droppedVariables) && data.droppedVariables.length > 0) {
|
|
319
|
+
console.log(`\n⚠ Variables removed: ${data.droppedVariables.join(", ")}`);
|
|
320
|
+
}
|
|
321
|
+
if (Array.isArray(data.addedVariables) && data.addedVariables.length > 0) {
|
|
322
|
+
console.log(`Variables added: ${data.addedVariables.join(", ")}`);
|
|
323
|
+
}
|
|
324
|
+
if (Array.isArray(data.warnings) && data.warnings.length > 0) {
|
|
325
|
+
for (const w of data.warnings) {
|
|
326
|
+
console.log(`⚠ ${w}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
293
329
|
}
|
|
294
330
|
function printSurveySummary(data) {
|
|
295
331
|
console.log(`Survey: ${data.name} (${data.id})`);
|
|
@@ -302,6 +338,65 @@ function printSurveySummary(data) {
|
|
|
302
338
|
if (questions != null)
|
|
303
339
|
console.log(`Questions: ${questions}`);
|
|
304
340
|
}
|
|
341
|
+
function printEnvironmentSummary(data) {
|
|
342
|
+
console.log(`${data.name} (${data.id})`);
|
|
343
|
+
console.log(`Tier: ${data.tier}`);
|
|
344
|
+
if (data.description)
|
|
345
|
+
console.log(`Description: ${data.description}`);
|
|
346
|
+
console.log(`Public key: ${data.publicKey}`);
|
|
347
|
+
if (data.secretKey) {
|
|
348
|
+
const masked = data.secretKey.slice(0, 10) + "****";
|
|
349
|
+
console.log(`Secret key: ${masked}`);
|
|
350
|
+
}
|
|
351
|
+
const vars = data.variables && typeof data.variables === "object" ? Object.entries(data.variables) : [];
|
|
352
|
+
if (vars.length > 0) {
|
|
353
|
+
console.log(`Variables:`);
|
|
354
|
+
for (const [k, v] of vars)
|
|
355
|
+
console.log(` ${k}=${v}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function printPromotionSummary(result) {
|
|
359
|
+
const src = result.source ?? {};
|
|
360
|
+
const tgt = result.target ?? {};
|
|
361
|
+
console.log(`Promoted ${src.tier} → ${tgt.tier} (${tgt.envId})`);
|
|
362
|
+
console.log("");
|
|
363
|
+
const changes = result.changes ?? {};
|
|
364
|
+
const rows = [];
|
|
365
|
+
for (const [key, val] of Object.entries(changes)) {
|
|
366
|
+
const label = key.padEnd(14);
|
|
367
|
+
if (val.action === "unchanged") {
|
|
368
|
+
rows.push([label, "unchanged"]);
|
|
369
|
+
}
|
|
370
|
+
else if (val.action === "skip") {
|
|
371
|
+
rows.push([label, `skipped — ${val.reason}`]);
|
|
372
|
+
}
|
|
373
|
+
else if (val.action === "update" || val.action === "add_only") {
|
|
374
|
+
const fields = Array.isArray(val.fields) && val.fields.length ? ` (${val.fields.join(", ")})` : "";
|
|
375
|
+
rows.push([label, `updated${fields}`]);
|
|
376
|
+
}
|
|
377
|
+
else if (val.items) {
|
|
378
|
+
const counts = Object.entries(val.counts ?? {}).map(([k, v]) => `${v} ${k}`).join(", ");
|
|
379
|
+
rows.push([label, counts || "unchanged"]);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
rows.push([label, val.action ?? "—"]);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
for (const [label, status] of rows) {
|
|
386
|
+
console.log(` ${label} ${status}`);
|
|
387
|
+
}
|
|
388
|
+
// Only show warnings not already conveyed by a skipped row in the table
|
|
389
|
+
const skippedKeys = new Set(Object.entries(changes)
|
|
390
|
+
.filter(([, v]) => v.action === "skip")
|
|
391
|
+
.map(([k]) => k.toUpperCase()));
|
|
392
|
+
const warnings = (Array.isArray(result.warnings) ? result.warnings : [])
|
|
393
|
+
.filter((w) => !skippedKeys.size || !Array.from(skippedKeys).some(k => w.code?.toUpperCase().includes(k)));
|
|
394
|
+
if (warnings.length > 0) {
|
|
395
|
+
console.log("");
|
|
396
|
+
for (const w of warnings)
|
|
397
|
+
console.log(`⚠ ${w.message}`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
305
400
|
function printProjectSummary(data) {
|
|
306
401
|
console.log(`Project: ${data.id}`);
|
|
307
402
|
console.log(`Name: ${data.name}`);
|
|
@@ -348,7 +443,36 @@ function table(rows, columns) {
|
|
|
348
443
|
}
|
|
349
444
|
}
|
|
350
445
|
async function run() {
|
|
446
|
+
installGlobalHandlers();
|
|
351
447
|
const args = process.argv.slice(2);
|
|
448
|
+
const dtEntered = new Date();
|
|
449
|
+
// Extract command/domain/action for telemetry before any early returns
|
|
450
|
+
const teleDomain = args[0] ?? null;
|
|
451
|
+
const teleAction = args[1] ?? null;
|
|
452
|
+
const redactedArgs = redactArgs(args);
|
|
453
|
+
// Register telemetry hook — runs on every exit path (success or failure)
|
|
454
|
+
onExit(async (code, error) => {
|
|
455
|
+
const dtCompleted = new Date();
|
|
456
|
+
const record = {
|
|
457
|
+
invocationId: getInvocationId(),
|
|
458
|
+
machineId: getMachineId(),
|
|
459
|
+
clientType: "cli",
|
|
460
|
+
clientVersion: CLI_VERSION,
|
|
461
|
+
command: redactedArgs.join(" ") || "(empty)",
|
|
462
|
+
domain: teleDomain,
|
|
463
|
+
action: teleAction,
|
|
464
|
+
args: redactedArgs,
|
|
465
|
+
dtEntered: dtEntered.toISOString(),
|
|
466
|
+
dtCompleted: dtCompleted.toISOString(),
|
|
467
|
+
durationMs: dtCompleted.getTime() - dtEntered.getTime(),
|
|
468
|
+
success: code === 0,
|
|
469
|
+
errorMessage: error?.message ?? null,
|
|
470
|
+
hostname: osHostname(),
|
|
471
|
+
os: osPlatform(),
|
|
472
|
+
nodeVersion: process.version,
|
|
473
|
+
};
|
|
474
|
+
await captureTelemetry(record);
|
|
475
|
+
});
|
|
352
476
|
if (args[0] === "--version" || args[0] === "-v" || args[0] === "-V") {
|
|
353
477
|
console.log(CLI_VERSION);
|
|
354
478
|
return;
|
|
@@ -362,7 +486,7 @@ async function run() {
|
|
|
362
486
|
if (!printSectionHelp(args[1])) {
|
|
363
487
|
console.error(`Unknown help section: ${args[1]}`);
|
|
364
488
|
console.error('Run "ascendkit --help" for available sections.');
|
|
365
|
-
|
|
489
|
+
return await exitCli(1);
|
|
366
490
|
}
|
|
367
491
|
return;
|
|
368
492
|
}
|
|
@@ -378,7 +502,7 @@ async function run() {
|
|
|
378
502
|
if (!printSectionHelp(domain)) {
|
|
379
503
|
console.error(`Unknown command section: ${domain}`);
|
|
380
504
|
console.error('Run "ascendkit --help" for usage');
|
|
381
|
-
|
|
505
|
+
return await exitCli(1);
|
|
382
506
|
}
|
|
383
507
|
return;
|
|
384
508
|
}
|
|
@@ -404,7 +528,7 @@ async function run() {
|
|
|
404
528
|
else if (action === "show") {
|
|
405
529
|
if (!args[2]) {
|
|
406
530
|
console.error("Usage: ascendkit project show <project-id>");
|
|
407
|
-
|
|
531
|
+
return await exitCli(1);
|
|
408
532
|
}
|
|
409
533
|
printProjectSummary(await platform.showProject(args[2]));
|
|
410
534
|
}
|
|
@@ -415,7 +539,7 @@ async function run() {
|
|
|
415
539
|
const flags = parseFlags(args.slice(2));
|
|
416
540
|
if (!flags.name) {
|
|
417
541
|
console.error("Usage: ascendkit project create --name <name> [--description <description>] [--services <s1,s2,...>]");
|
|
418
|
-
|
|
542
|
+
return await exitCli(1);
|
|
419
543
|
}
|
|
420
544
|
try {
|
|
421
545
|
const proj = await platform.createProject(flags.name, flags.description, flags.services?.split(","));
|
|
@@ -435,18 +559,18 @@ async function run() {
|
|
|
435
559
|
catch { /* use raw message */ }
|
|
436
560
|
}
|
|
437
561
|
console.error(message);
|
|
438
|
-
|
|
562
|
+
return await exitCli(1);
|
|
439
563
|
}
|
|
440
564
|
}
|
|
441
565
|
else {
|
|
442
566
|
console.error('Usage: ascendkit project list|create|show|env');
|
|
443
|
-
|
|
567
|
+
return await exitCli(1);
|
|
444
568
|
}
|
|
445
569
|
return;
|
|
446
570
|
case "set-env":
|
|
447
571
|
if (!action) {
|
|
448
572
|
console.error("Usage: ascendkit set-env <public-key>");
|
|
449
|
-
|
|
573
|
+
return await exitCli(1);
|
|
450
574
|
}
|
|
451
575
|
await platform.setEnv(action);
|
|
452
576
|
return;
|
|
@@ -495,7 +619,7 @@ async function run() {
|
|
|
495
619
|
default:
|
|
496
620
|
console.error(`Unknown command: ${domain}`);
|
|
497
621
|
console.error('Run "ascendkit --help" for usage');
|
|
498
|
-
|
|
622
|
+
return await exitCli(1);
|
|
499
623
|
}
|
|
500
624
|
}
|
|
501
625
|
async function runImport(client, source, rest) {
|
|
@@ -529,7 +653,7 @@ async function runImport(client, source, rest) {
|
|
|
529
653
|
console.error(`Unsupported import source: ${source}`);
|
|
530
654
|
console.error("Supported sources: clerk");
|
|
531
655
|
console.error('Run "ascendkit help import" for usage');
|
|
532
|
-
|
|
656
|
+
return await exitCli(1);
|
|
533
657
|
}
|
|
534
658
|
const dryRun = action !== "run";
|
|
535
659
|
const hasUsers = flags.users !== undefined;
|
|
@@ -542,7 +666,7 @@ async function runImport(client, source, rest) {
|
|
|
542
666
|
const filePath = flags.file;
|
|
543
667
|
if (!apiKey && !filePath) {
|
|
544
668
|
console.error("Usage: ascendkit import clerk preview|run --api-key <key> | --file <path>");
|
|
545
|
-
|
|
669
|
+
return await exitCli(1);
|
|
546
670
|
}
|
|
547
671
|
let clerkUsers = [];
|
|
548
672
|
if (filePath) {
|
|
@@ -668,7 +792,7 @@ async function runProjectEnvironment(rest) {
|
|
|
668
792
|
case "list":
|
|
669
793
|
if (!target) {
|
|
670
794
|
console.error("Usage: ascendkit project env list <project-id>");
|
|
671
|
-
|
|
795
|
+
return await exitCli(1);
|
|
672
796
|
}
|
|
673
797
|
table(await platform.listEnvironments(target), [
|
|
674
798
|
{ key: "id", label: "ID" },
|
|
@@ -679,7 +803,7 @@ async function runProjectEnvironment(rest) {
|
|
|
679
803
|
return;
|
|
680
804
|
default:
|
|
681
805
|
console.error("Usage: ascendkit project env list <project-id>");
|
|
682
|
-
|
|
806
|
+
return await exitCli(1);
|
|
683
807
|
}
|
|
684
808
|
}
|
|
685
809
|
async function runEnvironment(action, rest) {
|
|
@@ -687,23 +811,22 @@ async function runEnvironment(action, rest) {
|
|
|
687
811
|
const ctx = loadEnvContext();
|
|
688
812
|
if (!ctx) {
|
|
689
813
|
console.error("No environment set. Run: ascendkit set-env <public-key>");
|
|
690
|
-
|
|
814
|
+
return await exitCli(1);
|
|
691
815
|
}
|
|
692
816
|
switch (action) {
|
|
693
817
|
case "show":
|
|
694
|
-
|
|
818
|
+
printEnvironmentSummary(await platform.getEnvironment(ctx.projectId, ctx.environmentId));
|
|
695
819
|
return;
|
|
696
820
|
case "promote": {
|
|
697
821
|
const envId = rest[0] && !rest[0].startsWith("--") ? rest[0] : ctx.environmentId;
|
|
698
822
|
const target = flags.target;
|
|
699
823
|
if (!envId || !target) {
|
|
700
824
|
console.error("Usage: ascendkit environment promote [<env-id>] --target <tier>");
|
|
701
|
-
|
|
825
|
+
return await exitCli(1);
|
|
702
826
|
}
|
|
703
827
|
try {
|
|
704
828
|
const result = await platform.promoteEnvironment(envId, target);
|
|
705
|
-
|
|
706
|
-
console.log(JSON.stringify(result, null, 2));
|
|
829
|
+
printPromotionSummary(result);
|
|
707
830
|
}
|
|
708
831
|
catch (err) {
|
|
709
832
|
let message = err instanceof Error ? err.message : String(err);
|
|
@@ -719,7 +842,7 @@ async function runEnvironment(action, rest) {
|
|
|
719
842
|
catch { /* use raw message */ }
|
|
720
843
|
}
|
|
721
844
|
console.error(message);
|
|
722
|
-
|
|
845
|
+
return await exitCli(1);
|
|
723
846
|
}
|
|
724
847
|
return;
|
|
725
848
|
}
|
|
@@ -729,7 +852,7 @@ async function runEnvironment(action, rest) {
|
|
|
729
852
|
const description = flags.description;
|
|
730
853
|
if (!name && description === undefined) {
|
|
731
854
|
console.error("Provide at least --name or --description to update.");
|
|
732
|
-
|
|
855
|
+
return await exitCli(1);
|
|
733
856
|
}
|
|
734
857
|
try {
|
|
735
858
|
const result = await platform.updateEnvironment(ctx.projectId, envId, name, description);
|
|
@@ -750,21 +873,21 @@ async function runEnvironment(action, rest) {
|
|
|
750
873
|
catch { /* use raw message */ }
|
|
751
874
|
}
|
|
752
875
|
console.error(message);
|
|
753
|
-
|
|
876
|
+
return await exitCli(1);
|
|
754
877
|
}
|
|
755
878
|
return;
|
|
756
879
|
}
|
|
757
880
|
default:
|
|
758
881
|
console.error(`Unknown environment command: ${action}`);
|
|
759
882
|
console.error("Usage: ascendkit environment show|update|promote");
|
|
760
|
-
|
|
883
|
+
return await exitCli(1);
|
|
761
884
|
}
|
|
762
885
|
}
|
|
763
886
|
async function runKeystore(action, rest) {
|
|
764
887
|
const ctx = loadEnvContext();
|
|
765
888
|
if (!ctx) {
|
|
766
889
|
console.error("No environment set. Run: ascendkit set-env <public-key>");
|
|
767
|
-
|
|
890
|
+
return await exitCli(1);
|
|
768
891
|
}
|
|
769
892
|
const current = await platform.getEnvironment(ctx.projectId, ctx.environmentId);
|
|
770
893
|
const vars = { ...(current.variables ?? {}) };
|
|
@@ -777,7 +900,7 @@ async function runKeystore(action, rest) {
|
|
|
777
900
|
const value = rest[1];
|
|
778
901
|
if (!key || value === undefined) {
|
|
779
902
|
console.error("Usage: ascendkit keystore set <key> <value>");
|
|
780
|
-
|
|
903
|
+
return await exitCli(1);
|
|
781
904
|
}
|
|
782
905
|
vars[key] = value;
|
|
783
906
|
await platform.updateEnvironmentVariables(ctx.projectId, ctx.environmentId, vars);
|
|
@@ -788,11 +911,11 @@ async function runKeystore(action, rest) {
|
|
|
788
911
|
const key = rest[0];
|
|
789
912
|
if (!key) {
|
|
790
913
|
console.error("Usage: ascendkit keystore remove <key>");
|
|
791
|
-
|
|
914
|
+
return await exitCli(1);
|
|
792
915
|
}
|
|
793
916
|
if (!(key in vars)) {
|
|
794
917
|
console.error(`Variable "${key}" not found.`);
|
|
795
|
-
|
|
918
|
+
return await exitCli(1);
|
|
796
919
|
}
|
|
797
920
|
delete vars[key];
|
|
798
921
|
await platform.updateEnvironmentVariables(ctx.projectId, ctx.environmentId, vars);
|
|
@@ -828,7 +951,7 @@ async function runKeystore(action, rest) {
|
|
|
828
951
|
default:
|
|
829
952
|
console.error(`Unknown keystore command: ${action}`);
|
|
830
953
|
console.error("Usage: ascendkit keystore list|set|remove");
|
|
831
|
-
|
|
954
|
+
return await exitCli(1);
|
|
832
955
|
}
|
|
833
956
|
}
|
|
834
957
|
async function runAuth(client, action, rest) {
|
|
@@ -866,7 +989,7 @@ async function runAuth(client, action, rest) {
|
|
|
866
989
|
const providersArg = normalizedAction === "providers" ? rest[0] : rest[1];
|
|
867
990
|
if (!providersArg) {
|
|
868
991
|
console.error("Usage: ascendkit auth provider set <p1,p2,...>");
|
|
869
|
-
|
|
992
|
+
return await exitCli(1);
|
|
870
993
|
}
|
|
871
994
|
printAuthSettingsSummary(await auth.updateProviders(client, providersArg.split(",")));
|
|
872
995
|
}
|
|
@@ -885,22 +1008,22 @@ async function runAuth(client, action, rest) {
|
|
|
885
1008
|
if (oauthAction === "set") {
|
|
886
1009
|
if (!provider || !flags["client-id"]) {
|
|
887
1010
|
console.error("Usage: ascendkit auth oauth set <provider> --client-id <id> [--client-secret <secret> | --client-secret-stdin] [--callback-url <url>]");
|
|
888
|
-
|
|
1011
|
+
return await exitCli(1);
|
|
889
1012
|
}
|
|
890
1013
|
const secretFromArg = flags["client-secret"];
|
|
891
1014
|
const secretFromStdin = flags["client-secret-stdin"] === "true";
|
|
892
1015
|
if (!secretFromArg && !secretFromStdin) {
|
|
893
1016
|
console.error("Missing client secret. Use --client-secret-stdin (recommended) or --client-secret.");
|
|
894
|
-
|
|
1017
|
+
return await exitCli(1);
|
|
895
1018
|
}
|
|
896
1019
|
if (secretFromArg && secretFromStdin) {
|
|
897
1020
|
console.error("Use only one of --client-secret or --client-secret-stdin.");
|
|
898
|
-
|
|
1021
|
+
return await exitCli(1);
|
|
899
1022
|
}
|
|
900
1023
|
const clientSecret = secretFromArg ?? await readSecretFromStdin();
|
|
901
1024
|
if (!clientSecret) {
|
|
902
1025
|
console.error("Client secret cannot be empty.");
|
|
903
|
-
|
|
1026
|
+
return await exitCli(1);
|
|
904
1027
|
}
|
|
905
1028
|
await auth.updateOAuthCredentials(client, provider, flags["client-id"], clientSecret, flags["callback-url"]);
|
|
906
1029
|
console.log(`Saved OAuth credentials for ${provider}.`);
|
|
@@ -908,7 +1031,7 @@ async function runAuth(client, action, rest) {
|
|
|
908
1031
|
else if (oauthAction === "remove") {
|
|
909
1032
|
if (!provider) {
|
|
910
1033
|
console.error("Usage: ascendkit auth oauth remove <provider>");
|
|
911
|
-
|
|
1034
|
+
return await exitCli(1);
|
|
912
1035
|
}
|
|
913
1036
|
await auth.deleteOAuthCredentials(client, provider);
|
|
914
1037
|
console.log(`Removed OAuth credentials for ${provider}.`);
|
|
@@ -916,7 +1039,7 @@ async function runAuth(client, action, rest) {
|
|
|
916
1039
|
else {
|
|
917
1040
|
if (!provider) {
|
|
918
1041
|
console.error("Usage: ascendkit auth oauth open <provider>");
|
|
919
|
-
|
|
1042
|
+
return await exitCli(1);
|
|
920
1043
|
}
|
|
921
1044
|
const portalUrl = process.env.ASCENDKIT_PORTAL_URL ?? "http://localhost:3000";
|
|
922
1045
|
const url = auth.getOAuthSetupUrl(portalUrl, provider, client.currentPublicKey ?? undefined);
|
|
@@ -939,7 +1062,7 @@ async function runAuth(client, action, rest) {
|
|
|
939
1062
|
else if (rest[0] === "remove") {
|
|
940
1063
|
if (!rest[1]) {
|
|
941
1064
|
console.error("Usage: ascendkit auth user remove <user-id>");
|
|
942
|
-
|
|
1065
|
+
return await exitCli(1);
|
|
943
1066
|
}
|
|
944
1067
|
await auth.deleteUser(client, rest[1]);
|
|
945
1068
|
console.log(`Removed user ${rest[1]}.`);
|
|
@@ -947,19 +1070,19 @@ async function runAuth(client, action, rest) {
|
|
|
947
1070
|
else if (rest[0] === "reactivate") {
|
|
948
1071
|
if (!rest[1]) {
|
|
949
1072
|
console.error("Usage: ascendkit auth user reactivate <user-id>");
|
|
950
|
-
|
|
1073
|
+
return await exitCli(1);
|
|
951
1074
|
}
|
|
952
1075
|
await auth.reactivateUser(client, rest[1]);
|
|
953
1076
|
console.log(`Reactivated user ${rest[1]}.`);
|
|
954
1077
|
}
|
|
955
1078
|
else {
|
|
956
1079
|
console.error(`Unknown auth user command: ${rest[0]}`);
|
|
957
|
-
|
|
1080
|
+
return await exitCli(1);
|
|
958
1081
|
}
|
|
959
1082
|
break;
|
|
960
1083
|
default:
|
|
961
1084
|
console.error(`Unknown auth command: ${action}`);
|
|
962
|
-
|
|
1085
|
+
return await exitCli(1);
|
|
963
1086
|
}
|
|
964
1087
|
}
|
|
965
1088
|
async function runContent(client, action, rest) {
|
|
@@ -975,7 +1098,7 @@ async function runContent(client, action, rest) {
|
|
|
975
1098
|
case "create":
|
|
976
1099
|
if (!flags.name || !flags.subject || !flags["body-html"] || !flags["body-text"]) {
|
|
977
1100
|
console.error("Usage: ascendkit template create --name <n> --subject <s> --body-html <h> --body-text <t> [--slug <slug>] [--description <desc>]");
|
|
978
|
-
|
|
1101
|
+
return await exitCli(1);
|
|
979
1102
|
}
|
|
980
1103
|
printTemplateSummary(await content.createTemplate(client, {
|
|
981
1104
|
name: flags.name, subject: flags.subject,
|
|
@@ -1003,14 +1126,14 @@ async function runContent(client, action, rest) {
|
|
|
1003
1126
|
case "show":
|
|
1004
1127
|
if (!rest[0]) {
|
|
1005
1128
|
console.error("Usage: ascendkit template show <template-id>");
|
|
1006
|
-
|
|
1129
|
+
return await exitCli(1);
|
|
1007
1130
|
}
|
|
1008
|
-
printTemplateSummary(await content.getTemplate(client, rest[0]));
|
|
1131
|
+
printTemplateSummary(await content.getTemplate(client, rest[0]), { verbose: true });
|
|
1009
1132
|
break;
|
|
1010
1133
|
case "update":
|
|
1011
1134
|
if (!rest[0]) {
|
|
1012
1135
|
console.error("Usage: ascendkit template update <template-id> [--flags]");
|
|
1013
|
-
|
|
1136
|
+
return await exitCli(1);
|
|
1014
1137
|
}
|
|
1015
1138
|
printTemplateSummary(await content.updateTemplate(client, rest[0], {
|
|
1016
1139
|
subject: flags.subject,
|
|
@@ -1022,7 +1145,7 @@ async function runContent(client, action, rest) {
|
|
|
1022
1145
|
case "remove":
|
|
1023
1146
|
if (!rest[0]) {
|
|
1024
1147
|
console.error("Usage: ascendkit template remove <template-id>");
|
|
1025
|
-
|
|
1148
|
+
return await exitCli(1);
|
|
1026
1149
|
}
|
|
1027
1150
|
await content.deleteTemplate(client, rest[0]);
|
|
1028
1151
|
console.log(`Removed template ${rest[0]}.`);
|
|
@@ -1033,7 +1156,7 @@ async function runContent(client, action, rest) {
|
|
|
1033
1156
|
const templateId = normalizedAction === "versions" ? rest[0] : rest[1];
|
|
1034
1157
|
if (!templateId) {
|
|
1035
1158
|
console.error("Usage: ascendkit template version list <template-id>");
|
|
1036
|
-
|
|
1159
|
+
return await exitCli(1);
|
|
1037
1160
|
}
|
|
1038
1161
|
const versions = await content.listVersions(client, templateId);
|
|
1039
1162
|
table(versions, [
|
|
@@ -1047,14 +1170,14 @@ async function runContent(client, action, rest) {
|
|
|
1047
1170
|
const versionNumber = normalizedAction === "version" && rest[0] === "show" ? rest[2] : normalizedAction === "version" ? rest[1] : rest[2];
|
|
1048
1171
|
if (!templateId || !versionNumber) {
|
|
1049
1172
|
console.error("Usage: ascendkit template version show <template-id> <n>");
|
|
1050
|
-
|
|
1173
|
+
return await exitCli(1);
|
|
1051
1174
|
}
|
|
1052
1175
|
output(await content.getVersion(client, templateId, parseInt(versionNumber, 10)));
|
|
1053
1176
|
}
|
|
1054
1177
|
break;
|
|
1055
1178
|
default:
|
|
1056
1179
|
console.error(`Unknown template command: ${action}`);
|
|
1057
|
-
|
|
1180
|
+
return await exitCli(1);
|
|
1058
1181
|
}
|
|
1059
1182
|
}
|
|
1060
1183
|
async function runSurvey(client, action, rest) {
|
|
@@ -1070,7 +1193,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1070
1193
|
case "create":
|
|
1071
1194
|
if (!flags.name) {
|
|
1072
1195
|
console.error("Usage: ascendkit survey create --name <n> [--type nps|csat|custom]");
|
|
1073
|
-
|
|
1196
|
+
return await exitCli(1);
|
|
1074
1197
|
}
|
|
1075
1198
|
printSurveySummary(await surveys.createSurvey(client, {
|
|
1076
1199
|
name: flags.name,
|
|
@@ -1089,14 +1212,14 @@ async function runSurvey(client, action, rest) {
|
|
|
1089
1212
|
case "show":
|
|
1090
1213
|
if (!rest[0]) {
|
|
1091
1214
|
console.error("Usage: ascendkit survey show <survey-id>");
|
|
1092
|
-
|
|
1215
|
+
return await exitCli(1);
|
|
1093
1216
|
}
|
|
1094
1217
|
printSurveySummary(await surveys.getSurvey(client, rest[0]));
|
|
1095
1218
|
break;
|
|
1096
1219
|
case "update":
|
|
1097
1220
|
if (!rest[0]) {
|
|
1098
1221
|
console.error("Usage: ascendkit survey update <survey-id> [--flags]");
|
|
1099
|
-
|
|
1222
|
+
return await exitCli(1);
|
|
1100
1223
|
}
|
|
1101
1224
|
printSurveySummary(await surveys.updateSurvey(client, rest[0], {
|
|
1102
1225
|
name: flags.name,
|
|
@@ -1107,7 +1230,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1107
1230
|
case "remove":
|
|
1108
1231
|
if (!rest[0]) {
|
|
1109
1232
|
console.error("Usage: ascendkit survey remove <survey-id>");
|
|
1110
|
-
|
|
1233
|
+
return await exitCli(1);
|
|
1111
1234
|
}
|
|
1112
1235
|
await surveys.deleteSurvey(client, rest[0]);
|
|
1113
1236
|
console.log(`Removed survey ${rest[0]}.`);
|
|
@@ -1115,7 +1238,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1115
1238
|
case "distribute":
|
|
1116
1239
|
if (!rest[0] || !flags.users) {
|
|
1117
1240
|
console.error("Usage: ascendkit survey distribute <survey-id> --users <usr_id1,usr_id2,...>");
|
|
1118
|
-
|
|
1241
|
+
return await exitCli(1);
|
|
1119
1242
|
}
|
|
1120
1243
|
output(await surveys.distributeSurvey(client, rest[0], flags.users.split(",")));
|
|
1121
1244
|
break;
|
|
@@ -1125,19 +1248,19 @@ async function runSurvey(client, action, rest) {
|
|
|
1125
1248
|
const surveyId = normalizedAction === "invitations" ? rest[0] : rest[1];
|
|
1126
1249
|
if (!surveyId) {
|
|
1127
1250
|
console.error("Usage: ascendkit survey invitation list <survey-id>");
|
|
1128
|
-
|
|
1251
|
+
return await exitCli(1);
|
|
1129
1252
|
}
|
|
1130
1253
|
output(await surveys.listInvitations(client, surveyId));
|
|
1131
1254
|
}
|
|
1132
1255
|
else {
|
|
1133
1256
|
console.error(`Unknown survey invitation command: ${rest[0]}`);
|
|
1134
|
-
|
|
1257
|
+
return await exitCli(1);
|
|
1135
1258
|
}
|
|
1136
1259
|
break;
|
|
1137
1260
|
case "analytics":
|
|
1138
1261
|
if (!rest[0]) {
|
|
1139
1262
|
console.error("Usage: ascendkit survey analytics <survey-id>");
|
|
1140
|
-
|
|
1263
|
+
return await exitCli(1);
|
|
1141
1264
|
}
|
|
1142
1265
|
output(await surveys.getAnalytics(client, rest[0]));
|
|
1143
1266
|
break;
|
|
@@ -1151,7 +1274,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1151
1274
|
if (definitionAction === "export") {
|
|
1152
1275
|
if (!surveyId) {
|
|
1153
1276
|
console.error("Usage: ascendkit survey definition export <survey-id> [--out <file>]");
|
|
1154
|
-
|
|
1277
|
+
return await exitCli(1);
|
|
1155
1278
|
}
|
|
1156
1279
|
const survey = await surveys.getSurvey(client, surveyId);
|
|
1157
1280
|
const text = `${JSON.stringify(survey.definition ?? {}, null, 2)}\n`;
|
|
@@ -1167,7 +1290,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1167
1290
|
else {
|
|
1168
1291
|
if (!surveyId || !(flags.in || flags.file)) {
|
|
1169
1292
|
console.error("Usage: ascendkit survey definition import <survey-id> --in <file>");
|
|
1170
|
-
|
|
1293
|
+
return await exitCli(1);
|
|
1171
1294
|
}
|
|
1172
1295
|
const inPath = flags.in || flags.file;
|
|
1173
1296
|
const raw = readFileSync(inPath, "utf8");
|
|
@@ -1177,7 +1300,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1177
1300
|
: parsed;
|
|
1178
1301
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1179
1302
|
console.error("Invalid definition JSON: expected an object or { definition: object }");
|
|
1180
|
-
|
|
1303
|
+
return await exitCli(1);
|
|
1181
1304
|
}
|
|
1182
1305
|
printSurveySummary(await surveys.updateSurvey(client, surveyId, {
|
|
1183
1306
|
definition: candidate,
|
|
@@ -1201,7 +1324,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1201
1324
|
const questionName = normalizedAction === "question" ? rest[2] : rest[1];
|
|
1202
1325
|
if (!surveyId) {
|
|
1203
1326
|
console.error("Usage: ascendkit survey question list <survey-id>");
|
|
1204
|
-
|
|
1327
|
+
return await exitCli(1);
|
|
1205
1328
|
}
|
|
1206
1329
|
if (questionAction === "list") {
|
|
1207
1330
|
output(await surveys.listQuestions(client, surveyId));
|
|
@@ -1209,7 +1332,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1209
1332
|
else if (questionAction === "add") {
|
|
1210
1333
|
if (!flags.type || !flags.title) {
|
|
1211
1334
|
console.error("Usage: ascendkit survey question add <survey-id> --type <type> --title <title> [--name <name>] [--required <true|false>] [--choices <c1,c2,...>] [--position <n>]");
|
|
1212
|
-
|
|
1335
|
+
return await exitCli(1);
|
|
1213
1336
|
}
|
|
1214
1337
|
const params = { type: flags.type, title: flags.title };
|
|
1215
1338
|
if (flags.name)
|
|
@@ -1225,7 +1348,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1225
1348
|
else if (questionAction === "update") {
|
|
1226
1349
|
if (!questionName) {
|
|
1227
1350
|
console.error("Usage: ascendkit survey question update <survey-id> <question-name> [--title <title>] [--required <true|false>] [--choices <c1,c2,...>]");
|
|
1228
|
-
|
|
1351
|
+
return await exitCli(1);
|
|
1229
1352
|
}
|
|
1230
1353
|
const params = {};
|
|
1231
1354
|
if (flags.title)
|
|
@@ -1239,27 +1362,27 @@ async function runSurvey(client, action, rest) {
|
|
|
1239
1362
|
else if (questionAction === "remove") {
|
|
1240
1363
|
if (!questionName) {
|
|
1241
1364
|
console.error("Usage: ascendkit survey question remove <survey-id> <question-name>");
|
|
1242
|
-
|
|
1365
|
+
return await exitCli(1);
|
|
1243
1366
|
}
|
|
1244
1367
|
output(await surveys.removeQuestion(client, surveyId, questionName));
|
|
1245
1368
|
}
|
|
1246
1369
|
else if (questionAction === "reorder") {
|
|
1247
1370
|
if (!flags.order) {
|
|
1248
1371
|
console.error("Usage: ascendkit survey question reorder <survey-id> --order <name1,name2,...>");
|
|
1249
|
-
|
|
1372
|
+
return await exitCli(1);
|
|
1250
1373
|
}
|
|
1251
1374
|
output(await surveys.reorderQuestions(client, surveyId, flags.order.split(",")));
|
|
1252
1375
|
}
|
|
1253
1376
|
else {
|
|
1254
1377
|
console.error(`Unknown survey question command: ${questionAction}`);
|
|
1255
|
-
|
|
1378
|
+
return await exitCli(1);
|
|
1256
1379
|
}
|
|
1257
1380
|
break;
|
|
1258
1381
|
}
|
|
1259
1382
|
default:
|
|
1260
1383
|
console.error(`Unknown survey command: ${action}`);
|
|
1261
1384
|
console.error('Run "ascendkit survey --help" for usage');
|
|
1262
|
-
|
|
1385
|
+
return await exitCli(1);
|
|
1263
1386
|
}
|
|
1264
1387
|
}
|
|
1265
1388
|
function runStatus() {
|
|
@@ -1377,7 +1500,7 @@ async function runJourney(client, action, rest) {
|
|
|
1377
1500
|
case "create":
|
|
1378
1501
|
if (!flags.name || !flags["entry-event"] || !flags["entry-node"]) {
|
|
1379
1502
|
console.error("Usage: ascendkit journey create --name <n> --entry-event <e> --entry-node <n> [--nodes <json>] [--transitions <json>] [--description <d>] [--entry-conditions <json>] [--re-entry-policy <skip|restart>]");
|
|
1380
|
-
|
|
1503
|
+
return await exitCli(1);
|
|
1381
1504
|
}
|
|
1382
1505
|
console.log(formatJourneyWithGuidance((await journeys.createJourney(client, {
|
|
1383
1506
|
name: flags.name,
|
|
@@ -1407,14 +1530,14 @@ async function runJourney(client, action, rest) {
|
|
|
1407
1530
|
case "get":
|
|
1408
1531
|
if (!rest[0]) {
|
|
1409
1532
|
console.error("Usage: ascendkit journey show <journey-id>");
|
|
1410
|
-
|
|
1533
|
+
return await exitCli(1);
|
|
1411
1534
|
}
|
|
1412
1535
|
console.log(formatJourneyWithGuidance(await journeys.getJourney(client, rest[0])));
|
|
1413
1536
|
break;
|
|
1414
1537
|
case "update":
|
|
1415
1538
|
if (!rest[0]) {
|
|
1416
1539
|
console.error("Usage: ascendkit journey update <journey-id> [--flags]");
|
|
1417
|
-
|
|
1540
|
+
return await exitCli(1);
|
|
1418
1541
|
}
|
|
1419
1542
|
console.log(formatJourneyWithGuidance((await journeys.updateJourney(client, rest[0], {
|
|
1420
1543
|
name: flags.name,
|
|
@@ -1430,7 +1553,7 @@ async function runJourney(client, action, rest) {
|
|
|
1430
1553
|
case "delete":
|
|
1431
1554
|
if (!rest[0]) {
|
|
1432
1555
|
console.error("Usage: ascendkit journey remove <journey-id>");
|
|
1433
|
-
|
|
1556
|
+
return await exitCli(1);
|
|
1434
1557
|
}
|
|
1435
1558
|
await journeys.deleteJourney(client, rest[0]);
|
|
1436
1559
|
console.log(`Deleted journey ${rest[0]}.`);
|
|
@@ -1438,49 +1561,49 @@ async function runJourney(client, action, rest) {
|
|
|
1438
1561
|
case "activate":
|
|
1439
1562
|
if (!rest[0]) {
|
|
1440
1563
|
console.error("Usage: ascendkit journey activate <journey-id>");
|
|
1441
|
-
|
|
1564
|
+
return await exitCli(1);
|
|
1442
1565
|
}
|
|
1443
1566
|
console.log(formatJourneyWithGuidance(await journeys.activateJourney(client, rest[0])));
|
|
1444
1567
|
break;
|
|
1445
1568
|
case "pause":
|
|
1446
1569
|
if (!rest[0]) {
|
|
1447
1570
|
console.error("Usage: ascendkit journey pause <journey-id>");
|
|
1448
|
-
|
|
1571
|
+
return await exitCli(1);
|
|
1449
1572
|
}
|
|
1450
1573
|
console.log(formatJourneyWithGuidance(await journeys.pauseJourney(client, rest[0])));
|
|
1451
1574
|
break;
|
|
1452
1575
|
case "resume":
|
|
1453
1576
|
if (!rest[0]) {
|
|
1454
1577
|
console.error("Usage: ascendkit journey resume <journey-id>");
|
|
1455
|
-
|
|
1578
|
+
return await exitCli(1);
|
|
1456
1579
|
}
|
|
1457
1580
|
console.log(formatJourneyWithGuidance(await journeys.resumeJourney(client, rest[0])));
|
|
1458
1581
|
break;
|
|
1459
1582
|
case "archive":
|
|
1460
1583
|
if (!rest[0]) {
|
|
1461
1584
|
console.error("Usage: ascendkit journey archive <journey-id>");
|
|
1462
|
-
|
|
1585
|
+
return await exitCli(1);
|
|
1463
1586
|
}
|
|
1464
1587
|
console.log(formatJourneyWithGuidance(await journeys.archiveJourney(client, rest[0])));
|
|
1465
1588
|
break;
|
|
1466
1589
|
case "analytics":
|
|
1467
1590
|
if (!rest[0]) {
|
|
1468
1591
|
console.error("Usage: ascendkit journey analytics <journey-id>");
|
|
1469
|
-
|
|
1592
|
+
return await exitCli(1);
|
|
1470
1593
|
}
|
|
1471
1594
|
console.log(formatJourneyAnalytics(await journeys.getJourneyAnalytics(client, rest[0])));
|
|
1472
1595
|
break;
|
|
1473
1596
|
case "list-nodes":
|
|
1474
1597
|
if (!rest[0]) {
|
|
1475
1598
|
console.error("Usage: ascendkit journey node list <journey-id>");
|
|
1476
|
-
|
|
1599
|
+
return await exitCli(1);
|
|
1477
1600
|
}
|
|
1478
1601
|
console.log(formatNodeList(await journeys.listNodes(client, rest[0])));
|
|
1479
1602
|
break;
|
|
1480
1603
|
case "add-node": {
|
|
1481
1604
|
if (!rest[0] || !flags.name) {
|
|
1482
1605
|
console.error("Usage: ascendkit journey node add <journey-id> --name <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]");
|
|
1483
|
-
|
|
1606
|
+
return await exitCli(1);
|
|
1484
1607
|
}
|
|
1485
1608
|
const params = { name: flags.name };
|
|
1486
1609
|
if (flags.action)
|
|
@@ -1488,7 +1611,7 @@ async function runJourney(client, action, rest) {
|
|
|
1488
1611
|
if (flags["email-id"]) {
|
|
1489
1612
|
if (!params.action || params.action.type !== "send_email") {
|
|
1490
1613
|
console.error("--email-id requires a send_email action (use --action '{\"type\": \"send_email\", \"templateSlug\": \"...\"}')");
|
|
1491
|
-
|
|
1614
|
+
return await exitCli(1);
|
|
1492
1615
|
}
|
|
1493
1616
|
params.action.fromIdentityEmail = flags["email-id"];
|
|
1494
1617
|
}
|
|
@@ -1500,7 +1623,7 @@ async function runJourney(client, action, rest) {
|
|
|
1500
1623
|
case "edit-node": {
|
|
1501
1624
|
if (!rest[0] || !rest[1]) {
|
|
1502
1625
|
console.error("Usage: ascendkit journey node update <journey-id> <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]");
|
|
1503
|
-
|
|
1626
|
+
return await exitCli(1);
|
|
1504
1627
|
}
|
|
1505
1628
|
const params = {};
|
|
1506
1629
|
if (flags.action)
|
|
@@ -1511,13 +1634,13 @@ async function runJourney(client, action, rest) {
|
|
|
1511
1634
|
const current = nodesData.nodes?.find((n) => n.name === rest[1]);
|
|
1512
1635
|
if (!current?.action || current.action.type !== "send_email") {
|
|
1513
1636
|
console.error("--email-id can only be set on send_email nodes");
|
|
1514
|
-
|
|
1637
|
+
return await exitCli(1);
|
|
1515
1638
|
}
|
|
1516
1639
|
params.action = current.action;
|
|
1517
1640
|
}
|
|
1518
1641
|
else if (params.action.type !== "send_email") {
|
|
1519
1642
|
console.error("--email-id requires a send_email action");
|
|
1520
|
-
|
|
1643
|
+
return await exitCli(1);
|
|
1521
1644
|
}
|
|
1522
1645
|
params.action.fromIdentityEmail = flags["email-id"];
|
|
1523
1646
|
}
|
|
@@ -1529,14 +1652,14 @@ async function runJourney(client, action, rest) {
|
|
|
1529
1652
|
case "remove-node":
|
|
1530
1653
|
if (!rest[0] || !rest[1]) {
|
|
1531
1654
|
console.error("Usage: ascendkit journey node remove <journey-id> <node-name>");
|
|
1532
|
-
|
|
1655
|
+
return await exitCli(1);
|
|
1533
1656
|
}
|
|
1534
1657
|
console.log(formatSingleNode(await journeys.removeNode(client, rest[0], rest[1]), "Removed", rest[1]));
|
|
1535
1658
|
break;
|
|
1536
1659
|
case "list-transitions": {
|
|
1537
1660
|
if (!rest[0]) {
|
|
1538
1661
|
console.error("Usage: ascendkit journey transition list <journey-id> [--from <node-name>] [--to <node-name>]");
|
|
1539
|
-
|
|
1662
|
+
return await exitCli(1);
|
|
1540
1663
|
}
|
|
1541
1664
|
console.log(formatTransitionList(await journeys.listTransitions(client, rest[0], {
|
|
1542
1665
|
from_node: flags.from,
|
|
@@ -1547,7 +1670,7 @@ async function runJourney(client, action, rest) {
|
|
|
1547
1670
|
case "add-transition": {
|
|
1548
1671
|
if (!rest[0] || !flags.from || !flags.to || !(flags.on || flags.after || flags.trigger)) {
|
|
1549
1672
|
console.error("Usage: ascendkit journey transition add <journey-id> --from <node-name> --to <node-name> --on <event> | --after <delay> | --trigger <json> [--priority <n>] [--name <transition-name>]");
|
|
1550
|
-
|
|
1673
|
+
return await exitCli(1);
|
|
1551
1674
|
}
|
|
1552
1675
|
let trigger;
|
|
1553
1676
|
if (flags.on) {
|
|
@@ -1575,7 +1698,7 @@ async function runJourney(client, action, rest) {
|
|
|
1575
1698
|
case "edit-transition": {
|
|
1576
1699
|
if (!rest[0] || !rest[1]) {
|
|
1577
1700
|
console.error("Usage: ascendkit journey transition update <journey-id> <transition-name> [--on <event>] [--after <delay>] [--trigger <json>] [--priority <n>]");
|
|
1578
|
-
|
|
1701
|
+
return await exitCli(1);
|
|
1579
1702
|
}
|
|
1580
1703
|
const params = {};
|
|
1581
1704
|
if (flags.on) {
|
|
@@ -1595,13 +1718,13 @@ async function runJourney(client, action, rest) {
|
|
|
1595
1718
|
case "remove-transition":
|
|
1596
1719
|
if (!rest[0] || !rest[1]) {
|
|
1597
1720
|
console.error("Usage: ascendkit journey transition remove <journey-id> <transition-name>");
|
|
1598
|
-
|
|
1721
|
+
return await exitCli(1);
|
|
1599
1722
|
}
|
|
1600
1723
|
console.log(formatSingleTransition(await journeys.removeTransition(client, rest[0], rest[1]), "Removed", rest[1]));
|
|
1601
1724
|
break;
|
|
1602
1725
|
default:
|
|
1603
1726
|
console.error(`Unknown journey command: ${action}`);
|
|
1604
|
-
|
|
1727
|
+
return await exitCli(1);
|
|
1605
1728
|
}
|
|
1606
1729
|
}
|
|
1607
1730
|
async function runWebhook(client, action, rest) {
|
|
@@ -1610,7 +1733,7 @@ async function runWebhook(client, action, rest) {
|
|
|
1610
1733
|
case "create":
|
|
1611
1734
|
if (!flags.url) {
|
|
1612
1735
|
console.error("Usage: ascendkit webhook create --url <url> [--events <e1,e2,...>]");
|
|
1613
|
-
|
|
1736
|
+
return await exitCli(1);
|
|
1614
1737
|
}
|
|
1615
1738
|
output(await webhooks.createWebhook(client, {
|
|
1616
1739
|
url: flags.url,
|
|
@@ -1628,14 +1751,14 @@ async function runWebhook(client, action, rest) {
|
|
|
1628
1751
|
case "get":
|
|
1629
1752
|
if (!rest[0]) {
|
|
1630
1753
|
console.error("Usage: ascendkit webhook get <webhook-id>");
|
|
1631
|
-
|
|
1754
|
+
return await exitCli(1);
|
|
1632
1755
|
}
|
|
1633
1756
|
output(await webhooks.getWebhook(client, rest[0]));
|
|
1634
1757
|
break;
|
|
1635
1758
|
case "update": {
|
|
1636
1759
|
if (!rest[0]) {
|
|
1637
1760
|
console.error("Usage: ascendkit webhook update <webhook-id> [--flags]");
|
|
1638
|
-
|
|
1761
|
+
return await exitCli(1);
|
|
1639
1762
|
}
|
|
1640
1763
|
const updated = await webhooks.updateWebhook(client, rest[0], {
|
|
1641
1764
|
url: flags.url,
|
|
@@ -1651,21 +1774,21 @@ async function runWebhook(client, action, rest) {
|
|
|
1651
1774
|
case "delete":
|
|
1652
1775
|
if (!rest[0]) {
|
|
1653
1776
|
console.error("Usage: ascendkit webhook delete <webhook-id>");
|
|
1654
|
-
|
|
1777
|
+
return await exitCli(1);
|
|
1655
1778
|
}
|
|
1656
1779
|
output(await webhooks.deleteWebhook(client, rest[0]));
|
|
1657
1780
|
break;
|
|
1658
1781
|
case "test":
|
|
1659
1782
|
if (!rest[0]) {
|
|
1660
1783
|
console.error("Usage: ascendkit webhook test <webhook-id> [--event <event-type>]");
|
|
1661
|
-
|
|
1784
|
+
return await exitCli(1);
|
|
1662
1785
|
}
|
|
1663
1786
|
output(await webhooks.testWebhook(client, rest[0], flags.event));
|
|
1664
1787
|
break;
|
|
1665
1788
|
default:
|
|
1666
1789
|
console.error(`Unknown webhook command: ${action}`);
|
|
1667
1790
|
console.error('Run "ascendkit webhook --help" for usage');
|
|
1668
|
-
|
|
1791
|
+
return await exitCli(1);
|
|
1669
1792
|
}
|
|
1670
1793
|
}
|
|
1671
1794
|
async function runCampaign(client, action, rest) {
|
|
@@ -1675,10 +1798,10 @@ async function runCampaign(client, action, rest) {
|
|
|
1675
1798
|
return;
|
|
1676
1799
|
}
|
|
1677
1800
|
switch (action) {
|
|
1678
|
-
case "create":
|
|
1801
|
+
case "create": {
|
|
1679
1802
|
if (!flags.name || !flags.template || !flags.audience) {
|
|
1680
1803
|
console.error("Usage: ascendkit campaign create --name <name> --template <template-id> --audience <json> [--scheduled-at <datetime>]");
|
|
1681
|
-
|
|
1804
|
+
return await exitCli(1);
|
|
1682
1805
|
}
|
|
1683
1806
|
let createFilter;
|
|
1684
1807
|
try {
|
|
@@ -1686,7 +1809,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1686
1809
|
}
|
|
1687
1810
|
catch {
|
|
1688
1811
|
console.error("Invalid JSON for --audience flag. Provide a valid JSON object.");
|
|
1689
|
-
|
|
1812
|
+
return await exitCli(1);
|
|
1690
1813
|
}
|
|
1691
1814
|
output(await campaigns.createCampaign(client, {
|
|
1692
1815
|
name: flags.name,
|
|
@@ -1695,6 +1818,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1695
1818
|
scheduledAt: flags["scheduled-at"],
|
|
1696
1819
|
}));
|
|
1697
1820
|
break;
|
|
1821
|
+
}
|
|
1698
1822
|
case "list": {
|
|
1699
1823
|
const items = await campaigns.listCampaigns(client, flags.status);
|
|
1700
1824
|
table(items, [
|
|
@@ -1710,14 +1834,14 @@ async function runCampaign(client, action, rest) {
|
|
|
1710
1834
|
case "get":
|
|
1711
1835
|
if (!rest[0]) {
|
|
1712
1836
|
console.error("Usage: ascendkit campaign show <campaign-id>");
|
|
1713
|
-
|
|
1837
|
+
return await exitCli(1);
|
|
1714
1838
|
}
|
|
1715
1839
|
output(await campaigns.getCampaign(client, rest[0]));
|
|
1716
1840
|
break;
|
|
1717
|
-
case "update":
|
|
1841
|
+
case "update": {
|
|
1718
1842
|
if (!rest[0]) {
|
|
1719
1843
|
console.error("Usage: ascendkit campaign update <campaign-id> [--flags]");
|
|
1720
|
-
|
|
1844
|
+
return await exitCli(1);
|
|
1721
1845
|
}
|
|
1722
1846
|
let updateFilter;
|
|
1723
1847
|
if (flags.audience) {
|
|
@@ -1726,7 +1850,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1726
1850
|
}
|
|
1727
1851
|
catch {
|
|
1728
1852
|
console.error("Invalid JSON for --audience flag. Provide a valid JSON object.");
|
|
1729
|
-
|
|
1853
|
+
return await exitCli(1);
|
|
1730
1854
|
}
|
|
1731
1855
|
}
|
|
1732
1856
|
output(await campaigns.updateCampaign(client, rest[0], {
|
|
@@ -1736,45 +1860,45 @@ async function runCampaign(client, action, rest) {
|
|
|
1736
1860
|
scheduledAt: flags["scheduled-at"],
|
|
1737
1861
|
}));
|
|
1738
1862
|
break;
|
|
1739
|
-
|
|
1863
|
+
}
|
|
1864
|
+
case "preview": {
|
|
1740
1865
|
if (!rest[0]) {
|
|
1741
1866
|
console.error("Usage: ascendkit campaign preview <campaign-id>");
|
|
1742
|
-
|
|
1867
|
+
return await exitCli(1);
|
|
1743
1868
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
process.exit(1);
|
|
1749
|
-
}
|
|
1750
|
-
output(await campaigns.previewAudience(client, detail.audienceFilter));
|
|
1869
|
+
const detail = await campaigns.getCampaign(client, rest[0]);
|
|
1870
|
+
if (!detail?.audienceFilter) {
|
|
1871
|
+
console.error("Campaign has no audience filter set.");
|
|
1872
|
+
return await exitCli(1);
|
|
1751
1873
|
}
|
|
1874
|
+
output(await campaigns.previewAudience(client, detail.audienceFilter));
|
|
1752
1875
|
break;
|
|
1876
|
+
}
|
|
1753
1877
|
case "schedule":
|
|
1754
1878
|
if (!rest[0] || !flags.at) {
|
|
1755
1879
|
console.error("Usage: ascendkit campaign schedule <campaign-id> --at <datetime>");
|
|
1756
|
-
|
|
1880
|
+
return await exitCli(1);
|
|
1757
1881
|
}
|
|
1758
1882
|
output(await campaigns.updateCampaign(client, rest[0], { scheduledAt: flags.at }));
|
|
1759
1883
|
break;
|
|
1760
1884
|
case "cancel":
|
|
1761
1885
|
if (!rest[0]) {
|
|
1762
1886
|
console.error("Usage: ascendkit campaign cancel <campaign-id>");
|
|
1763
|
-
|
|
1887
|
+
return await exitCli(1);
|
|
1764
1888
|
}
|
|
1765
1889
|
output(await campaigns.deleteCampaign(client, rest[0]));
|
|
1766
1890
|
break;
|
|
1767
1891
|
case "analytics":
|
|
1768
1892
|
if (!rest[0]) {
|
|
1769
1893
|
console.error("Usage: ascendkit campaign analytics <campaign-id>");
|
|
1770
|
-
|
|
1894
|
+
return await exitCli(1);
|
|
1771
1895
|
}
|
|
1772
1896
|
output(await campaigns.getCampaignAnalytics(client, rest[0]));
|
|
1773
1897
|
break;
|
|
1774
1898
|
default:
|
|
1775
1899
|
console.error(`Unknown campaign command: ${action}`);
|
|
1776
1900
|
console.error('Run "ascendkit campaign --help" for usage');
|
|
1777
|
-
|
|
1901
|
+
return await exitCli(1);
|
|
1778
1902
|
}
|
|
1779
1903
|
}
|
|
1780
1904
|
async function runEmail(client, action, rest) {
|
|
@@ -1797,7 +1921,7 @@ async function runEmail(client, action, rest) {
|
|
|
1797
1921
|
case "setup-domain":
|
|
1798
1922
|
if (!rest[0]) {
|
|
1799
1923
|
console.error("Usage: ascendkit email-identity setup-domain <domain>");
|
|
1800
|
-
|
|
1924
|
+
return await exitCli(1);
|
|
1801
1925
|
}
|
|
1802
1926
|
await printEmailSetup(await email.setupDomain(client, rest[0]));
|
|
1803
1927
|
break;
|
|
@@ -1820,7 +1944,7 @@ async function runEmail(client, action, rest) {
|
|
|
1820
1944
|
const url = provider?.portalUrl;
|
|
1821
1945
|
if (!url) {
|
|
1822
1946
|
console.error("Could not determine DNS provider URL for this domain.");
|
|
1823
|
-
|
|
1947
|
+
return await exitCli(1);
|
|
1824
1948
|
}
|
|
1825
1949
|
console.log(url);
|
|
1826
1950
|
if (flags.open === "true") {
|
|
@@ -1829,7 +1953,8 @@ async function runEmail(client, action, rest) {
|
|
|
1829
1953
|
break;
|
|
1830
1954
|
}
|
|
1831
1955
|
case "remove-domain":
|
|
1832
|
-
|
|
1956
|
+
await email.removeDomain(client);
|
|
1957
|
+
console.log("Domain removed.");
|
|
1833
1958
|
break;
|
|
1834
1959
|
case "list": {
|
|
1835
1960
|
const result = await email.listIdentities(client);
|
|
@@ -1840,33 +1965,37 @@ async function runEmail(client, action, rest) {
|
|
|
1840
1965
|
const identityEmail = rest[0];
|
|
1841
1966
|
if (!identityEmail) {
|
|
1842
1967
|
console.error("Usage: ascendkit email-identity add <email> [--display-name <name>]");
|
|
1843
|
-
|
|
1968
|
+
return await exitCli(1);
|
|
1844
1969
|
}
|
|
1845
|
-
|
|
1970
|
+
const added = await email.createIdentity(client, {
|
|
1846
1971
|
email: identityEmail,
|
|
1847
1972
|
displayName: flags["display-name"],
|
|
1848
|
-
})
|
|
1973
|
+
});
|
|
1974
|
+
printEmailIdentities(added.identities ?? []);
|
|
1975
|
+
console.log("Verification email sent.");
|
|
1849
1976
|
break;
|
|
1850
1977
|
}
|
|
1851
1978
|
case "resend": {
|
|
1852
1979
|
const identityEmail = rest[0];
|
|
1853
1980
|
if (!identityEmail) {
|
|
1854
1981
|
console.error("Usage: ascendkit email-identity resend <email>");
|
|
1855
|
-
|
|
1982
|
+
return await exitCli(1);
|
|
1856
1983
|
}
|
|
1857
|
-
|
|
1984
|
+
await email.resendIdentityVerification(client, identityEmail);
|
|
1985
|
+
console.log(`Verification email sent to ${identityEmail}.`);
|
|
1858
1986
|
break;
|
|
1859
1987
|
}
|
|
1860
1988
|
case "set-default": {
|
|
1861
1989
|
const identityEmail = rest[0];
|
|
1862
1990
|
if (!identityEmail) {
|
|
1863
1991
|
console.error("Usage: ascendkit email-identity set-default <email> [--display-name <name>]");
|
|
1864
|
-
|
|
1992
|
+
return await exitCli(1);
|
|
1865
1993
|
}
|
|
1866
|
-
|
|
1994
|
+
const updated = await email.setDefaultIdentity(client, {
|
|
1867
1995
|
email: identityEmail,
|
|
1868
1996
|
displayName: flags["display-name"],
|
|
1869
|
-
})
|
|
1997
|
+
});
|
|
1998
|
+
printEmailIdentities(updated.identities ?? []);
|
|
1870
1999
|
break;
|
|
1871
2000
|
}
|
|
1872
2001
|
case "remove":
|
|
@@ -1874,39 +2003,42 @@ async function runEmail(client, action, rest) {
|
|
|
1874
2003
|
const identityEmail = rest[0];
|
|
1875
2004
|
if (!identityEmail) {
|
|
1876
2005
|
console.error("Usage: ascendkit email-identity remove <email>");
|
|
1877
|
-
|
|
2006
|
+
return await exitCli(1);
|
|
1878
2007
|
}
|
|
1879
|
-
|
|
2008
|
+
const remaining = await email.removeIdentity(client, identityEmail);
|
|
2009
|
+
console.log("Identity removed.");
|
|
2010
|
+
printEmailIdentities(remaining.identities ?? []);
|
|
1880
2011
|
break;
|
|
1881
2012
|
}
|
|
1882
2013
|
case "test": {
|
|
1883
2014
|
const identityEmail = rest[0];
|
|
1884
2015
|
if (!identityEmail || !flags.to) {
|
|
1885
2016
|
console.error("Usage: ascendkit email-identity test <email> --to <recipient>");
|
|
1886
|
-
|
|
2017
|
+
return await exitCli(1);
|
|
1887
2018
|
}
|
|
1888
|
-
|
|
2019
|
+
const testResult = await email.sendTestEmail(client, {
|
|
1889
2020
|
to: flags.to,
|
|
1890
2021
|
fromIdentityEmail: identityEmail,
|
|
1891
|
-
})
|
|
2022
|
+
});
|
|
2023
|
+
console.log(testResult.message ?? "Test email sent.");
|
|
1892
2024
|
break;
|
|
1893
2025
|
}
|
|
1894
2026
|
default:
|
|
1895
2027
|
console.error(`Unknown email-identity command: ${action}`);
|
|
1896
|
-
|
|
2028
|
+
return await exitCli(1);
|
|
1897
2029
|
}
|
|
1898
2030
|
}
|
|
1899
2031
|
run().catch((err) => {
|
|
1900
2032
|
console.error(err.message);
|
|
1901
|
-
|
|
2033
|
+
exitCli(1, err instanceof Error ? err : new Error(String(err)));
|
|
1902
2034
|
});
|
|
1903
2035
|
async function printEmailSetup(settings) {
|
|
1904
|
-
output(settings);
|
|
1905
2036
|
if (!settings.domain)
|
|
1906
2037
|
return;
|
|
1907
2038
|
const provider = settings.dnsProvider;
|
|
2039
|
+
console.log(`Domain: ${settings.domain}`);
|
|
1908
2040
|
if (provider?.name) {
|
|
1909
|
-
console.log(
|
|
2041
|
+
console.log(`DNS provider: ${provider.name} (${provider.confidence ?? "unknown"})`);
|
|
1910
2042
|
}
|
|
1911
2043
|
if (provider?.portalUrl) {
|
|
1912
2044
|
console.log(`Provider console: ${provider.portalUrl}`);
|
|
@@ -1914,10 +2046,54 @@ async function printEmailSetup(settings) {
|
|
|
1914
2046
|
if (provider?.assistantSetupUrl) {
|
|
1915
2047
|
console.log(`Guided setup: ${provider.assistantSetupUrl}`);
|
|
1916
2048
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2049
|
+
const records = Array.isArray(settings.dnsRecords) ? settings.dnsRecords : [];
|
|
2050
|
+
if (records.length > 0) {
|
|
2051
|
+
console.log("\nDNS records to add:");
|
|
2052
|
+
for (const rec of records) {
|
|
2053
|
+
console.log(` ${rec.type.padEnd(6)} ${rec.name} ${rec.value}`);
|
|
2054
|
+
}
|
|
2055
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
2056
|
+
const defaultFile = `dns-records-${settings.domain}.txt`;
|
|
2057
|
+
const { createInterface } = await import("node:readline/promises");
|
|
2058
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2059
|
+
try {
|
|
2060
|
+
const answer = (await rl.question(`\nSave records to file [${defaultFile}]: `)).trim();
|
|
2061
|
+
const filename = answer || defaultFile;
|
|
2062
|
+
const { existsSync, writeFileSync } = await import("node:fs");
|
|
2063
|
+
if (existsSync(filename)) {
|
|
2064
|
+
const overwrite = (await rl.question(`${filename} already exists. Overwrite? [y/N] `)).trim().toLowerCase();
|
|
2065
|
+
if (overwrite !== "y" && overwrite !== "yes") {
|
|
2066
|
+
console.log("Skipped.");
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const lines = [
|
|
2071
|
+
`; DNS records for ${settings.domain}`,
|
|
2072
|
+
`; Generated by AscendKit CLI`,
|
|
2073
|
+
"",
|
|
2074
|
+
...records.map(rec => {
|
|
2075
|
+
let value;
|
|
2076
|
+
if (rec.type === "TXT") {
|
|
2077
|
+
value = `"${rec.value}"`;
|
|
2078
|
+
}
|
|
2079
|
+
else if (rec.type === "CNAME" || rec.type === "MX") {
|
|
2080
|
+
// Ensure absolute FQDN with trailing dot to prevent zone-relative expansion
|
|
2081
|
+
const target = rec.type === "MX" ? rec.value.replace(/^(\d+)\s+/, "$1 ") : rec.value;
|
|
2082
|
+
value = target.endsWith(".") ? target : `${target}.`;
|
|
2083
|
+
}
|
|
2084
|
+
else {
|
|
2085
|
+
value = rec.value;
|
|
2086
|
+
}
|
|
2087
|
+
const name = rec.name.endsWith(".") ? rec.name : `${rec.name}.`;
|
|
2088
|
+
return `${name}\t3600\tIN\t${rec.type}\t${value} ; cf_tags=cf-proxied:false`;
|
|
2089
|
+
}),
|
|
2090
|
+
];
|
|
2091
|
+
writeFileSync(filename, lines.join("\n") + "\n");
|
|
2092
|
+
console.log(`Saved to ${filename}`);
|
|
2093
|
+
}
|
|
2094
|
+
finally {
|
|
2095
|
+
rl.close();
|
|
2096
|
+
}
|
|
1921
2097
|
}
|
|
1922
2098
|
}
|
|
1923
2099
|
}
|
|
@@ -1949,8 +2125,20 @@ function printEmailStatusSummary(settings, domainStatus, dnsCheck, identities) {
|
|
|
1949
2125
|
return;
|
|
1950
2126
|
}
|
|
1951
2127
|
console.log(`Domain: ${settings.domain} (${domainStatus.status || settings.verificationStatus || "unknown"})`);
|
|
1952
|
-
if (dnsCheck
|
|
1953
|
-
|
|
2128
|
+
if (dnsCheck) {
|
|
2129
|
+
const { summary, records } = dnsCheck;
|
|
2130
|
+
if (summary.notFound === 0 && summary.mismatch === 0 && summary.errored === 0) {
|
|
2131
|
+
console.log("DNS: all records verified");
|
|
2132
|
+
}
|
|
2133
|
+
else {
|
|
2134
|
+
console.log(`DNS: ${summary.found}/${summary.total} verified`);
|
|
2135
|
+
const pending = records.filter(r => !r.found || r.mismatch);
|
|
2136
|
+
if (pending.length > 0) {
|
|
2137
|
+
console.log("Pending:");
|
|
2138
|
+
for (const r of pending)
|
|
2139
|
+
console.log(` ${r.type.padEnd(6)} ${r.name}`);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
1954
2142
|
}
|
|
1955
2143
|
console.log("");
|
|
1956
2144
|
printEmailIdentities(identities);
|