shipmail-cli 0.6.2 → 0.6.4

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 (3) hide show
  1. package/README.md +7 -2
  2. package/dist/cli.js +98 -8
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -98,6 +98,7 @@ shipmail mailboxes sandbox-inbound mbx_123 --from customer@example.com --subject
98
98
 
99
99
  # Read inbound mail
100
100
  shipmail inbox list 550e8400-e29b-41d4-a716-446655440000 --folder-role inbox --after 2025-07-20T00:00:00Z --limit 25
101
+ shipmail inbox list 550e8400-e29b-41d4-a716-446655440000 --from billing@vendor.example --subject invoice --has-attachment
101
102
  shipmail inbox message 550e8400-e29b-41d4-a716-446655440000 eml_123
102
103
  shipmail inbox threads 550e8400-e29b-41d4-a716-446655440000 --attention-state needs_reply --after 2025-07-20T00:00:00Z --limit 50
103
104
  shipmail inbox thread 550e8400-e29b-41d4-a716-446655440000 thr_123
@@ -137,7 +138,11 @@ shipmail newsletter-assets register-url https://cdn.shipmail.to/newsletter-image
137
138
  # Manage webhooks
138
139
  shipmail webhooks create \
139
140
  --url https://example.com/shipmail/webhook \
140
- --events message.received,message.bounced
141
+ --events message.received,message.bounced \
142
+ --authorization "Bearer your-endpoint-key"
143
+ shipmail webhooks update whk_123 --clear-authorization
144
+ shipmail webhooks update whk_123 --standard-webhooks-secret "whsec_..."
145
+ shipmail webhooks update whk_123 --clear-standard-webhooks-secret
141
146
  shipmail webhooks deliveries whk_123 --status failed
142
147
  shipmail webhooks replay-delivery whk_123 dlv_123 --idempotency-key replay-123
143
148
  ```
@@ -173,7 +178,7 @@ Use repeatable `--header "Name: value"` flags for request headers. Use `--output
173
178
  - `messages send|list|analytics|get|reply` (test keys also support `--sandbox-outcome`)
174
179
  - `scheduled-messages list|get|update|cancel`
175
180
  - `mailboxes sandbox-inbound`
176
- - `webhooks list|create|test|deliveries|replay-delivery`
181
+ - `webhooks list|create|update|test|deliveries|replay-delivery`
177
182
  - `suppressions list|remove`
178
183
  - `audiences list|create|get|update|delete`
179
184
  - `audiences feed get|update|rotate|revoke`
package/dist/cli.js CHANGED
@@ -649,7 +649,7 @@ async function login(options) {
649
649
  }
650
650
 
651
651
  // src/version.ts
652
- var VERSION = "0.6.2";
652
+ var VERSION = "0.6.4";
653
653
 
654
654
  // src/cli.ts
655
655
  var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
