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