@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.
- package/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +319 -15
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/cli.js +27 -10
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.d.ts.map +1 -1
- package/dist/commands/campaigns.js +103 -8
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +63 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +91 -12
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.d.ts +5 -0
- package/dist/commands/interests.d.ts.map +1 -0
- package/dist/commands/interests.js +172 -0
- package/dist/commands/interests.js.map +1 -0
- package/dist/commands/lists.d.ts.map +1 -1
- package/dist/commands/lists.js +6 -8
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +237 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.d.ts.map +1 -1
- package/dist/commands/senders.js +11 -8
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.d.ts +5 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +124 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.d.ts +5 -0
- package/dist/commands/transactional-templates.d.ts.map +1 -0
- package/dist/commands/transactional-templates.js +354 -0
- package/dist/commands/transactional-templates.js.map +1 -0
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/auth.d.ts +8 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +39 -11
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-file.d.ts +7 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +15 -0
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/list-defaults.d.ts +33 -0
- package/dist/utils/list-defaults.d.ts.map +1 -0
- package/dist/utils/list-defaults.js +52 -0
- package/dist/utils/list-defaults.js.map +1 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +36 -13
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -47
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- 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
|
+
}
|