@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,385 @@
|
|
|
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 { displayError, validate } from '../utils/errors.js';
|
|
6
|
+
import { confirmDelete } from '../utils/confirm.js';
|
|
7
|
+
import { autoDetectList } from '../utils/defaults.js';
|
|
8
|
+
|
|
9
|
+
export function createTransactionalTemplatesCommand(
|
|
10
|
+
client: CakemailClient,
|
|
11
|
+
formatter: OutputFormatter
|
|
12
|
+
): Command {
|
|
13
|
+
const templates = new Command('transactional-templates')
|
|
14
|
+
.description('Manage transactional email templates');
|
|
15
|
+
|
|
16
|
+
// List transactional templates
|
|
17
|
+
templates
|
|
18
|
+
.command('list [list-id]')
|
|
19
|
+
.description('List transactional email templates (auto-detects if only one list exists)')
|
|
20
|
+
.option('-p, --page <number>', 'Page number')
|
|
21
|
+
.option('--per-page <number>', 'Results per page')
|
|
22
|
+
.option('--with-count', 'Include total count')
|
|
23
|
+
.action(async (listId, options) => {
|
|
24
|
+
// Auto-detect list ID if not provided
|
|
25
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
26
|
+
|
|
27
|
+
if (!detectedListId) {
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const spinner = ora('Fetching transactional templates...').start();
|
|
32
|
+
try {
|
|
33
|
+
const params: any = {
|
|
34
|
+
listId: detectedListId
|
|
35
|
+
};
|
|
36
|
+
if (options.page) params.page = parseInt(options.page);
|
|
37
|
+
if (options.perPage) params.perPage = parseInt(options.perPage);
|
|
38
|
+
if (options.withCount) params.withCount = true;
|
|
39
|
+
|
|
40
|
+
const data = await client.sdk.transactionalEmailService.listTransactionalEmailTemplates(params);
|
|
41
|
+
spinner.stop();
|
|
42
|
+
formatter.output(data);
|
|
43
|
+
} catch (error: any) {
|
|
44
|
+
spinner.stop();
|
|
45
|
+
displayError(error, {
|
|
46
|
+
command: 'transactional-templates list',
|
|
47
|
+
operation: 'list templates'
|
|
48
|
+
});
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Show transactional template
|
|
54
|
+
templates
|
|
55
|
+
.command('show [list-id] <template-id>')
|
|
56
|
+
.description('Show transactional email template details (auto-detects if only one list exists)')
|
|
57
|
+
.action(async (listId, templateId) => {
|
|
58
|
+
// Auto-detect list ID if not provided
|
|
59
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
60
|
+
|
|
61
|
+
if (!detectedListId) {
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const spinner = ora(`Fetching template ${templateId}...`).start();
|
|
66
|
+
try {
|
|
67
|
+
const data = await client.sdk.transactionalEmailService.showTransactionalEmailTemplate({
|
|
68
|
+
listId: detectedListId,
|
|
69
|
+
transactionalEmailTemplateId: parseInt(templateId)
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
spinner.stop();
|
|
73
|
+
formatter.output(data);
|
|
74
|
+
} catch (error: any) {
|
|
75
|
+
spinner.stop();
|
|
76
|
+
displayError(error, {
|
|
77
|
+
command: 'transactional-templates show',
|
|
78
|
+
resource: 'template',
|
|
79
|
+
resourceId: templateId,
|
|
80
|
+
operation: 'fetch'
|
|
81
|
+
});
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Create transactional template
|
|
87
|
+
templates
|
|
88
|
+
.command('create [list-id]')
|
|
89
|
+
.description('Create a transactional email template (auto-detects if only one list exists)')
|
|
90
|
+
.requiredOption('-n, --name <name>', 'Template name')
|
|
91
|
+
.requiredOption('-s, --subject <subject>', 'Email subject')
|
|
92
|
+
.requiredOption('--html <html>', 'HTML content')
|
|
93
|
+
.option('--text <text>', 'Plain text content')
|
|
94
|
+
.option('--sender-id <id>', 'Sender ID')
|
|
95
|
+
.option('--tracking <tracking>', 'Tracking settings (open, click)')
|
|
96
|
+
.action(async (listId, options) => {
|
|
97
|
+
// Auto-detect list ID if not provided
|
|
98
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
99
|
+
|
|
100
|
+
if (!detectedListId) {
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const spinner = ora('Creating transactional template...').start();
|
|
105
|
+
try {
|
|
106
|
+
const payload: any = {
|
|
107
|
+
name: options.name,
|
|
108
|
+
subject: options.subject,
|
|
109
|
+
html: options.html
|
|
110
|
+
};
|
|
111
|
+
if (options.text) payload.text = options.text;
|
|
112
|
+
if (options.senderId) payload.sender_id = parseInt(options.senderId);
|
|
113
|
+
if (options.tracking) payload.tracking = options.tracking;
|
|
114
|
+
|
|
115
|
+
const data = await client.sdk.transactionalEmailService.createTransactionalEmailTemplate({
|
|
116
|
+
listId: detectedListId,
|
|
117
|
+
requestBody: payload
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
spinner.stop();
|
|
121
|
+
formatter.success('Transactional template created successfully');
|
|
122
|
+
formatter.output(data);
|
|
123
|
+
} catch (error: any) {
|
|
124
|
+
spinner.stop();
|
|
125
|
+
displayError(error, {
|
|
126
|
+
command: 'transactional-templates create',
|
|
127
|
+
operation: 'create template'
|
|
128
|
+
});
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Update transactional template
|
|
134
|
+
templates
|
|
135
|
+
.command('update [list-id] <template-id>')
|
|
136
|
+
.description('Update a transactional email template (auto-detects if only one list exists)')
|
|
137
|
+
.option('-n, --name <name>', 'Template name')
|
|
138
|
+
.option('-s, --subject <subject>', 'Email subject')
|
|
139
|
+
.option('--html <html>', 'HTML content')
|
|
140
|
+
.option('--text <text>', 'Plain text content')
|
|
141
|
+
.option('--sender-id <id>', 'Sender ID')
|
|
142
|
+
.option('--tracking <tracking>', 'Tracking settings')
|
|
143
|
+
.action(async (listId, templateId, options) => {
|
|
144
|
+
// Auto-detect list ID if not provided
|
|
145
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
146
|
+
|
|
147
|
+
if (!detectedListId) {
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const spinner = ora(`Updating template ${templateId}...`).start();
|
|
152
|
+
try {
|
|
153
|
+
const payload: any = {};
|
|
154
|
+
if (options.name) payload.name = options.name;
|
|
155
|
+
if (options.subject) payload.subject = options.subject;
|
|
156
|
+
if (options.html) payload.html = options.html;
|
|
157
|
+
if (options.text) payload.text = options.text;
|
|
158
|
+
if (options.senderId) payload.sender_id = parseInt(options.senderId);
|
|
159
|
+
if (options.tracking) payload.tracking = options.tracking;
|
|
160
|
+
|
|
161
|
+
const data = await client.sdk.transactionalEmailService.updateTransactionalEmailTemplate({
|
|
162
|
+
listId: detectedListId,
|
|
163
|
+
transactionalEmailTemplateId: parseInt(templateId),
|
|
164
|
+
requestBody: payload
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
spinner.stop();
|
|
168
|
+
formatter.success('Template updated successfully');
|
|
169
|
+
formatter.output(data);
|
|
170
|
+
} catch (error: any) {
|
|
171
|
+
spinner.stop();
|
|
172
|
+
displayError(error, {
|
|
173
|
+
command: 'transactional-templates update',
|
|
174
|
+
resource: 'template',
|
|
175
|
+
resourceId: templateId,
|
|
176
|
+
operation: 'update'
|
|
177
|
+
});
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Delete transactional template
|
|
183
|
+
templates
|
|
184
|
+
.command('delete [list-id] <template-id>')
|
|
185
|
+
.description('Delete a transactional email template (auto-detects if only one list exists)')
|
|
186
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
187
|
+
.action(async (listId, templateId, options) => {
|
|
188
|
+
// Auto-detect list ID if not provided
|
|
189
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
190
|
+
|
|
191
|
+
if (!detectedListId) {
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Interactive confirmation (unless --force is used)
|
|
196
|
+
if (!options.force) {
|
|
197
|
+
const confirmed = await confirmDelete('transactional template', templateId, [
|
|
198
|
+
'Template will be permanently deleted',
|
|
199
|
+
'This action cannot be undone'
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
if (!confirmed) {
|
|
203
|
+
formatter.info('Deletion cancelled');
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const spinner = ora(`Deleting template ${templateId}...`).start();
|
|
209
|
+
try {
|
|
210
|
+
await client.sdk.transactionalEmailService.deleteTransactionalEmailTemplate({
|
|
211
|
+
listId: detectedListId,
|
|
212
|
+
transactionalEmailTemplateId: parseInt(templateId)
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
spinner.stop();
|
|
216
|
+
formatter.success('Template deleted successfully');
|
|
217
|
+
} catch (error: any) {
|
|
218
|
+
spinner.stop();
|
|
219
|
+
displayError(error, {
|
|
220
|
+
command: 'transactional-templates delete',
|
|
221
|
+
resource: 'template',
|
|
222
|
+
resourceId: templateId,
|
|
223
|
+
operation: 'delete'
|
|
224
|
+
});
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Send transactional email
|
|
230
|
+
templates
|
|
231
|
+
.command('send [list-id] <template-id>')
|
|
232
|
+
.description('Send a transactional email from template (auto-detects if only one list exists)')
|
|
233
|
+
.option('-c, --contact-id <id>', 'Contact ID to send to')
|
|
234
|
+
.option('-e, --email <email>', 'Email address to send to (alternative to contact-id)')
|
|
235
|
+
.option('--variables <json>', 'Template variables as JSON')
|
|
236
|
+
.action(async (listId, templateId, options) => {
|
|
237
|
+
// Auto-detect list ID if not provided
|
|
238
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
239
|
+
|
|
240
|
+
if (!detectedListId) {
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Validate that either contact-id or email is provided
|
|
245
|
+
if (!options.contactId && !options.email) {
|
|
246
|
+
formatter.error('Either --contact-id or --email is required');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const spinner = ora('Sending transactional email...').start();
|
|
251
|
+
try {
|
|
252
|
+
const payload: any = {};
|
|
253
|
+
|
|
254
|
+
if (options.contactId) {
|
|
255
|
+
payload.contact_id = parseInt(options.contactId);
|
|
256
|
+
} else if (options.email) {
|
|
257
|
+
payload.email = options.email;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (options.variables) {
|
|
261
|
+
payload.variables = JSON.parse(options.variables);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const data = await client.sdk.transactionalEmailService.sendTransactionalEmail({
|
|
265
|
+
listId: detectedListId,
|
|
266
|
+
transactionalEmailTemplateId: parseInt(templateId),
|
|
267
|
+
requestBody: payload
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
spinner.stop();
|
|
271
|
+
formatter.success('Transactional email sent successfully');
|
|
272
|
+
formatter.output(data);
|
|
273
|
+
} catch (error: any) {
|
|
274
|
+
spinner.stop();
|
|
275
|
+
displayError(error, {
|
|
276
|
+
command: 'transactional-templates send',
|
|
277
|
+
resource: 'template',
|
|
278
|
+
resourceId: templateId,
|
|
279
|
+
operation: 'send email'
|
|
280
|
+
});
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Send test email
|
|
286
|
+
templates
|
|
287
|
+
.command('test [list-id] <template-id>')
|
|
288
|
+
.description('Send a test transactional email (auto-detects if only one list exists)')
|
|
289
|
+
.requiredOption('-e, --email <email>', 'Email address to send test to')
|
|
290
|
+
.option('--variables <json>', 'Template variables as JSON')
|
|
291
|
+
.action(async (listId, templateId, options) => {
|
|
292
|
+
// Auto-detect list ID if not provided
|
|
293
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
294
|
+
|
|
295
|
+
if (!detectedListId) {
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Validate email
|
|
300
|
+
const emailValidation = validate.email(options.email);
|
|
301
|
+
if (!emailValidation.valid) {
|
|
302
|
+
formatter.error(emailValidation.error!);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const spinner = ora('Sending test email...').start();
|
|
307
|
+
try {
|
|
308
|
+
const payload: any = {
|
|
309
|
+
email: options.email
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
if (options.variables) {
|
|
313
|
+
payload.variables = JSON.parse(options.variables);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const data = await client.sdk.transactionalEmailService.sendTestTransactionalEmail({
|
|
317
|
+
listId: detectedListId,
|
|
318
|
+
transactionalEmailTemplateId: parseInt(templateId),
|
|
319
|
+
requestBody: payload
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
spinner.stop();
|
|
323
|
+
formatter.success(`Test email sent to ${options.email}`);
|
|
324
|
+
formatter.output(data);
|
|
325
|
+
} catch (error: any) {
|
|
326
|
+
spinner.stop();
|
|
327
|
+
displayError(error, {
|
|
328
|
+
command: 'transactional-templates test',
|
|
329
|
+
resource: 'template',
|
|
330
|
+
resourceId: templateId,
|
|
331
|
+
operation: 'send test'
|
|
332
|
+
});
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Render template
|
|
338
|
+
templates
|
|
339
|
+
.command('render [list-id] <template-id>')
|
|
340
|
+
.description('Render a transactional email template (auto-detects if only one list exists)')
|
|
341
|
+
.option('-c, --contact-id <id>', 'Contact ID for personalization')
|
|
342
|
+
.option('--variables <json>', 'Template variables as JSON')
|
|
343
|
+
.action(async (listId, templateId, options) => {
|
|
344
|
+
// Auto-detect list ID if not provided
|
|
345
|
+
const detectedListId = await autoDetectList(client, formatter, listId, { useCache: true });
|
|
346
|
+
|
|
347
|
+
if (!detectedListId) {
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const spinner = ora('Rendering template...').start();
|
|
352
|
+
try {
|
|
353
|
+
const payload: any = {};
|
|
354
|
+
|
|
355
|
+
if (options.contactId) {
|
|
356
|
+
payload.contact_id = parseInt(options.contactId);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (options.variables) {
|
|
360
|
+
payload.variables = JSON.parse(options.variables);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const html = await client.sdk.transactionalEmailService.renderTransactionalEmailTemplate({
|
|
364
|
+
listId: detectedListId,
|
|
365
|
+
transactionalEmailTemplateId: parseInt(templateId),
|
|
366
|
+
requestBody: payload
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
spinner.stop();
|
|
370
|
+
formatter.success('Template rendered successfully');
|
|
371
|
+
formatter.output({ html, template_id: templateId, list_id: detectedListId });
|
|
372
|
+
} catch (error: any) {
|
|
373
|
+
spinner.stop();
|
|
374
|
+
displayError(error, {
|
|
375
|
+
command: 'transactional-templates render',
|
|
376
|
+
resource: 'template',
|
|
377
|
+
resourceId: templateId,
|
|
378
|
+
operation: 'render'
|
|
379
|
+
});
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
return templates;
|
|
385
|
+
}
|