@ascendkit/cli 0.3.1 → 0.3.8
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/cli.js +339 -52
- package/dist/commands/content.d.ts +2 -0
- package/dist/commands/email.d.ts +4 -0
- package/dist/commands/email.js +3 -0
- package/dist/tools/email.js +7 -0
- package/dist/utils/journey-format.d.ts +10 -3
- package/dist/utils/journey-format.js +13 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { redactArgs } from "./utils/redaction.js";
|
|
|
20
20
|
import { captureTelemetry } from "./utils/telemetry.js";
|
|
21
21
|
import { hostname as osHostname, platform as osPlatform } from "node:os";
|
|
22
22
|
import { formatJourneyAnalytics, formatJourneyWithGuidance, formatNodeList, formatSingleNode, formatSingleTransition, formatTransitionList, } from "./utils/journey-format.js";
|
|
23
|
+
import { formatDistributionResult, formatQuestionList, formatSingleQuestion, } from "./utils/survey-format.js";
|
|
23
24
|
const require = createRequire(import.meta.url);
|
|
24
25
|
const { version: CLI_VERSION } = require("../package.json");
|
|
25
26
|
const HELP = `ascendkit v${CLI_VERSION} - AscendKit CLI
|
|
@@ -68,10 +69,10 @@ Commands:
|
|
|
68
69
|
template: `Usage: ascendkit template <command>
|
|
69
70
|
|
|
70
71
|
Commands:
|
|
71
|
-
template create --name <name> --subject <subject> --body-html <html> --body-text <text> [--slug <slug>] [--description <description>]
|
|
72
|
+
template create --name <name> --subject <subject> --body-html <html> --body-text <text> [--slug <slug>] [--description <description>] [--category <marketing|transactional>]
|
|
72
73
|
template list [--query <search>] [--system true|--custom true]
|
|
73
74
|
template show <template-id>
|
|
74
|
-
template update <template-id> [--subject <subject>] [--body-html <html>] [--body-text <text>] [--change-note <note>]
|
|
75
|
+
template update <template-id> [--subject <subject>] [--body-html <html>] [--body-text <text>] [--change-note <note>] [--category <marketing|transactional>]
|
|
75
76
|
template remove <template-id>
|
|
76
77
|
template version list <template-id>
|
|
77
78
|
template version show <template-id> <n>`,
|
|
@@ -102,16 +103,16 @@ Commands:
|
|
|
102
103
|
journey update <journey-id> [--name <name>] [--nodes <json>] [--transitions <json>] [--description <description>] [--entry-event <event>] [--entry-node <node>] [--entry-conditions <json>] [--re-entry-policy <skip|restart>]
|
|
103
104
|
journey remove <journey-id>
|
|
104
105
|
journey activate <journey-id>
|
|
105
|
-
journey pause <journey-id>
|
|
106
|
+
journey pause <journey-id> [--yes]
|
|
106
107
|
journey resume <journey-id>
|
|
107
108
|
journey archive <journey-id>
|
|
108
109
|
journey analytics <journey-id>
|
|
109
110
|
journey node list <journey-id>
|
|
110
|
-
journey node add <journey-id> --name <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]
|
|
111
|
+
journey node add <journey-id> --name <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>] [--quiet]
|
|
111
112
|
journey node update <journey-id> <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]
|
|
112
113
|
journey node remove <journey-id> <node-name>
|
|
113
114
|
journey transition list <journey-id> [--from <node-name>] [--to <node-name>]
|
|
114
|
-
journey transition add <journey-id> --from <node-name> --to <node-name> --trigger <json> [--priority <n>] [--name <transition-name>]
|
|
115
|
+
journey transition add <journey-id> --from <node-name> --to <node-name> --trigger <json> [--priority <n>] [--name <transition-name>] [--quiet]
|
|
115
116
|
journey transition update <journey-id> <transition-name> [--trigger <json>] [--priority <n>]
|
|
116
117
|
journey transition remove <journey-id> <transition-name>`,
|
|
117
118
|
"email-identity": `Usage: ascendkit email-identity <command>
|
|
@@ -123,6 +124,7 @@ Commands:
|
|
|
123
124
|
email-identity remove-domain
|
|
124
125
|
email-identity list
|
|
125
126
|
email-identity add <email> [--display-name <name>]
|
|
127
|
+
email-identity update <email> --display-name <name>
|
|
126
128
|
email-identity resend <email>
|
|
127
129
|
email-identity set-default <email> [--display-name <name>]
|
|
128
130
|
email-identity remove <email>
|
|
@@ -291,6 +293,8 @@ function printTemplateSummary(data, opts) {
|
|
|
291
293
|
console.log(`Template: ${data.name} (${data.id})`);
|
|
292
294
|
if (data.slug)
|
|
293
295
|
console.log(`Slug: ${data.slug}`);
|
|
296
|
+
if (data.category)
|
|
297
|
+
console.log(`Category: ${data.category}`);
|
|
294
298
|
console.log(`Subject: ${data.subject ?? "-"}`);
|
|
295
299
|
if (data.currentVersion != null)
|
|
296
300
|
console.log(`Version: ${data.currentVersion}`);
|
|
@@ -338,6 +342,65 @@ function printSurveySummary(data) {
|
|
|
338
342
|
if (questions != null)
|
|
339
343
|
console.log(`Questions: ${questions}`);
|
|
340
344
|
}
|
|
345
|
+
function printEnvironmentSummary(data) {
|
|
346
|
+
console.log(`${data.name} (${data.id})`);
|
|
347
|
+
console.log(`Tier: ${data.tier}`);
|
|
348
|
+
if (data.description)
|
|
349
|
+
console.log(`Description: ${data.description}`);
|
|
350
|
+
console.log(`Public key: ${data.publicKey}`);
|
|
351
|
+
if (data.secretKey) {
|
|
352
|
+
const masked = data.secretKey.slice(0, 10) + "****";
|
|
353
|
+
console.log(`Secret key: ${masked}`);
|
|
354
|
+
}
|
|
355
|
+
const vars = data.variables && typeof data.variables === "object" ? Object.entries(data.variables) : [];
|
|
356
|
+
if (vars.length > 0) {
|
|
357
|
+
console.log(`Variables:`);
|
|
358
|
+
for (const [k, v] of vars)
|
|
359
|
+
console.log(` ${k}=${v}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function printPromotionSummary(result) {
|
|
363
|
+
const src = result.source ?? {};
|
|
364
|
+
const tgt = result.target ?? {};
|
|
365
|
+
console.log(`Promoted ${src.tier} → ${tgt.tier} (${tgt.envId})`);
|
|
366
|
+
console.log("");
|
|
367
|
+
const changes = result.changes ?? {};
|
|
368
|
+
const rows = [];
|
|
369
|
+
for (const [key, val] of Object.entries(changes)) {
|
|
370
|
+
const label = key.padEnd(14);
|
|
371
|
+
if (val.action === "unchanged") {
|
|
372
|
+
rows.push([label, "unchanged"]);
|
|
373
|
+
}
|
|
374
|
+
else if (val.action === "skip") {
|
|
375
|
+
rows.push([label, `skipped — ${val.reason}`]);
|
|
376
|
+
}
|
|
377
|
+
else if (val.action === "update" || val.action === "add_only") {
|
|
378
|
+
const fields = Array.isArray(val.fields) && val.fields.length ? ` (${val.fields.join(", ")})` : "";
|
|
379
|
+
rows.push([label, `updated${fields}`]);
|
|
380
|
+
}
|
|
381
|
+
else if (val.items) {
|
|
382
|
+
const counts = Object.entries(val.counts ?? {}).map(([k, v]) => `${v} ${k}`).join(", ");
|
|
383
|
+
rows.push([label, counts || "unchanged"]);
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
rows.push([label, val.action ?? "—"]);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
for (const [label, status] of rows) {
|
|
390
|
+
console.log(` ${label} ${status}`);
|
|
391
|
+
}
|
|
392
|
+
// Only show warnings not already conveyed by a skipped row in the table
|
|
393
|
+
const skippedKeys = new Set(Object.entries(changes)
|
|
394
|
+
.filter(([, v]) => v.action === "skip")
|
|
395
|
+
.map(([k]) => k.toUpperCase()));
|
|
396
|
+
const warnings = (Array.isArray(result.warnings) ? result.warnings : [])
|
|
397
|
+
.filter((w) => !skippedKeys.size || !Array.from(skippedKeys).some(k => w.code?.toUpperCase().includes(k)));
|
|
398
|
+
if (warnings.length > 0) {
|
|
399
|
+
console.log("");
|
|
400
|
+
for (const w of warnings)
|
|
401
|
+
console.log(`⚠ ${w.message}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
341
404
|
function printProjectSummary(data) {
|
|
342
405
|
console.log(`Project: ${data.id}`);
|
|
343
406
|
console.log(`Name: ${data.name}`);
|
|
@@ -348,6 +411,92 @@ function printProjectSummary(data) {
|
|
|
348
411
|
console.log(`Environment: ${data.environment.publicKey}`);
|
|
349
412
|
}
|
|
350
413
|
}
|
|
414
|
+
function printCampaignSummary(data) {
|
|
415
|
+
console.log(`Campaign: ${data.name} (${data.id})`);
|
|
416
|
+
if (data.templateName)
|
|
417
|
+
console.log(`Template: ${data.templateName}`);
|
|
418
|
+
console.log(`Status: ${data.status} | Recipients: ${data.totalRecipients ?? 0}`);
|
|
419
|
+
if (data.audienceSummary)
|
|
420
|
+
console.log(`Audience: ${data.audienceSummary}`);
|
|
421
|
+
if (data.scheduledAt)
|
|
422
|
+
console.log(`Scheduled: ${data.scheduledAt}`);
|
|
423
|
+
if (data.sentAt)
|
|
424
|
+
console.log(`Sent: ${data.sentAt}`);
|
|
425
|
+
if (data.fromIdentityEmail)
|
|
426
|
+
console.log(`From: ${data.fromIdentityEmail}`);
|
|
427
|
+
}
|
|
428
|
+
function printCampaignAnalytics(data) {
|
|
429
|
+
const sent = data.sent ?? 0;
|
|
430
|
+
const opened = data.opened ?? 0;
|
|
431
|
+
const clicked = data.clicked ?? 0;
|
|
432
|
+
const bounced = data.bounced ?? 0;
|
|
433
|
+
const rates = data.rates ?? {};
|
|
434
|
+
const fmtRate = (r) => r != null ? ` (${Math.round(r * 100)}%)` : "";
|
|
435
|
+
console.log(`Sent: ${sent} | Opened: ${opened}${fmtRate(rates.openRate)} | Clicked: ${clicked}${fmtRate(rates.clickRate)} | Bounced: ${bounced}`);
|
|
436
|
+
}
|
|
437
|
+
function printAudiencePreview(data) {
|
|
438
|
+
const count = data.count ?? data.total ?? 0;
|
|
439
|
+
console.log(`Matched ${count} recipient(s)`);
|
|
440
|
+
}
|
|
441
|
+
function printWebhookSummary(data, opts) {
|
|
442
|
+
console.log(`Webhook: ${data.id}`);
|
|
443
|
+
const events = Array.isArray(data.events) && data.events.length > 0 ? data.events.join(", ") : "all";
|
|
444
|
+
console.log(`URL: ${data.url} | Status: ${data.status}`);
|
|
445
|
+
console.log(`Events: ${events}`);
|
|
446
|
+
if (opts?.showSecret && data.secret) {
|
|
447
|
+
console.log(`Secret: ${data.secret} (save this — it won't be shown again)`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function printWebhookTestResult(data) {
|
|
451
|
+
if (data.success) {
|
|
452
|
+
console.log(`✓ Delivered: HTTP ${data.statusCode}`);
|
|
453
|
+
}
|
|
454
|
+
else if (data.statusCode) {
|
|
455
|
+
console.log(`✗ Failed: HTTP ${data.statusCode}`);
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
console.log(`✗ Failed`);
|
|
459
|
+
}
|
|
460
|
+
if (data.error)
|
|
461
|
+
console.log(data.error);
|
|
462
|
+
}
|
|
463
|
+
function printTemplateVersionSummary(data) {
|
|
464
|
+
const note = data.changeNote || "no note";
|
|
465
|
+
console.log(`Version ${data.versionNumber} — ${note}`);
|
|
466
|
+
console.log(`Subject: ${data.subject ?? "—"}`);
|
|
467
|
+
if (Array.isArray(data.variables) && data.variables.length > 0) {
|
|
468
|
+
console.log(`Variables: ${data.variables.join(", ")}`);
|
|
469
|
+
}
|
|
470
|
+
if (data.createdAt) {
|
|
471
|
+
console.log(`Created: ${data.createdAt}`);
|
|
472
|
+
}
|
|
473
|
+
if (data.bodyHtml) {
|
|
474
|
+
console.log(`\n--- HTML Body ---\n${data.bodyHtml}`);
|
|
475
|
+
}
|
|
476
|
+
if (data.bodyText) {
|
|
477
|
+
console.log(`\n--- Plain Text Body ---\n${data.bodyText}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function printSurveyAnalytics(data) {
|
|
481
|
+
const funnel = data.funnel ?? {};
|
|
482
|
+
const invited = funnel.sent ?? data.totalInvited ?? 0;
|
|
483
|
+
const responded = funnel.submitted ?? data.totalResponded ?? 0;
|
|
484
|
+
const rate = funnel.completionRate ?? data.completionRate ?? 0;
|
|
485
|
+
console.log(`Responses: ${responded}/${invited} (${rate}%)`);
|
|
486
|
+
if (data.npsScore != null)
|
|
487
|
+
console.log(`NPS: ${data.npsScore}`);
|
|
488
|
+
if (data.csatAverage != null)
|
|
489
|
+
console.log(`CSAT: ${data.csatAverage}`);
|
|
490
|
+
}
|
|
491
|
+
function printSurveyInvitations(data) {
|
|
492
|
+
const rows = Array.isArray(data) ? data : [];
|
|
493
|
+
table(rows, [
|
|
494
|
+
{ key: "id", label: "ID", width: 20 },
|
|
495
|
+
{ key: "userId", label: "User", width: 20 },
|
|
496
|
+
{ key: "status", label: "Status", width: 12 },
|
|
497
|
+
{ key: "sentAt", label: "Sent At", width: 22 },
|
|
498
|
+
]);
|
|
499
|
+
}
|
|
351
500
|
function normalizeJourneyRows(data) {
|
|
352
501
|
if (Array.isArray(data)) {
|
|
353
502
|
return data;
|
|
@@ -383,6 +532,16 @@ function table(rows, columns) {
|
|
|
383
532
|
console.log(line);
|
|
384
533
|
}
|
|
385
534
|
}
|
|
535
|
+
function normalizeTemplateCategoryFlag(value) {
|
|
536
|
+
if (value === undefined)
|
|
537
|
+
return undefined;
|
|
538
|
+
if (typeof value != "string")
|
|
539
|
+
return undefined;
|
|
540
|
+
const normalized = value.trim().toLowerCase();
|
|
541
|
+
if (normalized === "marketing" || normalized === "transactional")
|
|
542
|
+
return normalized;
|
|
543
|
+
return undefined;
|
|
544
|
+
}
|
|
386
545
|
async function run() {
|
|
387
546
|
installGlobalHandlers();
|
|
388
547
|
const args = process.argv.slice(2);
|
|
@@ -447,6 +606,14 @@ async function run() {
|
|
|
447
606
|
}
|
|
448
607
|
return;
|
|
449
608
|
}
|
|
609
|
+
// --help anywhere after the action (e.g. ascendkit template update <id> --help)
|
|
610
|
+
if (args.slice(2).some(a => a === "--help" || a === "-h")) {
|
|
611
|
+
if (!printSectionHelp(domain)) {
|
|
612
|
+
console.error(`Unknown command section: ${domain}`);
|
|
613
|
+
return await exitCli(1);
|
|
614
|
+
}
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
450
617
|
// Platform commands (don't need environment key)
|
|
451
618
|
switch (domain) {
|
|
452
619
|
case "init": {
|
|
@@ -756,7 +923,7 @@ async function runEnvironment(action, rest) {
|
|
|
756
923
|
}
|
|
757
924
|
switch (action) {
|
|
758
925
|
case "show":
|
|
759
|
-
|
|
926
|
+
printEnvironmentSummary(await platform.getEnvironment(ctx.projectId, ctx.environmentId));
|
|
760
927
|
return;
|
|
761
928
|
case "promote": {
|
|
762
929
|
const envId = rest[0] && !rest[0].startsWith("--") ? rest[0] : ctx.environmentId;
|
|
@@ -767,8 +934,7 @@ async function runEnvironment(action, rest) {
|
|
|
767
934
|
}
|
|
768
935
|
try {
|
|
769
936
|
const result = await platform.promoteEnvironment(envId, target);
|
|
770
|
-
|
|
771
|
-
console.log(JSON.stringify(result, null, 2));
|
|
937
|
+
printPromotionSummary(result);
|
|
772
938
|
}
|
|
773
939
|
catch (err) {
|
|
774
940
|
let message = err instanceof Error ? err.message : String(err);
|
|
@@ -799,7 +965,7 @@ async function runEnvironment(action, rest) {
|
|
|
799
965
|
try {
|
|
800
966
|
const result = await platform.updateEnvironment(ctx.projectId, envId, name, description);
|
|
801
967
|
console.log("Environment updated:");
|
|
802
|
-
|
|
968
|
+
printEnvironmentSummary(result);
|
|
803
969
|
}
|
|
804
970
|
catch (err) {
|
|
805
971
|
let message = err instanceof Error ? err.message : String(err);
|
|
@@ -1029,6 +1195,16 @@ async function runAuth(client, action, rest) {
|
|
|
1029
1195
|
}
|
|
1030
1196
|
async function runContent(client, action, rest) {
|
|
1031
1197
|
const flags = parseFlags(rest);
|
|
1198
|
+
// Accept --html/--text as aliases for --body-html/--body-text
|
|
1199
|
+
if (!flags["body-html"] && flags.html)
|
|
1200
|
+
flags["body-html"] = flags.html;
|
|
1201
|
+
if (!flags["body-text"] && flags.text)
|
|
1202
|
+
flags["body-text"] = flags.text;
|
|
1203
|
+
const category = normalizeTemplateCategoryFlag(flags.category);
|
|
1204
|
+
if (flags.category && !category) {
|
|
1205
|
+
console.error("Invalid --category. Use marketing or transactional.");
|
|
1206
|
+
return await exitCli(1);
|
|
1207
|
+
}
|
|
1032
1208
|
if (!action) {
|
|
1033
1209
|
console.log(HELP_SECTION.template);
|
|
1034
1210
|
return;
|
|
@@ -1039,13 +1215,14 @@ async function runContent(client, action, rest) {
|
|
|
1039
1215
|
switch (normalizedAction) {
|
|
1040
1216
|
case "create":
|
|
1041
1217
|
if (!flags.name || !flags.subject || !flags["body-html"] || !flags["body-text"]) {
|
|
1042
|
-
console.error("Usage: ascendkit template create --name <n> --subject <s> --body-html <h> --body-text <t> [--slug <slug>] [--description <desc>]");
|
|
1218
|
+
console.error("Usage: ascendkit template create --name <n> --subject <s> --body-html <h> --body-text <t> [--slug <slug>] [--description <desc>] [--category <marketing|transactional>]");
|
|
1043
1219
|
return await exitCli(1);
|
|
1044
1220
|
}
|
|
1045
1221
|
printTemplateSummary(await content.createTemplate(client, {
|
|
1046
1222
|
name: flags.name, subject: flags.subject,
|
|
1047
1223
|
bodyHtml: flags["body-html"], bodyText: flags["body-text"],
|
|
1048
1224
|
slug: flags.slug, description: flags.description,
|
|
1225
|
+
category,
|
|
1049
1226
|
}));
|
|
1050
1227
|
break;
|
|
1051
1228
|
case "list": {
|
|
@@ -1061,6 +1238,7 @@ async function runContent(client, action, rest) {
|
|
|
1061
1238
|
{ key: "id", label: "ID" },
|
|
1062
1239
|
{ key: "name", label: "Name", width: 30 },
|
|
1063
1240
|
{ key: "slug", label: "Slug", width: 25 },
|
|
1241
|
+
{ key: "category", label: "Category", width: 14 },
|
|
1064
1242
|
{ key: "subject", label: "Subject", width: 30 },
|
|
1065
1243
|
]);
|
|
1066
1244
|
break;
|
|
@@ -1082,6 +1260,7 @@ async function runContent(client, action, rest) {
|
|
|
1082
1260
|
bodyHtml: flags["body-html"],
|
|
1083
1261
|
bodyText: flags["body-text"],
|
|
1084
1262
|
changeNote: flags["change-note"],
|
|
1263
|
+
category,
|
|
1085
1264
|
}));
|
|
1086
1265
|
break;
|
|
1087
1266
|
case "remove":
|
|
@@ -1114,7 +1293,7 @@ async function runContent(client, action, rest) {
|
|
|
1114
1293
|
console.error("Usage: ascendkit template version show <template-id> <n>");
|
|
1115
1294
|
return await exitCli(1);
|
|
1116
1295
|
}
|
|
1117
|
-
|
|
1296
|
+
printTemplateVersionSummary(await content.getVersion(client, templateId, parseInt(versionNumber, 10)));
|
|
1118
1297
|
}
|
|
1119
1298
|
break;
|
|
1120
1299
|
default:
|
|
@@ -1182,7 +1361,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1182
1361
|
console.error("Usage: ascendkit survey distribute <survey-id> --users <usr_id1,usr_id2,...>");
|
|
1183
1362
|
return await exitCli(1);
|
|
1184
1363
|
}
|
|
1185
|
-
|
|
1364
|
+
console.log(formatDistributionResult(await surveys.distributeSurvey(client, rest[0], flags.users.split(","))));
|
|
1186
1365
|
break;
|
|
1187
1366
|
case "invitations":
|
|
1188
1367
|
case "invitation":
|
|
@@ -1192,7 +1371,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1192
1371
|
console.error("Usage: ascendkit survey invitation list <survey-id>");
|
|
1193
1372
|
return await exitCli(1);
|
|
1194
1373
|
}
|
|
1195
|
-
|
|
1374
|
+
printSurveyInvitations(await surveys.listInvitations(client, surveyId));
|
|
1196
1375
|
}
|
|
1197
1376
|
else {
|
|
1198
1377
|
console.error(`Unknown survey invitation command: ${rest[0]}`);
|
|
@@ -1204,7 +1383,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1204
1383
|
console.error("Usage: ascendkit survey analytics <survey-id>");
|
|
1205
1384
|
return await exitCli(1);
|
|
1206
1385
|
}
|
|
1207
|
-
|
|
1386
|
+
printSurveyAnalytics(await surveys.getAnalytics(client, rest[0]));
|
|
1208
1387
|
break;
|
|
1209
1388
|
case "export-definition":
|
|
1210
1389
|
case "import-definition":
|
|
@@ -1269,7 +1448,7 @@ async function runSurvey(client, action, rest) {
|
|
|
1269
1448
|
return await exitCli(1);
|
|
1270
1449
|
}
|
|
1271
1450
|
if (questionAction === "list") {
|
|
1272
|
-
|
|
1451
|
+
console.log(formatQuestionList(await surveys.listQuestions(client, surveyId)));
|
|
1273
1452
|
}
|
|
1274
1453
|
else if (questionAction === "add") {
|
|
1275
1454
|
if (!flags.type || !flags.title) {
|
|
@@ -1285,13 +1464,17 @@ async function runSurvey(client, action, rest) {
|
|
|
1285
1464
|
params.choices = flags.choices.split(",");
|
|
1286
1465
|
if (flags.position != null)
|
|
1287
1466
|
params.position = Number(flags.position);
|
|
1288
|
-
|
|
1467
|
+
console.log(formatSingleQuestion(await surveys.addQuestion(client, surveyId, params), "Added"));
|
|
1289
1468
|
}
|
|
1290
1469
|
else if (questionAction === "update") {
|
|
1291
1470
|
if (!questionName) {
|
|
1292
1471
|
console.error("Usage: ascendkit survey question update <survey-id> <question-name> [--title <title>] [--required <true|false>] [--choices <c1,c2,...>]");
|
|
1293
1472
|
return await exitCli(1);
|
|
1294
1473
|
}
|
|
1474
|
+
if (flags.type) {
|
|
1475
|
+
console.error("Error: question type cannot be changed on an existing question. Remove and re-add it to change the type.");
|
|
1476
|
+
return await exitCli(1);
|
|
1477
|
+
}
|
|
1295
1478
|
const params = {};
|
|
1296
1479
|
if (flags.title)
|
|
1297
1480
|
params.title = flags.title;
|
|
@@ -1299,21 +1482,23 @@ async function runSurvey(client, action, rest) {
|
|
|
1299
1482
|
params.isRequired = flags.required === "true";
|
|
1300
1483
|
if (flags.choices)
|
|
1301
1484
|
params.choices = flags.choices.split(",");
|
|
1302
|
-
|
|
1485
|
+
console.log(formatSingleQuestion(await surveys.editQuestion(client, surveyId, questionName, params), "Updated"));
|
|
1303
1486
|
}
|
|
1304
1487
|
else if (questionAction === "remove") {
|
|
1305
1488
|
if (!questionName) {
|
|
1306
1489
|
console.error("Usage: ascendkit survey question remove <survey-id> <question-name>");
|
|
1307
1490
|
return await exitCli(1);
|
|
1308
1491
|
}
|
|
1309
|
-
|
|
1492
|
+
await surveys.removeQuestion(client, surveyId, questionName);
|
|
1493
|
+
console.log("Question removed.");
|
|
1310
1494
|
}
|
|
1311
1495
|
else if (questionAction === "reorder") {
|
|
1312
1496
|
if (!flags.order) {
|
|
1313
1497
|
console.error("Usage: ascendkit survey question reorder <survey-id> --order <name1,name2,...>");
|
|
1314
1498
|
return await exitCli(1);
|
|
1315
1499
|
}
|
|
1316
|
-
|
|
1500
|
+
await surveys.reorderQuestions(client, surveyId, flags.order.split(","));
|
|
1501
|
+
console.log("Questions reordered.");
|
|
1317
1502
|
}
|
|
1318
1503
|
else {
|
|
1319
1504
|
console.error(`Unknown survey question command: ${questionAction}`);
|
|
@@ -1507,13 +1692,36 @@ async function runJourney(client, action, rest) {
|
|
|
1507
1692
|
}
|
|
1508
1693
|
console.log(formatJourneyWithGuidance(await journeys.activateJourney(client, rest[0])));
|
|
1509
1694
|
break;
|
|
1510
|
-
case "pause":
|
|
1695
|
+
case "pause": {
|
|
1511
1696
|
if (!rest[0]) {
|
|
1512
|
-
console.error("Usage: ascendkit journey pause <journey-id>");
|
|
1697
|
+
console.error("Usage: ascendkit journey pause <journey-id> [--yes]");
|
|
1513
1698
|
return await exitCli(1);
|
|
1514
1699
|
}
|
|
1700
|
+
const journeyForPause = await journeys.getJourney(client, rest[0]);
|
|
1701
|
+
const activeUsers = journeyForPause?.stats?.currentlyActive ?? 0;
|
|
1702
|
+
if (activeUsers > 0 && !flags.yes) {
|
|
1703
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
1704
|
+
const { createInterface } = await import("node:readline/promises");
|
|
1705
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1706
|
+
try {
|
|
1707
|
+
const answer = (await rl.question(`${activeUsers} user(s) are currently active in this journey. Actions will be queued while paused. Proceed? [y/N] `)).trim().toLowerCase();
|
|
1708
|
+
if (answer !== "y" && answer !== "yes") {
|
|
1709
|
+
console.log("Cancelled.");
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
finally {
|
|
1714
|
+
rl.close();
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
else {
|
|
1718
|
+
console.error(`Warning: ${activeUsers} user(s) are currently active. Pass --yes to skip confirmation.`);
|
|
1719
|
+
return await exitCli(1);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1515
1722
|
console.log(formatJourneyWithGuidance(await journeys.pauseJourney(client, rest[0])));
|
|
1516
1723
|
break;
|
|
1724
|
+
}
|
|
1517
1725
|
case "resume":
|
|
1518
1726
|
if (!rest[0]) {
|
|
1519
1727
|
console.error("Usage: ascendkit journey resume <journey-id>");
|
|
@@ -1559,7 +1767,7 @@ async function runJourney(client, action, rest) {
|
|
|
1559
1767
|
}
|
|
1560
1768
|
if (flags.terminal)
|
|
1561
1769
|
params.terminal = flags.terminal === "true";
|
|
1562
|
-
console.log(formatSingleNode(await journeys.addNode(client, rest[0], params), "Added", flags.name));
|
|
1770
|
+
console.log(formatSingleNode(await journeys.addNode(client, rest[0], params), "Added", flags.name, { suppressWarnings: !!flags.quiet }));
|
|
1563
1771
|
break;
|
|
1564
1772
|
}
|
|
1565
1773
|
case "edit-node": {
|
|
@@ -1634,7 +1842,7 @@ async function runJourney(client, action, rest) {
|
|
|
1634
1842
|
if (flags.name)
|
|
1635
1843
|
params.name = flags.name;
|
|
1636
1844
|
const transitionName = flags.name || `${flags.from}-to-${flags.to}`;
|
|
1637
|
-
console.log(formatSingleTransition(await journeys.addTransition(client, rest[0], params), "Added", transitionName));
|
|
1845
|
+
console.log(formatSingleTransition(await journeys.addTransition(client, rest[0], params), "Added", transitionName, { suppressWarnings: !!flags.quiet }));
|
|
1638
1846
|
break;
|
|
1639
1847
|
}
|
|
1640
1848
|
case "edit-transition": {
|
|
@@ -1677,10 +1885,10 @@ async function runWebhook(client, action, rest) {
|
|
|
1677
1885
|
console.error("Usage: ascendkit webhook create --url <url> [--events <e1,e2,...>]");
|
|
1678
1886
|
return await exitCli(1);
|
|
1679
1887
|
}
|
|
1680
|
-
|
|
1888
|
+
printWebhookSummary(await webhooks.createWebhook(client, {
|
|
1681
1889
|
url: flags.url,
|
|
1682
1890
|
events: flags.events ? flags.events.split(",") : undefined,
|
|
1683
|
-
}));
|
|
1891
|
+
}), { showSecret: true });
|
|
1684
1892
|
break;
|
|
1685
1893
|
case "list":
|
|
1686
1894
|
table(await webhooks.listWebhooks(client), [
|
|
@@ -1695,7 +1903,7 @@ async function runWebhook(client, action, rest) {
|
|
|
1695
1903
|
console.error("Usage: ascendkit webhook get <webhook-id>");
|
|
1696
1904
|
return await exitCli(1);
|
|
1697
1905
|
}
|
|
1698
|
-
|
|
1906
|
+
printWebhookSummary(await webhooks.getWebhook(client, rest[0]));
|
|
1699
1907
|
break;
|
|
1700
1908
|
case "update": {
|
|
1701
1909
|
if (!rest[0]) {
|
|
@@ -1718,14 +1926,15 @@ async function runWebhook(client, action, rest) {
|
|
|
1718
1926
|
console.error("Usage: ascendkit webhook delete <webhook-id>");
|
|
1719
1927
|
return await exitCli(1);
|
|
1720
1928
|
}
|
|
1721
|
-
|
|
1929
|
+
await webhooks.deleteWebhook(client, rest[0]);
|
|
1930
|
+
console.log("Webhook deleted.");
|
|
1722
1931
|
break;
|
|
1723
1932
|
case "test":
|
|
1724
1933
|
if (!rest[0]) {
|
|
1725
1934
|
console.error("Usage: ascendkit webhook test <webhook-id> [--event <event-type>]");
|
|
1726
1935
|
return await exitCli(1);
|
|
1727
1936
|
}
|
|
1728
|
-
|
|
1937
|
+
printWebhookTestResult(await webhooks.testWebhook(client, rest[0], flags.event));
|
|
1729
1938
|
break;
|
|
1730
1939
|
default:
|
|
1731
1940
|
console.error(`Unknown webhook command: ${action}`);
|
|
@@ -1753,7 +1962,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1753
1962
|
console.error("Invalid JSON for --audience flag. Provide a valid JSON object.");
|
|
1754
1963
|
return await exitCli(1);
|
|
1755
1964
|
}
|
|
1756
|
-
|
|
1965
|
+
printCampaignSummary(await campaigns.createCampaign(client, {
|
|
1757
1966
|
name: flags.name,
|
|
1758
1967
|
templateId: flags.template,
|
|
1759
1968
|
audienceFilter: createFilter,
|
|
@@ -1778,7 +1987,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1778
1987
|
console.error("Usage: ascendkit campaign show <campaign-id>");
|
|
1779
1988
|
return await exitCli(1);
|
|
1780
1989
|
}
|
|
1781
|
-
|
|
1990
|
+
printCampaignSummary(await campaigns.getCampaign(client, rest[0]));
|
|
1782
1991
|
break;
|
|
1783
1992
|
case "update": {
|
|
1784
1993
|
if (!rest[0]) {
|
|
@@ -1795,7 +2004,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1795
2004
|
return await exitCli(1);
|
|
1796
2005
|
}
|
|
1797
2006
|
}
|
|
1798
|
-
|
|
2007
|
+
printCampaignSummary(await campaigns.updateCampaign(client, rest[0], {
|
|
1799
2008
|
name: flags.name,
|
|
1800
2009
|
templateId: flags.template,
|
|
1801
2010
|
audienceFilter: updateFilter,
|
|
@@ -1813,7 +2022,7 @@ async function runCampaign(client, action, rest) {
|
|
|
1813
2022
|
console.error("Campaign has no audience filter set.");
|
|
1814
2023
|
return await exitCli(1);
|
|
1815
2024
|
}
|
|
1816
|
-
|
|
2025
|
+
printAudiencePreview(await campaigns.previewAudience(client, detail.audienceFilter));
|
|
1817
2026
|
break;
|
|
1818
2027
|
}
|
|
1819
2028
|
case "schedule":
|
|
@@ -1821,21 +2030,22 @@ async function runCampaign(client, action, rest) {
|
|
|
1821
2030
|
console.error("Usage: ascendkit campaign schedule <campaign-id> --at <datetime>");
|
|
1822
2031
|
return await exitCli(1);
|
|
1823
2032
|
}
|
|
1824
|
-
|
|
2033
|
+
printCampaignSummary(await campaigns.updateCampaign(client, rest[0], { scheduledAt: flags.at }));
|
|
1825
2034
|
break;
|
|
1826
2035
|
case "cancel":
|
|
1827
2036
|
if (!rest[0]) {
|
|
1828
2037
|
console.error("Usage: ascendkit campaign cancel <campaign-id>");
|
|
1829
2038
|
return await exitCli(1);
|
|
1830
2039
|
}
|
|
1831
|
-
|
|
2040
|
+
await campaigns.deleteCampaign(client, rest[0]);
|
|
2041
|
+
console.log("Campaign cancelled.");
|
|
1832
2042
|
break;
|
|
1833
2043
|
case "analytics":
|
|
1834
2044
|
if (!rest[0]) {
|
|
1835
2045
|
console.error("Usage: ascendkit campaign analytics <campaign-id>");
|
|
1836
2046
|
return await exitCli(1);
|
|
1837
2047
|
}
|
|
1838
|
-
|
|
2048
|
+
printCampaignAnalytics(await campaigns.getCampaignAnalytics(client, rest[0]));
|
|
1839
2049
|
break;
|
|
1840
2050
|
default:
|
|
1841
2051
|
console.error(`Unknown campaign command: ${action}`);
|
|
@@ -1895,7 +2105,8 @@ async function runEmail(client, action, rest) {
|
|
|
1895
2105
|
break;
|
|
1896
2106
|
}
|
|
1897
2107
|
case "remove-domain":
|
|
1898
|
-
|
|
2108
|
+
await email.removeDomain(client);
|
|
2109
|
+
console.log("Domain removed.");
|
|
1899
2110
|
break;
|
|
1900
2111
|
case "list": {
|
|
1901
2112
|
const result = await email.listIdentities(client);
|
|
@@ -1908,10 +2119,25 @@ async function runEmail(client, action, rest) {
|
|
|
1908
2119
|
console.error("Usage: ascendkit email-identity add <email> [--display-name <name>]");
|
|
1909
2120
|
return await exitCli(1);
|
|
1910
2121
|
}
|
|
1911
|
-
|
|
2122
|
+
const added = await email.createIdentity(client, {
|
|
1912
2123
|
email: identityEmail,
|
|
1913
2124
|
displayName: flags["display-name"],
|
|
1914
|
-
})
|
|
2125
|
+
});
|
|
2126
|
+
printEmailIdentities(added.identities ?? []);
|
|
2127
|
+
console.log("Verification email sent.");
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
case "update": {
|
|
2131
|
+
const identityEmail = rest[0];
|
|
2132
|
+
if (!identityEmail || !flags["display-name"]) {
|
|
2133
|
+
console.error("Usage: ascendkit email-identity update <email> --display-name <name>");
|
|
2134
|
+
return await exitCli(1);
|
|
2135
|
+
}
|
|
2136
|
+
const updated = await email.updateIdentity(client, {
|
|
2137
|
+
email: identityEmail,
|
|
2138
|
+
displayName: flags["display-name"],
|
|
2139
|
+
});
|
|
2140
|
+
printEmailIdentities(updated.identities ?? []);
|
|
1915
2141
|
break;
|
|
1916
2142
|
}
|
|
1917
2143
|
case "resend": {
|
|
@@ -1920,7 +2146,8 @@ async function runEmail(client, action, rest) {
|
|
|
1920
2146
|
console.error("Usage: ascendkit email-identity resend <email>");
|
|
1921
2147
|
return await exitCli(1);
|
|
1922
2148
|
}
|
|
1923
|
-
|
|
2149
|
+
await email.resendIdentityVerification(client, identityEmail);
|
|
2150
|
+
console.log(`Verification email sent to ${identityEmail}.`);
|
|
1924
2151
|
break;
|
|
1925
2152
|
}
|
|
1926
2153
|
case "set-default": {
|
|
@@ -1929,10 +2156,11 @@ async function runEmail(client, action, rest) {
|
|
|
1929
2156
|
console.error("Usage: ascendkit email-identity set-default <email> [--display-name <name>]");
|
|
1930
2157
|
return await exitCli(1);
|
|
1931
2158
|
}
|
|
1932
|
-
|
|
2159
|
+
const updated = await email.setDefaultIdentity(client, {
|
|
1933
2160
|
email: identityEmail,
|
|
1934
2161
|
displayName: flags["display-name"],
|
|
1935
|
-
})
|
|
2162
|
+
});
|
|
2163
|
+
printEmailIdentities(updated.identities ?? []);
|
|
1936
2164
|
break;
|
|
1937
2165
|
}
|
|
1938
2166
|
case "remove":
|
|
@@ -1942,7 +2170,9 @@ async function runEmail(client, action, rest) {
|
|
|
1942
2170
|
console.error("Usage: ascendkit email-identity remove <email>");
|
|
1943
2171
|
return await exitCli(1);
|
|
1944
2172
|
}
|
|
1945
|
-
|
|
2173
|
+
const remaining = await email.removeIdentity(client, identityEmail);
|
|
2174
|
+
console.log("Identity removed.");
|
|
2175
|
+
printEmailIdentities(remaining.identities ?? []);
|
|
1946
2176
|
break;
|
|
1947
2177
|
}
|
|
1948
2178
|
case "test": {
|
|
@@ -1951,10 +2181,11 @@ async function runEmail(client, action, rest) {
|
|
|
1951
2181
|
console.error("Usage: ascendkit email-identity test <email> --to <recipient>");
|
|
1952
2182
|
return await exitCli(1);
|
|
1953
2183
|
}
|
|
1954
|
-
|
|
2184
|
+
const testResult = await email.sendTestEmail(client, {
|
|
1955
2185
|
to: flags.to,
|
|
1956
2186
|
fromIdentityEmail: identityEmail,
|
|
1957
|
-
})
|
|
2187
|
+
});
|
|
2188
|
+
console.log(testResult.message ?? "Test email sent.");
|
|
1958
2189
|
break;
|
|
1959
2190
|
}
|
|
1960
2191
|
default:
|
|
@@ -1967,12 +2198,12 @@ run().catch((err) => {
|
|
|
1967
2198
|
exitCli(1, err instanceof Error ? err : new Error(String(err)));
|
|
1968
2199
|
});
|
|
1969
2200
|
async function printEmailSetup(settings) {
|
|
1970
|
-
output(settings);
|
|
1971
2201
|
if (!settings.domain)
|
|
1972
2202
|
return;
|
|
1973
2203
|
const provider = settings.dnsProvider;
|
|
2204
|
+
console.log(`Domain: ${settings.domain}`);
|
|
1974
2205
|
if (provider?.name) {
|
|
1975
|
-
console.log(
|
|
2206
|
+
console.log(`DNS provider: ${provider.name} (${provider.confidence ?? "unknown"})`);
|
|
1976
2207
|
}
|
|
1977
2208
|
if (provider?.portalUrl) {
|
|
1978
2209
|
console.log(`Provider console: ${provider.portalUrl}`);
|
|
@@ -1980,10 +2211,54 @@ async function printEmailSetup(settings) {
|
|
|
1980
2211
|
if (provider?.assistantSetupUrl) {
|
|
1981
2212
|
console.log(`Guided setup: ${provider.assistantSetupUrl}`);
|
|
1982
2213
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2214
|
+
const records = Array.isArray(settings.dnsRecords) ? settings.dnsRecords : [];
|
|
2215
|
+
if (records.length > 0) {
|
|
2216
|
+
console.log("\nDNS records to add:");
|
|
2217
|
+
for (const rec of records) {
|
|
2218
|
+
console.log(` ${rec.type.padEnd(6)} ${rec.name} ${rec.value}`);
|
|
2219
|
+
}
|
|
2220
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
2221
|
+
const defaultFile = `dns-records-${settings.domain}.txt`;
|
|
2222
|
+
const { createInterface } = await import("node:readline/promises");
|
|
2223
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2224
|
+
try {
|
|
2225
|
+
const answer = (await rl.question(`\nSave records to file [${defaultFile}]: `)).trim();
|
|
2226
|
+
const filename = answer || defaultFile;
|
|
2227
|
+
const { existsSync, writeFileSync } = await import("node:fs");
|
|
2228
|
+
if (existsSync(filename)) {
|
|
2229
|
+
const overwrite = (await rl.question(`${filename} already exists. Overwrite? [y/N] `)).trim().toLowerCase();
|
|
2230
|
+
if (overwrite !== "y" && overwrite !== "yes") {
|
|
2231
|
+
console.log("Skipped.");
|
|
2232
|
+
return;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
const lines = [
|
|
2236
|
+
`; DNS records for ${settings.domain}`,
|
|
2237
|
+
`; Generated by AscendKit CLI`,
|
|
2238
|
+
"",
|
|
2239
|
+
...records.map(rec => {
|
|
2240
|
+
let value;
|
|
2241
|
+
if (rec.type === "TXT") {
|
|
2242
|
+
value = `"${rec.value}"`;
|
|
2243
|
+
}
|
|
2244
|
+
else if (rec.type === "CNAME" || rec.type === "MX") {
|
|
2245
|
+
// Ensure absolute FQDN with trailing dot to prevent zone-relative expansion
|
|
2246
|
+
const target = rec.type === "MX" ? rec.value.replace(/^(\d+)\s+/, "$1 ") : rec.value;
|
|
2247
|
+
value = target.endsWith(".") ? target : `${target}.`;
|
|
2248
|
+
}
|
|
2249
|
+
else {
|
|
2250
|
+
value = rec.value;
|
|
2251
|
+
}
|
|
2252
|
+
const name = rec.name.endsWith(".") ? rec.name : `${rec.name}.`;
|
|
2253
|
+
return `${name}\t3600\tIN\t${rec.type}\t${value} ; cf_tags=cf-proxied:false`;
|
|
2254
|
+
}),
|
|
2255
|
+
];
|
|
2256
|
+
writeFileSync(filename, lines.join("\n") + "\n");
|
|
2257
|
+
console.log(`Saved to ${filename}`);
|
|
2258
|
+
}
|
|
2259
|
+
finally {
|
|
2260
|
+
rl.close();
|
|
2261
|
+
}
|
|
1987
2262
|
}
|
|
1988
2263
|
}
|
|
1989
2264
|
}
|
|
@@ -2015,8 +2290,20 @@ function printEmailStatusSummary(settings, domainStatus, dnsCheck, identities) {
|
|
|
2015
2290
|
return;
|
|
2016
2291
|
}
|
|
2017
2292
|
console.log(`Domain: ${settings.domain} (${domainStatus.status || settings.verificationStatus || "unknown"})`);
|
|
2018
|
-
if (dnsCheck
|
|
2019
|
-
|
|
2293
|
+
if (dnsCheck) {
|
|
2294
|
+
const { summary, records } = dnsCheck;
|
|
2295
|
+
if (summary.notFound === 0 && summary.mismatch === 0 && summary.errored === 0) {
|
|
2296
|
+
console.log("DNS: all records verified");
|
|
2297
|
+
}
|
|
2298
|
+
else {
|
|
2299
|
+
console.log(`DNS: ${summary.found}/${summary.total} verified`);
|
|
2300
|
+
const pending = records.filter(r => !r.found || r.mismatch);
|
|
2301
|
+
if (pending.length > 0) {
|
|
2302
|
+
console.log("Pending:");
|
|
2303
|
+
for (const r of pending)
|
|
2304
|
+
console.log(` ${r.type.padEnd(6)} ${r.name}`);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2020
2307
|
}
|
|
2021
2308
|
console.log("");
|
|
2022
2309
|
printEmailIdentities(identities);
|
|
@@ -6,12 +6,14 @@ export interface CreateTemplateParams {
|
|
|
6
6
|
bodyText: string;
|
|
7
7
|
slug?: string;
|
|
8
8
|
description?: string;
|
|
9
|
+
category?: "marketing" | "transactional";
|
|
9
10
|
}
|
|
10
11
|
export interface UpdateTemplateParams {
|
|
11
12
|
subject?: string;
|
|
12
13
|
bodyHtml?: string;
|
|
13
14
|
bodyText?: string;
|
|
14
15
|
changeNote?: string;
|
|
16
|
+
category?: "marketing" | "transactional";
|
|
15
17
|
}
|
|
16
18
|
export declare function createTemplate(client: AscendKitClient, params: CreateTemplateParams): Promise<unknown>;
|
|
17
19
|
export declare function listTemplates(client: AscendKitClient, params?: {
|
package/dist/commands/email.d.ts
CHANGED
|
@@ -80,6 +80,10 @@ export declare function createIdentity(client: AscendKitClient, identity: {
|
|
|
80
80
|
displayName?: string;
|
|
81
81
|
}): Promise<EmailIdentitiesResponse>;
|
|
82
82
|
export declare function resendIdentityVerification(client: AscendKitClient, email: string): Promise<EmailIdentitiesResponse>;
|
|
83
|
+
export declare function updateIdentity(client: AscendKitClient, identity: {
|
|
84
|
+
email: string;
|
|
85
|
+
displayName: string;
|
|
86
|
+
}): Promise<EmailIdentitiesResponse>;
|
|
83
87
|
export declare function setDefaultIdentity(client: AscendKitClient, identity: {
|
|
84
88
|
email: string;
|
|
85
89
|
displayName?: string;
|
package/dist/commands/email.js
CHANGED
|
@@ -37,6 +37,9 @@ export async function createIdentity(client, identity) {
|
|
|
37
37
|
export async function resendIdentityVerification(client, email) {
|
|
38
38
|
return client.managedPost(`/api/email/settings/identities/${encodeURIComponent(email)}/resend`, {});
|
|
39
39
|
}
|
|
40
|
+
export async function updateIdentity(client, identity) {
|
|
41
|
+
return client.managedPost(`/api/email/settings/identities/${encodeURIComponent(identity.email)}/update`, { displayName: identity.displayName });
|
|
42
|
+
}
|
|
40
43
|
export async function setDefaultIdentity(client, identity) {
|
|
41
44
|
return client.managedPost(`/api/email/settings/identities/${encodeURIComponent(identity.email)}/default`, { displayName: identity.displayName ?? "" });
|
|
42
45
|
}
|
package/dist/tools/email.js
CHANGED
|
@@ -64,6 +64,13 @@ export function registerEmailTools(server, client) {
|
|
|
64
64
|
const data = await email.resendIdentityVerification(client, params.email);
|
|
65
65
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
66
66
|
});
|
|
67
|
+
server.tool("email_identity_update", "Update the display name of a sender identity", {
|
|
68
|
+
email: z.string().describe("Sender identity email"),
|
|
69
|
+
displayName: z.string().describe("New display name"),
|
|
70
|
+
}, async (params) => {
|
|
71
|
+
const data = await email.updateIdentity(client, params);
|
|
72
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
73
|
+
});
|
|
67
74
|
server.tool("email_identity_set_default", "Set the default sender identity for this environment", {
|
|
68
75
|
email: z.string().describe("Sender identity email"),
|
|
69
76
|
displayName: z.string().optional().describe("Optional updated display name"),
|
|
@@ -22,6 +22,7 @@ interface JourneyData {
|
|
|
22
22
|
terminal?: boolean;
|
|
23
23
|
}>;
|
|
24
24
|
transitions?: Array<{
|
|
25
|
+
name?: string;
|
|
25
26
|
from?: string;
|
|
26
27
|
from_?: string;
|
|
27
28
|
to?: string;
|
|
@@ -75,7 +76,9 @@ interface AnalyticsData {
|
|
|
75
76
|
exited?: number;
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
|
-
export declare function formatJourneyWithGuidance(journey: JourneyData
|
|
79
|
+
export declare function formatJourneyWithGuidance(journey: JourneyData, opts?: {
|
|
80
|
+
suppressWarnings?: boolean;
|
|
81
|
+
}): string;
|
|
79
82
|
export declare function formatJourneyList(data: {
|
|
80
83
|
journeys: JourneyData[];
|
|
81
84
|
total: number;
|
|
@@ -109,10 +112,14 @@ interface TransitionListItem {
|
|
|
109
112
|
export declare function formatNodeList(data: {
|
|
110
113
|
nodes: NodeListItem[];
|
|
111
114
|
}): string;
|
|
112
|
-
export declare function formatSingleNode(data: JourneyData, action: string, nodeName: string
|
|
115
|
+
export declare function formatSingleNode(data: JourneyData, action: string, nodeName: string, opts?: {
|
|
116
|
+
suppressWarnings?: boolean;
|
|
117
|
+
}): string;
|
|
113
118
|
export declare function formatTransitionList(data: {
|
|
114
119
|
transitions: TransitionListItem[];
|
|
115
120
|
}): string;
|
|
116
|
-
export declare function formatSingleTransition(data: JourneyData, action: string, transitionName: string
|
|
121
|
+
export declare function formatSingleTransition(data: JourneyData, action: string, transitionName: string, opts?: {
|
|
122
|
+
suppressWarnings?: boolean;
|
|
123
|
+
}): string;
|
|
117
124
|
export declare function formatJourneyAnalytics(data: AnalyticsData): string;
|
|
118
125
|
export {};
|
|
@@ -14,7 +14,7 @@ function nodeCount(journey) {
|
|
|
14
14
|
function transitionCount(journey) {
|
|
15
15
|
return (journey.transitions || []).length;
|
|
16
16
|
}
|
|
17
|
-
export function formatJourneyWithGuidance(journey) {
|
|
17
|
+
export function formatJourneyWithGuidance(journey, opts) {
|
|
18
18
|
const nodes = nodeCount(journey);
|
|
19
19
|
const transitions = transitionCount(journey);
|
|
20
20
|
const stats = journey.stats;
|
|
@@ -50,11 +50,16 @@ export function formatJourneyWithGuidance(journey) {
|
|
|
50
50
|
else {
|
|
51
51
|
desc = trigger?.event || "event";
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
const id = t.name ? ` (${t.name})` : "";
|
|
54
|
+
lines.push(` ${from} → ${t.to} [${desc}]${id}`);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
// Warnings
|
|
57
|
-
|
|
57
|
+
// Warnings — suppressed on paused journeys (mid-construction) or when opts.suppressWarnings is set
|
|
58
|
+
const showWarnings = !opts?.suppressWarnings &&
|
|
59
|
+
journey.status !== "paused" &&
|
|
60
|
+
journey.warnings &&
|
|
61
|
+
journey.warnings.length > 0;
|
|
62
|
+
if (showWarnings) {
|
|
58
63
|
lines.push("");
|
|
59
64
|
lines.push("Warnings:");
|
|
60
65
|
for (const w of journey.warnings) {
|
|
@@ -146,8 +151,8 @@ export function formatNodeList(data) {
|
|
|
146
151
|
}
|
|
147
152
|
return lines.join("\n");
|
|
148
153
|
}
|
|
149
|
-
export function formatSingleNode(data, action, nodeName) {
|
|
150
|
-
return `${action} node '${nodeName}'.\n\n${formatJourneyWithGuidance(data)}`;
|
|
154
|
+
export function formatSingleNode(data, action, nodeName, opts) {
|
|
155
|
+
return `${action} node '${nodeName}'.\n\n${formatJourneyWithGuidance(data, opts)}`;
|
|
151
156
|
}
|
|
152
157
|
export function formatTransitionList(data) {
|
|
153
158
|
const transitions = data.transitions || [];
|
|
@@ -162,8 +167,8 @@ export function formatTransitionList(data) {
|
|
|
162
167
|
}
|
|
163
168
|
return lines.join("\n");
|
|
164
169
|
}
|
|
165
|
-
export function formatSingleTransition(data, action, transitionName) {
|
|
166
|
-
return `${action} transition '${transitionName}'.\n\n${formatJourneyWithGuidance(data)}`;
|
|
170
|
+
export function formatSingleTransition(data, action, transitionName, opts) {
|
|
171
|
+
return `${action} transition '${transitionName}'.\n\n${formatJourneyWithGuidance(data, opts)}`;
|
|
167
172
|
}
|
|
168
173
|
export function formatJourneyAnalytics(data) {
|
|
169
174
|
const { journey, nodes, transitions, terminalDistribution, totals } = data;
|