@ascendkit/cli 0.2.6 → 0.3.0
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.d.ts +1 -0
- package/dist/api/client.js +31 -8
- package/dist/cli.js +713 -384
- package/dist/commands/content.js +4 -4
- package/dist/commands/email.d.ts +62 -6
- package/dist/commands/email.js +26 -17
- package/dist/commands/journeys.d.ts +1 -0
- package/dist/commands/journeys.js +9 -6
- package/dist/commands/platform.d.ts +22 -2
- package/dist/commands/platform.js +203 -101
- package/dist/commands/surveys.js +5 -5
- package/dist/mcp.js +31 -3
- package/dist/tools/auth.js +32 -11
- package/dist/tools/content.js +24 -12
- package/dist/tools/email.js +47 -17
- package/dist/tools/import.js +9 -9
- package/dist/tools/journeys.js +21 -14
- package/dist/tools/platform.js +125 -10
- package/dist/tools/surveys.js +9 -9
- package/dist/utils/journey-format.d.ts +6 -0
- package/dist/utils/journey-format.js +6 -4
- package/dist/utils/survey-format.js +2 -2
- package/package.json +5 -5
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ 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 { formatJourneyAnalytics, formatJourneyWithGuidance, formatNodeList, formatSingleNode, formatSingleTransition, formatTransitionList, } from "./utils/journey-format.js";
|
|
17
18
|
const require = createRequire(import.meta.url);
|
|
18
19
|
const { version: CLI_VERSION } = require("../package.json");
|
|
19
20
|
const HELP = `ascendkit v${CLI_VERSION} - AscendKit CLI
|
|
@@ -29,17 +30,18 @@ Getting Started:
|
|
|
29
30
|
|
|
30
31
|
Services:
|
|
31
32
|
auth Authentication, providers, OAuth, users
|
|
32
|
-
|
|
33
|
+
template Email templates and versioning
|
|
33
34
|
survey Surveys, questions, distribution, analytics
|
|
34
35
|
journey Lifecycle journeys, nodes, transitions
|
|
35
|
-
email
|
|
36
|
+
email-identity Email domains, sender identities, and DNS
|
|
37
|
+
keystore Environment runtime key-value settings
|
|
36
38
|
webhook Webhook endpoints and testing
|
|
37
39
|
campaign Email campaigns, scheduling, analytics
|
|
38
40
|
import Import users from external auth providers
|
|
39
41
|
|
|
40
42
|
Project Management:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
project Projects and environment selection
|
|
44
|
+
environment Active environment operations
|
|
43
45
|
verify Check all services in the active environment
|
|
44
46
|
|
|
45
47
|
Run "ascendkit help <section>" for detailed command usage.
|
|
@@ -48,70 +50,79 @@ const HELP_SECTION = {
|
|
|
48
50
|
auth: `Usage: ascendkit auth <command>
|
|
49
51
|
|
|
50
52
|
Commands:
|
|
51
|
-
auth
|
|
52
|
-
auth
|
|
53
|
-
auth
|
|
54
|
-
auth
|
|
53
|
+
auth show
|
|
54
|
+
auth update [--providers <p1,p2,...>] [--email-verification <true|false>] [--waitlist <true|false>] [--password-reset <true|false>] [--session-duration <duration>]
|
|
55
|
+
auth provider list
|
|
56
|
+
auth provider set <p1,p2,...>
|
|
57
|
+
auth oauth open <provider>
|
|
55
58
|
auth oauth set <provider> --client-id <id> [--client-secret <secret> | --client-secret-stdin] [--callback-url <url>]
|
|
56
|
-
auth
|
|
57
|
-
|
|
59
|
+
auth oauth remove <provider>
|
|
60
|
+
auth user list
|
|
61
|
+
auth user remove <user-id>
|
|
62
|
+
auth user reactivate <user-id>`,
|
|
63
|
+
template: `Usage: ascendkit template <command>
|
|
58
64
|
|
|
59
65
|
Commands:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
template create --name <name> --subject <subject> --body-html <html> --body-text <text> [--slug <slug>] [--description <description>]
|
|
67
|
+
template list [--query <search>] [--system true|--custom true]
|
|
68
|
+
template show <template-id>
|
|
69
|
+
template update <template-id> [--subject <subject>] [--body-html <html>] [--body-text <text>] [--change-note <note>]
|
|
70
|
+
template remove <template-id>
|
|
71
|
+
template version list <template-id>
|
|
72
|
+
template version show <template-id> <n>`,
|
|
67
73
|
survey: `Usage: ascendkit survey <command>
|
|
68
74
|
|
|
69
75
|
Commands:
|
|
70
76
|
survey create --name <name> [--type <nps|csat|custom>] [--definition <json>]
|
|
71
77
|
survey list
|
|
72
|
-
survey
|
|
78
|
+
survey show <survey-id>
|
|
73
79
|
survey update <survey-id> [--name <name>] [--status <draft|active|paused>] [--definition <json>]
|
|
74
|
-
survey
|
|
80
|
+
survey remove <survey-id>
|
|
75
81
|
survey distribute <survey-id> --users <usr_id1,usr_id2,...>
|
|
76
|
-
survey
|
|
82
|
+
survey invitation list <survey-id>
|
|
77
83
|
survey analytics <survey-id>
|
|
78
|
-
survey
|
|
79
|
-
survey
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
survey definition export <survey-id> [--out <file>]
|
|
85
|
+
survey definition import <survey-id> --in <file>
|
|
86
|
+
survey question list <survey-id>
|
|
87
|
+
survey question add <survey-id> --type <type> --title <title> [--name <name>] [--required <true|false>] [--choices <c1,c2,...>] [--position <n>]
|
|
88
|
+
survey question update <survey-id> <question-name> [--title <title>] [--required <true|false>] [--choices <c1,c2,...>]
|
|
89
|
+
survey question remove <survey-id> <question-name>
|
|
90
|
+
survey question reorder <survey-id> --order <name1,name2,...>`,
|
|
83
91
|
journey: `Usage: ascendkit journey <command>
|
|
84
92
|
|
|
85
93
|
Commands:
|
|
86
94
|
journey create --name <name> --entry-event <event> --entry-node <node> [--nodes <json>] [--transitions <json>] [--description <description>] [--entry-conditions <json>] [--re-entry-policy <skip|restart>]
|
|
87
95
|
journey list [--status <draft|active|paused|archived>]
|
|
88
|
-
journey
|
|
96
|
+
journey show <journey-id>
|
|
89
97
|
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>]
|
|
90
|
-
journey
|
|
98
|
+
journey remove <journey-id>
|
|
91
99
|
journey activate <journey-id>
|
|
92
100
|
journey pause <journey-id>
|
|
101
|
+
journey resume <journey-id>
|
|
93
102
|
journey archive <journey-id>
|
|
94
103
|
journey analytics <journey-id>
|
|
95
|
-
journey list
|
|
96
|
-
journey
|
|
97
|
-
journey
|
|
98
|
-
journey
|
|
99
|
-
journey list
|
|
100
|
-
journey
|
|
101
|
-
journey
|
|
102
|
-
journey
|
|
103
|
-
email: `Usage: ascendkit email <command>
|
|
104
|
+
journey node list <journey-id>
|
|
105
|
+
journey node add <journey-id> --name <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]
|
|
106
|
+
journey node update <journey-id> <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]
|
|
107
|
+
journey node remove <journey-id> <node-name>
|
|
108
|
+
journey transition list <journey-id> [--from <node-name>] [--to <node-name>]
|
|
109
|
+
journey transition add <journey-id> --from <node-name> --to <node-name> --trigger <json> [--priority <n>] [--name <transition-name>]
|
|
110
|
+
journey transition update <journey-id> <transition-name> [--trigger <json>] [--priority <n>]
|
|
111
|
+
journey transition remove <journey-id> <transition-name>`,
|
|
112
|
+
"email-identity": `Usage: ascendkit email-identity <command>
|
|
104
113
|
|
|
105
114
|
Commands:
|
|
106
|
-
email settings
|
|
107
|
-
email
|
|
108
|
-
email
|
|
109
|
-
email
|
|
110
|
-
email
|
|
111
|
-
email
|
|
112
|
-
email
|
|
113
|
-
email
|
|
114
|
-
email remove
|
|
115
|
+
email-identity settings [--json]
|
|
116
|
+
email-identity setup-domain <domain>
|
|
117
|
+
email-identity status [--watch] [--interval <seconds>]
|
|
118
|
+
email-identity remove-domain
|
|
119
|
+
email-identity list
|
|
120
|
+
email-identity add <email> [--display-name <name>]
|
|
121
|
+
email-identity resend <email>
|
|
122
|
+
email-identity set-default <email> [--display-name <name>]
|
|
123
|
+
email-identity remove <email>
|
|
124
|
+
email-identity test <email> --to <recipient>
|
|
125
|
+
email-identity open-dns [--domain <domain>] [--open]`,
|
|
115
126
|
webhook: `Usage: ascendkit webhook <command>
|
|
116
127
|
|
|
117
128
|
Commands:
|
|
@@ -137,50 +148,61 @@ Notes:
|
|
|
137
148
|
- --audience is a JSON filter object, e.g. '{"tags":{"$in":["premium"]}}'
|
|
138
149
|
- --scheduled-at / --at accepts ISO 8601 datetime, e.g. 2026-03-15T10:00:00Z
|
|
139
150
|
- cancel deletes a draft/failed campaign or cancels a scheduled/sending campaign`,
|
|
140
|
-
|
|
151
|
+
environment: `Usage: ascendkit environment <command>
|
|
152
|
+
|
|
153
|
+
Commands:
|
|
154
|
+
environment show
|
|
155
|
+
environment update [<env-id>] [--name <name>] [--description <desc>]
|
|
156
|
+
environment promote [<env-id>] --target <tier>`,
|
|
157
|
+
keystore: `Usage: ascendkit keystore <command>
|
|
141
158
|
|
|
142
159
|
Commands:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
env set-var <key> <value>
|
|
148
|
-
env unset-var <key>
|
|
149
|
-
env list-vars`,
|
|
150
|
-
import: `Usage: ascendkit import <source> [options]
|
|
160
|
+
keystore list
|
|
161
|
+
keystore set <key> <value>
|
|
162
|
+
keystore remove <key>`,
|
|
163
|
+
import: `Usage: ascendkit import <source> <action> [options]
|
|
151
164
|
|
|
152
165
|
Sources:
|
|
153
|
-
clerk
|
|
166
|
+
clerk Import users from Clerk
|
|
167
|
+
migration-journey Create migration email templates and journeys
|
|
154
168
|
|
|
155
169
|
Commands:
|
|
156
|
-
import clerk --api-key <key> [options]
|
|
157
|
-
import clerk --file <path> [options]
|
|
158
|
-
import
|
|
170
|
+
import clerk preview --api-key <key> [options]
|
|
171
|
+
import clerk preview --file <path> [options]
|
|
172
|
+
import clerk run --api-key <key> [options]
|
|
173
|
+
import clerk run --file <path> [options]
|
|
174
|
+
import migration-journey create [--from-identity <email>]
|
|
159
175
|
|
|
160
176
|
Options:
|
|
161
177
|
--api-key <key> Clerk secret API key (fetches users from Clerk API)
|
|
162
178
|
--file <path> Path to Clerk dashboard export (JSON)
|
|
163
179
|
--instance-url <url> Custom Clerk API URL (default: https://api.clerk.com)
|
|
164
|
-
--execute Run the import for real (default is dry-run preview)
|
|
165
180
|
--users Import users (included by default; use to select only users)
|
|
166
181
|
--settings Import auth settings / OAuth providers (included by default)
|
|
167
182
|
--from-identity <email> Email identity for migration journey emails
|
|
168
183
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
projects: `Usage: ascendkit projects <command>
|
|
184
|
+
Use "preview" for dry-run mode and "run" to apply changes. Pass --users or --settings alone to select
|
|
185
|
+
only that phase (e.g. "import clerk run --users ..." imports only users, not settings).`,
|
|
186
|
+
project: `Usage: ascendkit project <command>
|
|
173
187
|
|
|
174
188
|
Commands:
|
|
175
|
-
|
|
176
|
-
|
|
189
|
+
project list
|
|
190
|
+
project create --name <name> [--description <description>] [--services <s1,s2,...>]
|
|
191
|
+
project show <project-id>
|
|
192
|
+
project env list <project-id>`,
|
|
177
193
|
};
|
|
178
194
|
function printSectionHelp(section) {
|
|
179
195
|
if (!section)
|
|
180
196
|
return false;
|
|
181
197
|
let key = section.toLowerCase();
|
|
182
|
-
if (key === "content")
|
|
183
|
-
key = "
|
|
198
|
+
if (key === "content" || key === "templates")
|
|
199
|
+
key = "template";
|
|
200
|
+
if (key === "email")
|
|
201
|
+
key = "email-identity";
|
|
202
|
+
if (key === "projects")
|
|
203
|
+
key = "project";
|
|
204
|
+
if (key === "env" || key === "environments")
|
|
205
|
+
key = "environment";
|
|
184
206
|
const text = HELP_SECTION[key];
|
|
185
207
|
if (!text)
|
|
186
208
|
return false;
|
|
@@ -188,7 +210,7 @@ function printSectionHelp(section) {
|
|
|
188
210
|
return true;
|
|
189
211
|
}
|
|
190
212
|
function getClient() {
|
|
191
|
-
let publicKey = process.env.
|
|
213
|
+
let publicKey = process.env.ASCENDKIT_ENV_KEY;
|
|
192
214
|
let apiUrl = process.env.ASCENDKIT_API_URL;
|
|
193
215
|
const auth = loadAuth();
|
|
194
216
|
const env = loadEnvContext();
|
|
@@ -241,6 +263,55 @@ async function readSecretFromStdin() {
|
|
|
241
263
|
function output(data) {
|
|
242
264
|
console.log(JSON.stringify(data, null, 2));
|
|
243
265
|
}
|
|
266
|
+
function printAuthSettingsSummary(data) {
|
|
267
|
+
const providers = Array.isArray(data.providers) ? data.providers : [];
|
|
268
|
+
const features = data.features ?? {};
|
|
269
|
+
const featureLines = [
|
|
270
|
+
["Email verification", features.emailVerification],
|
|
271
|
+
["Waitlist", features.waitlist],
|
|
272
|
+
["Password reset", features.passwordReset],
|
|
273
|
+
["Require username", features.requireUsername],
|
|
274
|
+
];
|
|
275
|
+
console.log(`Providers: ${providers.length > 0 ? providers.join(", ") : "none"}`);
|
|
276
|
+
for (const [label, enabled] of featureLines) {
|
|
277
|
+
console.log(`${label}: ${enabled ? "on" : "off"}`);
|
|
278
|
+
}
|
|
279
|
+
if (data.sessionDuration) {
|
|
280
|
+
console.log(`Session: ${data.sessionDuration}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function printTemplateSummary(data) {
|
|
284
|
+
console.log(`Template: ${data.name} (${data.id})`);
|
|
285
|
+
if (data.slug)
|
|
286
|
+
console.log(`Slug: ${data.slug}`);
|
|
287
|
+
console.log(`Subject: ${data.subject ?? "-"}`);
|
|
288
|
+
if (data.currentVersion != null)
|
|
289
|
+
console.log(`Version: ${data.currentVersion}`);
|
|
290
|
+
if (Array.isArray(data.variables) && data.variables.length > 0) {
|
|
291
|
+
console.log(`Variables: ${data.variables.join(", ")}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function printSurveySummary(data) {
|
|
295
|
+
console.log(`Survey: ${data.name} (${data.id})`);
|
|
296
|
+
console.log(`Type: ${data.type ?? "custom"} | Status: ${data.status ?? "draft"}`);
|
|
297
|
+
if (data.slug)
|
|
298
|
+
console.log(`Slug: ${data.slug}`);
|
|
299
|
+
const questions = Array.isArray(data.definition?.pages)
|
|
300
|
+
? data.definition.pages.flatMap((page) => page.elements ?? []).length
|
|
301
|
+
: undefined;
|
|
302
|
+
if (questions != null)
|
|
303
|
+
console.log(`Questions: ${questions}`);
|
|
304
|
+
}
|
|
305
|
+
function printProjectSummary(data) {
|
|
306
|
+
console.log(`Project: ${data.id}`);
|
|
307
|
+
console.log(`Name: ${data.name}`);
|
|
308
|
+
if (Array.isArray(data.enabledServices) && data.enabledServices.length > 0) {
|
|
309
|
+
console.log(`Services: ${data.enabledServices.join(", ")}`);
|
|
310
|
+
}
|
|
311
|
+
if (data.environment?.publicKey) {
|
|
312
|
+
console.log(`Environment: ${data.environment.publicKey}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
244
315
|
function normalizeJourneyRows(data) {
|
|
245
316
|
if (Array.isArray(data)) {
|
|
246
317
|
return data;
|
|
@@ -321,7 +392,7 @@ async function run() {
|
|
|
321
392
|
case "logout":
|
|
322
393
|
platform.logout();
|
|
323
394
|
return;
|
|
324
|
-
case "
|
|
395
|
+
case "project":
|
|
325
396
|
if (action === "list") {
|
|
326
397
|
const projects = await platform.listProjects();
|
|
327
398
|
table(projects, [
|
|
@@ -330,18 +401,25 @@ async function run() {
|
|
|
330
401
|
{ key: "enabledServices", label: "Services", width: 30 },
|
|
331
402
|
]);
|
|
332
403
|
}
|
|
404
|
+
else if (action === "show") {
|
|
405
|
+
if (!args[2]) {
|
|
406
|
+
console.error("Usage: ascendkit project show <project-id>");
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
printProjectSummary(await platform.showProject(args[2]));
|
|
410
|
+
}
|
|
411
|
+
else if (action === "env") {
|
|
412
|
+
await runProjectEnvironment(args.slice(2));
|
|
413
|
+
}
|
|
333
414
|
else if (action === "create") {
|
|
334
415
|
const flags = parseFlags(args.slice(2));
|
|
335
416
|
if (!flags.name) {
|
|
336
|
-
console.error("Usage: ascendkit
|
|
417
|
+
console.error("Usage: ascendkit project create --name <name> [--description <description>] [--services <s1,s2,...>]");
|
|
337
418
|
process.exit(1);
|
|
338
419
|
}
|
|
339
420
|
try {
|
|
340
421
|
const proj = await platform.createProject(flags.name, flags.description, flags.services?.split(","));
|
|
341
|
-
|
|
342
|
-
console.log(`Project created: ${proj.id}`);
|
|
343
|
-
if (env)
|
|
344
|
-
console.log(`Environment: ${env.publicKey}`);
|
|
422
|
+
printProjectSummary(proj);
|
|
345
423
|
}
|
|
346
424
|
catch (err) {
|
|
347
425
|
let message = err instanceof Error ? err.message : String(err);
|
|
@@ -361,7 +439,7 @@ async function run() {
|
|
|
361
439
|
}
|
|
362
440
|
}
|
|
363
441
|
else {
|
|
364
|
-
console.error('Usage: ascendkit
|
|
442
|
+
console.error('Usage: ascendkit project list|create|show|env');
|
|
365
443
|
process.exit(1);
|
|
366
444
|
}
|
|
367
445
|
return;
|
|
@@ -378,8 +456,11 @@ async function run() {
|
|
|
378
456
|
case "verify":
|
|
379
457
|
await runVerify();
|
|
380
458
|
return;
|
|
381
|
-
case "
|
|
382
|
-
await
|
|
459
|
+
case "environment":
|
|
460
|
+
await runEnvironment(action, args.slice(2));
|
|
461
|
+
return;
|
|
462
|
+
case "keystore":
|
|
463
|
+
await runKeystore(action, args.slice(2));
|
|
383
464
|
return;
|
|
384
465
|
}
|
|
385
466
|
// Service commands (need environment key)
|
|
@@ -388,6 +469,7 @@ async function run() {
|
|
|
388
469
|
case "auth":
|
|
389
470
|
await runAuth(client, action, args.slice(2));
|
|
390
471
|
break;
|
|
472
|
+
case "template":
|
|
391
473
|
case "templates":
|
|
392
474
|
case "content":
|
|
393
475
|
await runContent(client, action, args.slice(2));
|
|
@@ -398,7 +480,7 @@ async function run() {
|
|
|
398
480
|
case "journey":
|
|
399
481
|
await runJourney(client, action, args.slice(2));
|
|
400
482
|
break;
|
|
401
|
-
case "email":
|
|
483
|
+
case "email-identity":
|
|
402
484
|
await runEmail(client, action, args.slice(2));
|
|
403
485
|
break;
|
|
404
486
|
case "webhook":
|
|
@@ -417,13 +499,29 @@ async function run() {
|
|
|
417
499
|
}
|
|
418
500
|
}
|
|
419
501
|
async function runImport(client, source, rest) {
|
|
420
|
-
|
|
502
|
+
if (!source) {
|
|
503
|
+
console.log(HELP_SECTION.import);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
let action = rest[0];
|
|
507
|
+
let args = rest;
|
|
421
508
|
if (source === "create-migration-journey") {
|
|
509
|
+
source = "migration-journey";
|
|
510
|
+
action = "create";
|
|
511
|
+
}
|
|
512
|
+
if (source === "clerk" && (action === "preview" || action === "run")) {
|
|
513
|
+
args = rest.slice(1);
|
|
514
|
+
}
|
|
515
|
+
else if (source === "clerk") {
|
|
516
|
+
action = flagsFromLegacy(rest).execute ? "run" : "preview";
|
|
517
|
+
}
|
|
518
|
+
const flags = parseFlags(args);
|
|
519
|
+
if (source === "migration-journey" && action === "create") {
|
|
422
520
|
const result = await importCmd.instantiateMigrationJourney(client, flags["from-identity"]);
|
|
423
521
|
output(result);
|
|
424
522
|
console.log("\nNext steps:");
|
|
425
523
|
console.log(" ascendkit journey list — review created journeys");
|
|
426
|
-
console.log(" ascendkit
|
|
524
|
+
console.log(" ascendkit template list — review migration email templates");
|
|
427
525
|
console.log(" ascendkit journey activate <journey-id> — activate when ready");
|
|
428
526
|
return;
|
|
429
527
|
}
|
|
@@ -433,8 +531,7 @@ async function runImport(client, source, rest) {
|
|
|
433
531
|
console.error('Run "ascendkit help import" for usage');
|
|
434
532
|
process.exit(1);
|
|
435
533
|
}
|
|
436
|
-
const
|
|
437
|
-
const dryRun = !execute;
|
|
534
|
+
const dryRun = action !== "run";
|
|
438
535
|
const hasUsers = flags.users !== undefined;
|
|
439
536
|
const hasSettings = flags.settings !== undefined;
|
|
440
537
|
// If neither --users nor --settings is passed, both default to true.
|
|
@@ -444,7 +541,7 @@ async function runImport(client, source, rest) {
|
|
|
444
541
|
const apiKey = flags["api-key"];
|
|
445
542
|
const filePath = flags.file;
|
|
446
543
|
if (!apiKey && !filePath) {
|
|
447
|
-
console.error("Usage: ascendkit import clerk --api-key <key> | --file <path>
|
|
544
|
+
console.error("Usage: ascendkit import clerk preview|run --api-key <key> | --file <path>");
|
|
448
545
|
process.exit(1);
|
|
449
546
|
}
|
|
450
547
|
let clerkUsers = [];
|
|
@@ -558,35 +655,49 @@ async function runImport(client, source, rest) {
|
|
|
558
655
|
}
|
|
559
656
|
else if (totalImported > 0) {
|
|
560
657
|
console.log("\nTo set up migration emails, run:\n" +
|
|
561
|
-
" ascendkit import
|
|
658
|
+
" ascendkit import migration-journey create");
|
|
562
659
|
}
|
|
563
660
|
}
|
|
564
|
-
|
|
565
|
-
|
|
661
|
+
function flagsFromLegacy(args) {
|
|
662
|
+
return parseFlags(args);
|
|
663
|
+
}
|
|
664
|
+
async function runProjectEnvironment(rest) {
|
|
665
|
+
const action = rest[0];
|
|
666
|
+
const target = rest[1];
|
|
566
667
|
switch (action) {
|
|
567
668
|
case "list":
|
|
568
|
-
if (!
|
|
569
|
-
console.error("Usage: ascendkit env list
|
|
669
|
+
if (!target) {
|
|
670
|
+
console.error("Usage: ascendkit project env list <project-id>");
|
|
570
671
|
process.exit(1);
|
|
571
672
|
}
|
|
572
|
-
table(await platform.listEnvironments(
|
|
673
|
+
table(await platform.listEnvironments(target), [
|
|
674
|
+
{ key: "id", label: "ID" },
|
|
573
675
|
{ key: "name", label: "Name", width: 20 },
|
|
574
676
|
{ key: "tier", label: "Tier" },
|
|
575
677
|
{ key: "publicKey", label: "Public Key" },
|
|
576
678
|
]);
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
679
|
+
return;
|
|
680
|
+
default:
|
|
681
|
+
console.error("Usage: ascendkit project env list <project-id>");
|
|
682
|
+
process.exit(1);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
async function runEnvironment(action, rest) {
|
|
686
|
+
const flags = parseFlags(rest);
|
|
687
|
+
const ctx = loadEnvContext();
|
|
688
|
+
if (!ctx) {
|
|
689
|
+
console.error("No environment set. Run: ascendkit set-env <public-key>");
|
|
690
|
+
process.exit(1);
|
|
691
|
+
}
|
|
692
|
+
switch (action) {
|
|
693
|
+
case "show":
|
|
694
|
+
output(await platform.getEnvironment(ctx.projectId, ctx.environmentId));
|
|
695
|
+
return;
|
|
585
696
|
case "promote": {
|
|
586
|
-
const envId = rest[0];
|
|
697
|
+
const envId = rest[0] && !rest[0].startsWith("--") ? rest[0] : ctx.environmentId;
|
|
587
698
|
const target = flags.target;
|
|
588
699
|
if (!envId || !target) {
|
|
589
|
-
console.error("Usage: ascendkit
|
|
700
|
+
console.error("Usage: ascendkit environment promote [<env-id>] --target <tier>");
|
|
590
701
|
process.exit(1);
|
|
591
702
|
}
|
|
592
703
|
try {
|
|
@@ -610,14 +721,10 @@ async function runEnv(action, rest) {
|
|
|
610
721
|
console.error(message);
|
|
611
722
|
process.exit(1);
|
|
612
723
|
}
|
|
613
|
-
|
|
724
|
+
return;
|
|
614
725
|
}
|
|
615
726
|
case "update": {
|
|
616
|
-
const envId = rest[0];
|
|
617
|
-
if (!envId || !flags.project) {
|
|
618
|
-
console.error("Usage: ascendkit env update <env-id> --project <project-id> [--name <name>] [--description <desc>]");
|
|
619
|
-
process.exit(1);
|
|
620
|
-
}
|
|
727
|
+
const envId = rest[0] && !rest[0].startsWith("--") ? rest[0] : ctx.environmentId;
|
|
621
728
|
const name = flags.name;
|
|
622
729
|
const description = flags.description;
|
|
623
730
|
if (!name && description === undefined) {
|
|
@@ -625,7 +732,7 @@ async function runEnv(action, rest) {
|
|
|
625
732
|
process.exit(1);
|
|
626
733
|
}
|
|
627
734
|
try {
|
|
628
|
-
const result = await platform.updateEnvironment(
|
|
735
|
+
const result = await platform.updateEnvironment(ctx.projectId, envId, name, description);
|
|
629
736
|
console.log("Environment updated:");
|
|
630
737
|
console.log(JSON.stringify(result, null, 2));
|
|
631
738
|
}
|
|
@@ -645,116 +752,137 @@ async function runEnv(action, rest) {
|
|
|
645
752
|
console.error(message);
|
|
646
753
|
process.exit(1);
|
|
647
754
|
}
|
|
648
|
-
|
|
755
|
+
return;
|
|
649
756
|
}
|
|
650
|
-
|
|
757
|
+
default:
|
|
758
|
+
console.error(`Unknown environment command: ${action}`);
|
|
759
|
+
console.error("Usage: ascendkit environment show|update|promote");
|
|
760
|
+
process.exit(1);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
async function runKeystore(action, rest) {
|
|
764
|
+
const ctx = loadEnvContext();
|
|
765
|
+
if (!ctx) {
|
|
766
|
+
console.error("No environment set. Run: ascendkit set-env <public-key>");
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
const current = await platform.getEnvironment(ctx.projectId, ctx.environmentId);
|
|
770
|
+
const vars = { ...(current.variables ?? {}) };
|
|
771
|
+
const systemVars = Array.isArray(current.systemVariables)
|
|
772
|
+
? current.systemVariables
|
|
773
|
+
: [];
|
|
774
|
+
switch (action) {
|
|
775
|
+
case "set": {
|
|
651
776
|
const key = rest[0];
|
|
652
777
|
const value = rest[1];
|
|
653
778
|
if (!key || value === undefined) {
|
|
654
|
-
console.error("Usage: ascendkit
|
|
779
|
+
console.error("Usage: ascendkit keystore set <key> <value>");
|
|
655
780
|
process.exit(1);
|
|
656
781
|
}
|
|
657
|
-
const ctx = loadEnvContext();
|
|
658
|
-
if (!ctx) {
|
|
659
|
-
console.error("No environment set. Run: ascendkit env use <tier> --project <project-id>");
|
|
660
|
-
process.exit(1);
|
|
661
|
-
}
|
|
662
|
-
const current = await platform.getEnvironment(ctx.projectId, ctx.environmentId);
|
|
663
|
-
const vars = { ...(current.variables ?? {}) };
|
|
664
782
|
vars[key] = value;
|
|
665
783
|
await platform.updateEnvironmentVariables(ctx.projectId, ctx.environmentId, vars);
|
|
666
|
-
console.log(`
|
|
667
|
-
|
|
784
|
+
console.log(`Saved ${key}=${value}`);
|
|
785
|
+
return;
|
|
668
786
|
}
|
|
669
|
-
case "
|
|
787
|
+
case "remove": {
|
|
670
788
|
const key = rest[0];
|
|
671
789
|
if (!key) {
|
|
672
|
-
console.error("Usage: ascendkit
|
|
790
|
+
console.error("Usage: ascendkit keystore remove <key>");
|
|
673
791
|
process.exit(1);
|
|
674
792
|
}
|
|
675
|
-
const ctx = loadEnvContext();
|
|
676
|
-
if (!ctx) {
|
|
677
|
-
console.error("No environment set. Run: ascendkit env use <tier> --project <project-id>");
|
|
678
|
-
process.exit(1);
|
|
679
|
-
}
|
|
680
|
-
const current = await platform.getEnvironment(ctx.projectId, ctx.environmentId);
|
|
681
|
-
const vars = { ...(current.variables ?? {}) };
|
|
682
793
|
if (!(key in vars)) {
|
|
683
794
|
console.error(`Variable "${key}" not found.`);
|
|
684
795
|
process.exit(1);
|
|
685
796
|
}
|
|
686
797
|
delete vars[key];
|
|
687
798
|
await platform.updateEnvironmentVariables(ctx.projectId, ctx.environmentId, vars);
|
|
688
|
-
console.log(`
|
|
689
|
-
|
|
799
|
+
console.log(`Removed ${key}`);
|
|
800
|
+
return;
|
|
690
801
|
}
|
|
691
|
-
case "list
|
|
692
|
-
const
|
|
693
|
-
if (!ctx) {
|
|
694
|
-
console.error("No environment set. Run: ascendkit env use <tier> --project <project-id>");
|
|
695
|
-
process.exit(1);
|
|
696
|
-
}
|
|
697
|
-
const current = await platform.getEnvironment(ctx.projectId, ctx.environmentId);
|
|
698
|
-
const vars = current.variables ?? {};
|
|
699
|
-
const entries = Object.entries(vars);
|
|
802
|
+
case "list": {
|
|
803
|
+
const entries = Object.entries(vars).map(([key, value]) => ({ key, value }));
|
|
700
804
|
if (entries.length === 0) {
|
|
701
|
-
console.log("No variables set.");
|
|
805
|
+
console.log("No custom variables set.");
|
|
702
806
|
}
|
|
703
807
|
else {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
808
|
+
console.log("Custom variables:");
|
|
809
|
+
table(entries, [
|
|
810
|
+
{ key: "key", label: "Key", width: 32 },
|
|
811
|
+
{ key: "value", label: "Value", width: 60 },
|
|
812
|
+
]);
|
|
707
813
|
}
|
|
708
|
-
|
|
814
|
+
if (systemVars.length > 0) {
|
|
815
|
+
console.log(entries.length > 0 ? "\nSystem variables:" : "System variables:");
|
|
816
|
+
table(systemVars.map((item) => ({
|
|
817
|
+
key: item.key,
|
|
818
|
+
value: item.valuePreview,
|
|
819
|
+
availability: item.availability,
|
|
820
|
+
})), [
|
|
821
|
+
{ key: "key", label: "Key", width: 24 },
|
|
822
|
+
{ key: "value", label: "Value", width: 48 },
|
|
823
|
+
{ key: "availability", label: "Availability", width: 22 },
|
|
824
|
+
]);
|
|
825
|
+
}
|
|
826
|
+
return;
|
|
709
827
|
}
|
|
710
828
|
default:
|
|
711
|
-
console.error(`Unknown
|
|
712
|
-
console.error("Usage: ascendkit
|
|
829
|
+
console.error(`Unknown keystore command: ${action}`);
|
|
830
|
+
console.error("Usage: ascendkit keystore list|set|remove");
|
|
713
831
|
process.exit(1);
|
|
714
832
|
}
|
|
715
833
|
}
|
|
716
834
|
async function runAuth(client, action, rest) {
|
|
717
835
|
const flags = parseFlags(rest);
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
836
|
+
const normalizedAction = !action ? "show" :
|
|
837
|
+
action === "settings" ? (rest[0] === "update" ? "update" : "show") :
|
|
838
|
+
action === "show" ? "show" :
|
|
839
|
+
action === "update" ? "update" :
|
|
840
|
+
action;
|
|
841
|
+
switch (normalizedAction) {
|
|
842
|
+
case "show":
|
|
843
|
+
printAuthSettingsSummary(await auth.getSettings(client));
|
|
844
|
+
break;
|
|
845
|
+
case "update": {
|
|
846
|
+
const params = {};
|
|
847
|
+
if (flags.providers)
|
|
848
|
+
params.providers = flags.providers.split(",");
|
|
849
|
+
if (flags["email-verification"] || flags.waitlist || flags["password-reset"]) {
|
|
850
|
+
params.features = {};
|
|
851
|
+
if (flags["email-verification"])
|
|
852
|
+
params.features.emailVerification = flags["email-verification"] === "true";
|
|
853
|
+
if (flags.waitlist)
|
|
854
|
+
params.features.waitlist = flags.waitlist === "true";
|
|
855
|
+
if (flags["password-reset"])
|
|
856
|
+
params.features.passwordReset = flags["password-reset"] === "true";
|
|
857
|
+
}
|
|
858
|
+
if (flags["session-duration"])
|
|
859
|
+
params.sessionDuration = flags["session-duration"];
|
|
860
|
+
printAuthSettingsSummary(await auth.updateSettings(client, params));
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
case "provider":
|
|
864
|
+
case "providers":
|
|
865
|
+
if (normalizedAction === "providers" || rest[0] === "set") {
|
|
866
|
+
const providersArg = normalizedAction === "providers" ? rest[0] : rest[1];
|
|
867
|
+
if (!providersArg) {
|
|
868
|
+
console.error("Usage: ascendkit auth provider set <p1,p2,...>");
|
|
869
|
+
process.exit(1);
|
|
732
870
|
}
|
|
733
|
-
|
|
734
|
-
params.sessionDuration = flags["session-duration"];
|
|
735
|
-
const s = await auth.updateSettings(client, params);
|
|
736
|
-
console.log(`Providers: ${Array.isArray(s.providers) ? s.providers.join(", ") : "none"}`);
|
|
737
|
-
const f = s.features ?? {};
|
|
738
|
-
const enabled = Object.entries(f).filter(([, v]) => v).map(([k]) => k);
|
|
739
|
-
if (enabled.length)
|
|
740
|
-
console.log(`Features: ${enabled.join(", ")}`);
|
|
741
|
-
if (s.sessionDuration)
|
|
742
|
-
console.log(`Session: ${s.sessionDuration}`);
|
|
871
|
+
printAuthSettingsSummary(await auth.updateProviders(client, providersArg.split(",")));
|
|
743
872
|
}
|
|
744
873
|
else {
|
|
745
|
-
|
|
874
|
+
const settings = await auth.getSettings(client);
|
|
875
|
+
const providers = Array.isArray(settings.providers) ? settings.providers.map((provider) => ({ provider })) : [];
|
|
876
|
+
if (providers.length === 0)
|
|
877
|
+
console.log("No providers configured.");
|
|
878
|
+
else
|
|
879
|
+
table(providers, [{ key: "provider", label: "Provider", width: 20 }]);
|
|
746
880
|
}
|
|
747
881
|
break;
|
|
748
|
-
case "providers":
|
|
749
|
-
if (!rest[0]) {
|
|
750
|
-
console.error("Usage: ascendkit auth providers <p1,p2,...>");
|
|
751
|
-
process.exit(1);
|
|
752
|
-
}
|
|
753
|
-
output(await auth.updateProviders(client, rest[0].split(",")));
|
|
754
|
-
break;
|
|
755
882
|
case "oauth": {
|
|
756
|
-
|
|
757
|
-
|
|
883
|
+
const oauthAction = rest[0] === "open" || rest[0] === "set" || rest[0] === "remove" ? rest[0] : "open";
|
|
884
|
+
const provider = oauthAction === "open" && rest[0] !== "open" ? rest[0] : rest[1];
|
|
885
|
+
if (oauthAction === "set") {
|
|
758
886
|
if (!provider || !flags["client-id"]) {
|
|
759
887
|
console.error("Usage: ascendkit auth oauth set <provider> --client-id <id> [--client-secret <secret> | --client-secret-stdin] [--callback-url <url>]");
|
|
760
888
|
process.exit(1);
|
|
@@ -774,28 +902,60 @@ async function runAuth(client, action, rest) {
|
|
|
774
902
|
console.error("Client secret cannot be empty.");
|
|
775
903
|
process.exit(1);
|
|
776
904
|
}
|
|
777
|
-
|
|
905
|
+
await auth.updateOAuthCredentials(client, provider, flags["client-id"], clientSecret, flags["callback-url"]);
|
|
906
|
+
console.log(`Saved OAuth credentials for ${provider}.`);
|
|
907
|
+
}
|
|
908
|
+
else if (oauthAction === "remove") {
|
|
909
|
+
if (!provider) {
|
|
910
|
+
console.error("Usage: ascendkit auth oauth remove <provider>");
|
|
911
|
+
process.exit(1);
|
|
912
|
+
}
|
|
913
|
+
await auth.deleteOAuthCredentials(client, provider);
|
|
914
|
+
console.log(`Removed OAuth credentials for ${provider}.`);
|
|
778
915
|
}
|
|
779
916
|
else {
|
|
780
|
-
if (!
|
|
781
|
-
console.error("Usage: ascendkit auth oauth <provider>");
|
|
917
|
+
if (!provider) {
|
|
918
|
+
console.error("Usage: ascendkit auth oauth open <provider>");
|
|
782
919
|
process.exit(1);
|
|
783
920
|
}
|
|
784
921
|
const portalUrl = process.env.ASCENDKIT_PORTAL_URL ?? "http://localhost:3000";
|
|
785
|
-
const url = auth.getOAuthSetupUrl(portalUrl,
|
|
786
|
-
console.log(`Opening browser to configure ${
|
|
922
|
+
const url = auth.getOAuthSetupUrl(portalUrl, provider, client.currentPublicKey ?? undefined);
|
|
923
|
+
console.log(`Opening browser to configure ${provider} OAuth credentials...`);
|
|
787
924
|
console.log(url);
|
|
788
925
|
openBrowser(url);
|
|
789
926
|
}
|
|
790
927
|
break;
|
|
791
928
|
}
|
|
929
|
+
case "user":
|
|
792
930
|
case "users":
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
931
|
+
if (normalizedAction === "users" || !rest[0] || rest[0] === "list") {
|
|
932
|
+
table(await auth.listUsers(client), [
|
|
933
|
+
{ key: "id", label: "ID" },
|
|
934
|
+
{ key: "email", label: "Email", width: 35 },
|
|
935
|
+
{ key: "name", label: "Name", width: 25 },
|
|
936
|
+
{ key: "status", label: "Status" },
|
|
937
|
+
]);
|
|
938
|
+
}
|
|
939
|
+
else if (rest[0] === "remove") {
|
|
940
|
+
if (!rest[1]) {
|
|
941
|
+
console.error("Usage: ascendkit auth user remove <user-id>");
|
|
942
|
+
process.exit(1);
|
|
943
|
+
}
|
|
944
|
+
await auth.deleteUser(client, rest[1]);
|
|
945
|
+
console.log(`Removed user ${rest[1]}.`);
|
|
946
|
+
}
|
|
947
|
+
else if (rest[0] === "reactivate") {
|
|
948
|
+
if (!rest[1]) {
|
|
949
|
+
console.error("Usage: ascendkit auth user reactivate <user-id>");
|
|
950
|
+
process.exit(1);
|
|
951
|
+
}
|
|
952
|
+
await auth.reactivateUser(client, rest[1]);
|
|
953
|
+
console.log(`Reactivated user ${rest[1]}.`);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
console.error(`Unknown auth user command: ${rest[0]}`);
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
799
959
|
break;
|
|
800
960
|
default:
|
|
801
961
|
console.error(`Unknown auth command: ${action}`);
|
|
@@ -804,13 +964,20 @@ async function runAuth(client, action, rest) {
|
|
|
804
964
|
}
|
|
805
965
|
async function runContent(client, action, rest) {
|
|
806
966
|
const flags = parseFlags(rest);
|
|
807
|
-
|
|
967
|
+
if (!action) {
|
|
968
|
+
console.log(HELP_SECTION.template);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const normalizedAction = action === "show" || action === "get" ? "show" :
|
|
972
|
+
action === "remove" || action === "delete" ? "remove" :
|
|
973
|
+
action;
|
|
974
|
+
switch (normalizedAction) {
|
|
808
975
|
case "create":
|
|
809
976
|
if (!flags.name || !flags.subject || !flags["body-html"] || !flags["body-text"]) {
|
|
810
|
-
console.error("Usage: ascendkit
|
|
977
|
+
console.error("Usage: ascendkit template create --name <n> --subject <s> --body-html <h> --body-text <t> [--slug <slug>] [--description <desc>]");
|
|
811
978
|
process.exit(1);
|
|
812
979
|
}
|
|
813
|
-
|
|
980
|
+
printTemplateSummary(await content.createTemplate(client, {
|
|
814
981
|
name: flags.name, subject: flags.subject,
|
|
815
982
|
bodyHtml: flags["body-html"], bodyText: flags["body-text"],
|
|
816
983
|
slug: flags.slug, description: flags.description,
|
|
@@ -833,64 +1000,79 @@ async function runContent(client, action, rest) {
|
|
|
833
1000
|
]);
|
|
834
1001
|
break;
|
|
835
1002
|
}
|
|
836
|
-
case "
|
|
1003
|
+
case "show":
|
|
837
1004
|
if (!rest[0]) {
|
|
838
|
-
console.error("Usage: ascendkit
|
|
1005
|
+
console.error("Usage: ascendkit template show <template-id>");
|
|
839
1006
|
process.exit(1);
|
|
840
1007
|
}
|
|
841
|
-
|
|
1008
|
+
printTemplateSummary(await content.getTemplate(client, rest[0]));
|
|
842
1009
|
break;
|
|
843
1010
|
case "update":
|
|
844
1011
|
if (!rest[0]) {
|
|
845
|
-
console.error("Usage: ascendkit
|
|
1012
|
+
console.error("Usage: ascendkit template update <template-id> [--flags]");
|
|
846
1013
|
process.exit(1);
|
|
847
1014
|
}
|
|
848
|
-
|
|
1015
|
+
printTemplateSummary(await content.updateTemplate(client, rest[0], {
|
|
849
1016
|
subject: flags.subject,
|
|
850
1017
|
bodyHtml: flags["body-html"],
|
|
851
1018
|
bodyText: flags["body-text"],
|
|
852
1019
|
changeNote: flags["change-note"],
|
|
853
1020
|
}));
|
|
854
1021
|
break;
|
|
855
|
-
case "
|
|
1022
|
+
case "remove":
|
|
856
1023
|
if (!rest[0]) {
|
|
857
|
-
console.error("Usage: ascendkit
|
|
1024
|
+
console.error("Usage: ascendkit template remove <template-id>");
|
|
858
1025
|
process.exit(1);
|
|
859
1026
|
}
|
|
860
|
-
|
|
1027
|
+
await content.deleteTemplate(client, rest[0]);
|
|
1028
|
+
console.log(`Removed template ${rest[0]}.`);
|
|
861
1029
|
break;
|
|
862
1030
|
case "versions":
|
|
863
|
-
if (!rest[0]) {
|
|
864
|
-
console.error("Usage: ascendkit templates versions <template-id>");
|
|
865
|
-
process.exit(1);
|
|
866
|
-
}
|
|
867
|
-
output(await content.listVersions(client, rest[0]));
|
|
868
|
-
break;
|
|
869
1031
|
case "version":
|
|
870
|
-
if (
|
|
871
|
-
|
|
872
|
-
|
|
1032
|
+
if (normalizedAction === "versions" || rest[0] === "list") {
|
|
1033
|
+
const templateId = normalizedAction === "versions" ? rest[0] : rest[1];
|
|
1034
|
+
if (!templateId) {
|
|
1035
|
+
console.error("Usage: ascendkit template version list <template-id>");
|
|
1036
|
+
process.exit(1);
|
|
1037
|
+
}
|
|
1038
|
+
const versions = await content.listVersions(client, templateId);
|
|
1039
|
+
table(versions, [
|
|
1040
|
+
{ key: "versionNumber", label: "Version" },
|
|
1041
|
+
{ key: "createdAt", label: "Created", width: 24 },
|
|
1042
|
+
{ key: "changeNote", label: "Change note", width: 40 },
|
|
1043
|
+
]);
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
const templateId = normalizedAction === "version" && rest[0] === "show" ? rest[1] : normalizedAction === "version" ? rest[0] : rest[1];
|
|
1047
|
+
const versionNumber = normalizedAction === "version" && rest[0] === "show" ? rest[2] : normalizedAction === "version" ? rest[1] : rest[2];
|
|
1048
|
+
if (!templateId || !versionNumber) {
|
|
1049
|
+
console.error("Usage: ascendkit template version show <template-id> <n>");
|
|
1050
|
+
process.exit(1);
|
|
1051
|
+
}
|
|
1052
|
+
output(await content.getVersion(client, templateId, parseInt(versionNumber, 10)));
|
|
873
1053
|
}
|
|
874
|
-
output(await content.getVersion(client, rest[0], parseInt(rest[1], 10)));
|
|
875
1054
|
break;
|
|
876
1055
|
default:
|
|
877
|
-
console.error(`Unknown
|
|
1056
|
+
console.error(`Unknown template command: ${action}`);
|
|
878
1057
|
process.exit(1);
|
|
879
1058
|
}
|
|
880
1059
|
}
|
|
881
1060
|
async function runSurvey(client, action, rest) {
|
|
882
1061
|
const flags = parseFlags(rest);
|
|
883
|
-
|
|
1062
|
+
const normalizedAction = action === "show" || action === "get" ? "show" :
|
|
1063
|
+
action === "remove" || action === "delete" ? "remove" :
|
|
1064
|
+
action;
|
|
1065
|
+
if (!normalizedAction) {
|
|
884
1066
|
console.log(HELP_SECTION.survey);
|
|
885
1067
|
return;
|
|
886
1068
|
}
|
|
887
|
-
switch (
|
|
1069
|
+
switch (normalizedAction) {
|
|
888
1070
|
case "create":
|
|
889
1071
|
if (!flags.name) {
|
|
890
1072
|
console.error("Usage: ascendkit survey create --name <n> [--type nps|csat|custom]");
|
|
891
1073
|
process.exit(1);
|
|
892
1074
|
}
|
|
893
|
-
|
|
1075
|
+
printSurveySummary(await surveys.createSurvey(client, {
|
|
894
1076
|
name: flags.name,
|
|
895
1077
|
type: flags.type ?? "custom",
|
|
896
1078
|
definition: flags.definition ? JSON.parse(flags.definition) : undefined,
|
|
@@ -904,30 +1086,31 @@ async function runSurvey(client, action, rest) {
|
|
|
904
1086
|
{ key: "status", label: "Status" },
|
|
905
1087
|
]);
|
|
906
1088
|
break;
|
|
907
|
-
case "
|
|
1089
|
+
case "show":
|
|
908
1090
|
if (!rest[0]) {
|
|
909
|
-
console.error("Usage: ascendkit survey
|
|
1091
|
+
console.error("Usage: ascendkit survey show <survey-id>");
|
|
910
1092
|
process.exit(1);
|
|
911
1093
|
}
|
|
912
|
-
|
|
1094
|
+
printSurveySummary(await surveys.getSurvey(client, rest[0]));
|
|
913
1095
|
break;
|
|
914
1096
|
case "update":
|
|
915
1097
|
if (!rest[0]) {
|
|
916
1098
|
console.error("Usage: ascendkit survey update <survey-id> [--flags]");
|
|
917
1099
|
process.exit(1);
|
|
918
1100
|
}
|
|
919
|
-
|
|
1101
|
+
printSurveySummary(await surveys.updateSurvey(client, rest[0], {
|
|
920
1102
|
name: flags.name,
|
|
921
1103
|
status: flags.status,
|
|
922
1104
|
definition: flags.definition ? JSON.parse(flags.definition) : undefined,
|
|
923
1105
|
}));
|
|
924
1106
|
break;
|
|
925
|
-
case "
|
|
1107
|
+
case "remove":
|
|
926
1108
|
if (!rest[0]) {
|
|
927
|
-
console.error("Usage: ascendkit survey
|
|
1109
|
+
console.error("Usage: ascendkit survey remove <survey-id>");
|
|
928
1110
|
process.exit(1);
|
|
929
1111
|
}
|
|
930
|
-
|
|
1112
|
+
await surveys.deleteSurvey(client, rest[0]);
|
|
1113
|
+
console.log(`Removed survey ${rest[0]}.`);
|
|
931
1114
|
break;
|
|
932
1115
|
case "distribute":
|
|
933
1116
|
if (!rest[0] || !flags.users) {
|
|
@@ -937,11 +1120,19 @@ async function runSurvey(client, action, rest) {
|
|
|
937
1120
|
output(await surveys.distributeSurvey(client, rest[0], flags.users.split(",")));
|
|
938
1121
|
break;
|
|
939
1122
|
case "invitations":
|
|
940
|
-
|
|
941
|
-
|
|
1123
|
+
case "invitation":
|
|
1124
|
+
if (normalizedAction === "invitations" || rest[0] === "list") {
|
|
1125
|
+
const surveyId = normalizedAction === "invitations" ? rest[0] : rest[1];
|
|
1126
|
+
if (!surveyId) {
|
|
1127
|
+
console.error("Usage: ascendkit survey invitation list <survey-id>");
|
|
1128
|
+
process.exit(1);
|
|
1129
|
+
}
|
|
1130
|
+
output(await surveys.listInvitations(client, surveyId));
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
console.error(`Unknown survey invitation command: ${rest[0]}`);
|
|
942
1134
|
process.exit(1);
|
|
943
1135
|
}
|
|
944
|
-
output(await surveys.listInvitations(client, rest[0]));
|
|
945
1136
|
break;
|
|
946
1137
|
case "analytics":
|
|
947
1138
|
if (!rest[0]) {
|
|
@@ -950,96 +1141,121 @@ async function runSurvey(client, action, rest) {
|
|
|
950
1141
|
}
|
|
951
1142
|
output(await surveys.getAnalytics(client, rest[0]));
|
|
952
1143
|
break;
|
|
953
|
-
case "export-definition":
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1144
|
+
case "export-definition":
|
|
1145
|
+
case "import-definition":
|
|
1146
|
+
case "definition": {
|
|
1147
|
+
const definitionAction = normalizedAction === "definition" ? rest[0] :
|
|
1148
|
+
normalizedAction === "export-definition" ? "export" :
|
|
1149
|
+
"import";
|
|
1150
|
+
const surveyId = normalizedAction === "definition" ? rest[1] : rest[0];
|
|
1151
|
+
if (definitionAction === "export") {
|
|
1152
|
+
if (!surveyId) {
|
|
1153
|
+
console.error("Usage: ascendkit survey definition export <survey-id> [--out <file>]");
|
|
1154
|
+
process.exit(1);
|
|
1155
|
+
}
|
|
1156
|
+
const survey = await surveys.getSurvey(client, surveyId);
|
|
1157
|
+
const text = `${JSON.stringify(survey.definition ?? {}, null, 2)}\n`;
|
|
1158
|
+
const outPath = flags.out || flags.file;
|
|
1159
|
+
if (outPath) {
|
|
1160
|
+
writeFileSync(outPath, text, "utf8");
|
|
1161
|
+
console.log(`Wrote survey definition to ${outPath}`);
|
|
1162
|
+
}
|
|
1163
|
+
else {
|
|
1164
|
+
process.stdout.write(text);
|
|
1165
|
+
}
|
|
964
1166
|
}
|
|
965
1167
|
else {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
process.exit(1);
|
|
1168
|
+
if (!surveyId || !(flags.in || flags.file)) {
|
|
1169
|
+
console.error("Usage: ascendkit survey definition import <survey-id> --in <file>");
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
}
|
|
1172
|
+
const inPath = flags.in || flags.file;
|
|
1173
|
+
const raw = readFileSync(inPath, "utf8");
|
|
1174
|
+
const parsed = JSON.parse(raw);
|
|
1175
|
+
const candidate = parsed && typeof parsed === "object" && "definition" in parsed
|
|
1176
|
+
? parsed.definition
|
|
1177
|
+
: parsed;
|
|
1178
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1179
|
+
console.error("Invalid definition JSON: expected an object or { definition: object }");
|
|
1180
|
+
process.exit(1);
|
|
1181
|
+
}
|
|
1182
|
+
printSurveySummary(await surveys.updateSurvey(client, surveyId, {
|
|
1183
|
+
definition: candidate,
|
|
1184
|
+
}));
|
|
984
1185
|
}
|
|
985
|
-
output(await surveys.updateSurvey(client, rest[0], {
|
|
986
|
-
definition: candidate,
|
|
987
|
-
}));
|
|
988
1186
|
break;
|
|
989
1187
|
}
|
|
990
1188
|
case "list-questions":
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1189
|
+
case "add-question":
|
|
1190
|
+
case "edit-question":
|
|
1191
|
+
case "remove-question":
|
|
1192
|
+
case "reorder-questions":
|
|
1193
|
+
case "question": {
|
|
1194
|
+
const questionAction = normalizedAction === "question" ? rest[0] :
|
|
1195
|
+
normalizedAction === "list-questions" ? "list" :
|
|
1196
|
+
normalizedAction === "add-question" ? "add" :
|
|
1197
|
+
normalizedAction === "edit-question" ? "update" :
|
|
1198
|
+
normalizedAction === "remove-question" ? "remove" :
|
|
1199
|
+
"reorder";
|
|
1200
|
+
const surveyId = normalizedAction === "question" ? rest[1] : rest[0];
|
|
1201
|
+
const questionName = normalizedAction === "question" ? rest[2] : rest[1];
|
|
1202
|
+
if (!surveyId) {
|
|
1203
|
+
console.error("Usage: ascendkit survey question list <survey-id>");
|
|
1204
|
+
process.exit(1);
|
|
1205
|
+
}
|
|
1206
|
+
if (questionAction === "list") {
|
|
1207
|
+
output(await surveys.listQuestions(client, surveyId));
|
|
1208
|
+
}
|
|
1209
|
+
else if (questionAction === "add") {
|
|
1210
|
+
if (!flags.type || !flags.title) {
|
|
1211
|
+
console.error("Usage: ascendkit survey question add <survey-id> --type <type> --title <title> [--name <name>] [--required <true|false>] [--choices <c1,c2,...>] [--position <n>]");
|
|
1212
|
+
process.exit(1);
|
|
1213
|
+
}
|
|
1214
|
+
const params = { type: flags.type, title: flags.title };
|
|
1215
|
+
if (flags.name)
|
|
1216
|
+
params.name = flags.name;
|
|
1217
|
+
if (flags.required)
|
|
1218
|
+
params.isRequired = flags.required === "true";
|
|
1219
|
+
if (flags.choices)
|
|
1220
|
+
params.choices = flags.choices.split(",");
|
|
1221
|
+
if (flags.position != null)
|
|
1222
|
+
params.position = Number(flags.position);
|
|
1223
|
+
output(await surveys.addQuestion(client, surveyId, params));
|
|
1224
|
+
}
|
|
1225
|
+
else if (questionAction === "update") {
|
|
1226
|
+
if (!questionName) {
|
|
1227
|
+
console.error("Usage: ascendkit survey question update <survey-id> <question-name> [--title <title>] [--required <true|false>] [--choices <c1,c2,...>]");
|
|
1228
|
+
process.exit(1);
|
|
1229
|
+
}
|
|
1230
|
+
const params = {};
|
|
1231
|
+
if (flags.title)
|
|
1232
|
+
params.title = flags.title;
|
|
1233
|
+
if (flags.required)
|
|
1234
|
+
params.isRequired = flags.required === "true";
|
|
1235
|
+
if (flags.choices)
|
|
1236
|
+
params.choices = flags.choices.split(",");
|
|
1237
|
+
output(await surveys.editQuestion(client, surveyId, questionName, params));
|
|
1238
|
+
}
|
|
1239
|
+
else if (questionAction === "remove") {
|
|
1240
|
+
if (!questionName) {
|
|
1241
|
+
console.error("Usage: ascendkit survey question remove <survey-id> <question-name>");
|
|
1242
|
+
process.exit(1);
|
|
1243
|
+
}
|
|
1244
|
+
output(await surveys.removeQuestion(client, surveyId, questionName));
|
|
994
1245
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1246
|
+
else if (questionAction === "reorder") {
|
|
1247
|
+
if (!flags.order) {
|
|
1248
|
+
console.error("Usage: ascendkit survey question reorder <survey-id> --order <name1,name2,...>");
|
|
1249
|
+
process.exit(1);
|
|
1250
|
+
}
|
|
1251
|
+
output(await surveys.reorderQuestions(client, surveyId, flags.order.split(",")));
|
|
1001
1252
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
params.name = flags.name;
|
|
1005
|
-
if (flags.required)
|
|
1006
|
-
params.isRequired = flags.required === "true";
|
|
1007
|
-
if (flags.choices)
|
|
1008
|
-
params.choices = flags.choices.split(",");
|
|
1009
|
-
if (flags.position != null)
|
|
1010
|
-
params.position = Number(flags.position);
|
|
1011
|
-
output(await surveys.addQuestion(client, rest[0], params));
|
|
1012
|
-
break;
|
|
1013
|
-
}
|
|
1014
|
-
case "edit-question": {
|
|
1015
|
-
if (!rest[0] || !rest[1]) {
|
|
1016
|
-
console.error("Usage: ascendkit survey edit-question <survey-id> <question-name> [--title <title>] [--required <true|false>] [--choices <c1,c2,...>]");
|
|
1253
|
+
else {
|
|
1254
|
+
console.error(`Unknown survey question command: ${questionAction}`);
|
|
1017
1255
|
process.exit(1);
|
|
1018
1256
|
}
|
|
1019
|
-
const params = {};
|
|
1020
|
-
if (flags.title)
|
|
1021
|
-
params.title = flags.title;
|
|
1022
|
-
if (flags.required)
|
|
1023
|
-
params.isRequired = flags.required === "true";
|
|
1024
|
-
if (flags.choices)
|
|
1025
|
-
params.choices = flags.choices.split(",");
|
|
1026
|
-
output(await surveys.editQuestion(client, rest[0], rest[1], params));
|
|
1027
1257
|
break;
|
|
1028
1258
|
}
|
|
1029
|
-
case "remove-question":
|
|
1030
|
-
if (!rest[0] || !rest[1]) {
|
|
1031
|
-
console.error("Usage: ascendkit survey remove-question <survey-id> <question-name>");
|
|
1032
|
-
process.exit(1);
|
|
1033
|
-
}
|
|
1034
|
-
output(await surveys.removeQuestion(client, rest[0], rest[1]));
|
|
1035
|
-
break;
|
|
1036
|
-
case "reorder-questions":
|
|
1037
|
-
if (!rest[0] || !flags.order) {
|
|
1038
|
-
console.error("Usage: ascendkit survey reorder-questions <survey-id> --order <name1,name2,...>");
|
|
1039
|
-
process.exit(1);
|
|
1040
|
-
}
|
|
1041
|
-
output(await surveys.reorderQuestions(client, rest[0], flags.order.split(",")));
|
|
1042
|
-
break;
|
|
1043
1259
|
default:
|
|
1044
1260
|
console.error(`Unknown survey command: ${action}`);
|
|
1045
1261
|
console.error('Run "ascendkit survey --help" for usage');
|
|
@@ -1064,7 +1280,7 @@ function runStatus() {
|
|
|
1064
1280
|
}
|
|
1065
1281
|
else {
|
|
1066
1282
|
console.log(" No environment set. Run: ascendkit set-env <public-key>");
|
|
1067
|
-
console.log(" List environments: ascendkit env list
|
|
1283
|
+
console.log(" List environments: ascendkit project env list <project-id>");
|
|
1068
1284
|
}
|
|
1069
1285
|
console.log();
|
|
1070
1286
|
}
|
|
@@ -1128,6 +1344,34 @@ async function runVerify() {
|
|
|
1128
1344
|
console.log();
|
|
1129
1345
|
}
|
|
1130
1346
|
async function runJourney(client, action, rest) {
|
|
1347
|
+
if (!action) {
|
|
1348
|
+
console.log(HELP_SECTION.journey);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
if (action === "show")
|
|
1352
|
+
action = "get";
|
|
1353
|
+
if (action === "remove")
|
|
1354
|
+
action = "delete";
|
|
1355
|
+
if (action === "node") {
|
|
1356
|
+
const nodeAction = rest[0];
|
|
1357
|
+
action =
|
|
1358
|
+
nodeAction === "list" ? "list-nodes" :
|
|
1359
|
+
nodeAction === "add" ? "add-node" :
|
|
1360
|
+
nodeAction === "update" ? "edit-node" :
|
|
1361
|
+
nodeAction === "remove" ? "remove-node" :
|
|
1362
|
+
action;
|
|
1363
|
+
rest = rest.slice(1);
|
|
1364
|
+
}
|
|
1365
|
+
if (action === "transition") {
|
|
1366
|
+
const transitionAction = rest[0];
|
|
1367
|
+
action =
|
|
1368
|
+
transitionAction === "list" ? "list-transitions" :
|
|
1369
|
+
transitionAction === "add" ? "add-transition" :
|
|
1370
|
+
transitionAction === "update" ? "edit-transition" :
|
|
1371
|
+
transitionAction === "remove" ? "remove-transition" :
|
|
1372
|
+
action;
|
|
1373
|
+
rest = rest.slice(1);
|
|
1374
|
+
}
|
|
1131
1375
|
const flags = parseFlags(rest);
|
|
1132
1376
|
switch (action) {
|
|
1133
1377
|
case "create":
|
|
@@ -1135,7 +1379,7 @@ async function runJourney(client, action, rest) {
|
|
|
1135
1379
|
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>]");
|
|
1136
1380
|
process.exit(1);
|
|
1137
1381
|
}
|
|
1138
|
-
|
|
1382
|
+
console.log(formatJourneyWithGuidance((await journeys.createJourney(client, {
|
|
1139
1383
|
name: flags.name,
|
|
1140
1384
|
entryEvent: flags["entry-event"],
|
|
1141
1385
|
entryNode: flags["entry-node"],
|
|
@@ -1144,7 +1388,7 @@ async function runJourney(client, action, rest) {
|
|
|
1144
1388
|
description: flags.description,
|
|
1145
1389
|
entryConditions: flags["entry-conditions"] ? JSON.parse(flags["entry-conditions"]) : undefined,
|
|
1146
1390
|
reEntryPolicy: flags["re-entry-policy"],
|
|
1147
|
-
}));
|
|
1391
|
+
}))));
|
|
1148
1392
|
break;
|
|
1149
1393
|
case "list": {
|
|
1150
1394
|
const opts = {};
|
|
@@ -1162,17 +1406,17 @@ async function runJourney(client, action, rest) {
|
|
|
1162
1406
|
}
|
|
1163
1407
|
case "get":
|
|
1164
1408
|
if (!rest[0]) {
|
|
1165
|
-
console.error("Usage: ascendkit journey
|
|
1409
|
+
console.error("Usage: ascendkit journey show <journey-id>");
|
|
1166
1410
|
process.exit(1);
|
|
1167
1411
|
}
|
|
1168
|
-
|
|
1412
|
+
console.log(formatJourneyWithGuidance(await journeys.getJourney(client, rest[0])));
|
|
1169
1413
|
break;
|
|
1170
1414
|
case "update":
|
|
1171
1415
|
if (!rest[0]) {
|
|
1172
1416
|
console.error("Usage: ascendkit journey update <journey-id> [--flags]");
|
|
1173
1417
|
process.exit(1);
|
|
1174
1418
|
}
|
|
1175
|
-
|
|
1419
|
+
console.log(formatJourneyWithGuidance((await journeys.updateJourney(client, rest[0], {
|
|
1176
1420
|
name: flags.name,
|
|
1177
1421
|
description: flags.description,
|
|
1178
1422
|
entryEvent: flags["entry-event"],
|
|
@@ -1181,53 +1425,61 @@ async function runJourney(client, action, rest) {
|
|
|
1181
1425
|
reEntryPolicy: flags["re-entry-policy"],
|
|
1182
1426
|
nodes: flags.nodes ? JSON.parse(flags.nodes) : undefined,
|
|
1183
1427
|
transitions: flags.transitions ? JSON.parse(flags.transitions) : undefined,
|
|
1184
|
-
}));
|
|
1428
|
+
}))));
|
|
1185
1429
|
break;
|
|
1186
1430
|
case "delete":
|
|
1187
1431
|
if (!rest[0]) {
|
|
1188
|
-
console.error("Usage: ascendkit journey
|
|
1432
|
+
console.error("Usage: ascendkit journey remove <journey-id>");
|
|
1189
1433
|
process.exit(1);
|
|
1190
1434
|
}
|
|
1191
|
-
|
|
1435
|
+
await journeys.deleteJourney(client, rest[0]);
|
|
1436
|
+
console.log(`Deleted journey ${rest[0]}.`);
|
|
1192
1437
|
break;
|
|
1193
1438
|
case "activate":
|
|
1194
1439
|
if (!rest[0]) {
|
|
1195
1440
|
console.error("Usage: ascendkit journey activate <journey-id>");
|
|
1196
1441
|
process.exit(1);
|
|
1197
1442
|
}
|
|
1198
|
-
|
|
1443
|
+
console.log(formatJourneyWithGuidance(await journeys.activateJourney(client, rest[0])));
|
|
1199
1444
|
break;
|
|
1200
1445
|
case "pause":
|
|
1201
1446
|
if (!rest[0]) {
|
|
1202
1447
|
console.error("Usage: ascendkit journey pause <journey-id>");
|
|
1203
1448
|
process.exit(1);
|
|
1204
1449
|
}
|
|
1205
|
-
|
|
1450
|
+
console.log(formatJourneyWithGuidance(await journeys.pauseJourney(client, rest[0])));
|
|
1451
|
+
break;
|
|
1452
|
+
case "resume":
|
|
1453
|
+
if (!rest[0]) {
|
|
1454
|
+
console.error("Usage: ascendkit journey resume <journey-id>");
|
|
1455
|
+
process.exit(1);
|
|
1456
|
+
}
|
|
1457
|
+
console.log(formatJourneyWithGuidance(await journeys.resumeJourney(client, rest[0])));
|
|
1206
1458
|
break;
|
|
1207
1459
|
case "archive":
|
|
1208
1460
|
if (!rest[0]) {
|
|
1209
1461
|
console.error("Usage: ascendkit journey archive <journey-id>");
|
|
1210
1462
|
process.exit(1);
|
|
1211
1463
|
}
|
|
1212
|
-
|
|
1464
|
+
console.log(formatJourneyWithGuidance(await journeys.archiveJourney(client, rest[0])));
|
|
1213
1465
|
break;
|
|
1214
1466
|
case "analytics":
|
|
1215
1467
|
if (!rest[0]) {
|
|
1216
1468
|
console.error("Usage: ascendkit journey analytics <journey-id>");
|
|
1217
1469
|
process.exit(1);
|
|
1218
1470
|
}
|
|
1219
|
-
|
|
1471
|
+
console.log(formatJourneyAnalytics(await journeys.getJourneyAnalytics(client, rest[0])));
|
|
1220
1472
|
break;
|
|
1221
1473
|
case "list-nodes":
|
|
1222
1474
|
if (!rest[0]) {
|
|
1223
|
-
console.error("Usage: ascendkit journey list
|
|
1475
|
+
console.error("Usage: ascendkit journey node list <journey-id>");
|
|
1224
1476
|
process.exit(1);
|
|
1225
1477
|
}
|
|
1226
|
-
|
|
1478
|
+
console.log(formatNodeList(await journeys.listNodes(client, rest[0])));
|
|
1227
1479
|
break;
|
|
1228
1480
|
case "add-node": {
|
|
1229
1481
|
if (!rest[0] || !flags.name) {
|
|
1230
|
-
console.error("Usage: ascendkit journey
|
|
1482
|
+
console.error("Usage: ascendkit journey node add <journey-id> --name <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]");
|
|
1231
1483
|
process.exit(1);
|
|
1232
1484
|
}
|
|
1233
1485
|
const params = { name: flags.name };
|
|
@@ -1242,12 +1494,12 @@ async function runJourney(client, action, rest) {
|
|
|
1242
1494
|
}
|
|
1243
1495
|
if (flags.terminal)
|
|
1244
1496
|
params.terminal = flags.terminal === "true";
|
|
1245
|
-
|
|
1497
|
+
console.log(formatSingleNode(await journeys.addNode(client, rest[0], params), "Added", flags.name));
|
|
1246
1498
|
break;
|
|
1247
1499
|
}
|
|
1248
1500
|
case "edit-node": {
|
|
1249
1501
|
if (!rest[0] || !rest[1]) {
|
|
1250
|
-
console.error("Usage: ascendkit journey
|
|
1502
|
+
console.error("Usage: ascendkit journey node update <journey-id> <node-name> [--action <json>] [--email-id <email>] [--terminal <true|false>]");
|
|
1251
1503
|
process.exit(1);
|
|
1252
1504
|
}
|
|
1253
1505
|
const params = {};
|
|
@@ -1271,30 +1523,30 @@ async function runJourney(client, action, rest) {
|
|
|
1271
1523
|
}
|
|
1272
1524
|
if (flags.terminal)
|
|
1273
1525
|
params.terminal = flags.terminal === "true";
|
|
1274
|
-
|
|
1526
|
+
console.log(formatSingleNode(await journeys.editNode(client, rest[0], rest[1], params), "Updated", rest[1]));
|
|
1275
1527
|
break;
|
|
1276
1528
|
}
|
|
1277
1529
|
case "remove-node":
|
|
1278
1530
|
if (!rest[0] || !rest[1]) {
|
|
1279
|
-
console.error("Usage: ascendkit journey
|
|
1531
|
+
console.error("Usage: ascendkit journey node remove <journey-id> <node-name>");
|
|
1280
1532
|
process.exit(1);
|
|
1281
1533
|
}
|
|
1282
|
-
|
|
1534
|
+
console.log(formatSingleNode(await journeys.removeNode(client, rest[0], rest[1]), "Removed", rest[1]));
|
|
1283
1535
|
break;
|
|
1284
1536
|
case "list-transitions": {
|
|
1285
1537
|
if (!rest[0]) {
|
|
1286
|
-
console.error("Usage: ascendkit journey list
|
|
1538
|
+
console.error("Usage: ascendkit journey transition list <journey-id> [--from <node-name>] [--to <node-name>]");
|
|
1287
1539
|
process.exit(1);
|
|
1288
1540
|
}
|
|
1289
|
-
|
|
1541
|
+
console.log(formatTransitionList(await journeys.listTransitions(client, rest[0], {
|
|
1290
1542
|
from_node: flags.from,
|
|
1291
1543
|
to_node: flags.to,
|
|
1292
|
-
}));
|
|
1544
|
+
})));
|
|
1293
1545
|
break;
|
|
1294
1546
|
}
|
|
1295
1547
|
case "add-transition": {
|
|
1296
1548
|
if (!rest[0] || !flags.from || !flags.to || !(flags.on || flags.after || flags.trigger)) {
|
|
1297
|
-
console.error("Usage: ascendkit journey
|
|
1549
|
+
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>]");
|
|
1298
1550
|
process.exit(1);
|
|
1299
1551
|
}
|
|
1300
1552
|
let trigger;
|
|
@@ -1316,12 +1568,13 @@ async function runJourney(client, action, rest) {
|
|
|
1316
1568
|
params.priority = Number(flags.priority);
|
|
1317
1569
|
if (flags.name)
|
|
1318
1570
|
params.name = flags.name;
|
|
1319
|
-
|
|
1571
|
+
const transitionName = flags.name || `${flags.from}-to-${flags.to}`;
|
|
1572
|
+
console.log(formatSingleTransition(await journeys.addTransition(client, rest[0], params), "Added", transitionName));
|
|
1320
1573
|
break;
|
|
1321
1574
|
}
|
|
1322
1575
|
case "edit-transition": {
|
|
1323
1576
|
if (!rest[0] || !rest[1]) {
|
|
1324
|
-
console.error("Usage: ascendkit journey
|
|
1577
|
+
console.error("Usage: ascendkit journey transition update <journey-id> <transition-name> [--on <event>] [--after <delay>] [--trigger <json>] [--priority <n>]");
|
|
1325
1578
|
process.exit(1);
|
|
1326
1579
|
}
|
|
1327
1580
|
const params = {};
|
|
@@ -1336,15 +1589,15 @@ async function runJourney(client, action, rest) {
|
|
|
1336
1589
|
}
|
|
1337
1590
|
if (flags.priority != null)
|
|
1338
1591
|
params.priority = Number(flags.priority);
|
|
1339
|
-
|
|
1592
|
+
console.log(formatSingleTransition(await journeys.editTransition(client, rest[0], rest[1], params), "Updated", rest[1]));
|
|
1340
1593
|
break;
|
|
1341
1594
|
}
|
|
1342
1595
|
case "remove-transition":
|
|
1343
1596
|
if (!rest[0] || !rest[1]) {
|
|
1344
|
-
console.error("Usage: ascendkit journey
|
|
1597
|
+
console.error("Usage: ascendkit journey transition remove <journey-id> <transition-name>");
|
|
1345
1598
|
process.exit(1);
|
|
1346
1599
|
}
|
|
1347
|
-
|
|
1600
|
+
console.log(formatSingleTransition(await journeys.removeTransition(client, rest[0], rest[1]), "Removed", rest[1]));
|
|
1348
1601
|
break;
|
|
1349
1602
|
default:
|
|
1350
1603
|
console.error(`Unknown journey command: ${action}`);
|
|
@@ -1526,56 +1779,39 @@ async function runCampaign(client, action, rest) {
|
|
|
1526
1779
|
}
|
|
1527
1780
|
async function runEmail(client, action, rest) {
|
|
1528
1781
|
const flags = parseFlags(rest);
|
|
1782
|
+
if (!action) {
|
|
1783
|
+
console.log(HELP_SECTION["email-identity"]);
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1529
1786
|
switch (action) {
|
|
1530
|
-
case "
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
}
|
|
1535
|
-
case "use-default": {
|
|
1536
|
-
const s = await email.useDefaultIdentity(client);
|
|
1537
|
-
printIdentityStatus(s);
|
|
1538
|
-
break;
|
|
1539
|
-
}
|
|
1540
|
-
case "use-custom": {
|
|
1541
|
-
if (!rest[0]) {
|
|
1542
|
-
console.error("Usage: ascendkit email use-custom <domain> [--from-email <email>] [--from-name <name>]");
|
|
1543
|
-
process.exit(1);
|
|
1544
|
-
}
|
|
1545
|
-
const s = await email.useCustomIdentity(client, rest[0], {
|
|
1546
|
-
fromEmail: flags["from-email"],
|
|
1547
|
-
fromName: flags["from-name"],
|
|
1548
|
-
});
|
|
1549
|
-
await printEmailSetup(s);
|
|
1550
|
-
break;
|
|
1551
|
-
}
|
|
1552
|
-
case "settings":
|
|
1553
|
-
if (rest[0] === "update") {
|
|
1554
|
-
const params = {};
|
|
1555
|
-
if (flags["from-email"])
|
|
1556
|
-
params.fromEmail = flags["from-email"];
|
|
1557
|
-
if (flags["from-name"])
|
|
1558
|
-
params.fromName = flags["from-name"];
|
|
1559
|
-
output(await email.updateSettings(client, params));
|
|
1787
|
+
case "settings": {
|
|
1788
|
+
const settings = await email.getSettings(client);
|
|
1789
|
+
if (flags.json === "true") {
|
|
1790
|
+
output(settings);
|
|
1560
1791
|
}
|
|
1561
1792
|
else {
|
|
1562
|
-
|
|
1793
|
+
printEmailSettingsSummary(settings);
|
|
1563
1794
|
}
|
|
1564
1795
|
break;
|
|
1796
|
+
}
|
|
1565
1797
|
case "setup-domain":
|
|
1566
1798
|
if (!rest[0]) {
|
|
1567
|
-
console.error("Usage: ascendkit email setup-domain <domain>");
|
|
1799
|
+
console.error("Usage: ascendkit email-identity setup-domain <domain>");
|
|
1568
1800
|
process.exit(1);
|
|
1569
1801
|
}
|
|
1570
1802
|
await printEmailSetup(await email.setupDomain(client, rest[0]));
|
|
1571
1803
|
break;
|
|
1572
|
-
case "
|
|
1804
|
+
case "status": {
|
|
1573
1805
|
const interval = Math.max(5, Number.parseInt(flags.interval || "15", 10) || 15);
|
|
1574
1806
|
if (flags.watch === "true") {
|
|
1575
1807
|
await watchDomainStatus(client, interval);
|
|
1576
1808
|
}
|
|
1577
1809
|
else {
|
|
1578
|
-
|
|
1810
|
+
const settings = await email.getSettings(client);
|
|
1811
|
+
const domainStatus = await email.checkDomainStatus(client);
|
|
1812
|
+
const dnsCheck = settings.domain ? await email.checkDnsRecords(client) : null;
|
|
1813
|
+
const identities = await email.listIdentities(client);
|
|
1814
|
+
printEmailStatusSummary(settings, domainStatus, dnsCheck, identities.identities ?? []);
|
|
1579
1815
|
}
|
|
1580
1816
|
break;
|
|
1581
1817
|
}
|
|
@@ -1595,8 +1831,68 @@ async function runEmail(client, action, rest) {
|
|
|
1595
1831
|
case "remove-domain":
|
|
1596
1832
|
output(await email.removeDomain(client));
|
|
1597
1833
|
break;
|
|
1834
|
+
case "list": {
|
|
1835
|
+
const result = await email.listIdentities(client);
|
|
1836
|
+
printEmailIdentities(result.identities ?? []);
|
|
1837
|
+
break;
|
|
1838
|
+
}
|
|
1839
|
+
case "add": {
|
|
1840
|
+
const identityEmail = rest[0];
|
|
1841
|
+
if (!identityEmail) {
|
|
1842
|
+
console.error("Usage: ascendkit email-identity add <email> [--display-name <name>]");
|
|
1843
|
+
process.exit(1);
|
|
1844
|
+
}
|
|
1845
|
+
output(await email.createIdentity(client, {
|
|
1846
|
+
email: identityEmail,
|
|
1847
|
+
displayName: flags["display-name"],
|
|
1848
|
+
}));
|
|
1849
|
+
break;
|
|
1850
|
+
}
|
|
1851
|
+
case "resend": {
|
|
1852
|
+
const identityEmail = rest[0];
|
|
1853
|
+
if (!identityEmail) {
|
|
1854
|
+
console.error("Usage: ascendkit email-identity resend <email>");
|
|
1855
|
+
process.exit(1);
|
|
1856
|
+
}
|
|
1857
|
+
output(await email.resendIdentityVerification(client, identityEmail));
|
|
1858
|
+
break;
|
|
1859
|
+
}
|
|
1860
|
+
case "set-default": {
|
|
1861
|
+
const identityEmail = rest[0];
|
|
1862
|
+
if (!identityEmail) {
|
|
1863
|
+
console.error("Usage: ascendkit email-identity set-default <email> [--display-name <name>]");
|
|
1864
|
+
process.exit(1);
|
|
1865
|
+
}
|
|
1866
|
+
output(await email.setDefaultIdentity(client, {
|
|
1867
|
+
email: identityEmail,
|
|
1868
|
+
displayName: flags["display-name"],
|
|
1869
|
+
}));
|
|
1870
|
+
break;
|
|
1871
|
+
}
|
|
1872
|
+
case "remove":
|
|
1873
|
+
case "delete": {
|
|
1874
|
+
const identityEmail = rest[0];
|
|
1875
|
+
if (!identityEmail) {
|
|
1876
|
+
console.error("Usage: ascendkit email-identity remove <email>");
|
|
1877
|
+
process.exit(1);
|
|
1878
|
+
}
|
|
1879
|
+
output(await email.removeIdentity(client, identityEmail));
|
|
1880
|
+
break;
|
|
1881
|
+
}
|
|
1882
|
+
case "test": {
|
|
1883
|
+
const identityEmail = rest[0];
|
|
1884
|
+
if (!identityEmail || !flags.to) {
|
|
1885
|
+
console.error("Usage: ascendkit email-identity test <email> --to <recipient>");
|
|
1886
|
+
process.exit(1);
|
|
1887
|
+
}
|
|
1888
|
+
output(await email.sendTestEmail(client, {
|
|
1889
|
+
to: flags.to,
|
|
1890
|
+
fromIdentityEmail: identityEmail,
|
|
1891
|
+
}));
|
|
1892
|
+
break;
|
|
1893
|
+
}
|
|
1598
1894
|
default:
|
|
1599
|
-
console.error(`Unknown email command: ${action}`);
|
|
1895
|
+
console.error(`Unknown email-identity command: ${action}`);
|
|
1600
1896
|
process.exit(1);
|
|
1601
1897
|
}
|
|
1602
1898
|
}
|
|
@@ -1625,28 +1921,61 @@ async function printEmailSetup(settings) {
|
|
|
1625
1921
|
}
|
|
1626
1922
|
}
|
|
1627
1923
|
}
|
|
1628
|
-
function
|
|
1629
|
-
const
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
console.log("Next step: add DNS records and run `ascendkit email domain-status --watch`");
|
|
1924
|
+
function printEmailSettingsSummary(settings) {
|
|
1925
|
+
const identities = Array.isArray(settings.identities) ? settings.identities : [];
|
|
1926
|
+
if (!settings.domain) {
|
|
1927
|
+
console.log("Sender: AscendKit default");
|
|
1928
|
+
console.log(`From: ${settings.fromEmail || "noreply@ascendkit.dev"}`);
|
|
1929
|
+
console.log(`Display name: ${settings.fromName || "not set"}`);
|
|
1930
|
+
console.log("Domain: not configured");
|
|
1931
|
+
if (identities.length > 0) {
|
|
1932
|
+
console.log("");
|
|
1933
|
+
printEmailIdentities(identities);
|
|
1639
1934
|
}
|
|
1935
|
+
return;
|
|
1640
1936
|
}
|
|
1641
|
-
|
|
1642
|
-
|
|
1937
|
+
console.log(`Domain: ${settings.domain} (${settings.verificationStatus || "unknown"})`);
|
|
1938
|
+
console.log("");
|
|
1939
|
+
printEmailIdentities(identities);
|
|
1940
|
+
}
|
|
1941
|
+
function printEmailStatusSummary(settings, domainStatus, dnsCheck, identities) {
|
|
1942
|
+
if (!settings.domain) {
|
|
1943
|
+
console.log("Domain: not configured");
|
|
1944
|
+
console.log("Sender: AscendKit default");
|
|
1945
|
+
if (identities.length > 0) {
|
|
1946
|
+
console.log("");
|
|
1947
|
+
printEmailIdentities(identities);
|
|
1948
|
+
}
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
console.log(`Domain: ${settings.domain} (${domainStatus.status || settings.verificationStatus || "unknown"})`);
|
|
1952
|
+
if (dnsCheck?.summary) {
|
|
1953
|
+
console.log(`DNS: ${dnsCheck.summary.found}/${dnsCheck.summary.total} verified`);
|
|
1643
1954
|
}
|
|
1955
|
+
console.log("");
|
|
1956
|
+
printEmailIdentities(identities);
|
|
1957
|
+
}
|
|
1958
|
+
function printEmailIdentities(identities) {
|
|
1959
|
+
table(identities.map((identity) => ({
|
|
1960
|
+
email: identity.email,
|
|
1961
|
+
displayName: identity.displayName || "—",
|
|
1962
|
+
verificationStatus: identity.verificationStatus,
|
|
1963
|
+
isDefault: identity.isDefault ? "yes" : "",
|
|
1964
|
+
})), [
|
|
1965
|
+
{ key: "email", label: "Email", width: 36 },
|
|
1966
|
+
{ key: "displayName", label: "Display Name", width: 24 },
|
|
1967
|
+
{ key: "verificationStatus", label: "Status", width: 12 },
|
|
1968
|
+
{ key: "isDefault", label: "Default", width: 7 },
|
|
1969
|
+
]);
|
|
1644
1970
|
}
|
|
1645
1971
|
async function watchDomainStatus(client, intervalSeconds) {
|
|
1646
1972
|
while (true) {
|
|
1647
|
-
const
|
|
1648
|
-
|
|
1649
|
-
|
|
1973
|
+
const settings = await email.getSettings(client);
|
|
1974
|
+
const domainStatus = await email.checkDomainStatus(client);
|
|
1975
|
+
const dnsCheck = settings.domain ? await email.checkDnsRecords(client) : null;
|
|
1976
|
+
const identities = await email.listIdentities(client);
|
|
1977
|
+
printEmailStatusSummary(settings, domainStatus, dnsCheck, identities.identities ?? []);
|
|
1978
|
+
if (domainStatus?.status === "verified" || domainStatus?.status === "failed" || domainStatus?.status === "none") {
|
|
1650
1979
|
return;
|
|
1651
1980
|
}
|
|
1652
1981
|
await new Promise((resolve) => setTimeout(resolve, intervalSeconds * 1000));
|