shipmail-cli 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +237 -1
  2. package/package.json +2 -2
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.6";
15
+ var VERSION = "0.1.7";
16
16
 
17
17
  // src/cli.ts
18
18
  var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
@@ -358,6 +358,17 @@ Usage:
358
358
  shipmail audiences subscribers unsubscribe <audience-id> <subscriber-id>
359
359
  shipmail audiences subscribers resubscribe <audience-id> <subscriber-id> --consent-source "Signup form"
360
360
  shipmail audiences subscribers remove <audience-id> <subscriber-id>
361
+ shipmail calendar events list --mailbox hello@example.com --from 2026-08-01T00:00:00Z --to 2026-08-08T00:00:00Z [--expand true] [--limit 100]
362
+ shipmail calendar events create --mailbox hello@example.com --title "Sync" --start 2026-08-01T14:00:00 [--timezone Europe/Paris] [--duration PT30M] [--all-day true] [--location "HQ"] [--video-url https://...] [--reminders JSON|@file]
363
+ shipmail calendar events get <event-id> --mailbox hello@example.com
364
+ shipmail calendar events update <event-id> --mailbox hello@example.com [--title "..."] [--start ...]
365
+ shipmail calendar events delete <event-id> --mailbox hello@example.com
366
+ 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
+ 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
369
+ shipmail booking-pages get <id>
370
+ shipmail booking-pages update <id> [--name "..."] [--active false]
371
+ shipmail booking-pages delete <id>
361
372
 
362
373
  Global options:
363
374
  --api-key <key> API key. Defaults to SHIPMAIL_API_KEY.
@@ -974,6 +985,229 @@ async function runNewsletterAssets(client, parsed, out) {
974
985
  }
975
986
  throw new CliUsageError("Unknown newsletter-assets command.");
976
987
  }
