@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,612 @@
|
|
|
1
|
+
// ABOUTME: CLI commands for Contact.
|
|
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 createContactsCommand(
|
|
9
|
+
client: any,
|
|
10
|
+
formatter: any
|
|
11
|
+
): Command {
|
|
12
|
+
const cmd = new Command('contacts')
|
|
13
|
+
.description('Manage contacts within lists. Contacts are individual email subscribers with an email address, subscription status, custom attributes, tags, and interests. Supports creating, importing, updating, unsubscribing, and deleting contacts. Bulk operations are available for tagging and interest management. Contact data can be exported to CSV files.');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cmd
|
|
17
|
+
.command('add-interests-to <list-id>')
|
|
18
|
+
.description('Add interest(s) to contact(s)')
|
|
19
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
20
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
21
|
+
.action(async (list_id, options) => {
|
|
22
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
23
|
+
try {
|
|
24
|
+
const body = JSON.parse(options.data);
|
|
25
|
+
const data = await client.addInterestsToContacts({
|
|
26
|
+
list_id: Number(list_id),
|
|
27
|
+
...body,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
spinner.stop();
|
|
31
|
+
formatter.success('Contact created successfully');
|
|
32
|
+
formatter.output(data);
|
|
33
|
+
} catch (error: any) {
|
|
34
|
+
spinner.stop();
|
|
35
|
+
formatter.error(error.message);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
cmd
|
|
42
|
+
.command('list-contacts-of-list <list-id>')
|
|
43
|
+
.description('Show contacts of a list')
|
|
44
|
+
.option('--query <value>', 'SQL selection query (only use one of query, fiql and json)')
|
|
45
|
+
.option('--json <value>', 'JSON selection expression (only use one of query, fiql and json)')
|
|
46
|
+
.option('--cursor <value>', 'Cursor pagination')
|
|
47
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
48
|
+
.option('--page <value>', 'page')
|
|
49
|
+
.option('--per-page <value>', 'per_page')
|
|
50
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
51
|
+
.option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
|
|
52
|
+
|
|
53
|
+
Valid terms:
|
|
54
|
+
- `id`
|
|
55
|
+
- `email`
|
|
56
|
+
- `status`
|
|
57
|
+
- `subscribed_on`
|
|
58
|
+
- `last_bounce_type`
|
|
59
|
+
- `bounces_count`')
|
|
60
|
+
.option('--filter <value>', 'Valid Terms:
|
|
61
|
+
- `status`
|
|
62
|
+
- `email`
|
|
63
|
+
- `tags`
|
|
64
|
+
- `interests`
|
|
65
|
+
|
|
66
|
+
Valid Operators:
|
|
67
|
+
- `==`
|
|
68
|
+
|
|
69
|
+
Query separator:
|
|
70
|
+
- `;`')
|
|
71
|
+
.option('--fiql <value>', 'fiql')
|
|
72
|
+
.action(async (list_id, options) => {
|
|
73
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
74
|
+
try {
|
|
75
|
+
const data = await client.listContactsOfList({
|
|
76
|
+
list_id: Number(list_id),
|
|
77
|
+
query: options.query,
|
|
78
|
+
json: options.json,
|
|
79
|
+
cursor: options.cursor,
|
|
80
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
81
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
82
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
83
|
+
withCount: options.withCount,
|
|
84
|
+
sort: options.sort,
|
|
85
|
+
filter: options.filter,
|
|
86
|
+
fiql: options.fiql,
|
|
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('create <list-id>')
|
|
101
|
+
.description('Add a contact')
|
|
102
|
+
.option('--send-double-opt-in <value>', 'send_double_opt_in')
|
|
103
|
+
.option('--resubscribe <value>', 'resubscribe')
|
|
104
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
105
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
106
|
+
.action(async (list_id, options) => {
|
|
107
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
108
|
+
try {
|
|
109
|
+
const body = JSON.parse(options.data);
|
|
110
|
+
const data = await client.createContact({
|
|
111
|
+
list_id: Number(list_id),
|
|
112
|
+
...body,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
spinner.stop();
|
|
116
|
+
formatter.success('Contact created successfully');
|
|
117
|
+
formatter.output(data);
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
spinner.stop();
|
|
120
|
+
formatter.error(error.message);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
cmd
|
|
127
|
+
.command('list-contacts-of-segment <segment-id> <list-id>')
|
|
128
|
+
.description('Show contacts of a segment')
|
|
129
|
+
.option('--query <value>', 'SQL selection query (only use one of query, fiql and json)')
|
|
130
|
+
.option('--json <value>', 'JSON selection expression (only use one of query, fiql and json)')
|
|
131
|
+
.option('--cursor <value>', 'Cursor pagination')
|
|
132
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
133
|
+
.option('--page <value>', 'page')
|
|
134
|
+
.option('--per-page <value>', 'per_page')
|
|
135
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
136
|
+
.option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
|
|
137
|
+
|
|
138
|
+
Valid terms:
|
|
139
|
+
- `id`
|
|
140
|
+
- `email`
|
|
141
|
+
- `status`
|
|
142
|
+
- `subscribed_on`
|
|
143
|
+
- `last_bounce_type`
|
|
144
|
+
- `bounces_count`')
|
|
145
|
+
.option('--filter <value>', 'Valid Terms:
|
|
146
|
+
- `status`
|
|
147
|
+
- `email`
|
|
148
|
+
- `tags`
|
|
149
|
+
- `interests`
|
|
150
|
+
|
|
151
|
+
Valid Operators:
|
|
152
|
+
- `==`
|
|
153
|
+
|
|
154
|
+
Query separator:
|
|
155
|
+
- `;`')
|
|
156
|
+
.option('--fiql <value>', 'fiql')
|
|
157
|
+
.action(async (segment_id, list_id, options) => {
|
|
158
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
159
|
+
try {
|
|
160
|
+
const data = await client.listContactsOfSegment({
|
|
161
|
+
segment_id: Number(segment_id),
|
|
162
|
+
list_id: Number(list_id),
|
|
163
|
+
query: options.query,
|
|
164
|
+
json: options.json,
|
|
165
|
+
cursor: options.cursor,
|
|
166
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
167
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
168
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
169
|
+
withCount: options.withCount,
|
|
170
|
+
sort: options.sort,
|
|
171
|
+
filter: options.filter,
|
|
172
|
+
fiql: options.fiql,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
spinner.stop();
|
|
176
|
+
formatter.output(data);
|
|
177
|
+
} catch (error: any) {
|
|
178
|
+
spinner.stop();
|
|
179
|
+
formatter.error(error.message);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
cmd
|
|
186
|
+
.command('tag-multiple <list-id>')
|
|
187
|
+
.description('Tags multiple contacts')
|
|
188
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
189
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
190
|
+
.action(async (list_id, options) => {
|
|
191
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
192
|
+
try {
|
|
193
|
+
const body = JSON.parse(options.data);
|
|
194
|
+
const data = await client.tagMultipleContacts({
|
|
195
|
+
list_id: Number(list_id),
|
|
196
|
+
...body,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
spinner.stop();
|
|
200
|
+
formatter.success('Contact created successfully');
|
|
201
|
+
formatter.output(data);
|
|
202
|
+
} catch (error: any) {
|
|
203
|
+
spinner.stop();
|
|
204
|
+
formatter.error(error.message);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
cmd
|
|
211
|
+
.command('untag-multiple <list-id>')
|
|
212
|
+
.description('Untags multiple contacts')
|
|
213
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
214
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
215
|
+
.action(async (list_id, options) => {
|
|
216
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
217
|
+
try {
|
|
218
|
+
const body = JSON.parse(options.data);
|
|
219
|
+
const data = await client.untagMultipleContacts({
|
|
220
|
+
list_id: Number(list_id),
|
|
221
|
+
...body,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
spinner.stop();
|
|
225
|
+
formatter.success('Contact created successfully');
|
|
226
|
+
formatter.output(data);
|
|
227
|
+
} catch (error: any) {
|
|
228
|
+
spinner.stop();
|
|
229
|
+
formatter.error(error.message);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
cmd
|
|
236
|
+
.command('get <list-id> <contact-id>')
|
|
237
|
+
.description('Show a contact details')
|
|
238
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
239
|
+
.action(async (list_id, contact_id, options) => {
|
|
240
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
241
|
+
try {
|
|
242
|
+
const data = await client.getContact({
|
|
243
|
+
list_id: Number(list_id),
|
|
244
|
+
contact_id: Number(contact_id),
|
|
245
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
spinner.stop();
|
|
249
|
+
formatter.output(data);
|
|
250
|
+
} catch (error: any) {
|
|
251
|
+
spinner.stop();
|
|
252
|
+
formatter.error(error.message);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
cmd
|
|
259
|
+
.command('patch <list-id> <contact-id>')
|
|
260
|
+
.description('Update a contact')
|
|
261
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
262
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
263
|
+
.action(async (list_id, contact_id, options) => {
|
|
264
|
+
const spinner = createSpinner('Updating contact...').start();
|
|
265
|
+
try {
|
|
266
|
+
const body = JSON.parse(options.data);
|
|
267
|
+
const data = await client.patchContact({
|
|
268
|
+
list_id: Number(list_id),
|
|
269
|
+
contact_id: Number(contact_id),
|
|
270
|
+
...body,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
spinner.stop();
|
|
274
|
+
formatter.success('Contact updated successfully');
|
|
275
|
+
formatter.output(data);
|
|
276
|
+
} catch (error: any) {
|
|
277
|
+
spinner.stop();
|
|
278
|
+
formatter.error(error.message);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
cmd
|
|
285
|
+
.command('delete <list-id> <contact-id>')
|
|
286
|
+
.description('Delete a contact')
|
|
287
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
288
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
289
|
+
.action(async (list_id, contact_id, options) => {
|
|
290
|
+
if (!options.force) {
|
|
291
|
+
const confirmed = await confirmDelete('contact', list_id);
|
|
292
|
+
if (!confirmed) {
|
|
293
|
+
formatter.info('Deletion cancelled');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const spinner = createSpinner('Deleting contact...').start();
|
|
299
|
+
try {
|
|
300
|
+
const data = await client.deleteContact({
|
|
301
|
+
list_id: Number(list_id),
|
|
302
|
+
contact_id: Number(contact_id),
|
|
303
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
spinner.stop();
|
|
307
|
+
formatter.success('Contact deleted successfully');
|
|
308
|
+
} catch (error: any) {
|
|
309
|
+
spinner.stop();
|
|
310
|
+
formatter.error(error.message);
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
cmd
|
|
317
|
+
.command('import <list-id>')
|
|
318
|
+
.description('Import contacts')
|
|
319
|
+
.option('--send-double-opt-in <value>', 'send_double_opt_in')
|
|
320
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
321
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
322
|
+
.action(async (list_id, options) => {
|
|
323
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
324
|
+
try {
|
|
325
|
+
const body = JSON.parse(options.data);
|
|
326
|
+
const data = await client.importContacts({
|
|
327
|
+
list_id: Number(list_id),
|
|
328
|
+
...body,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
spinner.stop();
|
|
332
|
+
formatter.success('Contact created successfully');
|
|
333
|
+
formatter.output(data);
|
|
334
|
+
} catch (error: any) {
|
|
335
|
+
spinner.stop();
|
|
336
|
+
formatter.error(error.message);
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
cmd
|
|
343
|
+
.command('unsubscribe <list-id> <contact-id>')
|
|
344
|
+
.description('Unsubscribe a contact from a list')
|
|
345
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
346
|
+
.action(async (list_id, contact_id, options) => {
|
|
347
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
348
|
+
try {
|
|
349
|
+
const data = await client.unsubscribeContact({
|
|
350
|
+
list_id: Number(list_id),
|
|
351
|
+
contact_id: Number(contact_id),
|
|
352
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
spinner.stop();
|
|
356
|
+
formatter.success('Contact created successfully');
|
|
357
|
+
formatter.output(data);
|
|
358
|
+
} catch (error: any) {
|
|
359
|
+
spinner.stop();
|
|
360
|
+
formatter.error(error.message);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
cmd
|
|
367
|
+
.command('tag <list-id> <contact-id>')
|
|
368
|
+
.description('Tags a contact')
|
|
369
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
370
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
371
|
+
.action(async (list_id, contact_id, options) => {
|
|
372
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
373
|
+
try {
|
|
374
|
+
const body = JSON.parse(options.data);
|
|
375
|
+
const data = await client.tagContact({
|
|
376
|
+
list_id: Number(list_id),
|
|
377
|
+
contact_id: Number(contact_id),
|
|
378
|
+
...body,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
spinner.stop();
|
|
382
|
+
formatter.success('Contact created successfully');
|
|
383
|
+
formatter.output(data);
|
|
384
|
+
} catch (error: any) {
|
|
385
|
+
spinner.stop();
|
|
386
|
+
formatter.error(error.message);
|
|
387
|
+
process.exit(1);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
cmd
|
|
393
|
+
.command('untag <list-id> <contact-id>')
|
|
394
|
+
.description('Untags a contact')
|
|
395
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
396
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
397
|
+
.action(async (list_id, contact_id, options) => {
|
|
398
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
399
|
+
try {
|
|
400
|
+
const body = JSON.parse(options.data);
|
|
401
|
+
const data = await client.untagContact({
|
|
402
|
+
list_id: Number(list_id),
|
|
403
|
+
contact_id: Number(contact_id),
|
|
404
|
+
...body,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
spinner.stop();
|
|
408
|
+
formatter.success('Contact created successfully');
|
|
409
|
+
formatter.output(data);
|
|
410
|
+
} catch (error: any) {
|
|
411
|
+
spinner.stop();
|
|
412
|
+
formatter.error(error.message);
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
cmd
|
|
419
|
+
.command('remove-interests-from <list-id>')
|
|
420
|
+
.description('Remove interest(s) from contact(s)')
|
|
421
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
422
|
+
.requiredOption('--data <value>', 'Request body as JSON string')
|
|
423
|
+
.action(async (list_id, options) => {
|
|
424
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
425
|
+
try {
|
|
426
|
+
const body = JSON.parse(options.data);
|
|
427
|
+
const data = await client.removeInterestsFromContacts({
|
|
428
|
+
list_id: Number(list_id),
|
|
429
|
+
...body,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
spinner.stop();
|
|
433
|
+
formatter.success('Contact created successfully');
|
|
434
|
+
formatter.output(data);
|
|
435
|
+
} catch (error: any) {
|
|
436
|
+
spinner.stop();
|
|
437
|
+
formatter.error(error.message);
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
cmd
|
|
444
|
+
.command('list-contacts-exports <list-id>')
|
|
445
|
+
.description('Show all Contacts Exports')
|
|
446
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
447
|
+
.option('--page <value>', 'page')
|
|
448
|
+
.option('--per-page <value>', 'per_page')
|
|
449
|
+
.option('--with-count <value>', 'Include count in the response')
|
|
450
|
+
.option('--sort <value>', 'Sort term and direction, using syntax `[-|+]term`.
|
|
451
|
+
|
|
452
|
+
Valid terms:
|
|
453
|
+
- `status`
|
|
454
|
+
- `created_on`
|
|
455
|
+
- `expires_on`')
|
|
456
|
+
.option('--filter <value>', 'Valid Terms:
|
|
457
|
+
- `status`
|
|
458
|
+
- `progress`
|
|
459
|
+
|
|
460
|
+
Valid Operators:
|
|
461
|
+
- `==`
|
|
462
|
+
|
|
463
|
+
Query separator:
|
|
464
|
+
- `;`')
|
|
465
|
+
.action(async (list_id, options) => {
|
|
466
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
467
|
+
try {
|
|
468
|
+
const data = await client.listContactsExports({
|
|
469
|
+
list_id: Number(list_id),
|
|
470
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
471
|
+
page: options.page != null ? Number(options.page) : undefined,
|
|
472
|
+
perPage: options.perPage != null ? Number(options.perPage) : undefined,
|
|
473
|
+
withCount: options.withCount,
|
|
474
|
+
sort: options.sort,
|
|
475
|
+
filter: options.filter,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
spinner.stop();
|
|
479
|
+
formatter.output(data);
|
|
480
|
+
} catch (error: any) {
|
|
481
|
+
spinner.stop();
|
|
482
|
+
formatter.error(error.message);
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
cmd
|
|
489
|
+
.command('export <list-id>')
|
|
490
|
+
.description('Create a Contacts Export')
|
|
491
|
+
.option('--description <value>', 'description')
|
|
492
|
+
.option('--query <value>', 'query')
|
|
493
|
+
.option('--json <value>', 'json')
|
|
494
|
+
.option('--segment-id <value>', 'segment_id')
|
|
495
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
496
|
+
.option('--filter <value>', 'Valid Terms:
|
|
497
|
+
- `status`
|
|
498
|
+
- `email`
|
|
499
|
+
- `tags`
|
|
500
|
+
- `interests`
|
|
501
|
+
|
|
502
|
+
Valid Operators:
|
|
503
|
+
- `==`
|
|
504
|
+
|
|
505
|
+
Query separator:
|
|
506
|
+
- `;`')
|
|
507
|
+
.option('--fiql <value>', 'fiql')
|
|
508
|
+
.action(async (list_id, options) => {
|
|
509
|
+
const spinner = createSpinner('Creating contact...').start();
|
|
510
|
+
try {
|
|
511
|
+
const data = await client.exportContacts({
|
|
512
|
+
list_id: Number(list_id),
|
|
513
|
+
description: options.description,
|
|
514
|
+
query: options.query,
|
|
515
|
+
json: options.json,
|
|
516
|
+
segmentId: options.segmentId != null ? Number(options.segmentId) : undefined,
|
|
517
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
518
|
+
filter: options.filter,
|
|
519
|
+
fiql: options.fiql,
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
spinner.stop();
|
|
523
|
+
formatter.success('Contact created successfully');
|
|
524
|
+
formatter.output(data);
|
|
525
|
+
} catch (error: any) {
|
|
526
|
+
spinner.stop();
|
|
527
|
+
formatter.error(error.message);
|
|
528
|
+
process.exit(1);
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
cmd
|
|
534
|
+
.command('get-contacts-export <export-id> <list-id>')
|
|
535
|
+
.description('Show a Contacts Export')
|
|
536
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
537
|
+
.action(async (export_id, list_id, options) => {
|
|
538
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
539
|
+
try {
|
|
540
|
+
const data = await client.getContactsExport({
|
|
541
|
+
export_id,
|
|
542
|
+
list_id: Number(list_id),
|
|
543
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
spinner.stop();
|
|
547
|
+
formatter.output(data);
|
|
548
|
+
} catch (error: any) {
|
|
549
|
+
spinner.stop();
|
|
550
|
+
formatter.error(error.message);
|
|
551
|
+
process.exit(1);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
cmd
|
|
557
|
+
.command('delete-contacts-export <export-id> <list-id>')
|
|
558
|
+
.description('Delete a Contacts Export')
|
|
559
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
560
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
561
|
+
.action(async (export_id, list_id, options) => {
|
|
562
|
+
if (!options.force) {
|
|
563
|
+
const confirmed = await confirmDelete('contact', export_id);
|
|
564
|
+
if (!confirmed) {
|
|
565
|
+
formatter.info('Deletion cancelled');
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const spinner = createSpinner('Deleting contact...').start();
|
|
571
|
+
try {
|
|
572
|
+
const data = await client.deleteContactsExport({
|
|
573
|
+
export_id,
|
|
574
|
+
list_id: Number(list_id),
|
|
575
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
spinner.stop();
|
|
579
|
+
formatter.success('Contact deleted successfully');
|
|
580
|
+
} catch (error: any) {
|
|
581
|
+
spinner.stop();
|
|
582
|
+
formatter.error(error.message);
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
cmd
|
|
589
|
+
.command('download-contacts-export <export-id> <list-id>')
|
|
590
|
+
.description('Download a Contacts Export')
|
|
591
|
+
.option('--account-id <value>', 'Optional Account ID to be used for the request')
|
|
592
|
+
.action(async (export_id, list_id, options) => {
|
|
593
|
+
const spinner = createSpinner('Fetching contact...').start();
|
|
594
|
+
try {
|
|
595
|
+
const data = await client.downloadContactsExport({
|
|
596
|
+
export_id,
|
|
597
|
+
list_id: Number(list_id),
|
|
598
|
+
accountId: options.accountId != null ? Number(options.accountId) : undefined,
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
spinner.stop();
|
|
602
|
+
formatter.output(data);
|
|
603
|
+
} catch (error: any) {
|
|
604
|
+
spinner.stop();
|
|
605
|
+
formatter.error(error.message);
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
return cmd;
|
|
612
|
+
}
|