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