988
+ var CALENDAR_EVENT_STATUSES = [
989
+ "confirmed",
990
+ "tentative",
991
+ "cancelled"
992
+ ];
993
+ var CALENDAR_FREE_BUSY_STATUSES = ["free", "busy"];
994
+ var CALENDAR_PRIVACIES = ["public", "private", "secret"];
995
+ function requireNumber(options, key) {
996
+ const value = getNumber(options, key);
997
+ if (value === void 0) throw new CliUsageError(`Missing --${key}.`);
998
+ return value;
999
+ }
1000
+ function getIntList(options, key) {
1001
+ return getStringList(options, key).map((raw) => {
1002
+ const value = Number(raw);
1003
+ if (!Number.isInteger(value)) {
1004
+ throw new CliUsageError(`--${key} must be a comma-separated list of integers.`);
1005
+ }
1006
+ return value;
1007
+ });
1008
+ }
1009
+ function requireIntList(options, key) {
1010
+ const values = getIntList(options, key);
1011
+ if (values.length === 0) throw new CliUsageError(`Missing --${key}.`);
1012
+ return values;
1013
+ }
1014
+ function getEnum(options, key, allowed) {
1015
+ const value = getString(options, key);
1016
+ if (value === void 0) return void 0;
1017
+ const match = allowed.find((candidate) => candidate === value);
1018
+ if (match === void 0) {
1019
+ throw new CliUsageError(`--${key} must be one of: ${allowed.join(", ")}.`);
1020
+ }
1021
+ return match;
1022
+ }
1023
+ function isReminderArray(value) {
1024
+ return Array.isArray(value) && value.every(
1025
+ (item) => typeof item === "object" && item !== null && !Array.isArray(item) && Number.isInteger(item.minutes_before)
1026
+ );
1027
+ }
1028
+ async function readRemindersInput(value) {
1029
+ const parsed = await readJsonInput(value);
1030
+ if (parsed === void 0) return void 0;
1031
+ if (!isReminderArray(parsed)) {
1032
+ throw new CliUsageError("--reminders must be a JSON array of { minutes_before } objects.");
1033
+ }
1034
+ return parsed;
1035
+ }
1036
+ async function calendarEventFields(options) {
1037
+ const description = getString(options, "description");
1038
+ const timezone = getString(options, "timezone");
1039
+ const duration = getString(options, "duration");
1040
+ const allDay = getBoolean(options, "all-day");
1041
+ const location = getString(options, "location");
1042
+ const videoUrl = getString(options, "video-url");
1043
+ const color = getString(options, "color");
1044
+ const status = getEnum(options, "status", CALENDAR_EVENT_STATUSES);
1045
+ const freeBusyStatus = getEnum(options, "free-busy-status", CALENDAR_FREE_BUSY_STATUSES);
1046
+ const privacy = getEnum(options, "privacy", CALENDAR_PRIVACIES);
1047
+ const reminders = await readRemindersInput(getString(options, "reminders"));
1048
+ return {
1049
+ ...description !== void 0 ? { description } : {},
1050
+ ...timezone !== void 0 ? { timezone } : {},
1051
+ ...duration !== void 0 ? { duration } : {},
1052
+ ...allDay !== void 0 ? { all_day: allDay } : {},
1053
+ ...location !== void 0 ? { location } : {},
1054
+ ...videoUrl !== void 0 ? { video_url: videoUrl } : {},
1055
+ ...color !== void 0 ? { color } : {},
1056
+ ...status !== void 0 ? { status } : {},
1057
+ ...freeBusyStatus !== void 0 ? { free_busy_status: freeBusyStatus } : {},
1058
+ ...privacy !== void 0 ? { privacy } : {},
1059
+ ...reminders !== void 0 ? { reminders } : {}
1060
+ };
1061
+ }
1062
+ async function runCalendarEvents(client, parsed, out) {
1063
+ const subcommand = parsed.positional[2];
1064
+ const options = parsed.options;
1065
+ if (subcommand === "list") {
1066
+ const params = {
1067
+ mailbox: getRequiredString(options, "mailbox"),
1068
+ from: getRequiredString(options, "from"),
1069
+ to: getRequiredString(options, "to"),
1070
+ expand: getBoolean(options, "expand"),
1071
+ calendar_id: getString(options, "calendar-id"),
1072
+ cursor: getString(options, "cursor"),
1073
+ limit: getNumber(options, "limit")
1074
+ };
1075
+ writeJson(out, await client.calendar.events.list(params));
1076
+ return;
1077
+ }
1078
+ if (subcommand === "create") {
1079
+ const params = {
1080
+ mailbox: getRequiredString(options, "mailbox"),
1081
+ title: getRequiredString(options, "title"),
1082
+ start: getRequiredString(options, "start"),
1083
+ calendar_id: getString(options, "calendar-id"),
1084
+ ...await calendarEventFields(options)
1085
+ };
1086
+ writeJson(out, await client.calendar.events.create(params));
1087
+ return;
1088
+ }
1089
+ if (subcommand === "get") {
1090
+ const id = requirePositional(parsed.positional, 3, "event id");
1091
+ writeJson(
1092
+ out,
1093
+ await client.calendar.events.get(id, { mailbox: getRequiredString(options, "mailbox") })
1094
+ );
1095
+ return;
1096
+ }
1097
+ if (subcommand === "update") {
1098
+ const id = requirePositional(parsed.positional, 3, "event id");
1099
+ const params = {
1100
+ mailbox: getRequiredString(options, "mailbox"),
1101
+ title: getString(options, "title"),
1102
+ start: getString(options, "start"),
1103
+ ...await calendarEventFields(options)
1104
+ };
1105
+ writeJson(out, await client.calendar.events.update(id, params));
1106
+ return;
1107
+ }
1108
+ if (subcommand === "delete") {
1109
+ const id = requirePositional(parsed.positional, 3, "event id");
1110
+ await client.calendar.events.delete(id, { mailbox: getRequiredString(options, "mailbox") });
1111
+ writeJson(out, { ok: true, id });
1112
+ return;
1113
+ }
1114
+ throw new CliUsageError("Unknown calendar events command.");
1115
+ }
1116
+ async function runCalendar(client, parsed, out) {
1117
+ const subcommand = parsed.positional[1];
1118
+ if (subcommand === "events") {
1119
+ await runCalendarEvents(client, parsed, out);
1120
+ return;
1121
+ }
1122
+ if (subcommand === "availability") {
1123
+ const options = parsed.options;
1124
+ const days = getIntList(options, "days");
1125
+ const params = {
1126
+ mailbox: getRequiredString(options, "mailbox"),
1127
+ from: getRequiredString(options, "from"),
1128
+ to: getRequiredString(options, "to"),
1129
+ duration: getNumber(options, "duration"),
1130
+ interval: getNumber(options, "interval"),
1131
+ timezone: getString(options, "timezone"),
1132
+ ...days.length > 0 ? { days } : {},
1133
+ window_start: getNumber(options, "window-start"),
1134
+ window_end: getNumber(options, "window-end"),
1135
+ buffer: getNumber(options, "buffer"),
1136
+ minimum_notice: getNumber(options, "minimum-notice")
1137
+ };
1138
+ writeJson(out, await client.calendar.availability(params));
1139
+ return;
1140
+ }
1141
+ throw new CliUsageError("Unknown calendar command.");
1142
+ }
1143
+ async function runBookingPages(client, parsed, out) {
1144
+ const subcommand = parsed.positional[1];
1145
+ const options = parsed.options;
1146
+ if (subcommand === "list") {
1147
+ writeJson(
1148
+ out,
1149
+ await client.bookingPages.list({
1150
+ cursor: getString(options, "cursor"),
1151
+ limit: getNumber(options, "limit")
1152
+ })
1153
+ );
1154
+ return;
1155
+ }
1156
+ if (subcommand === "create") {
1157
+ const params = {
1158
+ name: getRequiredString(options, "name"),
1159
+ mailbox: getRequiredString(options, "mailbox"),
1160
+ slug: getRequiredString(options, "slug"),
1161
+ duration_minutes: requireNumber(options, "duration-minutes"),
1162
+ availability_days: requireIntList(options, "availability-days"),
1163
+ window_start_minutes: requireNumber(options, "window-start-minutes"),
1164
+ window_end_minutes: requireNumber(options, "window-end-minutes"),
1165
+ timezone: getRequiredString(options, "timezone"),
1166
+ description: getString(options, "description"),
1167
+ buffer_minutes: getNumber(options, "buffer-minutes"),
1168
+ minimum_notice_minutes: getNumber(options, "minimum-notice-minutes"),
1169
+ max_advance_days: getNumber(options, "max-advance-days"),
1170
+ active: getBoolean(options, "active")
1171
+ };
1172
+ writeJson(out, await client.bookingPages.create(params));
1173
+ return;
1174
+ }
1175
+ if (subcommand === "get") {
1176
+ writeJson(
1177
+ out,
1178
+ await client.bookingPages.get(requirePositional(parsed.positional, 2, "booking page id"))
1179
+ );
1180
+ return;
1181
+ }
1182
+ if (subcommand === "update") {
1183
+ const id = requirePositional(parsed.positional, 2, "booking page id");
1184
+ const days = getIntList(options, "availability-days");
1185
+ const params = {
1186
+ name: getString(options, "name"),
1187
+ mailbox: getString(options, "mailbox"),
1188
+ slug: getString(options, "slug"),
1189
+ duration_minutes: getNumber(options, "duration-minutes"),
1190
+ ...days.length > 0 ? { availability_days: days } : {},
1191
+ window_start_minutes: getNumber(options, "window-start-minutes"),
1192
+ window_end_minutes: getNumber(options, "window-end-minutes"),
1193
+ timezone: getString(options, "timezone"),
1194
+ description: getString(options, "description"),
1195
+ buffer_minutes: getNumber(options, "buffer-minutes"),
1196
+ minimum_notice_minutes: getNumber(options, "minimum-notice-minutes"),
1197
+ max_advance_days: getNumber(options, "max-advance-days"),
1198
+ active: getBoolean(options, "active")
1199
+ };
1200
+ writeJson(out, await client.bookingPages.update(id, params));
1201
+ return;
1202
+ }
1203
+ if (subcommand === "delete") {
1204
+ const id = requirePositional(parsed.positional, 2, "booking page id");
1205
+ await client.bookingPages.delete(id);
1206
+ writeJson(out, { ok: true, id });
1207
+ return;
1208
+ }
1209
+ throw new CliUsageError("Unknown booking-pages command.");
1210
+ }
977
1211
  function writeError(err, errOut) {
978
1212
  if (err instanceof CliUsageError) {
979
1213
  errOut.write(`Error: ${err.message}
@@ -1037,6 +1271,8 @@ async function runCli(argv, options = {}) {
1037
1271
  else if (command === "newsletter-assets") await runNewsletterAssets(client, parsed, out);
1038
1272
  else if (command === "newsletter-domains") await runNewsletterDomains(client, parsed, out);
1039
1273
  else if (command === "audiences") await runAudiences(client, parsed, out);
1274
+ else if (command === "calendar") await runCalendar(client, parsed, out);
1275
+ else if (command === "booking-pages") await runBookingPages(client, parsed, out);
1040
1276
  else throw new CliUsageError(`Unknown command: ${command}.`);
1041
1277
  return 0;
1042
1278
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
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.29"
44
+ "shipmail": "0.1.30"
45
45
  },
46
46
  "devDependencies": {
47
47
  "tsup": "^8.4.0",