@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,469 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Campaign.
|
|
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 createCampaignsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('campaigns')
|
|
13
|
+
.description('Create and manage email campaigns. A campaign combines content (from a template or custom HTML), an audience (a list or segment), and a sender identity. Campaigns go through a lifecycle: incomplete → scheduled → delivering → delivered. They can also be active (ready to schedule), suspended, resumed, canceled, archived, or deleted. Send test emails before scheduling to preview the final result.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('list')
|
|
18
|
+
.description('Show all campaigns')
|
|
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
|
+
- `status`
|
|
25
|
+
- `name`
|
|
26
|
+
- `type`
|
|
27
|
+
- `list_id`
|
|
28
|
+
|
|
29
|
+
Valid Operators:
|
|
30
|
+
- `==`
|
|
31
|
+
|
|
32
|
+
Query separator:
|
|
33
|
+
- `;`')
|
|
34
|
+
.option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
|
|
35
|
+
|
|
36
|
+
Valid terms:
|
|
37
|
+
- `name`
|
|
38
|
+
- `created_on`
|
|
39
|
+
- `scheduled_for`
|
|
40
|
+
- `scheduled_on`
|
|
41
|
+
- `updated_on`
|
|
42
|
+
- `type`')
|
|
43
|
+
.action(async (options) => {
|
|
44
|
+
const spinner = createSpinner('Fetching campaign...').start();
|
|
45
|
+
try {
|
|
46
|
+
const data = await client.listCampaigns({
|
|
47
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
48
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
49
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
50
|
+
withCount: options.withCount,
|
|
51
|
+
filter: options.filter,
|
|
52
|
+
sort: options.sort,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
spinner.stop();
|
|
56
|
+
formatter.output(data);
|
|
57
|
+
} catch (error: any) {
|
|
58
|
+
spinner.stop();
|
|
59
|
+
formatter.error(error.message);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
cmd
|
|
66
|
+
.command('create')
|
|
67
|
+
.description('Create a campaign')
|
|
68
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
69
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
72
|
+
try {
|
|
73
|
+
const body = JSON.parse(options.data);
|
|
74
|
+
const data = await client.createCampaign({
|
|
75
|
+
...body,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
spinner.stop();
|
|
79
|
+
formatter.success('Campaign created successfully');
|
|
80
|
+
formatter.output(data);
|
|
81
|
+
} catch (error: any) {
|
|
82
|
+
spinner.stop();
|
|
83
|
+
formatter.error(error.message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
cmd
|
|
90
|
+
.command('get <campaign-id>')
|
|
91
|
+
.description('Show a campaign details')
|
|
92
|
+
.option('--revision-id <value>', 'revision_id')
|
|
93
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
94
|
+
.action(async (campaign_id, options) => {
|
|
95
|
+
const spinner = createSpinner('Fetching campaign...').start();
|
|
96
|
+
try {
|
|
97
|
+
const data = await client.getCampaign({
|
|
98
|
+
campaign_id: Number(campaign_id),
|
|
99
|
+
revisionId: options.revisionId != null ? Number(options.revisionId) : undefined,
|
|
100
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
spinner.stop();
|
|
104
|
+
formatter.output(data);
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
spinner.stop();
|
|
107
|
+
formatter.error(error.message);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
cmd
|
|
114
|
+
.command('patch <campaign-id>')
|
|
115
|
+
.description('Update a campaign')
|
|
116
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
117
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
118
|
+
.action(async (campaign_id, options) => {
|
|
119
|
+
const spinner = createSpinner('Updating campaign...').start();
|
|
120
|
+
try {
|
|
121
|
+
const body = JSON.parse(options.data);
|
|
122
|
+
const data = await client.patchCampaign({
|
|
123
|
+
campaign_id: Number(campaign_id),
|
|
124
|
+
...body,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
spinner.stop();
|
|
128
|
+
formatter.success('Campaign updated successfully');
|
|
129
|
+
formatter.output(data);
|
|
130
|
+
} catch (error: any) {
|
|
131
|
+
spinner.stop();
|
|
132
|
+
formatter.error(error.message);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
cmd
|
|
139
|
+
.command('delete <campaign-id>')
|
|
140
|
+
.description('Delete a campaign')
|
|
141
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
142
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
143
|
+
.action(async (campaign_id, options) => {
|
|
144
|
+
if (!options.force) {
|
|
145
|
+
const confirmed = await confirmDelete('campaign', campaign_id);
|
|
146
|
+
if (!confirmed) {
|
|
147
|
+
formatter.info('Deletion cancelled');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const spinner = createSpinner('Deleting campaign...').start();
|
|
153
|
+
try {
|
|
154
|
+
const data = await client.deleteCampaign({
|
|
155
|
+
campaign_id: Number(campaign_id),
|
|
156
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
spinner.stop();
|
|
160
|
+
formatter.success('Campaign deleted successfully');
|
|
161
|
+
} catch (error: any) {
|
|
162
|
+
spinner.stop();
|
|
163
|
+
formatter.error(error.message);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
cmd
|
|
170
|
+
.command('render <campaign-id>')
|
|
171
|
+
.description('Render a campaign')
|
|
172
|
+
.option('--contact-id <value>', 'contact_id')
|
|
173
|
+
.option('--account-id <value>', 'account_id')
|
|
174
|
+
.action(async (campaign_id, options) => {
|
|
175
|
+
const spinner = createSpinner('Fetching campaign...').start();
|
|
176
|
+
try {
|
|
177
|
+
const data = await client.renderCampaign({
|
|
178
|
+
campaign_id: Number(campaign_id),
|
|
179
|
+
contactId: options.contactId != null ? Number(options.contactId) : undefined,
|
|
180
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
spinner.stop();
|
|
184
|
+
formatter.output(data);
|
|
185
|
+
} catch (error: any) {
|
|
186
|
+
spinner.stop();
|
|
187
|
+
formatter.error(error.message);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
cmd
|
|
194
|
+
.command('send-test-email <campaign-id>')
|
|
195
|
+
.description('Send a test email')
|
|
196
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
197
|
+
.requiredOption('--email <value>', 'email')
|
|
198
|
+
.option('--type <value>', 'type')
|
|
199
|
+
.action(async (campaign_id, options) => {
|
|
200
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
201
|
+
try {
|
|
202
|
+
const data = await client.sendTestEmail({
|
|
203
|
+
campaign_id: Number(campaign_id),
|
|
204
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
205
|
+
email: options.email,
|
|
206
|
+
type: options.type,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
spinner.stop();
|
|
210
|
+
formatter.success('Campaign created successfully');
|
|
211
|
+
formatter.output(data);
|
|
212
|
+
} catch (error: any) {
|
|
213
|
+
spinner.stop();
|
|
214
|
+
formatter.error(error.message);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
cmd
|
|
221
|
+
.command('schedule <campaign-id>')
|
|
222
|
+
.description('Schedule a campaign')
|
|
223
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
224
|
+
.option('--date <value>', 'A UNIX timestamp in the future')
|
|
225
|
+
.option('--html-empty <value>', 'Required to be true if the html message is empty')
|
|
226
|
+
.action(async (campaign_id, options) => {
|
|
227
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
228
|
+
try {
|
|
229
|
+
const data = await client.scheduleCampaign({
|
|
230
|
+
campaign_id: Number(campaign_id),
|
|
231
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
232
|
+
date: options.date != null ? Number(options.date) : undefined,
|
|
233
|
+
htmlEmpty: options.htmlEmpty,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
spinner.stop();
|
|
237
|
+
formatter.success('Campaign created successfully');
|
|
238
|
+
formatter.output(data);
|
|
239
|
+
} catch (error: any) {
|
|
240
|
+
spinner.stop();
|
|
241
|
+
formatter.error(error.message);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
cmd
|
|
248
|
+
.command('unschedule <campaign-id>')
|
|
249
|
+
.description('Unschedule a campaign')
|
|
250
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
251
|
+
.action(async (campaign_id, options) => {
|
|
252
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
253
|
+
try {
|
|
254
|
+
const data = await client.unscheduleCampaign({
|
|
255
|
+
campaign_id: Number(campaign_id),
|
|
256
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
spinner.stop();
|
|
260
|
+
formatter.success('Campaign created successfully');
|
|
261
|
+
formatter.output(data);
|
|
262
|
+
} catch (error: any) {
|
|
263
|
+
spinner.stop();
|
|
264
|
+
formatter.error(error.message);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
cmd
|
|
271
|
+
.command('reschedule <campaign-id>')
|
|
272
|
+
.description('Reschedule a campaign')
|
|
273
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
274
|
+
.option('--date <value>', 'A UNIX timestamp in the future')
|
|
275
|
+
.option('--html-empty <value>', 'Required to be true if the html message is empty')
|
|
276
|
+
.action(async (campaign_id, options) => {
|
|
277
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
278
|
+
try {
|
|
279
|
+
const data = await client.rescheduleCampaign({
|
|
280
|
+
campaign_id: Number(campaign_id),
|
|
281
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
282
|
+
date: options.date != null ? Number(options.date) : undefined,
|
|
283
|
+
htmlEmpty: options.htmlEmpty,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
spinner.stop();
|
|
287
|
+
formatter.success('Campaign created successfully');
|
|
288
|
+
formatter.output(data);
|
|
289
|
+
} catch (error: any) {
|
|
290
|
+
spinner.stop();
|
|
291
|
+
formatter.error(error.message);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
cmd
|
|
298
|
+
.command('suspend <campaign-id>')
|
|
299
|
+
.description('Suspend a campaign')
|
|
300
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
301
|
+
.action(async (campaign_id, options) => {
|
|
302
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
303
|
+
try {
|
|
304
|
+
const data = await client.suspendCampaign({
|
|
305
|
+
campaign_id: Number(campaign_id),
|
|
306
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
spinner.stop();
|
|
310
|
+
formatter.success('Campaign created successfully');
|
|
311
|
+
formatter.output(data);
|
|
312
|
+
} catch (error: any) {
|
|
313
|
+
spinner.stop();
|
|
314
|
+
formatter.error(error.message);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
cmd
|
|
321
|
+
.command('resume <campaign-id>')
|
|
322
|
+
.description('Resume a campaign')
|
|
323
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
324
|
+
.action(async (campaign_id, options) => {
|
|
325
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
326
|
+
try {
|
|
327
|
+
const data = await client.resumeCampaign({
|
|
328
|
+
campaign_id: Number(campaign_id),
|
|
329
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
spinner.stop();
|
|
333
|
+
formatter.success('Campaign created successfully');
|
|
334
|
+
formatter.output(data);
|
|
335
|
+
} catch (error: any) {
|
|
336
|
+
spinner.stop();
|
|
337
|
+
formatter.error(error.message);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
cmd
|
|
344
|
+
.command('cancel <campaign-id>')
|
|
345
|
+
.description('Cancel a campaign')
|
|
346
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
347
|
+
.action(async (campaign_id, options) => {
|
|
348
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
349
|
+
try {
|
|
350
|
+
const data = await client.cancelCampaign({
|
|
351
|
+
campaign_id: Number(campaign_id),
|
|
352
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
spinner.stop();
|
|
356
|
+
formatter.success('Campaign created successfully');
|
|
357
|
+
formatter.output(data);
|
|
358
|
+
} catch (error: any) {
|
|
359
|
+
spinner.stop();
|
|
360
|
+
formatter.error(error.message);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
cmd
|
|
367
|
+
.command('archive <campaign-id>')
|
|
368
|
+
.description('Archive a campaign')
|
|
369
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
370
|
+
.action(async (campaign_id, options) => {
|
|
371
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
372
|
+
try {
|
|
373
|
+
const data = await client.archiveCampaign({
|
|
374
|
+
campaign_id: Number(campaign_id),
|
|
375
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
spinner.stop();
|
|
379
|
+
formatter.success('Campaign created successfully');
|
|
380
|
+
formatter.output(data);
|
|
381
|
+
} catch (error: any) {
|
|
382
|
+
spinner.stop();
|
|
383
|
+
formatter.error(error.message);
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
cmd
|
|
390
|
+
.command('unarchive <campaign-id>')
|
|
391
|
+
.description('Unarchive a campaign')
|
|
392
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
393
|
+
.action(async (campaign_id, options) => {
|
|
394
|
+
const spinner = createSpinner('Creating campaign...').start();
|
|
395
|
+
try {
|
|
396
|
+
const data = await client.unarchiveCampaign({
|
|
397
|
+
campaign_id: Number(campaign_id),
|
|
398
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
spinner.stop();
|
|
402
|
+
formatter.success('Campaign created successfully');
|
|
403
|
+
formatter.output(data);
|
|
404
|
+
} catch (error: any) {
|
|
405
|
+
spinner.stop();
|
|
406
|
+
formatter.error(error.message);
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
cmd
|
|
413
|
+
.command('get-campaign-revisions <campaign-id>')
|
|
414
|
+
.description('Show all campaign revisions')
|
|
415
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
416
|
+
.option('--page <value>', 'page')
|
|
417
|
+
.option('--per-page <value>', 'per_page')
|
|
418
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
419
|
+
.action(async (campaign_id, options) => {
|
|
420
|
+
const spinner = createSpinner('Fetching campaign...').start();
|
|
421
|
+
try {
|
|
422
|
+
const data = await client.getCampaignRevisions({
|
|
423
|
+
campaign_id: Number(campaign_id),
|
|
424
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
425
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
426
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
427
|
+
withCount: options.withCount,
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
spinner.stop();
|
|
431
|
+
formatter.output(data);
|
|
432
|
+
} catch (error: any) {
|
|
433
|
+
spinner.stop();
|
|
434
|
+
formatter.error(error.message);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
cmd
|
|
441
|
+
.command('list-links <campaign-id>')
|
|
442
|
+
.description('Show a campaign links')
|
|
443
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
444
|
+
.option('--page <value>', 'page')
|
|
445
|
+
.option('--per-page <value>', 'per_page')
|
|
446
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
447
|
+
.action(async (campaign_id, options) => {
|
|
448
|
+
const spinner = createSpinner('Fetching campaign...').start();
|
|
449
|
+
try {
|
|
450
|
+
const data = await client.listLinks({
|
|
451
|
+
campaign_id: Number(campaign_id),
|
|
452
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
453
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
454
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
455
|
+
withCount: options.withCount,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
spinner.stop();
|
|
459
|
+
formatter.output(data);
|
|
460
|
+
} catch (error: any) {
|
|
461
|
+
spinner.stop();
|
|
462
|
+
formatter.error(error.message);
|
|
463
|
+
process.exit(1);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
return cmd;
|
|
469
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// ABOUTME: Config management commands for the CLI.
|
|
2
|
+
// ABOUTME: Show, set, and manage profile and default settings.
|
|
3
|
+
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { loadConfigFile, updateConfigFile, setCurrentProfile, getCurrentProfile, getDefaults, setDefault } from '../utils/config-file.js';
|
|
6
|
+
import { getProfileConfig, type ProfileType } from '../types/profile.js';
|
|
7
|
+
|
|
8
|
+
export function createConfigCommand(): Command {
|
|
9
|
+
const cmd = new Command('config')
|
|
10
|
+
.description('Manage CLI configuration');
|
|
11
|
+
|
|
12
|
+
cmd
|
|
13
|
+
.command('show')
|
|
14
|
+
.description('Show current configuration')
|
|
15
|
+
.action(() => {
|
|
16
|
+
const config = loadConfigFile();
|
|
17
|
+
if (!config) {
|
|
18
|
+
console.log('No configuration file found. Using defaults.');
|
|
19
|
+
console.log(`Profile: ${getCurrentProfile()}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log(JSON.stringify(config, null, 2));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
cmd
|
|
26
|
+
.command('set <key> <value>')
|
|
27
|
+
.description('Set a configuration value')
|
|
28
|
+
.action((key: string, value: string) => {
|
|
29
|
+
if (key === 'profile') {
|
|
30
|
+
const valid: ProfileType[] = ['developer', 'marketer', 'balanced'];
|
|
31
|
+
if (!valid.includes(value as ProfileType)) {
|
|
32
|
+
console.error(`Invalid profile: ${value}. Valid: ${valid.join(', ')}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
setCurrentProfile(value as ProfileType);
|
|
36
|
+
console.log(`Profile set to: ${value}`);
|
|
37
|
+
} else if (key === 'default.list_id') {
|
|
38
|
+
setDefault('list_id', Number(value));
|
|
39
|
+
console.log(`Default list ID set to: ${value}`);
|
|
40
|
+
} else if (key === 'default.sender_id') {
|
|
41
|
+
setDefault('sender_id', Number(value));
|
|
42
|
+
console.log(`Default sender ID set to: ${value}`);
|
|
43
|
+
} else if (key === 'default.account_id') {
|
|
44
|
+
setDefault('account_id', Number(value));
|
|
45
|
+
console.log(`Default account ID set to: ${value}`);
|
|
46
|
+
} else {
|
|
47
|
+
console.error(`Unknown config key: ${key}`);
|
|
48
|
+
console.error('Valid keys: profile, default.list_id, default.sender_id, default.account_id');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
cmd
|
|
54
|
+
.command('profile [type]')
|
|
55
|
+
.description('Show or set the active profile')
|
|
56
|
+
.action((type?: string) => {
|
|
57
|
+
if (!type) {
|
|
58
|
+
const current = getCurrentProfile();
|
|
59
|
+
const config = getProfileConfig(current);
|
|
60
|
+
console.log(`Active profile: ${current}`);
|
|
61
|
+
console.log(` Output format: ${config.output.format}`);
|
|
62
|
+
console.log(` Colors: ${config.output.colors}`);
|
|
63
|
+
console.log(` Interactive: ${config.behavior.interactive_prompts}`);
|
|
64
|
+
console.log(` Date format: ${config.display.date_format}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const valid: ProfileType[] = ['developer', 'marketer', 'balanced'];
|
|
68
|
+
if (!valid.includes(type as ProfileType)) {
|
|
69
|
+
console.error(`Invalid profile: ${type}. Valid: ${valid.join(', ')}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
setCurrentProfile(type as ProfileType);
|
|
73
|
+
console.log(`Profile set to: ${type}`);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return cmd;
|
|
77
|
+
}
|