@cakemail-org/cakemail-cli 1.7.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 +41 -37
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/client.js +1 -1
- 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.js +1 -1
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/contacts.js +1 -1
- 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.js +1 -1
- package/dist/commands/interests.js.map +1 -1
- package/dist/commands/lists.js +1 -1
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.js +1 -1
- package/dist/commands/logs.js.map +1 -1
- 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.js +1 -1
- 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.js +1 -1
- package/dist/commands/tags.js.map +1 -1
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.js +1 -1
- package/dist/commands/transactional-templates.js.map +1 -1
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/config.js +2 -2
- 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/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 -61
- 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,234 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Suppressed Email.
|
|
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 createSuppressedEmailsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('suppressed-emails')
|
|
13
|
+
.description('Manage the account-level email suppression list. Suppressed emails are blocked from receiving any messages. Includes export functionality for bulk data extraction.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('list-suppressed-emails')
|
|
18
|
+
.description('Show all suppressed emails')
|
|
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('--filter <value>', 'Valid Terms:
|
|
24
|
+
- `email`
|
|
25
|
+
|
|
26
|
+
Valid Operators:
|
|
27
|
+
- `==`
|
|
28
|
+
|
|
29
|
+
Query separator:
|
|
30
|
+
- `;`')
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
const spinner = createSpinner('Fetching suppressed email...').start();
|
|
33
|
+
try {
|
|
34
|
+
const data = await client.listSuppressedEmails({
|
|
35
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
36
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
37
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
38
|
+
withCount: options.withCount,
|
|
39
|
+
filter: options.filter,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
spinner.stop();
|
|
43
|
+
formatter.output(data);
|
|
44
|
+
} catch (error: any) {
|
|
45
|
+
spinner.stop();
|
|
46
|
+
formatter.error(error.message);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
cmd
|
|
53
|
+
.command('create-suppressed-email')
|
|
54
|
+
.description('Add a suppressed email')
|
|
55
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
56
|
+
.requiredOption('--email <value>', 'Full email, a local part wildcard or a domain wildcard. Examples: *@hotmail.com, john@*, john@hotmail.com')
|
|
57
|
+
.action(async (options) => {
|
|
58
|
+
const spinner = createSpinner('Creating suppressed email...').start();
|
|
59
|
+
try {
|
|
60
|
+
const data = await client.createSuppressedEmail({
|
|
61
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
62
|
+
email: options.email,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
spinner.stop();
|
|
66
|
+
formatter.success('Suppressed Email created successfully');
|
|
67
|
+
formatter.output(data);
|
|
68
|
+
} catch (error: any) {
|
|
69
|
+
spinner.stop();
|
|
70
|
+
formatter.error(error.message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
cmd
|
|
77
|
+
.command('delete-suppressed-email <email>')
|
|
78
|
+
.description('Delete a suppressed email')
|
|
79
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
80
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
81
|
+
.action(async (email, options) => {
|
|
82
|
+
if (!options.force) {
|
|
83
|
+
const confirmed = await confirmDelete('suppressed email', email);
|
|
84
|
+
if (!confirmed) {
|
|
85
|
+
formatter.info('Deletion cancelled');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const spinner = createSpinner('Deleting suppressed email...').start();
|
|
91
|
+
try {
|
|
92
|
+
const data = await client.deleteSuppressedEmail({
|
|
93
|
+
email,
|
|
94
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
spinner.stop();
|
|
98
|
+
formatter.success('Suppressed Email deleted successfully');
|
|
99
|
+
} catch (error: any) {
|
|
100
|
+
spinner.stop();
|
|
101
|
+
formatter.error(error.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
cmd
|
|
108
|
+
.command('list-suppressed-emails-export')
|
|
109
|
+
.description('Show all Suppressed Emails Export')
|
|
110
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
111
|
+
.option('--page <value>', 'page')
|
|
112
|
+
.option('--per-page <value>', 'per_page')
|
|
113
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
114
|
+
.action(async (options) => {
|
|
115
|
+
const spinner = createSpinner('Fetching suppressed email...').start();
|
|
116
|
+
try {
|
|
117
|
+
const data = await client.listSuppressedEmailsExport({
|
|
118
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
119
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
120
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
121
|
+
withCount: options.withCount,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
spinner.stop();
|
|
125
|
+
formatter.output(data);
|
|
126
|
+
} catch (error: any) {
|
|
127
|
+
spinner.stop();
|
|
128
|
+
formatter.error(error.message);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
cmd
|
|
135
|
+
.command('create-suppressed-emails-export')
|
|
136
|
+
.description('Create a Suppressed Emails Export')
|
|
137
|
+
.option('--description <value>', 'description')
|
|
138
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
139
|
+
.action(async (options) => {
|
|
140
|
+
const spinner = createSpinner('Creating suppressed email...').start();
|
|
141
|
+
try {
|
|
142
|
+
const data = await client.createSuppressedEmailsExport({
|
|
143
|
+
description: options.description,
|
|
144
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
spinner.stop();
|
|
148
|
+
formatter.success('Suppressed Email created successfully');
|
|
149
|
+
formatter.output(data);
|
|
150
|
+
} catch (error: any) {
|
|
151
|
+
spinner.stop();
|
|
152
|
+
formatter.error(error.message);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
cmd
|
|
159
|
+
.command('get-suppressed-emails-export <export-id>')
|
|
160
|
+
.description('Show a Suppressed Emails Export')
|
|
161
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
162
|
+
.action(async (export_id, options) => {
|
|
163
|
+
const spinner = createSpinner('Fetching suppressed email...').start();
|
|
164
|
+
try {
|
|
165
|
+
const data = await client.getSuppressedEmailsExport({
|
|
166
|
+
export_id,
|
|
167
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
168
|
+
});
|
|
169
|
+
|
|
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
|
+
|
|
180
|
+
cmd
|
|
181
|
+
.command('delete-suppressed-emails-export <export-id>')
|
|
182
|
+
.description('Delete a Suppressed Emails Export')
|
|
183
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
184
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
185
|
+
.action(async (export_id, options) => {
|
|
186
|
+
if (!options.force) {
|
|
187
|
+
const confirmed = await confirmDelete('suppressed email', export_id);
|
|
188
|
+
if (!confirmed) {
|
|
189
|
+
formatter.info('Deletion cancelled');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const spinner = createSpinner('Deleting suppressed email...').start();
|
|
195
|
+
try {
|
|
196
|
+
const data = await client.deleteSuppressedEmailsExport({
|
|
197
|
+
export_id,
|
|
198
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
spinner.stop();
|
|
202
|
+
formatter.success('Suppressed Email deleted successfully');
|
|
203
|
+
} catch (error: any) {
|
|
204
|
+
spinner.stop();
|
|
205
|
+
formatter.error(error.message);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
cmd
|
|
212
|
+
.command('suppressed-emails-export-download <export-id>')
|
|
213
|
+
.description('Download a suppressed emails export')
|
|
214
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
215
|
+
.action(async (export_id, options) => {
|
|
216
|
+
const spinner = createSpinner('Fetching suppressed email...').start();
|
|
217
|
+
try {
|
|
218
|
+
const data = await client.suppressedEmailsExportDownload({
|
|
219
|
+
export_id,
|
|
220
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
spinner.stop();
|
|
224
|
+
formatter.output(data);
|
|
225
|
+
} catch (error: any) {
|
|
226
|
+
spinner.stop();
|
|
227
|
+
formatter.error(error.message);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
return cmd;
|
|
234
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
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 { confirmDelete } from '../utils/confirm.js';
|
|
6
|
+
|
|
7
|
+
export function createSuppressedCommand(client: CakemailClient, formatter: OutputFormatter): Command {
|
|
8
|
+
const suppressed = new Command('suppressed')
|
|
9
|
+
.description('Manage suppressed email addresses');
|
|
10
|
+
|
|
11
|
+
// List suppressed emails
|
|
12
|
+
suppressed
|
|
13
|
+
.command('list')
|
|
14
|
+
.description('List all suppressed email addresses')
|
|
15
|
+
.option('-l, --limit <number>', 'Limit number of results')
|
|
16
|
+
.option('-p, --page <number>', 'Page number')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const spinner = ora('Fetching suppressed emails...').start();
|
|
19
|
+
try {
|
|
20
|
+
const params: any = {};
|
|
21
|
+
if (options.limit) params.per_page = parseInt(options.limit);
|
|
22
|
+
if (options.page) params.page = parseInt(options.page);
|
|
23
|
+
|
|
24
|
+
const data = await client.sdk.suppressedEmailService.listSuppressedEmails(params);
|
|
25
|
+
spinner.stop();
|
|
26
|
+
formatter.output(data);
|
|
27
|
+
} catch (error: any) {
|
|
28
|
+
spinner.stop();
|
|
29
|
+
formatter.error(error.message);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Add suppressed email
|
|
35
|
+
suppressed
|
|
36
|
+
.command('add <email>')
|
|
37
|
+
.description('Add an email to the suppression list')
|
|
38
|
+
.action(async (email) => {
|
|
39
|
+
const spinner = ora(`Adding ${email} to suppression list...`).start();
|
|
40
|
+
try {
|
|
41
|
+
const data = await client.sdk.suppressedEmailService.createSuppressedEmail({
|
|
42
|
+
requestBody: { email }
|
|
43
|
+
});
|
|
44
|
+
spinner.stop();
|
|
45
|
+
formatter.success(`Email ${email} added to suppression list`);
|
|
46
|
+
formatter.output(data);
|
|
47
|
+
} catch (error: any) {
|
|
48
|
+
spinner.stop();
|
|
49
|
+
formatter.error(error.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Delete suppressed email
|
|
55
|
+
suppressed
|
|
56
|
+
.command('delete <email>')
|
|
57
|
+
.description('Remove an email from the suppression list')
|
|
58
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
59
|
+
.action(async (email, options) => {
|
|
60
|
+
// Interactive confirmation (unless --force is used)
|
|
61
|
+
if (!options.force) {
|
|
62
|
+
const confirmed = await confirmDelete('suppressed email', email, [
|
|
63
|
+
'Email will be removed from the suppression list',
|
|
64
|
+
'This email address will be able to receive emails again'
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
if (!confirmed) {
|
|
68
|
+
formatter.info('Deletion cancelled');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const spinner = ora(`Removing ${email} from suppression list...`).start();
|
|
74
|
+
try {
|
|
75
|
+
await client.sdk.suppressedEmailService.deleteSuppressedEmail({ email });
|
|
76
|
+
spinner.stop();
|
|
77
|
+
formatter.success(`Email ${email} removed from suppression list`);
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
spinner.stop();
|
|
80
|
+
formatter.error(error.message);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// List suppressed emails exports
|
|
86
|
+
suppressed
|
|
87
|
+
.command('exports')
|
|
88
|
+
.description('List suppressed emails exports')
|
|
89
|
+
.option('-l, --limit <number>', 'Limit number of results')
|
|
90
|
+
.option('-p, --page <number>', 'Page number')
|
|
91
|
+
.action(async (options) => {
|
|
92
|
+
const spinner = ora('Fetching exports...').start();
|
|
93
|
+
try {
|
|
94
|
+
const params: any = {};
|
|
95
|
+
if (options.limit) params.per_page = parseInt(options.limit);
|
|
96
|
+
if (options.page) params.page = parseInt(options.page);
|
|
97
|
+
|
|
98
|
+
const data = await client.sdk.suppressedEmailService.listSuppressedEmailsExport(params);
|
|
99
|
+
spinner.stop();
|
|
100
|
+
formatter.output(data);
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
spinner.stop();
|
|
103
|
+
formatter.error(error.message);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Create export
|
|
109
|
+
suppressed
|
|
110
|
+
.command('export')
|
|
111
|
+
.description('Create a suppressed emails export')
|
|
112
|
+
.action(async () => {
|
|
113
|
+
const spinner = ora('Creating suppressed emails export...').start();
|
|
114
|
+
try {
|
|
115
|
+
const data = await client.sdk.suppressedEmailService.createSuppressedEmailsExport({});
|
|
116
|
+
spinner.stop();
|
|
117
|
+
formatter.success('Suppressed emails export created');
|
|
118
|
+
formatter.output(data);
|
|
119
|
+
} catch (error: any) {
|
|
120
|
+
spinner.stop();
|
|
121
|
+
formatter.error(error.message);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Get export
|
|
127
|
+
suppressed
|
|
128
|
+
.command('export-get <export-id>')
|
|
129
|
+
.description('Get a suppressed emails export status')
|
|
130
|
+
.action(async (exportId) => {
|
|
131
|
+
const spinner = ora(`Fetching export ${exportId}...`).start();
|
|
132
|
+
try {
|
|
133
|
+
const data = await client.sdk.suppressedEmailService.getSuppressedEmailsExport({
|
|
134
|
+
exportId: exportId
|
|
135
|
+
});
|
|
136
|
+
spinner.stop();
|
|
137
|
+
formatter.output(data);
|
|
138
|
+
} catch (error: any) {
|
|
139
|
+
spinner.stop();
|
|
140
|
+
formatter.error(error.message);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Download export
|
|
146
|
+
suppressed
|
|
147
|
+
.command('export-download <export-id>')
|
|
148
|
+
.description('Download a suppressed emails export')
|
|
149
|
+
.action(async (exportId) => {
|
|
150
|
+
const spinner = ora(`Downloading export ${exportId}...`).start();
|
|
151
|
+
try {
|
|
152
|
+
const data = await client.sdk.suppressedEmailService.suppressedEmailsExportDownload({
|
|
153
|
+
exportId: exportId
|
|
154
|
+
});
|
|
155
|
+
spinner.stop();
|
|
156
|
+
formatter.success('Export downloaded');
|
|
157
|
+
formatter.output(data);
|
|
158
|
+
} catch (error: any) {
|
|
159
|
+
spinner.stop();
|
|
160
|
+
formatter.error(error.message);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Delete export
|
|
166
|
+
suppressed
|
|
167
|
+
.command('export-delete <export-id>')
|
|
168
|
+
.description('Delete a suppressed emails export')
|
|
169
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
170
|
+
.action(async (exportId, options) => {
|
|
171
|
+
// Interactive confirmation (unless --force is used)
|
|
172
|
+
if (!options.force) {
|
|
173
|
+
const confirmed = await confirmDelete('suppressed emails export', exportId, [
|
|
174
|
+
'Export file will be permanently deleted'
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
if (!confirmed) {
|
|
178
|
+
formatter.info('Deletion cancelled');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const spinner = ora(`Deleting export ${exportId}...`).start();
|
|
184
|
+
try {
|
|
185
|
+
await client.sdk.suppressedEmailService.deleteSuppressedEmailsExport({
|
|
186
|
+
exportId: exportId
|
|
187
|
+
});
|
|
188
|
+
spinner.stop();
|
|
189
|
+
formatter.success(`Export ${exportId} deleted`);
|
|
190
|
+
} catch (error: any) {
|
|
191
|
+
spinner.stop();
|
|
192
|
+
formatter.error(error.message);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return suppressed;
|
|
198
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for System Email.
|
|
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 createSystemEmailsCommand(
|
|
8
|
+
client: any,
|
|
9
|
+
formatter: any
|
|
10
|
+
): Command {
|
|
11
|
+
const cmd = new Command('system-emails')
|
|
12
|
+
.description('Configure system-generated emails such as double opt-in confirmations, welcome messages, and unsubscribe confirmations. System emails can be customized per language.');
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
cmd
|
|
16
|
+
.command('show-system-emails')
|
|
17
|
+
.description('Show system emails configuration')
|
|
18
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
const spinner = createSpinner('Fetching system email...').start();
|
|
21
|
+
try {
|
|
22
|
+
const data = await client.showSystemEmails({
|
|
23
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
spinner.stop();
|
|
27
|
+
formatter.output(data);
|
|
28
|
+
} catch (error: any) {
|
|
29
|
+
spinner.stop();
|
|
30
|
+
formatter.error(error.message);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
cmd
|
|
37
|
+
.command('set-system-emails')
|
|
38
|
+
.description('Set system emails configuration')
|
|
39
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
40
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
41
|
+
.action(async (options) => {
|
|
42
|
+
const spinner = createSpinner('Updating system email...').start();
|
|
43
|
+
try {
|
|
44
|
+
const body = JSON.parse(options.data);
|
|
45
|
+
const data = await client.setSystemEmails({
|
|
46
|
+
...body,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
spinner.stop();
|
|
50
|
+
formatter.success('System Email updated successfully');
|
|
51
|
+
formatter.output(data);
|
|
52
|
+
} catch (error: any) {
|
|
53
|
+
spinner.stop();
|
|
54
|
+
formatter.error(error.message);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
cmd
|
|
61
|
+
.command('patch-system-emails')
|
|
62
|
+
.description('Update system emails configuration')
|
|
63
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
64
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
65
|
+
.action(async (options) => {
|
|
66
|
+
const spinner = createSpinner('Updating system email...').start();
|
|
67
|
+
try {
|
|
68
|
+
const body = JSON.parse(options.data);
|
|
69
|
+
const data = await client.patchSystemEmails({
|
|
70
|
+
...body,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
spinner.stop();
|
|
74
|
+
formatter.success('System Email updated successfully');
|
|
75
|
+
formatter.output(data);
|
|
76
|
+
} catch (error: any) {
|
|
77
|
+
spinner.stop();
|
|
78
|
+
formatter.error(error.message);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
return cmd;
|
|
85
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Tags.
|
|
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 createTagsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('tags')
|
|
13
|
+
.description('Manage contact tags for flexible organization and segmentation. Tags are simple labels that can be attached to contacts for grouping and filtering.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('show <tag>')
|
|
18
|
+
.description('Show a Contact Tag')
|
|
19
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
20
|
+
.action(async (tag, options) => {
|
|
21
|
+
const spinner = createSpinner('Fetching tags...').start();
|
|
22
|
+
try {
|
|
23
|
+
const data = await client.showTag({
|
|
24
|
+
tag,
|
|
25
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
spinner.stop();
|
|
29
|
+
formatter.output(data);
|
|
30
|
+
} catch (error: any) {
|
|
31
|
+
spinner.stop();
|
|
32
|
+
formatter.error(error.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
cmd
|
|
39
|
+
.command('patch <tag>')
|
|
40
|
+
.description('Edit a Contact Tag')
|
|
41
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
42
|
+
.requiredOption('--tag <value>', 'tag')
|
|
43
|
+
.action(async (tag, options) => {
|
|
44
|
+
const spinner = createSpinner('Updating tags...').start();
|
|
45
|
+
try {
|
|
46
|
+
const data = await client.patchTag({
|
|
47
|
+
tag,
|
|
48
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
49
|
+
tag: options.tag,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
spinner.stop();
|
|
53
|
+
formatter.success('Tags updated successfully');
|
|
54
|
+
formatter.output(data);
|
|
55
|
+
} catch (error: any) {
|
|
56
|
+
spinner.stop();
|
|
57
|
+
formatter.error(error.message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
cmd
|
|
64
|
+
.command('delete <tag>')
|
|
65
|
+
.description('Delete a Contact Tag')
|
|
66
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
67
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
68
|
+
.action(async (tag, options) => {
|
|
69
|
+
if (!options.force) {
|
|
70
|
+
const confirmed = await confirmDelete('tags', tag);
|
|
71
|
+
if (!confirmed) {
|
|
72
|
+
formatter.info('Deletion cancelled');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const spinner = createSpinner('Deleting tags...').start();
|
|
78
|
+
try {
|
|
79
|
+
const data = await client.deleteTag({
|
|
80
|
+
tag,
|
|
81
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
spinner.stop();
|
|
85
|
+
formatter.success('Tags deleted successfully');
|
|
86
|
+
} catch (error: any) {
|
|
87
|
+
spinner.stop();
|
|
88
|
+
formatter.error(error.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
cmd
|
|
95
|
+
.command('list')
|
|
96
|
+
.description('List Contact Tags')
|
|
97
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
98
|
+
.option('--page <value>', 'page')
|
|
99
|
+
.option('--per-page <value>', 'per_page')
|
|
100
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
101
|
+
.action(async (options) => {
|
|
102
|
+
const spinner = createSpinner('Fetching tags...').start();
|
|
103
|
+
try {
|
|
104
|
+
const data = await client.listTags({
|
|
105
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
106
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
107
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
108
|
+
withCount: options.withCount,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
spinner.stop();
|
|
112
|
+
formatter.output(data);
|
|
113
|
+
} catch (error: any) {
|
|
114
|
+
spinner.stop();
|
|
115
|
+
formatter.error(error.message);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
cmd
|
|
122
|
+
.command('create')
|
|
123
|
+
.description('Create a Contact Tag')
|
|
124
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
125
|
+
.requiredOption('--tag <value>', 'tag')
|
|
126
|
+
.action(async (options) => {
|
|
127
|
+
const spinner = createSpinner('Creating tags...').start();
|
|
128
|
+
try {
|
|
129
|
+
const data = await client.createTag({
|
|
130
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
131
|
+
tag: options.tag,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
spinner.stop();
|
|
135
|
+
formatter.success('Tags created successfully');
|
|
136
|
+
formatter.output(data);
|
|
137
|
+
} catch (error: any) {
|
|
138
|
+
spinner.stop();
|
|
139
|
+
formatter.error(error.message);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
return cmd;
|
|
146
|
+
}
|