shipmail-cli 0.1.8 → 0.1.10
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/README.md +33 -7
- package/dist/cli.js +316 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Most commands require an API key. Create one in the Shipmail dashboard and expor
|
|
|
14
14
|
export SHIPMAIL_API_KEY="sm_live_..."
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
You can also pass `--api-key` to any command. Use `SHIPMAIL_BASE_URL` or `--base-url` when targeting a non-production API.
|
|
17
|
+
You can also pass `--api-key` to any command. Use `SHIPMAIL_BASE_URL` or `--base-url` when targeting a non-production API. Approved partners can set `SHIPMAIL_ORGANIZATION_ID` or pass `--organization-id` for delegated infrastructure calls.
|
|
18
18
|
|
|
19
19
|
## Common Commands
|
|
20
20
|
|
|
@@ -22,19 +22,35 @@ You can also pass `--api-key` to any command. Use `SHIPMAIL_BASE_URL` or `--base
|
|
|
22
22
|
# Check public API health
|
|
23
23
|
shipmail status
|
|
24
24
|
|
|
25
|
-
# Create a domain and verify DNS
|
|
25
|
+
# Create a domain, retrieve records, and verify DNS
|
|
26
26
|
shipmail domains create example.com
|
|
27
|
+
shipmail domains dns-records dom_123
|
|
27
28
|
shipmail domains verify dom_123
|
|
28
29
|
|
|
29
30
|
# Create a mailbox
|
|
30
|
-
shipmail mailboxes create --domain-id dom_123 --address hello --display-name "Hello"
|
|
31
|
+
shipmail mailboxes create --domain-id dom_123 --address hello --password-file ./mailbox-password.txt --display-name "Hello"
|
|
32
|
+
shipmail mailboxes suspend mbx_123
|
|
33
|
+
shipmail mailboxes resume mbx_123
|
|
34
|
+
shipmail mailboxes forwarding-add mbx_123 --destination owner@example.net
|
|
35
|
+
shipmail mailboxes forwarding mbx_123
|
|
36
|
+
shipmail mailboxes forwarding-remove mbx_123 fwd_123
|
|
31
37
|
|
|
32
38
|
# Send email
|
|
33
39
|
shipmail messages send \
|
|
34
40
|
--mailbox-id mbx_123 \
|
|
35
41
|
--to user@example.com \
|
|
36
42
|
--subject "Hello" \
|
|
37
|
-
--text "It works."
|
|
43
|
+
--text "It works." \
|
|
44
|
+
--client-reference crm-123 \
|
|
45
|
+
--metadata '{"campaign":"onboarding"}' \
|
|
46
|
+
--source-rfc-message-id '<crm-123@example.com>'
|
|
47
|
+
|
|
48
|
+
shipmail messages list --client-reference crm-123
|
|
49
|
+
shipmail messages reply msg_123 --to user@example.com --text "Thanks"
|
|
50
|
+
|
|
51
|
+
# Use an sm_test_... key to simulate an outbound result and fake inbound reply
|
|
52
|
+
shipmail messages send --mailbox-id mbx_123 --to user@example.com --subject "Test" --text "Not delivered" --sandbox-outcome bounced
|
|
53
|
+
shipmail mailboxes sandbox-inbound mbx_123 --from customer@example.com --subject "Re: Test" --text "Fake inbound reply"
|
|
38
54
|
|
|
39
55
|
# Read inbound mail
|
|
40
56
|
shipmail inbox list mbx_123 --folder-role inbox --limit 25
|
|
@@ -62,6 +78,13 @@ shipmail webhooks create \
|
|
|
62
78
|
--url https://example.com/shipmail/webhook \
|
|
63
79
|
--events message.received,message.bounced
|
|
64
80
|
shipmail webhooks deliveries whk_123 --status failed
|
|
81
|
+
shipmail webhooks replay-delivery whk_123 dlv_123 --idempotency-key replay-123
|
|
82
|
+
|
|
83
|
+
# Partner beta lifecycle and delegated infrastructure
|
|
84
|
+
shipmail partner organizations create --name "Operator" --external-reference operator_123 --owner-email owner@example.com --mailbox-limit 3 --data-classification internal_test
|
|
85
|
+
shipmail partner usage
|
|
86
|
+
shipmail domains list --organization-id 00000000-0000-4000-8000-000000000123
|
|
87
|
+
shipmail mailboxes create --organization-id 00000000-0000-4000-8000-000000000123 --domain-id dom_123 --address support --generate-password
|
|
65
88
|
```
|
|
66
89
|
|
|
67
90
|
`newsletter-assets list` includes current newsletter media storage usage in the JSON response.
|
|
@@ -87,13 +110,16 @@ Use repeatable `--header "Name: value"` flags for request headers. Use `--output
|
|
|
87
110
|
- `status`
|
|
88
111
|
- `api <METHOD> <PATH>`
|
|
89
112
|
- `domains list|search|create|get|verify|delete`
|
|
90
|
-
- `mailboxes list|create|get|folders|identities|rules`
|
|
113
|
+
- `mailboxes list|create|get|suspend|resume|forwarding|forwarding-add|forwarding-remove|folders|identities|rules`
|
|
91
114
|
- `inbox list|thread|update|move`
|
|
92
|
-
- `messages send|list|get`
|
|
93
|
-
- `
|
|
115
|
+
- `messages send|list|get|reply` (test keys also support `--sandbox-outcome`)
|
|
116
|
+
- `mailboxes sandbox-inbound`
|
|
117
|
+
- `webhooks list|create|test|deliveries|replay-delivery`
|
|
94
118
|
- `suppressions list|remove`
|
|
95
119
|
- `newsletter-domains list`
|
|
96
120
|
- `newsletters create|update|preview|preflight|test-send|schedule|cancel|resume`
|
|
97
121
|
- `newsletter-assets list|upload|register-url`
|
|
122
|
+
- `partner organizations list|create|get|update|invite|suspend|resume|offboard`
|
|
123
|
+
- `partner usage`
|
|
98
124
|
|
|
99
125
|
Run `shipmail --help` for flags and examples.
|
package/dist/cli.js
CHANGED
|
@@ -6,13 +6,14 @@ import { readFile, writeFile } from "fs/promises";
|
|
|
6
6
|
import { env as processEnv, exit, stderr, stdout } from "process";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
import {
|
|
9
|
+
CONFERENCING_PROVIDER_IDS,
|
|
9
10
|
ShipMailClient,
|
|
10
11
|
ShipMailError,
|
|
11
12
|
WEBHOOK_EVENT_TYPES
|
|
12
13
|
} from "shipmail";
|
|
13
14
|
|
|
14
15
|
// src/version.ts
|
|
15
|
-
var VERSION = "0.1.
|
|
16
|
+
var VERSION = "0.1.10";
|
|
16
17
|
|
|
17
18
|
// src/cli.ts
|
|
18
19
|
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
@@ -123,6 +124,9 @@ function apiKey(parsed, env) {
|
|
|
123
124
|
function baseUrl(parsed, env) {
|
|
124
125
|
return normalizeBaseUrl(getString(parsed.options, "base-url") ?? env["SHIPMAIL_BASE_URL"]);
|
|
125
126
|
}
|
|
127
|
+
function organizationId(parsed, env) {
|
|
128
|
+
return getString(parsed.options, "organization-id") ?? env["SHIPMAIL_ORGANIZATION_ID"];
|
|
129
|
+
}
|
|
126
130
|
function requireApiKey(parsed, env) {
|
|
127
131
|
const key = apiKey(parsed, env);
|
|
128
132
|
if (!key) {
|
|
@@ -135,6 +139,7 @@ function createClient(parsed, options) {
|
|
|
135
139
|
const config = {
|
|
136
140
|
apiKey: requireApiKey(parsed, env),
|
|
137
141
|
baseUrl: baseUrl(parsed, env),
|
|
142
|
+
organizationId: organizationId(parsed, env),
|
|
138
143
|
...options.fetch ? { fetch: options.fetch } : {}
|
|
139
144
|
};
|
|
140
145
|
return new ShipMailClient(config);
|
|
@@ -264,6 +269,10 @@ async function rawApiRequest(parsed, runOptions, method, path, body, authRequire
|
|
|
264
269
|
const key = apiKey(parsed, env);
|
|
265
270
|
if (key) headers["Authorization"] = `Bearer ${key}`;
|
|
266
271
|
}
|
|
272
|
+
const targetOrganizationId = organizationId(parsed, env);
|
|
273
|
+
if (targetOrganizationId) {
|
|
274
|
+
headers["X-ShipMail-Organization-Id"] = targetOrganizationId;
|
|
275
|
+
}
|
|
267
276
|
let requestBody;
|
|
268
277
|
if (body !== void 0) {
|
|
269
278
|
headers["Content-Type"] = "application/json";
|
|
@@ -311,21 +320,34 @@ Usage:
|
|
|
311
320
|
shipmail domains search <keyword>
|
|
312
321
|
shipmail domains create <name>
|
|
313
322
|
shipmail domains get <id>
|
|
323
|
+
shipmail domains dns-records <id>
|
|
314
324
|
shipmail domains verify <id>
|
|
315
325
|
shipmail domains delete <id>
|
|
316
326
|
shipmail mailboxes list [--domain-id dom] [--limit 25] [--cursor cur]
|
|
317
|
-
shipmail mailboxes create --domain-id dom --address hello [--display-name "Hello"]
|
|
327
|
+
shipmail mailboxes create --domain-id dom --address hello (--password value | --password-file path | --generate-password) [--display-name "Hello"]
|
|
318
328
|
shipmail mailboxes get <id>
|
|
329
|
+
shipmail mailboxes suspend <id>
|
|
330
|
+
shipmail mailboxes resume <id>
|
|
331
|
+
shipmail mailboxes export <id>
|
|
332
|
+
shipmail mailboxes export-status <id> <export-id>
|
|
319
333
|
shipmail mailboxes folders <id>
|
|
320
334
|
shipmail mailboxes identities <id>
|
|
321
335
|
shipmail mailboxes rules <id>
|
|
336
|
+
shipmail mailboxes forwarding <id>
|
|
337
|
+
shipmail mailboxes forwarding-add <id> --destination owner@example.com
|
|
338
|
+
shipmail mailboxes forwarding-remove <id> <forwarding-id>
|
|
339
|
+
shipmail mailboxes sandbox-inbound <id> --from sender@example.com --subject "Test" (--text "Hello" | --html "<p>Hello</p>") [--to support@example.com]
|
|
322
340
|
shipmail inbox list <mailbox-id> [--folder-role inbox] [--limit 25]
|
|
323
341
|
shipmail inbox thread <mailbox-id> <thread-id>
|
|
324
342
|
shipmail inbox update <mailbox-id> <message-id> [--read true] [--starred false]
|
|
325
343
|
shipmail inbox move <mailbox-id> <message-id> (--target-role archive | --target-folder-id fld)
|
|
326
|
-
shipmail messages send --mailbox-id mbx --to user@example.com --subject "Hi" --text "Hello"
|
|
344
|
+
shipmail messages send --mailbox-id mbx --to user@example.com --subject "Hi" --text "Hello" [--sandbox-outcome delivered|bounced|complained] [--client-reference crm-123] [--metadata JSON|@file] [--source-rfc-message-id '<crm-123@example.com>'] [--header 'X-CRM-ID: 123']
|
|
345
|
+
shipmail messages list (--mailbox-id mbx | --client-reference crm-123) [--limit 25] [--cursor cur]
|
|
346
|
+
shipmail messages get <message-id>
|
|
347
|
+
shipmail messages reply <message-id> --to user@example.com (--text "Hello" | --html "<p>Hello</p>") [--client-reference crm-reply-123]
|
|
327
348
|
shipmail webhooks list
|
|
328
349
|
shipmail webhooks create --url https://example.com/hook --events message.received,message.bounced
|
|
350
|
+
shipmail webhooks replay-delivery <webhook-id> <delivery-id> [--idempotency-key key]
|
|
329
351
|
shipmail suppressions list
|
|
330
352
|
shipmail suppressions remove <email>
|
|
331
353
|
shipmail newsletters create \\
|
|
@@ -365,19 +387,34 @@ Usage:
|
|
|
365
387
|
shipmail calendar events delete <event-id> --mailbox hello@example.com
|
|
366
388
|
shipmail calendar availability --mailbox hello@example.com --from 2026-08-03T00:00:00Z --to 2026-08-04T00:00:00Z [--duration 30] [--days 1,2,3,4,5] [--window-start 540] [--window-end 1020]
|
|
367
389
|
shipmail booking-pages list [--limit 25] [--cursor cur]
|
|
368
|
-
shipmail booking-pages create --name "Intro" --mailbox hello@example.com --slug intro --duration-minutes 30 --availability-days 1,2,3,4,5 --window-start-minutes 540 --window-end-minutes 1020 --timezone America/New_York
|
|
390
|
+
shipmail booking-pages create --name "Intro" --mailbox hello@example.com --slug intro --duration-minutes 30 --availability-days 1,2,3,4,5 --window-start-minutes 540 --window-end-minutes 1020 --timezone America/New_York [--conferencing-provider zoom|google_meet]
|
|
369
391
|
shipmail booking-pages get <id>
|
|
370
|
-
shipmail booking-pages update <id> [--name "..."] [--active false]
|
|
392
|
+
shipmail booking-pages update <id> [--name "..."] [--conferencing-provider zoom|google_meet|none] [--active false]
|
|
371
393
|
shipmail booking-pages delete <id>
|
|
394
|
+
shipmail partner organizations list
|
|
395
|
+
shipmail partner organizations create --name "Operator" --external-reference op_123 --owner-email owner@example.com [--mailbox-limit 3] [--data-classification internal_test|customer]
|
|
396
|
+
shipmail partner organizations get <id>
|
|
397
|
+
shipmail partner organizations update <id> [--name "Operator"] [--mailbox-limit 5]
|
|
398
|
+
shipmail partner organizations invite <id> [--owner-email owner@example.com]
|
|
399
|
+
shipmail partner organizations suspend <id>
|
|
400
|
+
shipmail partner organizations resume <id>
|
|
401
|
+
shipmail partner organizations offboard <id>
|
|
402
|
+
shipmail partner usage
|
|
403
|
+
|
|
404
|
+
Booking page conferencing:
|
|
405
|
+
--conferencing-provider <zoom|google_meet> Create a meeting for every booking.
|
|
406
|
+
--conferencing-provider none Stop creating meeting links on update.
|
|
372
407
|
|
|
373
408
|
Global options:
|
|
374
409
|
--api-key <key> API key. Defaults to SHIPMAIL_API_KEY.
|
|
375
410
|
--base-url <url> API base URL. Defaults to SHIPMAIL_BASE_URL or ${DEFAULT_BASE_URL}.
|
|
411
|
+
--organization-id Delegated child organization for supported infrastructure commands.
|
|
376
412
|
--header "K: V" Extra header for the generic api command. Repeatable.
|
|
377
413
|
|
|
378
414
|
Environment:
|
|
379
415
|
SHIPMAIL_API_KEY API key for authenticated commands.
|
|
380
416
|
SHIPMAIL_BASE_URL Optional API base URL.
|
|
417
|
+
SHIPMAIL_ORGANIZATION_ID Optional delegated child organization ID.
|
|
381
418
|
`;
|
|
382
419
|
}
|
|
383
420
|
function requirePositional(positional, index, label) {
|
|
@@ -425,7 +462,24 @@ function webhookDeliveryParams(options) {
|
|
|
425
462
|
...eventType ? { event_type: eventType } : {}
|
|
426
463
|
};
|
|
427
464
|
}
|
|
428
|
-
function
|
|
465
|
+
function outboundMessageHeaders(options) {
|
|
466
|
+
const headers = getStringList(options, "header");
|
|
467
|
+
return headers.map((value) => {
|
|
468
|
+
const index = value.indexOf(":");
|
|
469
|
+
if (index <= 0) throw new CliUsageError("--header must use 'Name: value' format.");
|
|
470
|
+
return { name: value.slice(0, index).trim(), value: value.slice(index + 1).trim() };
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async function messageMetadata(options) {
|
|
474
|
+
const raw = getString(options, "metadata");
|
|
475
|
+
if (!raw) return void 0;
|
|
476
|
+
const parsed = await readJsonInput(raw);
|
|
477
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
478
|
+
throw new CliUsageError("--metadata must be a JSON object or @path/to/file.json.");
|
|
479
|
+
}
|
|
480
|
+
return parsed;
|
|
481
|
+
}
|
|
482
|
+
async function sendMessageParams(options) {
|
|
429
483
|
const mailboxId = getString(options, "mailbox-id");
|
|
430
484
|
const from = getString(options, "from");
|
|
431
485
|
const to = messageRecipients(options, "to");
|
|
@@ -435,6 +489,8 @@ function sendMessageParams(options) {
|
|
|
435
489
|
const subject = getRequiredString(options, "subject");
|
|
436
490
|
const text = getString(options, "text");
|
|
437
491
|
const html = getString(options, "html");
|
|
492
|
+
const headers = outboundMessageHeaders(options);
|
|
493
|
+
const metadata = await messageMetadata(options);
|
|
438
494
|
if (!mailboxId && !from) throw new CliUsageError("Provide --mailbox-id or --from.");
|
|
439
495
|
if (to.length === 0) throw new CliUsageError("Provide at least one --to recipient.");
|
|
440
496
|
if (!text && !html) throw new CliUsageError("Provide --text or --html.");
|
|
@@ -447,7 +503,47 @@ function sendMessageParams(options) {
|
|
|
447
503
|
...replyTo ? { reply_to: replyTo } : {},
|
|
448
504
|
subject,
|
|
449
505
|
...html ? { html } : {},
|
|
450
|
-
...text ? { text } : {}
|
|
506
|
+
...text ? { text } : {},
|
|
507
|
+
...getString(options, "client-reference") ? { client_reference: getString(options, "client-reference") } : {},
|
|
508
|
+
...metadata ? { metadata } : {},
|
|
509
|
+
...getString(options, "source-rfc-message-id") ? { source_rfc_message_id: getString(options, "source-rfc-message-id") } : {},
|
|
510
|
+
...headers.length > 0 ? { headers } : {},
|
|
511
|
+
...getString(options, "scheduled-at") ? { scheduled_at: getString(options, "scheduled-at") } : {},
|
|
512
|
+
...getString(options, "sandbox-outcome") ? {
|
|
513
|
+
sandbox_outcome: getEnum(options, "sandbox-outcome", [
|
|
514
|
+
"delivered",
|
|
515
|
+
"bounced",
|
|
516
|
+
"complained"
|
|
517
|
+
])
|
|
518
|
+
} : {}
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
async function replyToMessageParams(options) {
|
|
522
|
+
const to = messageRecipients(options, "to");
|
|
523
|
+
const cc = messageRecipients(options, "cc");
|
|
524
|
+
const text = getString(options, "text");
|
|
525
|
+
const html = getString(options, "html");
|
|
526
|
+
const headers = outboundMessageHeaders(options);
|
|
527
|
+
const metadata = await messageMetadata(options);
|
|
528
|
+
if (to.length === 0) throw new CliUsageError("Provide at least one --to recipient.");
|
|
529
|
+
if (!text && !html) throw new CliUsageError("Provide --text or --html.");
|
|
530
|
+
return {
|
|
531
|
+
to,
|
|
532
|
+
...cc.length > 0 ? { cc } : {},
|
|
533
|
+
...html ? { html } : {},
|
|
534
|
+
...text ? { text } : {},
|
|
535
|
+
...getString(options, "client-reference") ? { client_reference: getString(options, "client-reference") } : {},
|
|
536
|
+
...metadata ? { metadata } : {},
|
|
537
|
+
...getString(options, "source-rfc-message-id") ? { source_rfc_message_id: getString(options, "source-rfc-message-id") } : {},
|
|
538
|
+
...headers.length > 0 ? { headers } : {},
|
|
539
|
+
...getString(options, "scheduled-at") ? { scheduled_at: getString(options, "scheduled-at") } : {},
|
|
540
|
+
...getString(options, "sandbox-outcome") ? {
|
|
541
|
+
sandbox_outcome: getEnum(options, "sandbox-outcome", [
|
|
542
|
+
"delivered",
|
|
543
|
+
"bounced",
|
|
544
|
+
"complained"
|
|
545
|
+
])
|
|
546
|
+
} : {}
|
|
451
547
|
};
|
|
452
548
|
}
|
|
453
549
|
async function runDomains(client, parsed, out) {
|
|
@@ -480,6 +576,13 @@ async function runDomains(client, parsed, out) {
|
|
|
480
576
|
writeJson(out, await client.domains.get(requirePositional(parsed.positional, 2, "domain id")));
|
|
481
577
|
return;
|
|
482
578
|
}
|
|
579
|
+
if (subcommand === "dns-records") {
|
|
580
|
+
writeJson(
|
|
581
|
+
out,
|
|
582
|
+
await client.domains.getDnsRecords(requirePositional(parsed.positional, 2, "domain id"))
|
|
583
|
+
);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
483
586
|
if (subcommand === "verify") {
|
|
484
587
|
writeJson(
|
|
485
588
|
out,
|
|
@@ -510,11 +613,27 @@ async function runMailboxes(client, parsed, out) {
|
|
|
510
613
|
}
|
|
511
614
|
if (subcommand === "create") {
|
|
512
615
|
const displayName = getString(parsed.options, "display-name");
|
|
616
|
+
const passwordValue = getString(parsed.options, "password");
|
|
617
|
+
const passwordFile = getString(parsed.options, "password-file");
|
|
618
|
+
const generatePassword = getBoolean(parsed.options, "generate-password") === true;
|
|
619
|
+
if ([Boolean(passwordValue), Boolean(passwordFile), generatePassword].filter(Boolean).length > 1) {
|
|
620
|
+
throw new CliUsageError(
|
|
621
|
+
"Pass only one of --password, --password-file, or --generate-password."
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
if (!passwordValue && !passwordFile && !generatePassword) {
|
|
625
|
+
throw new CliUsageError("Missing --password, --password-file, or --generate-password.");
|
|
626
|
+
}
|
|
627
|
+
const password = passwordFile ? (await readFile(passwordFile, "utf8")).replace(/\r?\n$/, "") : passwordValue;
|
|
628
|
+
if (!generatePassword && !password) {
|
|
629
|
+
throw new CliUsageError("Mailbox password must not be empty.");
|
|
630
|
+
}
|
|
513
631
|
writeJson(
|
|
514
632
|
out,
|
|
515
633
|
await client.mailboxes.create({
|
|
516
634
|
domain_id: getRequiredString(parsed.options, "domain-id"),
|
|
517
635
|
address: getRequiredString(parsed.options, "address"),
|
|
636
|
+
...generatePassword ? { generate_password: true } : { password },
|
|
518
637
|
...displayName ? { display_name: displayName } : {}
|
|
519
638
|
})
|
|
520
639
|
);
|
|
@@ -527,6 +646,37 @@ async function runMailboxes(client, parsed, out) {
|
|
|
527
646
|
);
|
|
528
647
|
return;
|
|
529
648
|
}
|
|
649
|
+
if (subcommand === "suspend") {
|
|
650
|
+
writeJson(
|
|
651
|
+
out,
|
|
652
|
+
await client.mailboxes.suspend(requirePositional(parsed.positional, 2, "mailbox id"))
|
|
653
|
+
);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (subcommand === "resume") {
|
|
657
|
+
writeJson(
|
|
658
|
+
out,
|
|
659
|
+
await client.mailboxes.resume(requirePositional(parsed.positional, 2, "mailbox id"))
|
|
660
|
+
);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
if (subcommand === "export") {
|
|
664
|
+
writeJson(
|
|
665
|
+
out,
|
|
666
|
+
await client.mailboxes.createExport(requirePositional(parsed.positional, 2, "mailbox id"))
|
|
667
|
+
);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
if (subcommand === "export-status") {
|
|
671
|
+
writeJson(
|
|
672
|
+
out,
|
|
673
|
+
await client.mailboxes.getExport(
|
|
674
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
675
|
+
requirePositional(parsed.positional, 3, "export id")
|
|
676
|
+
)
|
|
677
|
+
);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
530
680
|
if (subcommand === "folders") {
|
|
531
681
|
writeJson(
|
|
532
682
|
out,
|
|
@@ -548,6 +698,58 @@ async function runMailboxes(client, parsed, out) {
|
|
|
548
698
|
);
|
|
549
699
|
return;
|
|
550
700
|
}
|
|
701
|
+
if (subcommand === "forwarding") {
|
|
702
|
+
writeJson(
|
|
703
|
+
out,
|
|
704
|
+
await client.mailboxes.listForwarding(requirePositional(parsed.positional, 2, "mailbox id"))
|
|
705
|
+
);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
if (subcommand === "forwarding-add") {
|
|
709
|
+
writeJson(
|
|
710
|
+
out,
|
|
711
|
+
await client.mailboxes.createForwarding(
|
|
712
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
713
|
+
{ destination: getRequiredString(parsed.options, "destination") }
|
|
714
|
+
)
|
|
715
|
+
);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
if (subcommand === "forwarding-remove") {
|
|
719
|
+
const mailboxId = requirePositional(parsed.positional, 2, "mailbox id");
|
|
720
|
+
const forwardingId = requirePositional(parsed.positional, 3, "forwarding id");
|
|
721
|
+
await client.mailboxes.deleteForwarding(mailboxId, forwardingId);
|
|
722
|
+
writeJson(out, { ok: true, id: forwardingId });
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (subcommand === "sandbox-inbound") {
|
|
726
|
+
const text = getString(parsed.options, "text");
|
|
727
|
+
const html = getString(parsed.options, "html");
|
|
728
|
+
if (!text && !html) throw new CliUsageError("Provide --text or --html.");
|
|
729
|
+
const to = messageRecipients(parsed.options, "to");
|
|
730
|
+
const cc = messageRecipients(parsed.options, "cc");
|
|
731
|
+
const headers = outboundMessageHeaders(parsed.options);
|
|
732
|
+
writeJson(
|
|
733
|
+
out,
|
|
734
|
+
await client.mailboxes.injectSandboxInbound(
|
|
735
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
736
|
+
{
|
|
737
|
+
from: getRequiredString(parsed.options, "from"),
|
|
738
|
+
...to.length > 0 ? { to } : {},
|
|
739
|
+
...cc.length > 0 ? { cc } : {},
|
|
740
|
+
subject: getRequiredString(parsed.options, "subject"),
|
|
741
|
+
...text ? { text } : {},
|
|
742
|
+
...html ? { html } : {},
|
|
743
|
+
...getString(parsed.options, "message-id") ? { message_id: getString(parsed.options, "message-id") } : {},
|
|
744
|
+
...getString(parsed.options, "in-reply-to") ? { in_reply_to: getString(parsed.options, "in-reply-to") } : {},
|
|
745
|
+
...getStringList(parsed.options, "reference").length > 0 ? { references: getStringList(parsed.options, "reference") } : {},
|
|
746
|
+
...getString(parsed.options, "received-at") ? { received_at: getString(parsed.options, "received-at") } : {},
|
|
747
|
+
...headers.length > 0 ? { headers } : {}
|
|
748
|
+
}
|
|
749
|
+
)
|
|
750
|
+
);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
551
753
|
throw new CliUsageError("Unknown mailboxes command.");
|
|
552
754
|
}
|
|
553
755
|
async function runInbox(client, parsed, out) {
|
|
@@ -616,20 +818,36 @@ async function runInbox(client, parsed, out) {
|
|
|
616
818
|
async function runMessages(client, parsed, out) {
|
|
617
819
|
const subcommand = parsed.positional[1];
|
|
618
820
|
if (subcommand === "send") {
|
|
619
|
-
writeJson(out, await client.messages.send(sendMessageParams(parsed.options)));
|
|
821
|
+
writeJson(out, await client.messages.send(await sendMessageParams(parsed.options)));
|
|
620
822
|
return;
|
|
621
823
|
}
|
|
622
824
|
if (subcommand === "list") {
|
|
825
|
+
const mailboxId = getString(parsed.options, "mailbox-id");
|
|
826
|
+
const clientReference = getString(parsed.options, "client-reference");
|
|
827
|
+
if (!mailboxId && !clientReference) {
|
|
828
|
+
throw new CliUsageError("Provide --mailbox-id or --client-reference.");
|
|
829
|
+
}
|
|
830
|
+
const filter = mailboxId ? { mailbox_id: mailboxId, ...clientReference ? { client_reference: clientReference } : {} } : { client_reference: clientReference };
|
|
623
831
|
writeJson(
|
|
624
832
|
out,
|
|
625
833
|
await client.messages.list({
|
|
626
|
-
|
|
834
|
+
...filter,
|
|
627
835
|
cursor: getString(parsed.options, "cursor"),
|
|
628
836
|
limit: getNumber(parsed.options, "limit")
|
|
629
837
|
})
|
|
630
838
|
);
|
|
631
839
|
return;
|
|
632
840
|
}
|
|
841
|
+
if (subcommand === "reply") {
|
|
842
|
+
writeJson(
|
|
843
|
+
out,
|
|
844
|
+
await client.messages.reply(
|
|
845
|
+
requirePositional(parsed.positional, 2, "message id"),
|
|
846
|
+
await replyToMessageParams(parsed.options)
|
|
847
|
+
)
|
|
848
|
+
);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
633
851
|
if (subcommand === "get") {
|
|
634
852
|
writeJson(
|
|
635
853
|
out,
|
|
@@ -680,6 +898,18 @@ async function runWebhooks(client, parsed, out) {
|
|
|
680
898
|
);
|
|
681
899
|
return;
|
|
682
900
|
}
|
|
901
|
+
if (subcommand === "replay-delivery") {
|
|
902
|
+
const idempotencyKey = getString(parsed.options, "idempotency-key");
|
|
903
|
+
writeJson(
|
|
904
|
+
out,
|
|
905
|
+
await client.webhooks.replayDelivery(
|
|
906
|
+
requirePositional(parsed.positional, 2, "webhook id"),
|
|
907
|
+
requirePositional(parsed.positional, 3, "delivery id"),
|
|
908
|
+
idempotencyKey ? { idempotencyKey } : void 0
|
|
909
|
+
)
|
|
910
|
+
);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
683
913
|
throw new CliUsageError("Unknown webhooks command.");
|
|
684
914
|
}
|
|
685
915
|
async function runSuppressions(client, parsed, out) {
|
|
@@ -1021,6 +1251,12 @@ function getEnum(options, key, allowed) {
|
|
|
1021
1251
|
}
|
|
1022
1252
|
return match;
|
|
1023
1253
|
}
|
|
1254
|
+
function getConferencingProvider(options) {
|
|
1255
|
+
const value = getString(options, "conferencing-provider");
|
|
1256
|
+
if (value === void 0) return void 0;
|
|
1257
|
+
if (value === "none") return null;
|
|
1258
|
+
return getEnum(options, "conferencing-provider", CONFERENCING_PROVIDER_IDS);
|
|
1259
|
+
}
|
|
1024
1260
|
function isReminderArray(value) {
|
|
1025
1261
|
return Array.isArray(value) && value.every(
|
|
1026
1262
|
(item) => typeof item === "object" && item !== null && !Array.isArray(item) && Number.isInteger(item.minutes_before)
|
|
@@ -1186,6 +1422,7 @@ async function runBookingPages(client, parsed, out) {
|
|
|
1186
1422
|
buffer_minutes: getNumber(options, "buffer-minutes"),
|
|
1187
1423
|
minimum_notice_minutes: getNumber(options, "minimum-notice-minutes"),
|
|
1188
1424
|
max_advance_days: getNumber(options, "max-advance-days"),
|
|
1425
|
+
conferencing_provider: getConferencingProvider(options),
|
|
1189
1426
|
active: getBoolean(options, "active")
|
|
1190
1427
|
};
|
|
1191
1428
|
writeJson(out, await client.bookingPages.create(params));
|
|
@@ -1214,6 +1451,7 @@ async function runBookingPages(client, parsed, out) {
|
|
|
1214
1451
|
buffer_minutes: getNumber(options, "buffer-minutes"),
|
|
1215
1452
|
minimum_notice_minutes: getNumber(options, "minimum-notice-minutes"),
|
|
1216
1453
|
max_advance_days: getNumber(options, "max-advance-days"),
|
|
1454
|
+
conferencing_provider: getConferencingProvider(options),
|
|
1217
1455
|
active: getBoolean(options, "active")
|
|
1218
1456
|
};
|
|
1219
1457
|
writeJson(out, await client.bookingPages.update(id, params));
|
|
@@ -1227,6 +1465,74 @@ async function runBookingPages(client, parsed, out) {
|
|
|
1227
1465
|
}
|
|
1228
1466
|
throw new CliUsageError("Unknown booking-pages command.");
|
|
1229
1467
|
}
|
|
1468
|
+
async function runPartner(client, parsed, out) {
|
|
1469
|
+
const group = parsed.positional[1];
|
|
1470
|
+
if (group === "usage") {
|
|
1471
|
+
writeJson(out, await client.partner.usage());
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
if (group !== "organizations") throw new CliUsageError("Unknown partner command.");
|
|
1475
|
+
const command = parsed.positional[2];
|
|
1476
|
+
if (command === "list") {
|
|
1477
|
+
writeJson(out, await client.partner.listOrganizations());
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
if (command === "create") {
|
|
1481
|
+
const classification = getString(parsed.options, "data-classification") ?? "customer";
|
|
1482
|
+
if (classification !== "internal_test" && classification !== "customer") {
|
|
1483
|
+
throw new CliUsageError("--data-classification must be internal_test or customer.");
|
|
1484
|
+
}
|
|
1485
|
+
const params = {
|
|
1486
|
+
name: getRequiredString(parsed.options, "name"),
|
|
1487
|
+
external_reference: getRequiredString(parsed.options, "external-reference"),
|
|
1488
|
+
owner_email: getRequiredString(parsed.options, "owner-email"),
|
|
1489
|
+
mailbox_limit: getNumber(parsed.options, "mailbox-limit") ?? 3,
|
|
1490
|
+
data_classification: classification
|
|
1491
|
+
};
|
|
1492
|
+
writeJson(out, await client.partner.createOrganization(params));
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const id = requirePositional(parsed.positional, 3, "partner organization id");
|
|
1496
|
+
if (command === "get") {
|
|
1497
|
+
writeJson(out, await client.partner.getOrganization(id));
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
if (command === "update") {
|
|
1501
|
+
const name = getString(parsed.options, "name");
|
|
1502
|
+
const mailboxLimit = getNumber(parsed.options, "mailbox-limit");
|
|
1503
|
+
if (name === void 0 && mailboxLimit === void 0) {
|
|
1504
|
+
throw new CliUsageError("Provide --name or --mailbox-limit.");
|
|
1505
|
+
}
|
|
1506
|
+
const params = {
|
|
1507
|
+
...name !== void 0 ? { name } : {},
|
|
1508
|
+
...mailboxLimit !== void 0 ? { mailbox_limit: mailboxLimit } : {}
|
|
1509
|
+
};
|
|
1510
|
+
writeJson(out, await client.partner.updateOrganization(id, params));
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
if (command === "invite") {
|
|
1514
|
+
writeJson(
|
|
1515
|
+
out,
|
|
1516
|
+
await client.partner.resendOwnershipInvitation(id, {
|
|
1517
|
+
owner_email: getString(parsed.options, "owner-email")
|
|
1518
|
+
})
|
|
1519
|
+
);
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
if (command === "suspend") {
|
|
1523
|
+
writeJson(out, await client.partner.suspendOrganization(id));
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
if (command === "resume") {
|
|
1527
|
+
writeJson(out, await client.partner.resumeOrganization(id));
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (command === "offboard") {
|
|
1531
|
+
writeJson(out, await client.partner.offboardOrganization(id));
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
throw new CliUsageError("Unknown partner organizations command.");
|
|
1535
|
+
}
|
|
1230
1536
|
function writeError(err, errOut) {
|
|
1231
1537
|
if (err instanceof CliUsageError) {
|
|
1232
1538
|
errOut.write(`Error: ${err.message}
|
|
@@ -1292,6 +1598,7 @@ async function runCli(argv, options = {}) {
|
|
|
1292
1598
|
else if (command === "audiences") await runAudiences(client, parsed, out);
|
|
1293
1599
|
else if (command === "calendar") await runCalendar(client, parsed, out);
|
|
1294
1600
|
else if (command === "booking-pages") await runBookingPages(client, parsed, out);
|
|
1601
|
+
else if (command === "partner") await runPartner(client, parsed, out);
|
|
1295
1602
|
else throw new CliUsageError(`Unknown command: ${command}.`);
|
|
1296
1603
|
return 0;
|
|
1297
1604
|
} catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shipmail-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Official CLI for the ShipMail API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"shipmail": "0.1.
|
|
44
|
+
"shipmail": "0.1.33"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"tsup": "^8.4.0",
|