@@ -1035,6 +1035,7 @@ async function newsletterCreateParams(options) {
1035
1035
  const feed_entry_url = getString(options, "feed-entry-url");
1036
1036
  const styling_mode = parseStylingMode(options);
1037
1037
  const track_engagement = getBoolean(options, "track-engagement");
1038
+ const add_utm_tags = getBoolean(options, "add-utm-tags");
1038
1039
  const preview_text = getString(options, "preview-text");
1039
1040
  return {
1040
1041
  audience_id,
@@ -1049,7 +1050,8 @@ async function newsletterCreateParams(options) {
1049
1050
  ...archive_visibility !== void 0 ? { archive_visibility } : {},
1050
1051
  ...feed_entry_url !== void 0 ? { feed_entry_url } : {},
1051
1052
  ...styling_mode !== void 0 ? { styling_mode } : {},
1052
- ...track_engagement !== void 0 ? { track_engagement } : {}
1053
+ ...track_engagement !== void 0 ? { track_engagement } : {},
1054
+ ...add_utm_tags !== void 0 ? { add_utm_tags } : {}
1053
1055
  };
1054
1056
  }
1055
1057
  async function newsletterUpdateParams(options) {
@@ -1063,6 +1065,7 @@ async function newsletterUpdateParams(options) {
1063
1065
  const feed_entry_url = getString(options, "feed-entry-url");
1064
1066
  const styling_mode = parseStylingMode(options);
1065
1067
  const track_engagement = getBoolean(options, "track-engagement");
1068
+ const add_utm_tags = getBoolean(options, "add-utm-tags");
1066
1069
  const blocksInput = getString(options, "blocks");
1067
1070
  const bodyHtmlInput = getString(options, "body-html");
1068
1071
  const bodyTextInput = getString(options, "body-text");
@@ -1082,7 +1085,8 @@ async function newsletterUpdateParams(options) {
1082
1085
  ...archive_visibility !== void 0 ? { archive_visibility } : {},
1083
1086
  ...feed_entry_url !== void 0 ? { feed_entry_url } : {},
1084
1087
  ...styling_mode !== void 0 ? { styling_mode } : {},
1085
- ...track_engagement !== void 0 ? { track_engagement } : {}
1088
+ ...track_engagement !== void 0 ? { track_engagement } : {},
1089
+ ...add_utm_tags !== void 0 ? { add_utm_tags } : {}
1086
1090
  };
1087
1091
  if (Object.keys(params).length === 0) {
1088
1092
  throw new CliUsageError("Provide at least one field to update.");
@@ -1202,7 +1206,7 @@ Usage:
1202
1206
  shipmail mailboxes sandbox-inbound <id> --from sender@example.com --subject "Test" (--text "Hello" | --html "<p>Hello</p>") [--to support@example.com]
1203
1207
  shipmail members list [--limit 25] [--cursor cur]
1204
1208
  shipmail members get <id>
1205
- shipmail inbox list <mailbox-id> [--folder-role inbox] [--search text] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
1209
+ shipmail inbox list <mailbox-id> [--folder-role inbox] [--search text] [--from text] [--to text] [--subject text] [--has-attachment [true|false]] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
1206
1210
  shipmail inbox message <mailbox-id> <message-id>
1207
1211
  shipmail inbox threads <mailbox-id> [--attention-state needs_reply] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
1208
1212
  shipmail inbox thread <mailbox-id> <thread-id>
@@ -1227,7 +1231,8 @@ Usage:
1227
1231
  shipmail reply-scans status <scan-id>
1228
1232
  shipmail reply-scans results <scan-id> [--limit 25] [--cursor cur]
1229
1233
  shipmail webhooks list
1230
- shipmail webhooks create --url https://example.com/hook --events message.received,message.bounced
1234
+ shipmail webhooks create --url https://example.com/hook --events message.received,message.bounced [--authorization "Bearer key"] [--standard-webhooks-secret whsec_...] [--include-reply-text] [--authenticated-senders-only] [--allowed-sender jane@customer.com --allowed-sender customer.com]
1235
+ shipmail webhooks update <webhook-id> [--url https://example.com/hook] [--events message.received] [--description text] [--active true|false] [--authorization "Bearer key" | --clear-authorization] [--standard-webhooks-secret whsec_... | --clear-standard-webhooks-secret] [--include-reply-text true|false] [--authenticated-senders-only true|false] [--allowed-sender customer.com ... | --clear-allowed-senders]
1231
1236
  shipmail webhooks replay-delivery <webhook-id> <delivery-id> [--idempotency-key key]
1232
1237
  shipmail suppressions list
1233
1238
  shipmail suppressions remove <email>
@@ -1237,8 +1242,8 @@ Usage:
1237
1242
  --name "July changelog" \\
1238
1243
  --subject "What shipped in July" \\
1239
1244
  --blocks @blocks.json \\
1240
- [--feed-entry-url https://example.com/post] [--styling-mode styled|plain] [--track-engagement true|false]
1241
- shipmail newsletters update nws_789 --subject "Updated subject" --blocks @blocks-v2.json [--feed-entry-url https://example.com/post] [--styling-mode styled|plain] [--track-engagement true|false]
1245
+ [--feed-entry-url https://example.com/post] [--styling-mode styled|plain] [--track-engagement true|false] [--add-utm-tags true|false]
1246
+ shipmail newsletters update nws_789 --subject "Updated subject" --blocks @blocks-v2.json [--feed-entry-url https://example.com/post] [--styling-mode styled|plain] [--track-engagement true|false] [--add-utm-tags true|false]
1242
1247
  shipmail newsletters preview <id>
1243
1248
  shipmail newsletters preflight <id>
1244
1249
  shipmail newsletters test-send <id> --recipient-email owner@example.com
@@ -1296,6 +1301,7 @@ Newsletter styling:
1296
1301
 
1297
1302
  Newsletter tracking:
1298
1303
  --track-engagement <true|false> Track opens and clicks for this issue. Off by default. Changes only while the issue is a draft or scheduled for later.
1304
+ --add-utm-tags <true|false> Add utm_source, utm_medium and utm_campaign to the issue's links in the email and the feed. Off by default. Changes only while the issue is a draft or scheduled for later.
1299
1305
 
1300
1306
  Newsletter block prose:
1301
1307
  Paragraph, quote, callout, list-item, and column bodies accept bare text or sanitized inline HTML. Use <p> and <br> for line breaks.
@@ -1346,11 +1352,22 @@ function requirePositional(positional, index, label) {
1346
1352
  if (!value) throw new CliUsageError(`Missing ${label}.`);
1347
1353
  return value;
1348
1354
  }
1355
+ function inboxTextFilters(options) {
1356
+ const from = getString(options, "from");
1357
+ const to = getString(options, "to");
1358
+ const subject = getString(options, "subject");
1359
+ return {
1360
+ ...from ? { from } : {},
1361
+ ...to ? { to } : {},
1362
+ ...subject ? { subject } : {}
1363
+ };
1364
+ }
1349
1365
  function inboxListParams(options) {
1350
1366
  const params = {};
1351
1367
  const folderId = getString(options, "folder-id");
1352
1368
  const folderRole = getString(options, "folder-role");
1353
1369
  const searchText = getString(options, "search");
1370
+ const hasAttachment = getBoolean(options, "has-attachment");
1354
1371
  const cursor = getString(options, "cursor");
1355
1372
  const after = getString(options, "after");
1356
1373
  const before = getString(options, "before");
@@ -1360,6 +1377,8 @@ function inboxListParams(options) {
1360
1377
  if (folderId) params.folder_id = folderId;
1361
1378
  if (folderRole) params.folder_role = folderRole;
1362
1379
  if (searchText) params.search_text = searchText;
1380
+ Object.assign(params, inboxTextFilters(options));
1381
+ if (hasAttachment !== void 0) params.has_attachment = hasAttachment;
1363
1382
  if (cursor) params.cursor = cursor;
1364
1383
  if (after) params.after = after;
1365
1384
  if (before) params.before = before;
@@ -1380,6 +1399,59 @@ function webhookEvents(options) {
1380
1399
  }
1381
1400
  return events;
1382
1401
  }
1402
+ function webhookWriteOnlyOption(options, name) {
1403
+ const value = optionValue(options, name);
1404
+ if (value === void 0) return void 0;
1405
+ if (typeof value === "boolean") throw new CliUsageError(`Missing value for --${name}.`);
1406
+ return getString(options, name);
1407
+ }
1408
+ function webhookWriteOnlyUpdate(options, name) {
1409
+ const value = webhookWriteOnlyOption(options, name);
1410
+ const clear = getBoolean(options, `clear-${name}`) === true;
1411
+ if (value !== void 0 && clear) {
1412
+ throw new CliUsageError(`Use --${name} or --clear-${name}, not both.`);
1413
+ }
1414
+ return clear ? null : value;
1415
+ }
1416
+ function webhookAllowedSenders(options) {
1417
+ const value = optionValue(options, "allowed-sender");
1418
+ if (value === void 0) return void 0;
1419
+ if (typeof value === "boolean") throw new CliUsageError("Missing value for --allowed-sender.");
1420
+ return getStringList(options, "allowed-sender");
1421
+ }
1422
+ function webhookAllowedSendersUpdate(options) {
1423
+ const senders = webhookAllowedSenders(options);
1424
+ const clear = getBoolean(options, "clear-allowed-senders") === true;
1425
+ if (senders !== void 0 && clear) {
1426
+ throw new CliUsageError("Use --allowed-sender or --clear-allowed-senders, not both.");
1427
+ }
1428
+ return clear ? null : senders;
1429
+ }
1430
+ function webhookUpdateParams(options) {
1431
+ const authorization = webhookWriteOnlyUpdate(options, "authorization");
1432
+ const standardWebhooksSecret = webhookWriteOnlyUpdate(options, "standard-webhooks-secret");
1433
+ const url = getString(options, "url");
1434
+ const description = getString(options, "description");
1435
+ const active = getBoolean(options, "active");
1436
+ const includeReplyText = getBoolean(options, "include-reply-text");
1437
+ const authenticatedSendersOnly = getBoolean(options, "authenticated-senders-only");
1438
+ const allowedSenders = webhookAllowedSendersUpdate(options);
1439
+ const params = {
1440
+ ...url !== void 0 ? { url } : {},
1441
+ ...optionValue(options, "events") !== void 0 ? { events: webhookEvents(options) } : {},
1442
+ ...description !== void 0 ? { description } : {},
1443
+ ...active !== void 0 ? { active } : {},
1444
+ ...authorization !== void 0 ? { authorization } : {},
1445
+ ...standardWebhooksSecret !== void 0 ? { standard_webhooks_secret: standardWebhooksSecret } : {},
1446
+ ...includeReplyText !== void 0 ? { include_reply_text: includeReplyText } : {},
1447
+ ...authenticatedSendersOnly !== void 0 ? { authenticated_senders_only: authenticatedSendersOnly } : {},
1448
+ ...allowedSenders !== void 0 ? { allowed_senders: allowedSenders } : {}
1449
+ };
1450
+ if (Object.keys(params).length === 0) {
1451
+ throw new CliUsageError("Nothing to update. Pass at least one webhook option.");
1452
+ }
1453
+ return params;
1454
+ }
1383
1455
  function webhookDeliveryParams(options) {
1384
1456
  const status = getString(options, "status");
1385
1457
  const eventType = getString(options, "event-type");
@@ -2170,16 +2242,34 @@ async function runWebhooks(client, parsed, out) {
2170
2242
  }
2171
2243
  if (subcommand === "create") {
2172
2244
  const description = getString(parsed.options, "description");
2245
+ const authorization = webhookWriteOnlyOption(parsed.options, "authorization");
2246
+ const standardWebhooksSecret = webhookWriteOnlyOption(
2247
+ parsed.options,
2248
+ "standard-webhooks-secret"
2249
+ );
2250
+ const includeReplyText = getBoolean(parsed.options, "include-reply-text");
2251
+ const authenticatedSendersOnly = getBoolean(parsed.options, "authenticated-senders-only");
2252
+ const allowedSenders = webhookAllowedSenders(parsed.options);
2173
2253
  writeJson(
2174
2254
  out,
2175
2255
  await client.webhooks.create({
2176
2256
  url: getRequiredString(parsed.options, "url"),
2177
2257
  events: webhookEvents(parsed.options),
2178
- ...description ? { description } : {}
2258
+ ...description ? { description } : {},
2259
+ ...authorization !== void 0 ? { authorization } : {},
2260
+ ...standardWebhooksSecret !== void 0 ? { standard_webhooks_secret: standardWebhooksSecret } : {},
2261
+ ...includeReplyText !== void 0 ? { include_reply_text: includeReplyText } : {},
2262
+ ...authenticatedSendersOnly !== void 0 ? { authenticated_senders_only: authenticatedSendersOnly } : {},
2263
+ ...allowedSenders !== void 0 ? { allowed_senders: allowedSenders } : {}
2179
2264
  })
2180
2265
  );
2181
2266
  return;
2182
2267
  }
2268
+ if (subcommand === "update") {
2269
+ const webhookId = requirePositional(parsed.positional, 2, "webhook id");
2270
+ writeJson(out, await client.webhooks.update(webhookId, webhookUpdateParams(parsed.options)));
2271
+ return;
2272
+ }
2183
2273
  if (subcommand === "test") {
2184
2274
  writeJson(
2185
2275
  out,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail-cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
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.6.3",
44
+ "shipmail": "0.6.5",
45
45
  "zod": "^4.6.5"
46
46
  },
47
47
  "devDependencies": {