@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,158 @@
1
+ // ABOUTME: CLI commands for Segment.
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 createSegmentsCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('segments')
13
+ .description('Create and manage segments within lists. A segment is a dynamic filter that defines a subset of contacts based on query criteria. Segments can be defined using SQL-like expressions, FIQL, or JSON query format. Segments are used to target specific audiences when sending campaigns.');
14
+
15
+
16
+ cmd
17
+ .command('list <list-id>')
18
+ .description('Show all segments')
19
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
20
+ .option('--page <value>', 'page')
21
+ .option('--per-page <value>', 'per_page')
22
+ .option('--with-count <value>', 'Include count in the response')
23
+ .option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
24
+
25
+ Valid terms:
26
+ - `id`
27
+ - `name`
28
+ - `created_on`')
29
+ .action(async (list_id, options) => {
30
+ const spinner = createSpinner('Fetching segment...').start();
31
+ try {
32
+ const data = await client.listSegments({
33
+ list_id: Number(list_id),
34
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
35
+ page: options.page != null ? Number(options.page) : undefined,
36
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
37
+ withCount: options.withCount,
38
+ sort: options.sort,
39
+ });
40
+
41
+ spinner.stop();
42
+ formatter.output(data);
43
+ } catch (error: any) {
44
+ spinner.stop();
45
+ formatter.error(error.message);
46
+ process.exit(1);
47
+ }
48
+ });
49
+
50
+
51
+ cmd
52
+ .command('create <list-id>')
53
+ .description('Create a segment')
54
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
55
+ .requiredOption('--data <value>', 'Request body as JSON string')
56
+ .action(async (list_id, options) => {
57
+ const spinner = createSpinner('Creating segment...').start();
58
+ try {
59
+ const body = JSON.parse(options.data);
60
+ const data = await client.createSegment({
61
+ list_id: Number(list_id),
62
+ ...body,
63
+ });
64
+
65
+ spinner.stop();
66
+ formatter.success('Segment 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('get <list-id> <segment-id>')
78
+ .description('Show a segment details')
79
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
80
+ .action(async (list_id, segment_id, options) => {
81
+ const spinner = createSpinner('Fetching segment...').start();
82
+ try {
83
+ const data = await client.getSegment({
84
+ list_id: Number(list_id),
85
+ segment_id: Number(segment_id),
86
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
87
+ });
88
+
89
+ spinner.stop();
90
+ formatter.output(data);
91
+ } catch (error: any) {
92
+ spinner.stop();
93
+ formatter.error(error.message);
94
+ process.exit(1);
95
+ }
96
+ });
97
+
98
+
99
+ cmd
100
+ .command('patch <list-id> <segment-id>')
101
+ .description('Update a segment')
102
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
103
+ .requiredOption('--data <value>', 'Request body as JSON string')
104
+ .action(async (list_id, segment_id, options) => {
105
+ const spinner = createSpinner('Updating segment...').start();
106
+ try {
107
+ const body = JSON.parse(options.data);
108
+ const data = await client.patchSegment({
109
+ list_id: Number(list_id),
110
+ segment_id: Number(segment_id),
111
+ ...body,
112
+ });
113
+
114
+ spinner.stop();
115
+ formatter.success('Segment updated successfully');
116
+ formatter.output(data);
117
+ } catch (error: any) {
118
+ spinner.stop();
119
+ formatter.error(error.message);
120
+ process.exit(1);
121
+ }
122
+ });
123
+
124
+
125
+ cmd
126
+ .command('delete <list-id> <segment-id>')
127
+ .description('Delete a segment')
128
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
129
+ .option('-f, --force', 'Skip confirmation prompt')
130
+ .action(async (list_id, segment_id, options) => {
131
+ if (!options.force) {
132
+ const confirmed = await confirmDelete('segment', list_id);
133
+ if (!confirmed) {
134
+ formatter.info('Deletion cancelled');
135
+ return;
136
+ }
137
+ }
138
+
139
+ const spinner = createSpinner('Deleting segment...').start();
140
+ try {
141
+ const data = await client.deleteSegment({
142
+ list_id: Number(list_id),
143
+ segment_id: Number(segment_id),
144
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
145
+ });
146
+
147
+ spinner.stop();
148
+ formatter.success('Segment deleted successfully');
149
+ } catch (error: any) {
150
+ spinner.stop();
151
+ formatter.error(error.message);
152
+ process.exit(1);
153
+ }
154
+ });
155
+
156
+
157
+ return cmd;
158
+ }
@@ -0,0 +1,204 @@
1
+ // ABOUTME: CLI commands for Sender.
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 createSendersCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('senders')
13
+ .description('Manage sender identities (name and email pairs) used as the 'From' address in campaigns and transactional emails. New senders require email confirmation before use.');
14
+
15
+
16
+ cmd
17
+ .command('list')
18
+ .description('Show all senders')
19
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
20
+ .option('--page <value>', 'page')
21
+ .option('--per-page <value>', 'per_page')
22
+ .option('--with-count <value>', 'Include count in the response')
23
+ .option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
24
+
25
+ Valid terms:
26
+ - `name`
27
+ - `email`
28
+ - `confirmed`')
29
+ .action(async (options) => {
30
+ const spinner = createSpinner('Fetching sender...').start();
31
+ try {
32
+ const data = await client.listSenders({
33
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
34
+ page: options.page != null ? Number(options.page) : undefined,
35
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
36
+ withCount: options.withCount,
37
+ sort: options.sort,
38
+ });
39
+
40
+ spinner.stop();
41
+ formatter.output(data);
42
+ } catch (error: any) {
43
+ spinner.stop();
44
+ formatter.error(error.message);
45
+ process.exit(1);
46
+ }
47
+ });
48
+
49
+
50
+ cmd
51
+ .command('create')
52
+ .description('Add a sender')
53
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
54
+ .requiredOption('--name <value>', 'Display name of the sender')
55
+ .requiredOption('--email <value>', 'Email address of the sender')
56
+ .option('--language <value>', 'Language for sender-related communications')
57
+ .action(async (options) => {
58
+ const spinner = createSpinner('Creating sender...').start();
59
+ try {
60
+ const data = await client.createSender({
61
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
62
+ name: options.name,
63
+ email: options.email,
64
+ language: options.language,
65
+ });
66
+
67
+ spinner.stop();
68
+ formatter.success('Sender created successfully');
69
+ formatter.output(data);
70
+ } catch (error: any) {
71
+ spinner.stop();
72
+ formatter.error(error.message);
73
+ process.exit(1);
74
+ }
75
+ });
76
+
77
+
78
+ cmd
79
+ .command('get <sender-id>')
80
+ .description('Show a sender details')
81
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
82
+ .action(async (sender_id, options) => {
83
+ const spinner = createSpinner('Fetching sender...').start();
84
+ try {
85
+ const data = await client.getSender({
86
+ sender_id,
87
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
88
+ });
89
+
90
+ spinner.stop();
91
+ formatter.output(data);
92
+ } catch (error: any) {
93
+ spinner.stop();
94
+ formatter.error(error.message);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+
100
+ cmd
101
+ .command('patch <sender-id>')
102
+ .description('Update a sender')
103
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
104
+ .option('--name <value>', 'Display name of the sender')
105
+ .option('--language <value>', 'Language for sender-related communications')
106
+ .action(async (sender_id, options) => {
107
+ const spinner = createSpinner('Updating sender...').start();
108
+ try {
109
+ const data = await client.patchSender({
110
+ sender_id,
111
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
112
+ name: options.name,
113
+ language: options.language,
114
+ });
115
+
116
+ spinner.stop();
117
+ formatter.success('Sender updated successfully');
118
+ formatter.output(data);
119
+ } catch (error: any) {
120
+ spinner.stop();
121
+ formatter.error(error.message);
122
+ process.exit(1);
123
+ }
124
+ });
125
+
126
+
127
+ cmd
128
+ .command('delete <sender-id>')
129
+ .description('Delete a sender')
130
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
131
+ .option('-f, --force', 'Skip confirmation prompt')
132
+ .action(async (sender_id, options) => {
133
+ if (!options.force) {
134
+ const confirmed = await confirmDelete('sender', sender_id);
135
+ if (!confirmed) {
136
+ formatter.info('Deletion cancelled');
137
+ return;
138
+ }
139
+ }
140
+
141
+ const spinner = createSpinner('Deleting sender...').start();
142
+ try {
143
+ const data = await client.deleteSender({
144
+ sender_id,
145
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
146
+ });
147
+
148
+ spinner.stop();
149
+ formatter.success('Sender deleted successfully');
150
+ } catch (error: any) {
151
+ spinner.stop();
152
+ formatter.error(error.message);
153
+ process.exit(1);
154
+ }
155
+ });
156
+
157
+
158
+ cmd
159
+ .command('confirm')
160
+ .description('Confirm a sender')
161
+ .requiredOption('--confirmation-id <value>', 'Confirmation token from the verification email')
162
+ .action(async (options) => {
163
+ const spinner = createSpinner('Creating sender...').start();
164
+ try {
165
+ const data = await client.confirmSender({
166
+ confirmationId: options.confirmationId,
167
+ });
168
+
169
+ spinner.stop();
170
+ formatter.success('Sender created successfully');
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('resend-confirmation-email <sender-id>')
182
+ .description('Resend confirmation email')
183
+ .option('--account-id <value>', 'Optional Account ID to be used for the request')
184
+ .action(async (sender_id, options) => {
185
+ const spinner = createSpinner('Creating sender...').start();
186
+ try {
187
+ const data = await client.resendConfirmationEmail({
188
+ sender_id,
189
+ accountId: options.accountId != null ? Number(options.accountId) : undefined,
190
+ });
191
+
192
+ spinner.stop();
193
+ formatter.success('Sender created successfully');
194
+ formatter.output(data);
195
+ } catch (error: any) {
196
+ spinner.stop();
197
+ formatter.error(error.message);
198
+ process.exit(1);
199
+ }
200
+ });
201
+
202
+
203
+ return cmd;
204
+ }
@@ -0,0 +1,271 @@
1
+ // ABOUTME: CLI commands for Sub-Account.
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 createSubAccountsCommand(
9
+ client: any,
10
+ formatter: any
11
+ ): Command {
12
+ const cmd = new Command('sub-accounts')
13
+ .description('Manage sub-accounts under a partner or organization account. Sub-accounts are independent accounts with their own users, contacts, and campaigns, managed by the parent account. Includes creation, suspension, and configuration.');
14
+
15
+
16
+ cmd
17
+ .command('list-accounts')
18
+ .description('Show all sub-accounts')
19
+ .option('--partner-account-id <value>', 'partner_account_id')
20
+ .option('--recursive <value>', 'recursive')
21
+ .option('--page <value>', 'page')
22
+ .option('--per-page <value>', 'per_page')
23
+ .option('--with-count <value>', 'Include count in the response')
24
+ .option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
25
+
26
+ Valid terms:
27
+ - `name`
28
+ - `created_on`')
29
+ .option('--filter <value>', 'Valid Terms:
30
+ - `name`
31
+ - `status`
32
+
33
+ Valid Operators:
34
+ - `==`
35
+
36
+ Query separator:
37
+ - `;`')
38
+ .action(async (options) => {
39
+ const spinner = createSpinner('Fetching sub-account...').start();
40
+ try {
41
+ const data = await client.listAccounts({
42
+ partnerAccountId: options.partnerAccountId != null ? Number(options.partnerAccountId) : undefined,
43
+ recursive: options.recursive,
44
+ page: options.page != null ? Number(options.page) : undefined,
45
+ perPage: options.perPage != null ? Number(options.perPage) : undefined,
46
+ withCount: options.withCount,
47
+ sort: options.sort,
48
+ filter: options.filter,
49
+ });
50
+
51
+ spinner.stop();
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('create-account')
63
+ .description('Create a sub-account')
64
+ .option('--partner-account-id <value>', 'partner_account_id')
65
+ .option('--skip-verification <value>', 'skip_verification')
66
+ .requiredOption('--data <value>', 'Request body as JSON string')
67
+ .action(async (options) => {
68
+ const spinner = createSpinner('Creating sub-account...').start();
69
+ try {
70
+ const body = JSON.parse(options.data);
71
+ const data = await client.createAccount({
72
+ ...body,
73
+ });
74
+
75
+ spinner.stop();
76
+ formatter.success('Sub-Account created successfully');
77
+ formatter.output(data);
78
+ } catch (error: any) {
79
+ spinner.stop();
80
+ formatter.error(error.message);
81
+ process.exit(1);
82
+ }
83
+ });
84
+
85
+
86
+ cmd
87
+ .command('get-account <account-id>')
88
+ .description('Show sub-account details')
89
+ .action(async (account_id) => {
90
+ const spinner = createSpinner('Fetching sub-account...').start();
91
+ try {
92
+ const data = await client.getAccount({
93
+ account_id,
94
+ });
95
+
96
+ spinner.stop();
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('patch-account <account-id>')
108
+ .description('Update a sub-account')
109
+ .requiredOption('--data <value>', 'Request body as JSON string')
110
+ .action(async (account_id, options) => {
111
+ const spinner = createSpinner('Updating sub-account...').start();
112
+ try {
113
+ const body = JSON.parse(options.data);
114
+ const data = await client.patchAccount({
115
+ account_id: Number(account_id),
116
+ ...body,
117
+ });
118
+
119
+ spinner.stop();
120
+ formatter.success('Sub-Account updated 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('delete-account <account-id>')
132
+ .description('Delete a sub-account')
133
+ .option('-f, --force', 'Skip confirmation prompt')
134
+ .action(async (account_idoptions) => {
135
+ if (!options.force) {
136
+ const confirmed = await confirmDelete('sub-account', account_id);
137
+ if (!confirmed) {
138
+ formatter.info('Deletion cancelled');
139
+ return;
140
+ }
141
+ }
142
+
143
+ const spinner = createSpinner('Deleting sub-account...').start();
144
+ try {
145
+ const data = await client.deleteAccount({
146
+ account_id,
147
+ });
148
+
149
+ spinner.stop();
150
+ formatter.success('Sub-Account deleted successfully');
151
+ } catch (error: any) {
152
+ spinner.stop();
153
+ formatter.error(error.message);
154
+ process.exit(1);
155
+ }
156
+ });
157
+
158
+
159
+ cmd
160
+ .command('suspend-account <account-id>')
161
+ .description('Suspend a sub-account')
162
+ .action(async (account_id) => {
163
+ const spinner = createSpinner('Creating sub-account...').start();
164
+ try {
165
+ const data = await client.suspendAccount({
166
+ account_id: Number(account_id),
167
+ });
168
+
169
+ spinner.stop();
170
+ formatter.success('Sub-Account created successfully');
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('unsuspend-account <account-id>')
182
+ .description('Unsuspend a sub-account')
183
+ .action(async (account_id) => {
184
+ const spinner = createSpinner('Creating sub-account...').start();
185
+ try {
186
+ const data = await client.unsuspendAccount({
187
+ account_id: Number(account_id),
188
+ });
189
+
190
+ spinner.stop();
191
+ formatter.success('Sub-Account created successfully');
192
+ formatter.output(data);
193
+ } catch (error: any) {
194
+ spinner.stop();
195
+ formatter.error(error.message);
196
+ process.exit(1);
197
+ }
198
+ });
199
+
200
+
201
+ cmd
202
+ .command('confirm-account <account-id>')
203
+ .description('Confirm sub-account creation')
204
+ .requiredOption('--confirmation <value>', 'confirmation')
205
+ .action(async (account_id, options) => {
206
+ const spinner = createSpinner('Creating sub-account...').start();
207
+ try {
208
+ const data = await client.confirmAccount({
209
+ account_id,
210
+ confirmation: options.confirmation,
211
+ });
212
+
213
+ spinner.stop();
214
+ formatter.success('Sub-Account created successfully');
215
+ formatter.output(data);
216
+ } catch (error: any) {
217
+ spinner.stop();
218
+ formatter.error(error.message);
219
+ process.exit(1);
220
+ }
221
+ });
222
+
223
+
224
+ cmd
225
+ .command('resend-account-verification')
226
+ .description('Resend the account verification email')
227
+ .requiredOption('--email <value>', 'Email address to resend the verification to')
228
+ .action(async (options) => {
229
+ const spinner = createSpinner('Creating sub-account...').start();
230
+ try {
231
+ const data = await client.resendAccountVerification({
232
+ email: options.email,
233
+ });
234
+
235
+ spinner.stop();
236
+ formatter.success('Sub-Account created successfully');
237
+ formatter.output(data);
238
+ } catch (error: any) {
239
+ spinner.stop();
240
+ formatter.error(error.message);
241
+ process.exit(1);
242
+ }
243
+ });
244
+
245
+
246
+ cmd
247
+ .command('convert-account-to-organization <account-id>')
248
+ .description('Convert an account to an Organization')
249
+ .requiredOption('--data <value>', 'Request body as JSON string')
250
+ .action(async (account_id, options) => {
251
+ const spinner = createSpinner('Creating sub-account...').start();
252
+ try {
253
+ const body = JSON.parse(options.data);
254
+ const data = await client.convertAccountToOrganization({
255
+ account_id: Number(account_id),
256
+ ...body,
257
+ });
258
+
259
+ spinner.stop();
260
+ formatter.success('Sub-Account created successfully');
261
+ formatter.output(data);
262
+ } catch (error: any) {
263
+ spinner.stop();
264
+ formatter.error(error.message);
265
+ process.exit(1);
266
+ }
267
+ });
268
+
269
+
270
+ return cmd;
271
+ }