@cakemail-org/cakemail-cli 1.7.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 (198) 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 +41 -37
  6. package/audit-formats.js +128 -0
  7. package/cakemail.rb +20 -0
  8. package/dist/client.js +1 -1
  9. package/dist/client.js.map +1 -1
  10. package/dist/commands/account.js +1 -1
  11. package/dist/commands/account.js.map +1 -1
  12. package/dist/commands/attributes.js +1 -1
  13. package/dist/commands/attributes.js.map +1 -1
  14. package/dist/commands/campaigns.js +1 -1
  15. package/dist/commands/campaigns.js.map +1 -1
  16. package/dist/commands/contacts.js +1 -1
  17. package/dist/commands/contacts.js.map +1 -1
  18. package/dist/commands/emails.js +1 -1
  19. package/dist/commands/emails.js.map +1 -1
  20. package/dist/commands/interests.js +1 -1
  21. package/dist/commands/interests.js.map +1 -1
  22. package/dist/commands/lists.js +1 -1
  23. package/dist/commands/lists.js.map +1 -1
  24. package/dist/commands/logs.js +1 -1
  25. package/dist/commands/logs.js.map +1 -1
  26. package/dist/commands/reports.js +1 -1
  27. package/dist/commands/reports.js.map +1 -1
  28. package/dist/commands/segments.js +1 -1
  29. package/dist/commands/segments.js.map +1 -1
  30. package/dist/commands/senders.js +1 -1
  31. package/dist/commands/senders.js.map +1 -1
  32. package/dist/commands/suppressed.js +1 -1
  33. package/dist/commands/suppressed.js.map +1 -1
  34. package/dist/commands/tags.js +1 -1
  35. package/dist/commands/tags.js.map +1 -1
  36. package/dist/commands/templates.js +1 -1
  37. package/dist/commands/templates.js.map +1 -1
  38. package/dist/commands/transactional-templates.js +1 -1
  39. package/dist/commands/transactional-templates.js.map +1 -1
  40. package/dist/commands/webhooks.js +1 -1
  41. package/dist/commands/webhooks.js.map +1 -1
  42. package/dist/utils/config.js +2 -2
  43. package/dist/utils/config.js.map +1 -1
  44. package/dist/utils/errors.js +1 -1
  45. package/dist/utils/errors.js.map +1 -1
  46. package/dist/utils/progress.d.ts.map +1 -1
  47. package/dist/utils/progress.js +32 -4
  48. package/dist/utils/progress.js.map +1 -1
  49. package/dist/utils/spinner.d.ts +17 -0
  50. package/dist/utils/spinner.d.ts.map +1 -0
  51. package/dist/utils/spinner.js +43 -0
  52. package/dist/utils/spinner.js.map +1 -0
  53. package/docs/DOCUMENTATION-STANDARD.md +1068 -0
  54. package/docs/README.md +161 -0
  55. package/docs/developer/ARCHITECTURE.md +516 -0
  56. package/docs/developer/AUTH.md +204 -0
  57. package/docs/developer/CONTRIBUTING.md +227 -0
  58. package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
  59. package/docs/developer/PROJECT_INDEX.md +365 -0
  60. package/docs/planning/API_COVERAGE.md +1045 -0
  61. package/docs/planning/BACKLOG.md +1159 -0
  62. package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
  63. package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
  64. package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
  65. package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
  66. package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
  67. package/docs/planning/cakemail-profile-system-plan.md +1121 -0
  68. package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
  69. package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
  70. package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
  71. package/docs/user-manual/.obsidian/app.json +1 -0
  72. package/docs/user-manual/.obsidian/appearance.json +1 -0
  73. package/docs/user-manual/.obsidian/core-plugins.json +33 -0
  74. package/docs/user-manual/.obsidian/workspace.json +167 -0
  75. package/docs/user-manual/01-getting-started/01-installation.md +214 -0
  76. package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
  77. package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
  78. package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
  79. package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
  80. package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
  81. package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
  82. package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
  83. package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
  84. package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
  85. package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
  86. package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
  87. package/docs/user-manual/03-email-operations/01-senders.md +490 -0
  88. package/docs/user-manual/03-email-operations/02-templates.md +444 -0
  89. package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
  90. package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
  91. package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
  92. package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
  93. package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
  94. package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
  95. package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
  96. package/docs/user-manual/05-contact-management/01-lists.md +836 -0
  97. package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
  98. package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
  99. package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
  100. package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
  101. package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
  102. package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
  103. package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
  104. package/docs/user-manual/07-integrations/02-automation.md +326 -0
  105. package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
  106. package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
  107. package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
  108. package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
  109. package/docs/user-manual/09-command-reference/01-config.md +776 -0
  110. package/docs/user-manual/09-command-reference/02-account.md +652 -0
  111. package/docs/user-manual/09-command-reference/03-lists.md +958 -0
  112. package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
  113. package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
  114. package/docs/user-manual/09-command-reference/06-segments.md +894 -0
  115. package/docs/user-manual/09-command-reference/07-senders.md +803 -0
  116. package/docs/user-manual/09-command-reference/08-templates.md +818 -0
  117. package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
  118. package/docs/user-manual/09-command-reference/10-emails.md +807 -0
  119. package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
  120. package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
  121. package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
  122. package/docs/user-manual/09-command-reference/14-interests.md +630 -0
  123. package/docs/user-manual/09-command-reference/15-tags.md +584 -0
  124. package/docs/user-manual/09-command-reference/16-logs.md +656 -0
  125. package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
  126. package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
  127. package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
  128. package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
  129. package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
  130. package/docs/user-manual/11-appendix/04-faq.md +484 -0
  131. package/docs/user-manual/11-appendix/05-glossary.md +250 -0
  132. package/docs/user-manual/README.md +0 -0
  133. package/package.json +13 -61
  134. package/src/cli.ts +125 -0
  135. package/src/client.ts +16 -0
  136. package/src/commands/account.ts +267 -0
  137. package/src/commands/accounts.ts +78 -0
  138. package/src/commands/actions.ts +249 -0
  139. package/src/commands/attributes.ts +139 -0
  140. package/src/commands/campaign-blueprints.ts +106 -0
  141. package/src/commands/campaigns.ts +469 -0
  142. package/src/commands/config.ts +77 -0
  143. package/src/commands/contacts.ts +612 -0
  144. package/src/commands/custom-attributes.ts +127 -0
  145. package/src/commands/dkims.ts +117 -0
  146. package/src/commands/domains.ts +82 -0
  147. package/src/commands/email-apis.ts +569 -0
  148. package/src/commands/emails.ts +197 -0
  149. package/src/commands/forms.ts +283 -0
  150. package/src/commands/interests.ts +155 -0
  151. package/src/commands/links.ts +38 -0
  152. package/src/commands/lists.ts +406 -0
  153. package/src/commands/logos.ts +71 -0
  154. package/src/commands/logs.ts +386 -0
  155. package/src/commands/reports.ts +306 -0
  156. package/src/commands/segments.ts +158 -0
  157. package/src/commands/senders.ts +204 -0
  158. package/src/commands/sub-accounts.ts +271 -0
  159. package/src/commands/suppressed-emails.ts +234 -0
  160. package/src/commands/suppressed.ts +198 -0
  161. package/src/commands/system-emails.ts +85 -0
  162. package/src/commands/tags.ts +146 -0
  163. package/src/commands/tasks.ts +116 -0
  164. package/src/commands/templates.ts +189 -0
  165. package/src/commands/tokens.ts +83 -0
  166. package/src/commands/transactional-emails.ts +374 -0
  167. package/src/commands/transactional-templates.ts +385 -0
  168. package/src/commands/users.ts +506 -0
  169. package/src/commands/webhooks.ts +172 -0
  170. package/src/commands/workflow-blueprints.ts +123 -0
  171. package/src/commands/workflows.ts +265 -0
  172. package/src/types/profile.ts +93 -0
  173. package/src/utils/auth.ts +272 -0
  174. package/src/utils/config-file.ts +96 -0
  175. package/src/utils/config.ts +134 -0
  176. package/src/utils/confirm.ts +32 -0
  177. package/src/utils/defaults.ts +99 -0
  178. package/src/utils/errors.ts +116 -0
  179. package/src/utils/interactive.ts +91 -0
  180. package/src/utils/list-defaults.ts +74 -0
  181. package/src/utils/output.ts +190 -0
  182. package/src/utils/progress.ts +320 -0
  183. package/src/utils/spinner.ts +22 -0
  184. package/tests/IMPLEMENTATION_STATUS.md +258 -0
  185. package/tests/PTY_SETUP.md +118 -0
  186. package/tests/PTY_TESTING_GUIDE.md +507 -0
  187. package/tests/README.md +244 -0
  188. package/tests/fixtures/api-responses/campaigns.json +34 -0
  189. package/tests/fixtures/test-config.json +13 -0
  190. package/tests/helpers/cli-runner.ts +128 -0
  191. package/tests/helpers/mock-server.ts +301 -0
  192. package/tests/helpers/pty-runner.ts +181 -0
  193. package/tests/integration/campaigns-real-api.test.ts +196 -0
  194. package/tests/integration/setup-integration.ts +50 -0
  195. package/tests/pty/campaigns.test.ts +241 -0
  196. package/tests/setup.ts +34 -0
  197. package/tsconfig.json +15 -0
  198. package/vitest.config.ts +28 -0
