@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,406 @@
1
+ // ABOUTME: CLI commands for List.
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 createListsCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('lists')
13
+ .description('Manage contact lists. A list is a collection of contacts (email subscribers) with its own sender identity, language, and subscription settings. Lists support double opt-in, custom redirect URLs after subscription events, and webhook notifications. Also includes deprecated subscription form endpoints for legacy integrations — use the Form endpoints instead.');
14
+
15
+
16
+ cmd
17
+ .command('list')
18
+ .description('Show all lists')
19
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
20
+ .option('--page <value>', 'page')
21
+ .option('--per-page <value>', 'per_page')
22
+ .option('--with-count <value>', 'Include count in the response')
23
+ .option('--filter <value>', 'Valid Terms:
24
+ - `status`
25
+ - `name`
26
+
27
+ Valid Operators:
28
+ - `==`
29
+
30
+ Query separator:
31
+ - `;`')
32
+ .option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
33
+
34
+ Valid terms:
35
+ - `name`
36
+ - `created_on`')
37
+ .action(async (options) => {
38
+ const spinner = createSpinner('Fetching list...').start();
39
+ try {
40
+ const data = await client.listLists({
41
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
42
+ page: options.page != null ? Number(options.page) : undefined,
43
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
44
+ withCount: options.withCount,
45
+ filter: options.filter,
46
+ sort: options.sort,
47
+ });
48
+
49
+ spinner.stop();
50
+ formatter.output(data);
51
+ } catch (error: any) {
52
+ spinner.stop();
53
+ formatter.error(error.message);
54
+ process.exit(1);
55
+ }
56
+ });
57
+
58
+
59
+ cmd
60
+ .command('create')
61
+ .description('Create a List')
62
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
63
+ .requiredOption('--name <value>', 'List Name')
64
+ .requiredOption('--default-sender <value>', 'default_sender')
65
+ .option('--language <value>', 'language')
66
+ .option('--redirections <value>', 'redirections')
67
+ .option('--webhook <value>', 'webhook')
68
+ .action(async (options) => {
69
+ const spinner = createSpinner('Creating list...').start();
70
+ try {
71
+ const data = await client.createList({
72
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
73
+ name: options.name,
74
+ defaultSender: options.defaultSender,
75
+ language: options.language,
76
+ redirections: options.redirections,
77
+ webhook: options.webhook,
78
+ });
79
+
80
+ spinner.stop();
81
+ formatter.success('List created successfully');
82
+ formatter.output(data);
83
+ } catch (error: any) {
84
+ spinner.stop();
85
+ formatter.error(error.message);
86
+ process.exit(1);
87
+ }
88
+ });
89
+
90
+
91
+ cmd
92
+ .command('get <list-id>')
93
+ .description('Show a list parameters')
94
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
95
+ .action(async (list_id, options) => {
96
+ const spinner = createSpinner('Fetching list...').start();
97
+ try {
98
+ const data = await client.getList({
99
+ list_id: Number(list_id),
100
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
101
+ });
102
+
103
+ spinner.stop();
104
+ formatter.output(data);
105
+ } catch (error: any) {
106
+ spinner.stop();
107
+ formatter.error(error.message);
108
+ process.exit(1);
109
+ }
110
+ });
111
+
112
+
113
+ cmd
114
+ .command('patch <list-id>')
115
+ .description('Update a list parameters')
116
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
117
+ .option('--name <value>', 'name')
118
+ .option('--default-sender <value>', 'default_sender')
119
+ .option('--language <value>', 'language')
120
+ .option('--redirections <value>', 'redirections')
121
+ .option('--webhook <value>', 'webhook')
122
+ .action(async (list_id, options) => {
123
+ const spinner = createSpinner('Updating list...').start();
124
+ try {
125
+ const data = await client.patchList({
126
+ list_id: Number(list_id),
127
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
128
+ name: options.name,
129
+ defaultSender: options.defaultSender,
130
+ language: options.language,
131
+ redirections: options.redirections,
132
+ webhook: options.webhook,
133
+ });
134
+
135
+ spinner.stop();
136
+ formatter.success('List updated successfully');
137
+ formatter.output(data);
138
+ } catch (error: any) {
139
+ spinner.stop();
140
+ formatter.error(error.message);
141
+ process.exit(1);
142
+ }
143
+ });
144
+
145
+
146
+ cmd
147
+ .command('delete <list-id>')
148
+ .description('Delete a List')
149
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
150
+ .option('-f, --force', 'Skip confirmation prompt')
151
+ .action(async (list_id, options) => {
152
+ if (!options.force) {
153
+ const confirmed = await confirmDelete('list', list_id);
154
+ if (!confirmed) {
155
+ formatter.info('Deletion cancelled');
156
+ return;
157
+ }
158
+ }
159
+
160
+ const spinner = createSpinner('Deleting list...').start();
161
+ try {
162
+ const data = await client.deleteList({
163
+ list_id: Number(list_id),
164
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
165
+ });
166
+
167
+ spinner.stop();
168
+ formatter.success('List deleted successfully');
169
+ } catch (error: any) {
170
+ spinner.stop();
171
+ formatter.error(error.message);
172
+ process.exit(1);
173
+ }
174
+ });
175
+
176
+
177
+ cmd
178
+ .command('accept-list-policy <list-id>')
179
+ .description('Accept policy for a list')
180
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
181
+ .action(async (list_id, options) => {
182
+ const spinner = createSpinner('Creating list...').start();
183
+ try {
184
+ const data = await client.acceptListPolicy({
185
+ list_id: Number(list_id),
186
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
187
+ });
188
+
189
+ spinner.stop();
190
+ formatter.success('List created successfully');
191
+ formatter.output(data);
192
+ } catch (error: any) {
193
+ spinner.stop();
194
+ formatter.error(error.message);
195
+ process.exit(1);
196
+ }
197
+ });
198
+
199
+
200
+ cmd
201
+ .command('archive <list-id>')
202
+ .description('Archive a list')
203
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
204
+ .action(async (list_id, options) => {
205
+ const spinner = createSpinner('Creating list...').start();
206
+ try {
207
+ const data = await client.archiveList({
208
+ list_id: Number(list_id),
209
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
210
+ });
211
+
212
+ spinner.stop();
213
+ formatter.success('List created successfully');
214
+ formatter.output(data);
215
+ } catch (error: any) {
216
+ spinner.stop();
217
+ formatter.error(error.message);
218
+ process.exit(1);
219
+ }
220
+ });
221
+
222
+
223
+ cmd
224
+ .command('enable-subscription-form-endpoint <form-id> <list-id>')
225
+ .description('Enable a subscription form endpoint')
226
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
227
+ .action(async (form_id, list_id, options) => {
228
+ const spinner = createSpinner('Creating list...').start();
229
+ try {
230
+ const data = await client.enableSubscriptionFormEndpoint({
231
+ form_id,
232
+ list_id: Number(list_id),
233
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
234
+ });
235
+
236
+ spinner.stop();
237
+ formatter.success('List created successfully');
238
+ formatter.output(data);
239
+ } catch (error: any) {
240
+ spinner.stop();
241
+ formatter.error(error.message);
242
+ process.exit(1);
243
+ }
244
+ });
245
+
246
+
247
+ cmd
248
+ .command('disable-subscription-form-endpoint <form-id> <list-id>')
249
+ .description('Disable a subscription form endpoint')
250
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
251
+ .action(async (form_id, list_id, options) => {
252
+ const spinner = createSpinner('Creating list...').start();
253
+ try {
254
+ const data = await client.disableSubscriptionFormEndpoint({
255
+ form_id,
256
+ list_id: Number(list_id),
257
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
258
+ });
259
+
260
+ spinner.stop();
261
+ formatter.success('List created successfully');
262
+ formatter.output(data);
263
+ } catch (error: any) {
264
+ spinner.stop();
265
+ formatter.error(error.message);
266
+ process.exit(1);
267
+ }
268
+ });
269
+
270
+
271
+ cmd
272
+ .command('list-subscription-form-endpoints <list-id>')
273
+ .description('List subscription form endpoints')
274
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
275
+ .option('--page <value>', 'page')
276
+ .option('--per-page <value>', 'per_page')
277
+ .option('--with-count <value>', 'Include count in the response')
278
+ .action(async (list_id, options) => {
279
+ const spinner = createSpinner('Fetching list...').start();
280
+ try {
281
+ const data = await client.listSubscriptionFormEndpoints({
282
+ list_id: Number(list_id),
283
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
284
+ page: options.page != null ? Number(options.page) : undefined,
285
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
286
+ withCount: options.withCount,
287
+ });
288
+
289
+ spinner.stop();
290
+ formatter.output(data);
291
+ } catch (error: any) {
292
+ spinner.stop();
293
+ formatter.error(error.message);
294
+ process.exit(1);
295
+ }
296
+ });
297
+
298
+
299
+ cmd
300
+ .command('create-subscription-form-endpoint <list-id>')
301
+ .description('Create a subscription form endpoint')
302
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
303
+ .requiredOption('--data <value>', 'Request body as JSON string')
304
+ .action(async (list_id, options) => {
305
+ const spinner = createSpinner('Creating list...').start();
306
+ try {
307
+ const body = JSON.parse(options.data);
308
+ const data = await client.createSubscriptionFormEndpoint({
309
+ list_id: Number(list_id),
310
+ ...body,
311
+ });
312
+
313
+ spinner.stop();
314
+ formatter.success('List created successfully');
315
+ formatter.output(data);
316
+ } catch (error: any) {
317
+ spinner.stop();
318
+ formatter.error(error.message);
319
+ process.exit(1);
320
+ }
321
+ });
322
+
323
+
324
+ cmd
325
+ .command('show-subscription-form-endpoint <form-id> <list-id>')
326
+ .description('Show a subscription form endpoint')
327
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
328
+ .action(async (form_id, list_id, options) => {
329
+ const spinner = createSpinner('Fetching list...').start();
330
+ try {
331
+ const data = await client.showSubscriptionFormEndpoint({
332
+ form_id,
333
+ list_id: Number(list_id),
334
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
335
+ });
336
+
337
+ spinner.stop();
338
+ formatter.output(data);
339
+ } catch (error: any) {
340
+ spinner.stop();
341
+ formatter.error(error.message);
342
+ process.exit(1);
343
+ }
344
+ });
345
+
346
+
347
+ cmd
348
+ .command('patch-subscription-form-endpoint <form-id> <list-id>')
349
+ .description('Patch a subscription form endpoint')
350
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
351
+ .requiredOption('--data <value>', 'Request body as JSON string')
352
+ .action(async (form_id, list_id, options) => {
353
+ const spinner = createSpinner('Updating list...').start();
354
+ try {
355
+ const body = JSON.parse(options.data);
356
+ const data = await client.patchSubscriptionFormEndpoint({
357
+ form_id,
358
+ list_id: Number(list_id),
359
+ ...body,
360
+ });
361
+
362
+ spinner.stop();
363
+ formatter.success('List updated successfully');
364
+ formatter.output(data);
365
+ } catch (error: any) {
366
+ spinner.stop();
367
+ formatter.error(error.message);
368
+ process.exit(1);
369
+ }
370
+ });
371
+
372
+
373
+ cmd
374
+ .command('delete-subscription-form-endpoint <form-id> <list-id>')
375
+ .description('Delete a subscription form endpoint')
376
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
377
+ .option('-f, --force', 'Skip confirmation prompt')
378
+ .action(async (form_id, list_id, options) => {
379
+ if (!options.force) {
380
+ const confirmed = await confirmDelete('list', form_id);
381
+ if (!confirmed) {
382
+ formatter.info('Deletion cancelled');
383
+ return;
384
+ }
385
+ }
386
+
387
+ const spinner = createSpinner('Deleting list...').start();
388
+ try {
389
+ const data = await client.deleteSubscriptionFormEndpoint({
390
+ form_id,
391
+ list_id: Number(list_id),
392
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
393
+ });
394
+
395
+ spinner.stop();
396
+ formatter.success('List deleted successfully');
397
+ } catch (error: any) {
398
+ spinner.stop();
399
+ formatter.error(error.message);
400
+ process.exit(1);
401
+ }
402
+ });
403
+
404
+
405
+ return cmd;
406
+ }
@@ -0,0 +1,71 @@
1
+ // ABOUTME: CLI commands for Logo.
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 createLogosCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('logos')
13
+ .description('Upload and manage the account logo used in campaigns and forms.');
14
+
15
+
16
+ cmd
17
+ .command('upload-default')
18
+ .description('Upload a default logo')
19
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
20
+ .requiredOption('--file <value>', 'Data URI scheme, base64 encoded')
21
+ .action(async (options) => {
22
+ const spinner = createSpinner('Updating logo...').start();
23
+ try {
24
+ const data = await client.uploadDefaultLogo({
25
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
26
+ file: options.file,
27
+ });
28
+
29
+ spinner.stop();
30
+ formatter.success('Logo updated successfully');
31
+ formatter.output(data);
32
+ } catch (error: any) {
33
+ spinner.stop();
34
+ formatter.error(error.message);
35
+ process.exit(1);
36
+ }
37
+ });
38
+
39
+
40
+ cmd
41
+ .command('delete-default')
42
+ .description('Delete the default logo')
43
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
44
+ .option('-f, --force', 'Skip confirmation prompt')
45
+ .action(async (options) => {
46
+ if (!options.force) {
47
+ const confirmed = await confirmDelete('logo', 'this resource');
48
+ if (!confirmed) {
49
+ formatter.info('Deletion cancelled');
50
+ return;
51
+ }
52
+ }
53
+
54
+ const spinner = createSpinner('Deleting logo...').start();
55
+ try {
56
+ const data = await client.deleteDefaultLogo({
57
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
58
+ });
59
+
60
+ spinner.stop();
61
+ formatter.success('Logo deleted successfully');
62
+ } catch (error: any) {
63
+ spinner.stop();
64
+ formatter.error(error.message);
65
+ process.exit(1);
66
+ }
67
+ });
68
+
69
+
70
+ return cmd;
71
+ }