shipmail-cli 0.1.3 → 0.1.5
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 +19 -0
- package/dist/cli.js +385 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,6 +40,22 @@ shipmail messages send \
|
|
|
40
40
|
shipmail inbox list mbx_123 --folder-role inbox --limit 25
|
|
41
41
|
shipmail inbox thread mbx_123 thr_123
|
|
42
42
|
|
|
43
|
+
# Find newsletter sending domain IDs, then create a draft with blocks
|
|
44
|
+
shipmail newsletter-domains list
|
|
45
|
+
shipmail newsletters create \
|
|
46
|
+
--audience-id aud_123 \
|
|
47
|
+
--newsletter-domain-id nwsdom_456 \
|
|
48
|
+
--name "July changelog" \
|
|
49
|
+
--subject "What shipped in July" \
|
|
50
|
+
--blocks @blocks.json
|
|
51
|
+
shipmail newsletters update nws_123 --subject "Updated subject"
|
|
52
|
+
shipmail newsletters preview nws_123
|
|
53
|
+
shipmail newsletters test-send nws_123 --recipient-email owner@example.com
|
|
54
|
+
shipmail newsletters preflight nws_123
|
|
55
|
+
shipmail newsletters schedule nws_123 --scheduled-at 2026-08-01T09:00:00.000Z
|
|
56
|
+
shipmail newsletter-assets list --kind image
|
|
57
|
+
shipmail newsletter-assets upload ./hero.png --content-type image/png
|
|
58
|
+
|
|
43
59
|
# Manage webhooks
|
|
44
60
|
shipmail webhooks create \
|
|
45
61
|
--url https://example.com/shipmail/webhook \
|
|
@@ -73,5 +89,8 @@ Use repeatable `--header "Name: value"` flags for request headers. Use `--output
|
|
|
73
89
|
- `messages send|list|get`
|
|
74
90
|
- `webhooks list|create|test|deliveries`
|
|
75
91
|
- `suppressions list|remove`
|
|
92
|
+
- `newsletter-domains list`
|
|
93
|
+
- `newsletters create|update|preview|preflight|test-send|schedule|cancel|resume`
|
|
94
|
+
- `newsletter-assets list|upload`
|
|
76
95
|
|
|
77
96
|
Run `shipmail --help` for flags and examples.
|
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "shipmail";
|
|
13
13
|
|
|
14
14
|
// src/version.ts
|
|
15
|
-
var VERSION = "0.1.
|
|
15
|
+
var VERSION = "0.1.5";
|
|
16
16
|
|
|
17
17
|
// src/cli.ts
|
|
18
18
|
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
@@ -149,9 +149,95 @@ async function readJsonInput(value) {
|
|
|
149
149
|
try {
|
|
150
150
|
return JSON.parse(raw);
|
|
151
151
|
} catch {
|
|
152
|
-
throw new CliUsageError("
|
|
152
|
+
throw new CliUsageError("Value must be valid JSON or @path/to/file.json.");
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
async function readTextInput(value) {
|
|
156
|
+
if (value === void 0) return void 0;
|
|
157
|
+
if (value.startsWith("@")) return readFile(value.slice(1), "utf8");
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
async function readNewsletterBlocks(value) {
|
|
161
|
+
const parsed = await readJsonInput(value);
|
|
162
|
+
if (!Array.isArray(parsed)) {
|
|
163
|
+
throw new CliUsageError("--blocks must be a JSON array of newsletter blocks.");
|
|
164
|
+
}
|
|
165
|
+
if (parsed.length === 0) {
|
|
166
|
+
throw new CliUsageError("--blocks must include at least one block.");
|
|
167
|
+
}
|
|
168
|
+
return parsed;
|
|
169
|
+
}
|
|
170
|
+
function parseArchiveVisibility(options) {
|
|
171
|
+
const value = getString(options, "archive-visibility");
|
|
172
|
+
if (value === void 0) return void 0;
|
|
173
|
+
if (value === "private" || value === "public") return value;
|
|
174
|
+
throw new CliUsageError("--archive-visibility must be private or public.");
|
|
175
|
+
}
|
|
176
|
+
async function newsletterCreateParams(options) {
|
|
177
|
+
const audience_id = getRequiredString(options, "audience-id");
|
|
178
|
+
const newsletter_domain_id = getRequiredString(options, "newsletter-domain-id");
|
|
179
|
+
const name = getRequiredString(options, "name");
|
|
180
|
+
const subject = getRequiredString(options, "subject");
|
|
181
|
+
const blocksInput = getString(options, "blocks");
|
|
182
|
+
const bodyHtmlInput = getString(options, "body-html");
|
|
183
|
+
const bodyTextInput = getString(options, "body-text");
|
|
184
|
+
const blocks = blocksInput ? await readNewsletterBlocks(blocksInput) : void 0;
|
|
185
|
+
const body_html = bodyHtmlInput ? await readTextInput(bodyHtmlInput) : void 0;
|
|
186
|
+
const body_text = bodyTextInput ? await readTextInput(bodyTextInput) : void 0;
|
|
187
|
+
if (!blocks?.length && !body_html?.trim() && !body_text?.trim()) {
|
|
188
|
+
throw new CliUsageError("Provide at least one of --blocks, --body-html, or --body-text.");
|
|
189
|
+
}
|
|
190
|
+
const send_window_hours = getNumber(options, "send-window-hours");
|
|
191
|
+
const archive_visibility = parseArchiveVisibility(options);
|
|
192
|
+
const preview_text = getString(options, "preview-text");
|
|
193
|
+
const from_name = getString(options, "from-name");
|
|
194
|
+
return {
|
|
195
|
+
audience_id,
|
|
196
|
+
newsletter_domain_id,
|
|
197
|
+
name,
|
|
198
|
+
subject,
|
|
199
|
+
...preview_text !== void 0 ? { preview_text } : {},
|
|
200
|
+
...from_name !== void 0 ? { from_name } : {},
|
|
201
|
+
...blocks ? { blocks } : {},
|
|
202
|
+
...body_html !== void 0 ? { body_html } : {},
|
|
203
|
+
...body_text !== void 0 ? { body_text } : {},
|
|
204
|
+
...send_window_hours !== void 0 ? { send_window_hours } : {},
|
|
205
|
+
...archive_visibility !== void 0 ? { archive_visibility } : {}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function newsletterUpdateParams(options) {
|
|
209
|
+
const audience_id = getString(options, "audience-id");
|
|
210
|
+
const newsletter_domain_id = getString(options, "newsletter-domain-id");
|
|
211
|
+
const name = getString(options, "name");
|
|
212
|
+
const subject = getString(options, "subject");
|
|
213
|
+
const preview_text = getString(options, "preview-text");
|
|
214
|
+
const from_name = getString(options, "from-name");
|
|
215
|
+
const send_window_hours = getNumber(options, "send-window-hours");
|
|
216
|
+
const archive_visibility = parseArchiveVisibility(options);
|
|
217
|
+
const blocksInput = getString(options, "blocks");
|
|
218
|
+
const bodyHtmlInput = getString(options, "body-html");
|
|
219
|
+
const bodyTextInput = getString(options, "body-text");
|
|
220
|
+
const blocks = blocksInput ? await readNewsletterBlocks(blocksInput) : void 0;
|
|
221
|
+
const body_html = bodyHtmlInput ? await readTextInput(bodyHtmlInput) : void 0;
|
|
222
|
+
const body_text = bodyTextInput ? await readTextInput(bodyTextInput) : void 0;
|
|
223
|
+
const params = {
|
|
224
|
+
...audience_id ? { audience_id } : {},
|
|
225
|
+
...newsletter_domain_id ? { newsletter_domain_id } : {},
|
|
226
|
+
...name ? { name } : {},
|
|
227
|
+
...subject ? { subject } : {},
|
|
228
|
+
...preview_text !== void 0 ? { preview_text } : {},
|
|
229
|
+
...from_name !== void 0 ? { from_name } : {},
|
|
230
|
+
...blocks ? { blocks } : {},
|
|
231
|
+
...body_html !== void 0 ? { body_html } : {},
|
|
232
|
+
...body_text !== void 0 ? { body_text } : {},
|
|
233
|
+
...send_window_hours !== void 0 ? { send_window_hours } : {},
|
|
234
|
+
...archive_visibility !== void 0 ? { archive_visibility } : {}
|
|
235
|
+
};
|
|
236
|
+
if (Object.keys(params).length === 0) {
|
|
237
|
+
throw new CliUsageError("Provide at least one field to update.");
|
|
238
|
+
}
|
|
239
|
+
return params;
|
|
240
|
+
}
|
|
155
241
|
function apiPath(rawPath) {
|
|
156
242
|
if (!rawPath) throw new CliUsageError("Missing API path.");
|
|
157
243
|
if (!rawPath.startsWith("/")) throw new CliUsageError("API path must start with '/'.");
|
|
@@ -242,6 +328,34 @@ Usage:
|
|
|
242
328
|
shipmail webhooks create --url https://example.com/hook --events message.received,message.bounced
|
|
243
329
|
shipmail suppressions list
|
|
244
330
|
shipmail suppressions remove <email>
|
|
331
|
+
shipmail newsletters create \\
|
|
332
|
+
--audience-id aud_123 \\
|
|
333
|
+
--newsletter-domain-id nwsdom_456 \\
|
|
334
|
+
--name "July changelog" \\
|
|
335
|
+
--subject "What shipped in July" \\
|
|
336
|
+
--blocks @blocks.json
|
|
337
|
+
shipmail newsletters update nws_789 --subject "Updated subject" --blocks @blocks-v2.json
|
|
338
|
+
shipmail newsletters preview <id>
|
|
339
|
+
shipmail newsletters preflight <id>
|
|
340
|
+
shipmail newsletters test-send <id> --recipient-email owner@example.com
|
|
341
|
+
shipmail newsletters schedule <id> --scheduled-at 2026-08-01T09:00:00.000Z
|
|
342
|
+
shipmail newsletters cancel <id>
|
|
343
|
+
shipmail newsletters resume <id>
|
|
344
|
+
shipmail newsletter-assets list [--kind image|video] [--q text] [--limit 25] [--cursor cur]
|
|
345
|
+
shipmail newsletter-assets upload <file> [--filename name] [--content-type type]
|
|
346
|
+
shipmail newsletter-domains list [--limit 25] [--cursor cur]
|
|
347
|
+
shipmail audiences list [--limit 25] [--cursor cur]
|
|
348
|
+
shipmail audiences create <name> --consent-source "Signup form" [--description "..."]
|
|
349
|
+
shipmail audiences get <id>
|
|
350
|
+
shipmail audiences update <id> [--name "..."] [--description "..."]
|
|
351
|
+
shipmail audiences delete <id>
|
|
352
|
+
shipmail audiences subscribers add <audience-id> <email> [--name "Jane"] [--consent-source "..."]
|
|
353
|
+
shipmail audiences subscribers list <audience-id> [--status subscribed] [--email jane@x.com] [--limit 25]
|
|
354
|
+
shipmail audiences subscribers get <audience-id> <subscriber-id>
|
|
355
|
+
shipmail audiences subscribers by-email <audience-id> <email>
|
|
356
|
+
shipmail audiences subscribers update <audience-id> <subscriber-id> [--name "..."]
|
|
357
|
+
shipmail audiences subscribers unsubscribe <audience-id> <subscriber-id>
|
|
358
|
+
shipmail audiences subscribers remove <audience-id> <subscriber-id>
|
|
245
359
|
|
|
246
360
|
Global options:
|
|
247
361
|
--api-key <key> API key. Defaults to SHIPMAIL_API_KEY.
|
|
@@ -575,6 +689,267 @@ async function runSuppressions(client, parsed, out) {
|
|
|
575
689
|
}
|
|
576
690
|
throw new CliUsageError("Unknown suppressions command.");
|
|
577
691
|
}
|
|
692
|
+
var SUBSCRIBER_STATUS_VALUES = [
|
|
693
|
+
"subscribed",
|
|
694
|
+
"unsubscribed",
|
|
695
|
+
"bounced",
|
|
696
|
+
"complained",
|
|
697
|
+
"suppressed",
|
|
698
|
+
"transactional_only"
|
|
699
|
+
];
|
|
700
|
+
function subscriberListParams(options) {
|
|
701
|
+
const email = getString(options, "email");
|
|
702
|
+
const statusRaw = getString(options, "status");
|
|
703
|
+
const status = statusRaw ? SUBSCRIBER_STATUS_VALUES.find((s) => s === statusRaw) : void 0;
|
|
704
|
+
if (statusRaw && !status) {
|
|
705
|
+
throw new CliUsageError(`Invalid --status: ${statusRaw}.`);
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
cursor: getString(options, "cursor"),
|
|
709
|
+
limit: getNumber(options, "limit"),
|
|
710
|
+
...status ? { status } : {},
|
|
711
|
+
...email ? { email } : {}
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
async function runSubscribers(client, parsed, out) {
|
|
715
|
+
const action = parsed.positional[2];
|
|
716
|
+
const audienceId = requirePositional(parsed.positional, 3, "audience id");
|
|
717
|
+
if (action === "list") {
|
|
718
|
+
writeJson(
|
|
719
|
+
out,
|
|
720
|
+
await client.audiences.subscribers.list(audienceId, subscriberListParams(parsed.options))
|
|
721
|
+
);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
if (action === "add") {
|
|
725
|
+
const name = getString(parsed.options, "name");
|
|
726
|
+
const consentSource = getString(parsed.options, "consent-source");
|
|
727
|
+
const consentIp = getString(parsed.options, "consent-ip");
|
|
728
|
+
writeJson(
|
|
729
|
+
out,
|
|
730
|
+
await client.audiences.subscribers.add(audienceId, {
|
|
731
|
+
email_address: requirePositional(parsed.positional, 4, "email"),
|
|
732
|
+
...name ? { display_name: name } : {},
|
|
733
|
+
...consentSource ? { consent_source: consentSource } : {},
|
|
734
|
+
...consentIp ? { consent_ip: consentIp } : {}
|
|
735
|
+
})
|
|
736
|
+
);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (action === "get") {
|
|
740
|
+
writeJson(
|
|
741
|
+
out,
|
|
742
|
+
await client.audiences.subscribers.get(
|
|
743
|
+
audienceId,
|
|
744
|
+
requirePositional(parsed.positional, 4, "subscriber id")
|
|
745
|
+
)
|
|
746
|
+
);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (action === "by-email") {
|
|
750
|
+
writeJson(
|
|
751
|
+
out,
|
|
752
|
+
await client.audiences.subscribers.getByEmail(
|
|
753
|
+
audienceId,
|
|
754
|
+
requirePositional(parsed.positional, 4, "email")
|
|
755
|
+
)
|
|
756
|
+
);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (action === "update") {
|
|
760
|
+
const subscriberId = requirePositional(parsed.positional, 4, "subscriber id");
|
|
761
|
+
const name = getString(parsed.options, "name");
|
|
762
|
+
writeJson(
|
|
763
|
+
out,
|
|
764
|
+
await client.audiences.subscribers.update(audienceId, subscriberId, {
|
|
765
|
+
...name ? { display_name: name } : {}
|
|
766
|
+
})
|
|
767
|
+
);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
if (action === "unsubscribe") {
|
|
771
|
+
writeJson(
|
|
772
|
+
out,
|
|
773
|
+
await client.audiences.subscribers.unsubscribe(
|
|
774
|
+
audienceId,
|
|
775
|
+
requirePositional(parsed.positional, 4, "subscriber id")
|
|
776
|
+
)
|
|
777
|
+
);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
if (action === "remove") {
|
|
781
|
+
const subscriberId = requirePositional(parsed.positional, 4, "subscriber id");
|
|
782
|
+
await client.audiences.subscribers.remove(audienceId, subscriberId);
|
|
783
|
+
writeJson(out, { ok: true, id: subscriberId });
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
throw new CliUsageError("Unknown audiences subscribers command.");
|
|
787
|
+
}
|
|
788
|
+
async function runAudiences(client, parsed, out) {
|
|
789
|
+
const subcommand = parsed.positional[1];
|
|
790
|
+
if (subcommand === "subscribers") {
|
|
791
|
+
await runSubscribers(client, parsed, out);
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (subcommand === "list") {
|
|
795
|
+
writeJson(
|
|
796
|
+
out,
|
|
797
|
+
await client.audiences.list({
|
|
798
|
+
cursor: getString(parsed.options, "cursor"),
|
|
799
|
+
limit: getNumber(parsed.options, "limit")
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
if (subcommand === "create") {
|
|
805
|
+
const description = getString(parsed.options, "description");
|
|
806
|
+
writeJson(
|
|
807
|
+
out,
|
|
808
|
+
await client.audiences.create({
|
|
809
|
+
name: requirePositional(parsed.positional, 2, "audience name"),
|
|
810
|
+
consent_source: getRequiredString(parsed.options, "consent-source"),
|
|
811
|
+
...description ? { description } : {}
|
|
812
|
+
})
|
|
813
|
+
);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
if (subcommand === "get") {
|
|
817
|
+
writeJson(
|
|
818
|
+
out,
|
|
819
|
+
await client.audiences.get(requirePositional(parsed.positional, 2, "audience id"))
|
|
820
|
+
);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
if (subcommand === "update") {
|
|
824
|
+
const id = requirePositional(parsed.positional, 2, "audience id");
|
|
825
|
+
const name = getString(parsed.options, "name");
|
|
826
|
+
const description = getString(parsed.options, "description");
|
|
827
|
+
writeJson(
|
|
828
|
+
out,
|
|
829
|
+
await client.audiences.update(id, {
|
|
830
|
+
...name ? { name } : {},
|
|
831
|
+
...description ? { description } : {}
|
|
832
|
+
})
|
|
833
|
+
);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (subcommand === "delete") {
|
|
837
|
+
const id = requirePositional(parsed.positional, 2, "audience id");
|
|
838
|
+
await client.audiences.delete(id);
|
|
839
|
+
writeJson(out, { ok: true, id });
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
throw new CliUsageError("Unknown audiences command.");
|
|
843
|
+
}
|
|
844
|
+
async function runNewsletterDomains(client, parsed, out) {
|
|
845
|
+
const subcommand = parsed.positional[1];
|
|
846
|
+
if (subcommand === "list") {
|
|
847
|
+
writeJson(
|
|
848
|
+
out,
|
|
849
|
+
await client.newsletters.domains.list({
|
|
850
|
+
cursor: getString(parsed.options, "cursor"),
|
|
851
|
+
limit: getNumber(parsed.options, "limit")
|
|
852
|
+
})
|
|
853
|
+
);
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
throw new CliUsageError("Unknown newsletter-domains command.");
|
|
857
|
+
}
|
|
858
|
+
async function runNewsletters(client, parsed, out) {
|
|
859
|
+
const subcommand = parsed.positional[1];
|
|
860
|
+
if (subcommand === "create") {
|
|
861
|
+
writeJson(out, await client.newsletters.create(await newsletterCreateParams(parsed.options)));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (subcommand === "update") {
|
|
865
|
+
const id = requirePositional(parsed.positional, 2, "newsletter id");
|
|
866
|
+
writeJson(
|
|
867
|
+
out,
|
|
868
|
+
await client.newsletters.update(id, await newsletterUpdateParams(parsed.options))
|
|
869
|
+
);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (subcommand === "preview") {
|
|
873
|
+
writeJson(
|
|
874
|
+
out,
|
|
875
|
+
await client.newsletters.preview(requirePositional(parsed.positional, 2, "newsletter id"))
|
|
876
|
+
);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
if (subcommand === "preflight") {
|
|
880
|
+
writeJson(
|
|
881
|
+
out,
|
|
882
|
+
await client.newsletters.preflight(requirePositional(parsed.positional, 2, "newsletter id"))
|
|
883
|
+
);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
if (subcommand === "test-send") {
|
|
887
|
+
writeJson(
|
|
888
|
+
out,
|
|
889
|
+
await client.newsletters.sendTest(requirePositional(parsed.positional, 2, "newsletter id"), {
|
|
890
|
+
recipient_email: getRequiredString(parsed.options, "recipient-email")
|
|
891
|
+
})
|
|
892
|
+
);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (subcommand === "schedule") {
|
|
896
|
+
writeJson(
|
|
897
|
+
out,
|
|
898
|
+
await client.newsletters.schedule(requirePositional(parsed.positional, 2, "newsletter id"), {
|
|
899
|
+
scheduled_at: getRequiredString(parsed.options, "scheduled-at")
|
|
900
|
+
})
|
|
901
|
+
);
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
if (subcommand === "cancel") {
|
|
905
|
+
writeJson(
|
|
906
|
+
out,
|
|
907
|
+
await client.newsletters.cancel(requirePositional(parsed.positional, 2, "newsletter id"))
|
|
908
|
+
);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (subcommand === "resume") {
|
|
912
|
+
writeJson(
|
|
913
|
+
out,
|
|
914
|
+
await client.newsletters.resume(requirePositional(parsed.positional, 2, "newsletter id"))
|
|
915
|
+
);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
throw new CliUsageError("Unknown newsletters command.");
|
|
919
|
+
}
|
|
920
|
+
async function runNewsletterAssets(client, parsed, out) {
|
|
921
|
+
const subcommand = parsed.positional[1];
|
|
922
|
+
if (subcommand === "list") {
|
|
923
|
+
const kind = getString(parsed.options, "kind");
|
|
924
|
+
if (kind !== void 0 && kind !== "image" && kind !== "video") {
|
|
925
|
+
throw new CliUsageError("--kind must be image or video.");
|
|
926
|
+
}
|
|
927
|
+
writeJson(
|
|
928
|
+
out,
|
|
929
|
+
await client.newsletters.assets.list({
|
|
930
|
+
cursor: getString(parsed.options, "cursor"),
|
|
931
|
+
limit: getNumber(parsed.options, "limit"),
|
|
932
|
+
kind,
|
|
933
|
+
q: getString(parsed.options, "q")
|
|
934
|
+
})
|
|
935
|
+
);
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (subcommand === "upload") {
|
|
939
|
+
const filePath = requirePositional(parsed.positional, 2, "file");
|
|
940
|
+
const data = await readFile(realpathSync(filePath));
|
|
941
|
+
writeJson(
|
|
942
|
+
out,
|
|
943
|
+
await client.newsletters.assets.upload({
|
|
944
|
+
filename: getString(parsed.options, "filename") ?? filePath.split(/[\\/]/).at(-1) ?? "newsletter-asset",
|
|
945
|
+
data,
|
|
946
|
+
content_type: getString(parsed.options, "content-type")
|
|
947
|
+
})
|
|
948
|
+
);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
throw new CliUsageError("Unknown newsletter-assets command.");
|
|
952
|
+
}
|
|
578
953
|
function writeError(err, errOut) {
|
|
579
954
|
if (err instanceof CliUsageError) {
|
|
580
955
|
errOut.write(`Error: ${err.message}
|
|
@@ -589,9 +964,10 @@ ${JSON.stringify(err.body, null, 2)}
|
|
|
589
964
|
return;
|
|
590
965
|
}
|
|
591
966
|
if (err instanceof ShipMailError) {
|
|
592
|
-
const
|
|
593
|
-
const
|
|
594
|
-
|
|
967
|
+
const shipmailError = err;
|
|
968
|
+
const status = shipmailError.status !== void 0 ? ` (HTTP ${shipmailError.status})` : "";
|
|
969
|
+
const requestId = shipmailError.requestId ? ` request_id=${shipmailError.requestId}` : "";
|
|
970
|
+
errOut.write(`Error: ${shipmailError.message}${status}${requestId}
|
|
595
971
|
`);
|
|
596
972
|
return;
|
|
597
973
|
}
|
|
@@ -633,6 +1009,10 @@ async function runCli(argv, options = {}) {
|
|
|
633
1009
|
else if (command === "messages") await runMessages(client, parsed, out);
|
|
634
1010
|
else if (command === "webhooks") await runWebhooks(client, parsed, out);
|
|
635
1011
|
else if (command === "suppressions") await runSuppressions(client, parsed, out);
|
|
1012
|
+
else if (command === "newsletters") await runNewsletters(client, parsed, out);
|
|
1013
|
+
else if (command === "newsletter-assets") await runNewsletterAssets(client, parsed, out);
|
|
1014
|
+
else if (command === "newsletter-domains") await runNewsletterDomains(client, parsed, out);
|
|
1015
|
+
else if (command === "audiences") await runAudiences(client, parsed, out);
|
|
636
1016
|
else throw new CliUsageError(`Unknown command: ${command}.`);
|
|
637
1017
|
return 0;
|
|
638
1018
|
} 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.5",
|
|
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.26"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"tsup": "^8.4.0",
|