@@ -0,0 +1,506 @@
1
+ // ABOUTME: CLI commands for User.
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 createUsersCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('users')
13
+ .description('Manage users within an account. Users are individuals who can log in and perform actions. Each account can have multiple users with different roles. Includes user creation with email verification, password management, suspension, and multi-factor authentication (MFA) setup.');
14
+
15
+
16
+ cmd
17
+ .command('get-self')
18
+ .description('Show my user details')
19
+ .action(async () => {
20
+ const spinner = createSpinner('Fetching user...').start();
21
+ try {
22
+ const data = await client.getSelfUser({
23
+ });
24
+
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
+
35
+ cmd
36
+ .command('forgot-my-password')
37
+ .description('Forgot my password')
38
+ .option('--account-id <value>', 'account_id')
39
+ .option('--language <value>', 'language')
40
+ .requiredOption('--email <value>', 'Email address of the user requesting a password reset')
41
+ .action(async (options) => {
42
+ const spinner = createSpinner('Creating user...').start();
43
+ try {
44
+ const data = await client.forgotMyPassword({
45
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
46
+ language: options.language,
47
+ email: options.email,
48
+ });
49
+
50
+ spinner.stop();
51
+ formatter.success('User created successfully');
52
+ formatter.output(data);
53
+ } catch (error: any) {
54
+ spinner.stop();
55
+ formatter.error(error.message);
56
+ process.exit(1);
57
+ }
58
+ });
59
+
60
+
61
+ cmd
62
+ .command('reset-self-password')
63
+ .description('Reset my password')
64
+ .action(async () => {
65
+ const spinner = createSpinner('Creating user...').start();
66
+ try {
67
+ const data = await client.resetSelfPassword({
68
+ });
69
+
70
+ spinner.stop();
71
+ formatter.success('User created successfully');
72
+ formatter.output(data);
73
+ } catch (error: any) {
74
+ spinner.stop();
75
+ formatter.error(error.message);
76
+ process.exit(1);
77
+ }
78
+ });
79
+
80
+
81
+ cmd
82
+ .command('reset-user-password <user-id>')
83
+ .description('Reset a user password')
84
+ .option('--account-id <value>', 'account_id')
85
+ .option('--invalidate-current-password <value>', 'If true, immediately invalidates the current password, forcing the user to reset')
86
+ .action(async (user_id, options) => {
87
+ const spinner = createSpinner('Creating user...').start();
88
+ try {
89
+ const data = await client.resetUserPassword({
90
+ user_id: Number(user_id),
91
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
92
+ invalidateCurrentPassword: options.invalidateCurrentPassword,
93
+ });
94
+
95
+ spinner.stop();
96
+ formatter.success('User created successfully');
97
+ formatter.output(data);
98
+ } catch (error: any) {
99
+ spinner.stop();
100
+ formatter.error(error.message);
101
+ process.exit(1);
102
+ }
103
+ });
104
+
105
+
106
+ cmd
107
+ .command('reset-password-confirm')
108
+ .description('Reset password confirmation')
109
+ .requiredOption('--token <value>', 'Password reset token received via email')
110
+ .requiredOption('--password <value>', 'New password to set')
111
+ .action(async (options) => {
112
+ const spinner = createSpinner('Creating user...').start();
113
+ try {
114
+ const data = await client.resetPasswordConfirm({
115
+ token: options.token,
116
+ password: options.password,
117
+ });
118
+
119
+ spinner.stop();
120
+ formatter.success('User created successfully');
121
+ formatter.output(data);
122
+ } catch (error: any) {
123
+ spinner.stop();
124
+ formatter.error(error.message);
125
+ process.exit(1);
126
+ }
127
+ });
128
+
129
+
130
+ cmd
131
+ .command('list')
132
+ .description('Show all users in my account')
133
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
134
+ .option('--page <value>', 'page')
135
+ .option('--per-page <value>', 'per_page')
136
+ .option('--with-count <value>', 'Include count in the response')
137
+ .option('--filter <value>', 'Valid Terms:
138
+ - `email`
139
+ - `status`
140
+
141
+ Valid Operators:
142
+ - `==`
143
+
144
+ Query separator:
145
+ - `;`')
146
+ .action(async (options) => {
147
+ const spinner = createSpinner('Fetching user...').start();
148
+ try {
149
+ const data = await client.listUsers({
150
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
151
+ page: options.page != null ? Number(options.page) : undefined,
152
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
153
+ withCount: options.withCount,
154
+ filter: options.filter,
155
+ });
156
+
157
+ spinner.stop();
158
+ formatter.output(data);
159
+ } catch (error: any) {
160
+ spinner.stop();
161
+ formatter.error(error.message);
162
+ process.exit(1);
163
+ }
164
+ });
165
+
166
+
167
+ cmd
168
+ .command('create')
169
+ .description('Create a user')
170
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
171
+ .option('--skip-verification <value>', 'skip_verification')
172
+ .requiredOption('--data <value>', 'Request body as JSON string')
173
+ .action(async (options) => {
174
+ const spinner = createSpinner('Creating user...').start();
175
+ try {
176
+ const body = JSON.parse(options.data);
177
+ const data = await client.createUser({
178
+ ...body,
179
+ });
180
+
181
+ spinner.stop();
182
+ formatter.success('User created successfully');
183
+ formatter.output(data);
184
+ } catch (error: any) {
185
+ spinner.stop();
186
+ formatter.error(error.message);
187
+ process.exit(1);
188
+ }
189
+ });
190
+
191
+
192
+ cmd
193
+ .command('get <user-id>')
194
+ .description('Show a user details')
195
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
196
+ .action(async (user_id, options) => {
197
+ const spinner = createSpinner('Fetching user...').start();
198
+ try {
199
+ const data = await client.getUser({
200
+ user_id,
201
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
202
+ });
203
+
204
+ spinner.stop();
205
+ formatter.output(data);
206
+ } catch (error: any) {
207
+ spinner.stop();
208
+ formatter.error(error.message);
209
+ process.exit(1);
210
+ }
211
+ });
212
+
213
+
214
+ cmd
215
+ .command('patch <user-id>')
216
+ .description('Update a user')
217
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
218
+ .requiredOption('--data <value>', 'Request body as JSON string')
219
+ .action(async (user_id, options) => {
220
+ const spinner = createSpinner('Updating user...').start();
221
+ try {
222
+ const body = JSON.parse(options.data);
223
+ const data = await client.patchUser({
224
+ user_id,
225
+ ...body,
226
+ });
227
+
228
+ spinner.stop();
229
+ formatter.success('User updated successfully');
230
+ formatter.output(data);
231
+ } catch (error: any) {
232
+ spinner.stop();
233
+ formatter.error(error.message);
234
+ process.exit(1);
235
+ }
236
+ });
237
+
238
+
239
+ cmd
240
+ .command('delete <user-id>')
241
+ .description('Delete a user')
242
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
243
+ .option('-f, --force', 'Skip confirmation prompt')
244
+ .action(async (user_id, options) => {
245
+ if (!options.force) {
246
+ const confirmed = await confirmDelete('user', user_id);
247
+ if (!confirmed) {
248
+ formatter.info('Deletion cancelled');
249
+ return;
250
+ }
251
+ }
252
+
253
+ const spinner = createSpinner('Deleting user...').start();
254
+ try {
255
+ const data = await client.deleteUser({
256
+ user_id,
257
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
258
+ });
259
+
260
+ spinner.stop();
261
+ formatter.success('User deleted successfully');
262
+ } catch (error: any) {
263
+ spinner.stop();
264
+ formatter.error(error.message);
265
+ process.exit(1);
266
+ }
267
+ });
268
+
269
+
270
+ cmd
271
+ .command('suspend <user-id>')
272
+ .description('Suspend a user')
273
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
274
+ .action(async (user_id, options) => {
275
+ const spinner = createSpinner('Creating user...').start();
276
+ try {
277
+ const data = await client.suspendUser({
278
+ user_id: Number(user_id),
279
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
280
+ });
281
+
282
+ spinner.stop();
283
+ formatter.success('User created successfully');
284
+ formatter.output(data);
285
+ } catch (error: any) {
286
+ spinner.stop();
287
+ formatter.error(error.message);
288
+ process.exit(1);
289
+ }
290
+ });
291
+
292
+
293
+ cmd
294
+ .command('unsuspend <user-id>')
295
+ .description('Unsuspend a user')
296
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
297
+ .action(async (user_id, options) => {
298
+ const spinner = createSpinner('Creating user...').start();
299
+ try {
300
+ const data = await client.unsuspendUser({
301
+ user_id: Number(user_id),
302
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
303
+ });
304
+
305
+ spinner.stop();
306
+ formatter.success('User created successfully');
307
+ formatter.output(data);
308
+ } catch (error: any) {
309
+ spinner.stop();
310
+ formatter.error(error.message);
311
+ process.exit(1);
312
+ }
313
+ });
314
+
315
+
316
+ cmd
317
+ .command('confirm <user-id>')
318
+ .description('Confirm a user')
319
+ .requiredOption('--confirmation <value>', 'Confirmation hash from the verification email')
320
+ .requiredOption('--password <value>', 'Password to set for the new account (minimum 8 characters)')
321
+ .action(async (user_id, options) => {
322
+ const spinner = createSpinner('Creating user...').start();
323
+ try {
324
+ const data = await client.confirmUser({
325
+ user_id,
326
+ confirmation: options.confirmation,
327
+ password: options.password,
328
+ });
329
+
330
+ spinner.stop();
331
+ formatter.success('User created successfully');
332
+ formatter.output(data);
333
+ } catch (error: any) {
334
+ spinner.stop();
335
+ formatter.error(error.message);
336
+ process.exit(1);
337
+ }
338
+ });
339
+
340
+
341
+ cmd
342
+ .command('resend-user-verification <user-id>')
343
+ .description('Resend the user verification email')
344
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
345
+ .action(async (user_id, options) => {
346
+ const spinner = createSpinner('Creating user...').start();
347
+ try {
348
+ const data = await client.resendUserVerification({
349
+ user_id,
350
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
351
+ });
352
+
353
+ spinner.stop();
354
+ formatter.success('User created successfully');
355
+ formatter.output(data);
356
+ } catch (error: any) {
357
+ spinner.stop();
358
+ formatter.error(error.message);
359
+ process.exit(1);
360
+ }
361
+ });
362
+
363
+
364
+ cmd
365
+ .command('list-mfa')
366
+ .description('List active MFA methods')
367
+ .option('--page <value>', 'page')
368
+ .option('--per-page <value>', 'per_page')
369
+ .option('--with-count <value>', 'Include count in the response')
370
+ .action(async (options) => {
371
+ const spinner = createSpinner('Fetching user...').start();
372
+ try {
373
+ const data = await client.listMfa({
374
+ page: options.page != null ? Number(options.page) : undefined,
375
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
376
+ withCount: options.withCount,
377
+ });
378
+
379
+ spinner.stop();
380
+ formatter.output(data);
381
+ } catch (error: any) {
382
+ spinner.stop();
383
+ formatter.error(error.message);
384
+ process.exit(1);
385
+ }
386
+ });
387
+
388
+
389
+ cmd
390
+ .command('create-mfa')
391
+ .description('Attach an MFA method')
392
+ .requiredOption('--type <value>', 'An enumeration.')
393
+ .option('--description <value>', 'description')
394
+ .action(async (options) => {
395
+ const spinner = createSpinner('Creating user...').start();
396
+ try {
397
+ const data = await client.createMfa({
398
+ type: options.type,
399
+ description: options.description,
400
+ });
401
+
402
+ spinner.stop();
403
+ formatter.success('User created successfully');
404
+ formatter.output(data);
405
+ } catch (error: any) {
406
+ spinner.stop();
407
+ formatter.error(error.message);
408
+ process.exit(1);
409
+ }
410
+ });
411
+
412
+
413
+ cmd
414
+ .command('activate-mfa <mfa-id>')
415
+ .description('Activate an MFA method')
416
+ .requiredOption('--code <value>', '6 digit code from this MFA method')
417
+ .action(async (mfa_id, options) => {
418
+ const spinner = createSpinner('Creating user...').start();
419
+ try {
420
+ const data = await client.activateMfa({
421
+ mfa_id,
422
+ code: options.code,
423
+ });
424
+
425
+ spinner.stop();
426
+ formatter.success('User created successfully');
427
+ formatter.output(data);
428
+ } catch (error: any) {
429
+ spinner.stop();
430
+ formatter.error(error.message);
431
+ process.exit(1);
432
+ }
433
+ });
434
+
435
+
436
+ cmd
437
+ .command('get-mfa-recovery-codes')
438
+ .description('Get MFA recovery codes')
439
+ .action(async () => {
440
+ const spinner = createSpinner('Fetching user...').start();
441
+ try {
442
+ const data = await client.getMfaRecoveryCodes({
443
+ });
444
+
445
+ spinner.stop();
446
+ formatter.output(data);
447
+ } catch (error: any) {
448
+ spinner.stop();
449
+ formatter.error(error.message);
450
+ process.exit(1);
451
+ }
452
+ });
453
+
454
+
455
+ cmd
456
+ .command('get-mfa-portal')
457
+ .description('Get the MFA portal URL')
458
+ .option('--return-url <value>', 'return_url')
459
+ .action(async (options) => {
460
+ const spinner = createSpinner('Fetching user...').start();
461
+ try {
462
+ const data = await client.getMfaPortal({
463
+ returnUrl: options.returnUrl,
464
+ });
465
+
466
+ spinner.stop();
467
+ formatter.output(data);
468
+ } catch (error: any) {
469
+ spinner.stop();
470
+ formatter.error(error.message);
471
+ process.exit(1);
472
+ }
473
+ });
474
+
475
+
476
+ cmd
477
+ .command('delete-mfa <mfa-id>')
478
+ .description('Remove an MFA method')
479
+ .option('-f, --force', 'Skip confirmation prompt')
480
+ .action(async (mfa_idoptions) => {
481
+ if (!options.force) {
482
+ const confirmed = await confirmDelete('user', mfa_id);
483
+ if (!confirmed) {
484
+ formatter.info('Deletion cancelled');
485
+ return;
486
+ }
487
+ }
488
+
489
+ const spinner = createSpinner('Deleting user...').start();
490
+ try {
491
+ const data = await client.deleteMfa({
492
+ mfa_id,
493
+ });
494
+
495
+ spinner.stop();
496
+ formatter.success('User deleted successfully');
497
+ } catch (error: any) {
498
+ spinner.stop();
499
+ formatter.error(error.message);
500
+ process.exit(1);
501
+ }
502
+ });
503
+
504
+
505
+ return cmd;
506
+ }
@@ -0,0 +1,172 @@
1
+ // ABOUTME: CLI commands for Webhook.
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 createWebhooksCommand(
8
+ client: any,
9
+ formatter: any
10
+ ): Command {
11
+ const cmd = new Command('webhooks')
12
+ .description('Configure webhooks to receive real-time HTTP notifications when email events occur (delivery, open, click, bounce, unsubscribe, spam complaint). Webhooks can be filtered by event type and archived when no longer needed.');
13
+
14
+
15
+ cmd
16
+ .command('list')
17
+ .description('List all webhooks')
18
+ .option('--with-archived <value>', 'with_archived')
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 (options) => {
24
+ const spinner = createSpinner('Fetching webhook...').start();
25
+ try {
26
+ const data = await client.listWebhooks({
27
+ withArchived: options.withArchived,
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')
46
+ .description('Create a webhook')
47
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
48
+ .requiredOption('--event <value>', 'An enumeration.')
49
+ .requiredOption('--url <value>', 'url')
50
+ .option('--rate-limit <value>', 'rate_limit')
51
+ .option('--rate-limit-period <value>', 'rate_limit_period')
52
+ .action(async (options) => {
53
+ const spinner = createSpinner('Creating webhook...').start();
54
+ try {
55
+ const data = await client.createWebhook({
56
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
57
+ event: options.event,
58
+ url: options.url,
59
+ rateLimit: options.rateLimit != null ? Number(options.rateLimit) : undefined,
60
+ rateLimitPeriod: options.rateLimitPeriod,
61
+ });
62
+
63
+ spinner.stop();
64
+ formatter.success('Webhook created successfully');
65
+ formatter.output(data);
66
+ } catch (error: any) {
67
+ spinner.stop();
68
+ formatter.error(error.message);
69
+ process.exit(1);
70
+ }
71
+ });
72
+
73
+
74
+ cmd
75
+ .command('archive <webhook-id>')
76
+ .description('Archive a webhook')
77
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
78
+ .action(async (webhook_id, options) => {
79
+ const spinner = createSpinner('Creating webhook...').start();
80
+ try {
81
+ const data = await client.archiveWebhook({
82
+ webhook_id,
83
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
84
+ });
85
+
86
+ spinner.stop();
87
+ formatter.success('Webhook created successfully');
88
+ formatter.output(data);
89
+ } catch (error: any) {
90
+ spinner.stop();
91
+ formatter.error(error.message);
92
+ process.exit(1);
93
+ }
94
+ });
95
+
96
+
97
+ cmd
98
+ .command('unarchive <webhook-id>')
99
+ .description('Unarchive a webhook')
100
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
101
+ .action(async (webhook_id, options) => {
102
+ const spinner = createSpinner('Creating webhook...').start();
103
+ try {
104
+ const data = await client.unarchiveWebhook({
105
+ webhook_id,
106
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
107
+ });
108
+
109
+ spinner.stop();
110
+ formatter.success('Webhook created successfully');
111
+ formatter.output(data);
112
+ } catch (error: any) {
113
+ spinner.stop();
114
+ formatter.error(error.message);
115
+ process.exit(1);
116
+ }
117
+ });
118
+
119
+
120
+ cmd
121
+ .command('get <webhook-id>')
122
+ .description('Show a webhook')
123
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
124
+ .action(async (webhook_id, options) => {
125
+ const spinner = createSpinner('Fetching webhook...').start();
126
+ try {
127
+ const data = await client.getWebhook({
128
+ webhook_id,
129
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
130
+ });
131
+
132
+ spinner.stop();
133
+ formatter.output(data);
134
+ } catch (error: any) {
135
+ spinner.stop();
136
+ formatter.error(error.message);
137
+ process.exit(1);
138
+ }
139
+ });
140
+
141
+
142
+ cmd
143
+ .command('patch <webhook-id>')
144
+ .description('Patch a webhook')
145
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
146
+ .option('--url <value>', 'url')
147
+ .option('--rate-limit <value>', 'rate_limit')
148
+ .option('--rate-limit-period <value>', 'An enumeration.')
149
+ .action(async (webhook_id, options) => {
150
+ const spinner = createSpinner('Updating webhook...').start();
151
+ try {
152
+ const data = await client.patchWebhook({
153
+ webhook_id,
154
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
155
+ url: options.url,
156
+ rateLimit: options.rateLimit != null ? Number(options.rateLimit) : undefined,
157
+ rateLimitPeriod: options.rateLimitPeriod,
158
+ });
159
+
160
+ spinner.stop();
161
+ formatter.success('Webhook updated successfully');
162
+ formatter.output(data);
163
+ } catch (error: any) {
164
+ spinner.stop();
165
+ formatter.error(error.message);
166
+ process.exit(1);
167
+ }
168
+ });
169
+
170
+
171
+ return cmd;
172
+ }