@cakemail-org/cakemail-cli 1.5.0 → 2.0.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/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +319 -15
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/cli.js +27 -10
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.d.ts.map +1 -1
- package/dist/commands/campaigns.js +103 -8
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +63 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +91 -12
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.d.ts +5 -0
- package/dist/commands/interests.d.ts.map +1 -0
- package/dist/commands/interests.js +172 -0
- package/dist/commands/interests.js.map +1 -0
- package/dist/commands/lists.d.ts.map +1 -1
- package/dist/commands/lists.js +6 -8
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +237 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.d.ts.map +1 -1
- package/dist/commands/senders.js +11 -8
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.d.ts +5 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +124 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.d.ts +5 -0
- package/dist/commands/transactional-templates.d.ts.map +1 -0
- package/dist/commands/transactional-templates.js +354 -0
- package/dist/commands/transactional-templates.js.map +1 -0
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/auth.d.ts +8 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +39 -11
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-file.d.ts +7 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +15 -0
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/list-defaults.d.ts +33 -0
- package/dist/utils/list-defaults.d.ts.map +1 -0
- package/dist/utils/list-defaults.js +52 -0
- package/dist/utils/list-defaults.js.map +1 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +36 -13
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -47
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { CakemailClient } from '../client.js';
|
|
3
|
+
import { OutputFormatter } from '../utils/output.js';
|
|
4
|
+
import ora from '../utils/spinner.js';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
|
|
7
|
+
export function createEmailsCommand(client: CakemailClient, formatter: OutputFormatter): Command {
|
|
8
|
+
const emails = new Command('emails')
|
|
9
|
+
.description('Manage Email API v2 - Send and track transactional emails');
|
|
10
|
+
|
|
11
|
+
// Submit email
|
|
12
|
+
emails
|
|
13
|
+
.command('send')
|
|
14
|
+
.description('Submit an email to be sent')
|
|
15
|
+
.requiredOption('-t, --to <email>', 'Recipient email address')
|
|
16
|
+
.requiredOption('-s, --subject <subject>', 'Email subject')
|
|
17
|
+
.option('--from-email <email>', 'Sender email address')
|
|
18
|
+
.option('--from-name <name>', 'Sender name')
|
|
19
|
+
.option('--reply-to <email>', 'Reply-to email address')
|
|
20
|
+
.option('--html <html>', 'HTML content')
|
|
21
|
+
.option('--html-file <path>', 'Path to HTML file')
|
|
22
|
+
.option('--text <text>', 'Plain text content')
|
|
23
|
+
.option('--text-file <path>', 'Path to text file')
|
|
24
|
+
.option('--template-id <id>', 'Template ID to use')
|
|
25
|
+
.option('--params <json>', 'Template parameters as JSON string')
|
|
26
|
+
.option('--tracking', 'Enable tracking (open/click tracking)')
|
|
27
|
+
.option('--tags <tags>', 'Comma-separated tags for categorization')
|
|
28
|
+
.option('--headers <json>', 'Custom headers as JSON object')
|
|
29
|
+
.option('--attachments <json>', 'Attachments as JSON array')
|
|
30
|
+
.action(async (options) => {
|
|
31
|
+
const spinner = ora('Submitting email...').start();
|
|
32
|
+
try {
|
|
33
|
+
const payload: any = {
|
|
34
|
+
to: options.to,
|
|
35
|
+
subject: options.subject,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// From
|
|
39
|
+
if (options.fromEmail) {
|
|
40
|
+
payload.from = { email: options.fromEmail };
|
|
41
|
+
if (options.fromName) payload.from.name = options.fromName;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Reply-to
|
|
45
|
+
if (options.replyTo) {
|
|
46
|
+
payload.reply_to = options.replyTo;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Content
|
|
50
|
+
if (options.templateId) {
|
|
51
|
+
payload.template_id = parseInt(options.templateId);
|
|
52
|
+
if (options.params) {
|
|
53
|
+
payload.params = JSON.parse(options.params);
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
payload.content = {};
|
|
57
|
+
|
|
58
|
+
if (options.htmlFile) {
|
|
59
|
+
payload.content.html = fs.readFileSync(options.htmlFile, 'utf-8');
|
|
60
|
+
} else if (options.html) {
|
|
61
|
+
payload.content.html = options.html;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (options.textFile) {
|
|
65
|
+
payload.content.text = fs.readFileSync(options.textFile, 'utf-8');
|
|
66
|
+
} else if (options.text) {
|
|
67
|
+
payload.content.text = options.text;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!payload.content.html && !payload.content.text) {
|
|
71
|
+
spinner.fail();
|
|
72
|
+
formatter.error('Either --html/--html-file, --text/--text-file, or --template-id is required');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Tracking
|
|
78
|
+
if (options.tracking !== undefined) {
|
|
79
|
+
payload.tracking = options.tracking;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Tags
|
|
83
|
+
if (options.tags) {
|
|
84
|
+
payload.tags = options.tags.split(',').map((t: string) => t.trim());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Headers
|
|
88
|
+
if (options.headers) {
|
|
89
|
+
payload.headers = JSON.parse(options.headers);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Attachments
|
|
93
|
+
if (options.attachments) {
|
|
94
|
+
payload.attachments = JSON.parse(options.attachments);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const data = await client.sdk.email.submit(payload);
|
|
98
|
+
spinner.stop();
|
|
99
|
+
formatter.success(`Email submitted: ${data.id}`);
|
|
100
|
+
formatter.output(data);
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
spinner.stop();
|
|
103
|
+
formatter.error(error.message);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Get email
|
|
109
|
+
emails
|
|
110
|
+
.command('get <email-id>')
|
|
111
|
+
.description('Retrieve a submitted email')
|
|
112
|
+
.action(async (emailId) => {
|
|
113
|
+
const spinner = ora(`Fetching email ${emailId}...`).start();
|
|
114
|
+
try {
|
|
115
|
+
const data = await client.sdk.email.retrieve(emailId);
|
|
116
|
+
spinner.stop();
|
|
117
|
+
formatter.output(data);
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
spinner.stop();
|
|
120
|
+
formatter.error(error.message);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Render email
|
|
126
|
+
emails
|
|
127
|
+
.command('render <email-id>')
|
|
128
|
+
.description('Render a submitted email (returns HTML)')
|
|
129
|
+
.option('--as-submitted', 'Render the original submitted content')
|
|
130
|
+
.option('--tracking', 'Enable tracking in rendered HTML')
|
|
131
|
+
.action(async (emailId, options) => {
|
|
132
|
+
const spinner = ora(`Rendering email ${emailId}...`).start();
|
|
133
|
+
try {
|
|
134
|
+
const params: any = {};
|
|
135
|
+
if (options.asSubmitted !== undefined) params.as_submitted = options.asSubmitted;
|
|
136
|
+
if (options.tracking !== undefined) params.tracking = options.tracking;
|
|
137
|
+
|
|
138
|
+
const data = await client.sdk.email.render(emailId, params);
|
|
139
|
+
spinner.stop();
|
|
140
|
+
formatter.output(data);
|
|
141
|
+
} catch (error: any) {
|
|
142
|
+
spinner.stop();
|
|
143
|
+
formatter.error(error.message);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Email API logs
|
|
149
|
+
emails
|
|
150
|
+
.command('logs')
|
|
151
|
+
.description('Get Email API activity logs')
|
|
152
|
+
.option('--from <date>', 'Start date (YYYY-MM-DD)')
|
|
153
|
+
.option('--to <date>', 'End date (YYYY-MM-DD)')
|
|
154
|
+
.option('--tag <tag>', 'Filter by tag')
|
|
155
|
+
.option('--status <status>', 'Filter by status (delivered, bounced, etc.)')
|
|
156
|
+
.option('-l, --limit <number>', 'Limit number of results')
|
|
157
|
+
.option('-p, --page <number>', 'Page number')
|
|
158
|
+
.action(async (options) => {
|
|
159
|
+
const spinner = ora('Fetching Email API logs...').start();
|
|
160
|
+
try {
|
|
161
|
+
const params: any = {};
|
|
162
|
+
if (options.from) params.from = options.from;
|
|
163
|
+
if (options.to) params.to = options.to;
|
|
164
|
+
if (options.tag) params.tag = options.tag;
|
|
165
|
+
if (options.status) params.status = options.status;
|
|
166
|
+
if (options.limit) params.perPage = parseInt(options.limit);
|
|
167
|
+
if (options.page) params.page = parseInt(options.page);
|
|
168
|
+
|
|
169
|
+
const data = await client.sdk.emailApiService.getEmailApiLogs(params);
|
|
170
|
+
spinner.stop();
|
|
171
|
+
formatter.output(data);
|
|
172
|
+
} catch (error: any) {
|
|
173
|
+
spinner.stop();
|
|
174
|
+
formatter.error(error.message);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// List email tags
|
|
180
|
+
emails
|
|
181
|
+
.command('tags')
|
|
182
|
+
.description('List all email tags')
|
|
183
|
+
.action(async () => {
|
|
184
|
+
const spinner = ora('Fetching email tags...').start();
|
|
185
|
+
try {
|
|
186
|
+
const data = await client.sdk.emailApiService.listEmailTags({});
|
|
187
|
+
spinner.stop();
|
|
188
|
+
formatter.output(data);
|
|
189
|
+
} catch (error: any) {
|
|
190
|
+
spinner.stop();
|
|
191
|
+
formatter.error(error.message);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return emails;
|
|
197
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Form.
|
|
2
|
+
// ABOUTME: Generated by api-kit from the OpenAPI spec.
|
|
3
|
+
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
+
import { confirmDelete } from '../utils/confirm.js';
|
|
7
|
+
|
|
8
|
+
export function createFormsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('forms')
|
|
13
|
+
.description('Create and manage hosted forms for collecting subscriber data. Forms can include reCAPTCHA verification, custom redirect URLs, and double opt-in. Forms are published to generate a public submission URL.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('list')
|
|
18
|
+
.description('Show all forms')
|
|
19
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
20
|
+
.option('--page <value>', 'page')
|
|
21
|
+
.option('--per-page <value>', 'per_page')
|
|
22
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
23
|
+
.option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
|
|
24
|
+
|
|
25
|
+
Valid terms:
|
|
26
|
+
- `name`
|
|
27
|
+
- `language`
|
|
28
|
+
- `created_on`
|
|
29
|
+
- `last_updated_on`
|
|
30
|
+
- `list_id`
|
|
31
|
+
- `status`
|
|
32
|
+
- `enabled`
|
|
33
|
+
- `updated_on`
|
|
34
|
+
- `published_on`
|
|
35
|
+
- `branding`')
|
|
36
|
+
.option('--filter <value>', 'Valid Terms:
|
|
37
|
+
- `name`
|
|
38
|
+
|
|
39
|
+
Valid Operators:
|
|
40
|
+
- `==`
|
|
41
|
+
|
|
42
|
+
Query separator:
|
|
43
|
+
- `;`')
|
|
44
|
+
.action(async (options) => {
|
|
45
|
+
const spinner = createSpinner('Fetching form...').start();
|
|
46
|
+
try {
|
|
47
|
+
const data = await client.listForms({
|
|
48
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
49
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
50
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
51
|
+
withCount: options.withCount,
|
|
52
|
+
sort: options.sort,
|
|
53
|
+
filter: options.filter,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
spinner.stop();
|
|
57
|
+
formatter.output(data);
|
|
58
|
+
} catch (error: any) {
|
|
59
|
+
spinner.stop();
|
|
60
|
+
formatter.error(error.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
cmd
|
|
67
|
+
.command('create')
|
|
68
|
+
.description('Create a form')
|
|
69
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
70
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
71
|
+
.action(async (options) => {
|
|
72
|
+
const spinner = createSpinner('Creating form...').start();
|
|
73
|
+
try {
|
|
74
|
+
const body = JSON.parse(options.data);
|
|
75
|
+
const data = await client.createForm({
|
|
76
|
+
...body,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
spinner.stop();
|
|
80
|
+
formatter.success('Form created successfully');
|
|
81
|
+
formatter.output(data);
|
|
82
|
+
} catch (error: any) {
|
|
83
|
+
spinner.stop();
|
|
84
|
+
formatter.error(error.message);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
cmd
|
|
91
|
+
.command('get <form-id>')
|
|
92
|
+
.description('Show a form details')
|
|
93
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
94
|
+
.action(async (form_id, options) => {
|
|
95
|
+
const spinner = createSpinner('Fetching form...').start();
|
|
96
|
+
try {
|
|
97
|
+
const data = await client.getForm({
|
|
98
|
+
form_id,
|
|
99
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
spinner.stop();
|
|
103
|
+
formatter.output(data);
|
|
104
|
+
} catch (error: any) {
|
|
105
|
+
spinner.stop();
|
|
106
|
+
formatter.error(error.message);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
cmd
|
|
113
|
+
.command('patch <form-id>')
|
|
114
|
+
.description('Update a form')
|
|
115
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
116
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
117
|
+
.action(async (form_id, options) => {
|
|
118
|
+
const spinner = createSpinner('Updating form...').start();
|
|
119
|
+
try {
|
|
120
|
+
const body = JSON.parse(options.data);
|
|
121
|
+
const data = await client.patchForm({
|
|
122
|
+
form_id,
|
|
123
|
+
...body,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
spinner.stop();
|
|
127
|
+
formatter.success('Form updated successfully');
|
|
128
|
+
formatter.output(data);
|
|
129
|
+
} catch (error: any) {
|
|
130
|
+
spinner.stop();
|
|
131
|
+
formatter.error(error.message);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
cmd
|
|
138
|
+
.command('delete <form-id>')
|
|
139
|
+
.description('Delete a form')
|
|
140
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
141
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
142
|
+
.action(async (form_id, options) => {
|
|
143
|
+
if (!options.force) {
|
|
144
|
+
const confirmed = await confirmDelete('form', form_id);
|
|
145
|
+
if (!confirmed) {
|
|
146
|
+
formatter.info('Deletion cancelled');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const spinner = createSpinner('Deleting form...').start();
|
|
152
|
+
try {
|
|
153
|
+
const data = await client.deleteForm({
|
|
154
|
+
form_id,
|
|
155
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
spinner.stop();
|
|
159
|
+
formatter.success('Form deleted successfully');
|
|
160
|
+
} catch (error: any) {
|
|
161
|
+
spinner.stop();
|
|
162
|
+
formatter.error(error.message);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
cmd
|
|
169
|
+
.command('publish <form-id>')
|
|
170
|
+
.description('Publish a form')
|
|
171
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
172
|
+
.action(async (form_id, options) => {
|
|
173
|
+
const spinner = createSpinner('Creating form...').start();
|
|
174
|
+
try {
|
|
175
|
+
const data = await client.publishForm({
|
|
176
|
+
form_id,
|
|
177
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
spinner.stop();
|
|
181
|
+
formatter.success('Form created successfully');
|
|
182
|
+
formatter.output(data);
|
|
183
|
+
} catch (error: any) {
|
|
184
|
+
spinner.stop();
|
|
185
|
+
formatter.error(error.message);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
cmd
|
|
192
|
+
.command('render <form-id>')
|
|
193
|
+
.description('Render a form')
|
|
194
|
+
.option('--published <value>', 'Render the published content of the form')
|
|
195
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
196
|
+
.action(async (form_id, options) => {
|
|
197
|
+
const spinner = createSpinner('Fetching form...').start();
|
|
198
|
+
try {
|
|
199
|
+
const data = await client.renderForm({
|
|
200
|
+
form_id,
|
|
201
|
+
published: options.published,
|
|
202
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
spinner.stop();
|
|
206
|
+
formatter.output(data);
|
|
207
|
+
} catch (error: any) {
|
|
208
|
+
spinner.stop();
|
|
209
|
+
formatter.error(error.message);
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
cmd
|
|
216
|
+
.command('submit <token>')
|
|
217
|
+
.description('Submit a form')
|
|
218
|
+
.action(async (token) => {
|
|
219
|
+
const spinner = createSpinner('Creating form...').start();
|
|
220
|
+
try {
|
|
221
|
+
const data = await client.submitForm({
|
|
222
|
+
token,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
spinner.stop();
|
|
226
|
+
formatter.success('Form created successfully');
|
|
227
|
+
formatter.output(data);
|
|
228
|
+
} catch (error: any) {
|
|
229
|
+
spinner.stop();
|
|
230
|
+
formatter.error(error.message);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
cmd
|
|
237
|
+
.command('disable <form-id>')
|
|
238
|
+
.description('Disable a form')
|
|
239
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
240
|
+
.action(async (form_id, options) => {
|
|
241
|
+
const spinner = createSpinner('Creating form...').start();
|
|
242
|
+
try {
|
|
243
|
+
const data = await client.disableForm({
|
|
244
|
+
form_id,
|
|
245
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
spinner.stop();
|
|
249
|
+
formatter.success('Form created successfully');
|
|
250
|
+
formatter.output(data);
|
|
251
|
+
} catch (error: any) {
|
|
252
|
+
spinner.stop();
|
|
253
|
+
formatter.error(error.message);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
cmd
|
|
260
|
+
.command('enable <form-id>')
|
|
261
|
+
.description('Enable a form')
|
|
262
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
263
|
+
.action(async (form_id, options) => {
|
|
264
|
+
const spinner = createSpinner('Creating form...').start();
|
|
265
|
+
try {
|
|
266
|
+
const data = await client.enableForm({
|
|
267
|
+
form_id,
|
|
268
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
spinner.stop();
|
|
272
|
+
formatter.success('Form created successfully');
|
|
273
|
+
formatter.output(data);
|
|
274
|
+
} catch (error: any) {
|
|
275
|
+
spinner.stop();
|
|
276
|
+
formatter.error(error.message);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
return cmd;
|
|
283
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Interest.
|
|
2
|
+
// ABOUTME: Generated by api-kit from the OpenAPI spec.
|
|
3
|
+
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
+
import { confirmDelete } from '../utils/confirm.js';
|
|
7
|
+
|
|
8
|
+
export function createInterestsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('interests')
|
|
13
|
+
.description('Manage interests (preference categories) that can be assigned to contacts. Interests enable preference-based segmentation and can be used in preference centers.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('list <list-id>')
|
|
18
|
+
.description('Show all Interests')
|
|
19
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
20
|
+
.option('--page <value>', 'page')
|
|
21
|
+
.option('--per-page <value>', 'per_page')
|
|
22
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
23
|
+
.action(async (list_id, options) => {
|
|
24
|
+
const spinner = createSpinner('Fetching interest...').start();
|
|
25
|
+
try {
|
|
26
|
+
const data = await client.listInterests({
|
|
27
|
+
list_id: Number(list_id),
|
|
28
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
29
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
30
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
31
|
+
withCount: options.withCount,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
spinner.stop();
|
|
35
|
+
formatter.output(data);
|
|
36
|
+
} catch (error: any) {
|
|
37
|
+
spinner.stop();
|
|
38
|
+
formatter.error(error.message);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
cmd
|
|
45
|
+
.command('create <list-id>')
|
|
46
|
+
.description('Create an Interest')
|
|
47
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
48
|
+
.requiredOption('--name <value>', 'name')
|
|
49
|
+
.option('--alias <value>', 'alias')
|
|
50
|
+
.action(async (list_id, options) => {
|
|
51
|
+
const spinner = createSpinner('Creating interest...').start();
|
|
52
|
+
try {
|
|
53
|
+
const data = await client.createInterest({
|
|
54
|
+
list_id: Number(list_id),
|
|
55
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
56
|
+
name: options.name,
|
|
57
|
+
alias: options.alias,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
spinner.stop();
|
|
61
|
+
formatter.success('Interest created successfully');
|
|
62
|
+
formatter.output(data);
|
|
63
|
+
} catch (error: any) {
|
|
64
|
+
spinner.stop();
|
|
65
|
+
formatter.error(error.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
cmd
|
|
72
|
+
.command('get <list-id> <interest-name>')
|
|
73
|
+
.description('Get an Interest')
|
|
74
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
75
|
+
.action(async (list_id, interest_name, options) => {
|
|
76
|
+
const spinner = createSpinner('Fetching interest...').start();
|
|
77
|
+
try {
|
|
78
|
+
const data = await client.getInterest({
|
|
79
|
+
list_id: Number(list_id),
|
|
80
|
+
interest_name,
|
|
81
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
spinner.stop();
|
|
85
|
+
formatter.output(data);
|
|
86
|
+
} catch (error: any) {
|
|
87
|
+
spinner.stop();
|
|
88
|
+
formatter.error(error.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
cmd
|
|
95
|
+
.command('patch <list-id> <interest-name>')
|
|
96
|
+
.description('Update an Interest')
|
|
97
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
98
|
+
.option('--name <value>', 'name')
|
|
99
|
+
.option('--alias <value>', 'alias')
|
|
100
|
+
.action(async (list_id, interest_name, options) => {
|
|
101
|
+
const spinner = createSpinner('Updating interest...').start();
|
|
102
|
+
try {
|
|
103
|
+
const data = await client.patchInterest({
|
|
104
|
+
list_id: Number(list_id),
|
|
105
|
+
interest_name,
|
|
106
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
107
|
+
name: options.name,
|
|
108
|
+
alias: options.alias,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
spinner.stop();
|
|
112
|
+
formatter.success('Interest updated successfully');
|
|
113
|
+
formatter.output(data);
|
|
114
|
+
} catch (error: any) {
|
|
115
|
+
spinner.stop();
|
|
116
|
+
formatter.error(error.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
cmd
|
|
123
|
+
.command('delete <list-id> <interest-name>')
|
|
124
|
+
.description('Delete an Interest')
|
|
125
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
126
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
127
|
+
.action(async (list_id, interest_name, options) => {
|
|
128
|
+
if (!options.force) {
|
|
129
|
+
const confirmed = await confirmDelete('interest', list_id);
|
|
130
|
+
if (!confirmed) {
|
|
131
|
+
formatter.info('Deletion cancelled');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const spinner = createSpinner('Deleting interest...').start();
|
|
137
|
+
try {
|
|
138
|
+
const data = await client.deleteInterest({
|
|
139
|
+
list_id: Number(list_id),
|
|
140
|
+
interest_name,
|
|
141
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
spinner.stop();
|
|
145
|
+
formatter.success('Interest deleted successfully');
|
|
146
|
+
} catch (error: any) {
|
|
147
|
+
spinner.stop();
|
|
148
|
+
formatter.error(error.message);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
return cmd;
|
|
155
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Links.
|
|
2
|
+
// ABOUTME: Generated by api-kit from the OpenAPI spec.
|
|
3
|
+
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
+
|
|
7
|
+
export function createLinksCommand(
|
|
8
|
+
client: any,
|
|
9
|
+
formatter: any
|
|
10
|
+
): Command {
|
|
11
|
+
const cmd = new Command('links')
|
|
12
|
+
.description('Retrieve link information from campaigns, including tracked URLs.');
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
cmd
|
|
16
|
+
.command('get <link-id>')
|
|
17
|
+
.description('Show a link information')
|
|
18
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
19
|
+
.action(async (link_id, options) => {
|
|
20
|
+
const spinner = createSpinner('Fetching links...').start();
|
|
21
|
+
try {
|
|
22
|
+
const data = await client.getLink({
|
|
23
|
+
link_id: Number(link_id),
|
|
24
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
spinner.stop();
|
|
28
|
+
formatter.output(data);
|
|
29
|
+
} catch (error: any) {
|
|
30
|
+
spinner.stop();
|
|
31
|
+
formatter.error(error.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
return cmd;
|
|
38
|
+
}
|