groundmail-cli 0.35.1 → 0.36.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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +81 -30
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -75,6 +75,8 @@ groundmail domains list
75
75
  groundmail domains verify example.com
76
76
  groundmail webhooks list
77
77
  groundmail emails list
78
+ groundmail batches get batch_… # status counts for an emails batch
79
+ groundmail batches cancel batch_… # cancel the batch's emails that are still scheduled
78
80
  groundmail brand set --logo-url https://cdn.acme.com/logo.png --color '#2f6feb' --company "Acme Inc" # logo, color and footer every template follows
79
81
  groundmail senders list # saved senders; send with --sender billing instead of --from
80
82
  SENDGRID_API_KEY=… groundmail migrate sendgrid --dry-run # import from SendGrid, Postmark, Mailgun, Resend or Amazon SES (beta)
package/dist/cli.js CHANGED
@@ -2055,7 +2055,7 @@ function trimUrl(value) {
2055
2055
  }
2056
2056
 
2057
2057
  // package.json
2058
- var version = "0.35.1";
2058
+ var version = "0.36.0";
2059
2059
 
2060
2060
  // src/user-agent.ts
2061
2061
  function buildUserAgent(own) {
@@ -4159,6 +4159,51 @@ async function runSetCommand(args, env = process.env) {
4159
4159
  });
4160
4160
  }
4161
4161
 
4162
+ // src/commands/batches/commands.ts
4163
+ var VALUE_FLAGS3 = ["--api-key", "--base-url", "--id"];
4164
+ var MISSING_KEY3 = "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.";
4165
+ function readFlag23(args, flag) {
4166
+ const index = args.indexOf(flag);
4167
+ if (index === -1) return void 0;
4168
+ return args[index + 1];
4169
+ }
4170
+ function batchRef(args) {
4171
+ const id = readFlag23(args, "--id");
4172
+ if (id) return id;
4173
+ for (let i = 0; i < args.length; i += 1) {
4174
+ const arg = args[i];
4175
+ if (arg.startsWith("--")) {
4176
+ if (VALUE_FLAGS3.includes(arg)) i += 1;
4177
+ continue;
4178
+ }
4179
+ return arg;
4180
+ }
4181
+ return void 0;
4182
+ }
4183
+ async function createBatchesClient(apiKey, baseUrl) {
4184
+ const { Groundmail } = await import("groundmail");
4185
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
4186
+ }
4187
+ async function withBatch(args, env, usage, run) {
4188
+ const batchId = batchRef(args);
4189
+ if (!batchId) return { exitCode: 1, error: `Missing batch id (batch_\u2026). Usage: ${usage}` };
4190
+ const apiKey = readFlag23(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4191
+ if (!apiKey) return { exitCode: 1, error: MISSING_KEY3 };
4192
+ try {
4193
+ const client2 = await createBatchesClient(apiKey, readFlag23(args, "--base-url"));
4194
+ console.log(JSON.stringify(await run(client2, batchId)));
4195
+ return { exitCode: 0 };
4196
+ } catch (error) {
4197
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
4198
+ }
4199
+ }
4200
+ async function runGetCommand10(args, env = process.env) {
4201
+ return withBatch(args, env, "groundmail batches get <batch_id>", (client2, id) => client2.batches.get(id));
4202
+ }
4203
+ async function runCancelCommand2(args, env = process.env) {
4204
+ return withBatch(args, env, "groundmail batches cancel <batch_id>", (client2, id) => client2.batches.cancel(id));
4205
+ }
4206
+
4162
4207
  // src/commands/auth.ts
4163
4208
  async function runAuthCommand(subcommand, argv, deps = {}) {
4164
4209
  const env = deps.env ?? process.env;
@@ -4322,7 +4367,7 @@ function sesParams(args, env) {
4322
4367
  "Use a key with the read-only import policy (https://docs.groundmail.dev/migrations#amazon-ses-iam-policy). It is used for this import only and never stored."
4323
4368
  ].join("\n");
4324
4369
  }
4325
- const region = readFlag23(args, "--region") || env.AWS_REGION || env.AWS_DEFAULT_REGION;
4370
+ const region = readFlag24(args, "--region") || env.AWS_REGION || env.AWS_DEFAULT_REGION;
4326
4371
  if (!region) return "Set the SES region with --region (for example --region us-east-1) or AWS_REGION. One region per import.";
4327
4372
  if (!AWS_REGION.test(region)) return `--region must be an AWS region such as us-east-1, not ${region}`;
4328
4373
  return {
@@ -4333,8 +4378,8 @@ function sesParams(args, env) {
4333
4378
  aws_region: region
4334
4379
  };
4335
4380
  }
4336
- var VALUE_FLAGS3 = /* @__PURE__ */ new Set(["--api-key", "--base-url"]);
4337
- function readFlag23(args, flag) {
4381
+ var VALUE_FLAGS4 = /* @__PURE__ */ new Set(["--api-key", "--base-url"]);
4382
+ function readFlag24(args, flag) {
4338
4383
  const index = args.indexOf(flag);
4339
4384
  if (index === -1) return void 0;
4340
4385
  return args[index + 1];
@@ -4409,10 +4454,10 @@ function formatMigrationSummary(m) {
4409
4454
  return lines.join("\n");
4410
4455
  }
4411
4456
  async function client(args, env) {
4412
- const apiKey = readFlag23(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4457
+ const apiKey = readFlag24(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4413
4458
  if (!apiKey) return null;
4414
4459
  const { Groundmail } = await import("groundmail");
4415
- const baseUrl = readFlag23(args, "--base-url");
4460
+ const baseUrl = readFlag24(args, "--base-url");
4416
4461
  return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
4417
4462
  }
4418
4463
  async function runStoredCommand(sub, args, env) {
@@ -4426,7 +4471,7 @@ async function runStoredCommand(sub, args, env) {
4426
4471
  if (!data.length) console.error("No imports yet. Previews are not stored.");
4427
4472
  return { exitCode: 0 };
4428
4473
  }
4429
- const id = args.find((arg, i) => !arg.startsWith("--") && !VALUE_FLAGS3.has(args[i - 1] ?? ""));
4474
+ const id = args.find((arg, i) => !arg.startsWith("--") && !VALUE_FLAGS4.has(args[i - 1] ?? ""));
4430
4475
  if (!id) return { exitCode: 1, error: "Usage: groundmail migrate report <import id> [--csv]" };
4431
4476
  if (args.includes("--csv")) {
4432
4477
  process.stdout.write(await gm.migrations.reportCsv(id));
@@ -4449,7 +4494,7 @@ async function runMigrateCommand(provider, args, env = process.env) {
4449
4494
  };
4450
4495
  }
4451
4496
  const id = provider;
4452
- const apiKey = readFlag23(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4497
+ const apiKey = readFlag24(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4453
4498
  if (!apiKey) {
4454
4499
  return { exitCode: 1, error: "Not signed in. Run `groundmail login`, or set GROUNDMAIL_API_KEY." };
4455
4500
  }
@@ -4459,7 +4504,7 @@ async function runMigrateCommand(provider, args, env = process.env) {
4459
4504
  if (typeof ses === "string") return { exitCode: 1, error: ses };
4460
4505
  params = ses;
4461
4506
  } else {
4462
- const providerKey = readFlag23(args, "--key") || env[KEY_ENV[id]];
4507
+ const providerKey = readFlag24(args, "--key") || env[KEY_ENV[id]];
4463
4508
  if (!providerKey) {
4464
4509
  const resend = id === "resend" ? " Use a key with Full access (Resend \u2192 API Keys); a Sending access key cannot read your account." : "";
4465
4510
  return {
@@ -4469,15 +4514,15 @@ async function runMigrateCommand(provider, args, env = process.env) {
4469
4514
  }
4470
4515
  params = { provider: id, api_key: providerKey };
4471
4516
  if (id === "postmark") {
4472
- const accountToken = readFlag23(args, "--account-token") || env.POSTMARK_ACCOUNT_TOKEN;
4517
+ const accountToken = readFlag24(args, "--account-token") || env.POSTMARK_ACCOUNT_TOKEN;
4473
4518
  if (accountToken) params.account_api_key = accountToken;
4474
4519
  } else if (id === "sendgrid" || id === "mailgun") {
4475
- const region = readFlag23(args, "--region");
4520
+ const region = readFlag24(args, "--region");
4476
4521
  if (region === "us" || region === "eu") params.region = region;
4477
4522
  else if (region) return { exitCode: 1, error: "--region must be us or eu" };
4478
4523
  }
4479
4524
  }
4480
- const only = readFlag23(args, "--only");
4525
+ const only = readFlag24(args, "--only");
4481
4526
  if (only) {
4482
4527
  const list = only.split(",").map((s) => s.trim()).filter(Boolean);
4483
4528
  const bad = list.filter((r) => !RESOURCES.includes(r));
@@ -4489,7 +4534,7 @@ async function runMigrateCommand(provider, args, env = process.env) {
4489
4534
  if (args.includes("--dry-run")) params.dry_run = true;
4490
4535
  try {
4491
4536
  const { Groundmail } = await import("groundmail");
4492
- const baseUrl = readFlag23(args, "--base-url");
4537
+ const baseUrl = readFlag24(args, "--base-url");
4493
4538
  const client2 = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
4494
4539
  console.error(`${params.dry_run ? "Previewing" : "Importing"} from ${LABELS[id]}${params.provider === "ses" ? ` (${params.aws_region})` : ""} (Beta)\u2026`);
4495
4540
  const report = await client2.migrations.run(params, {
@@ -4533,17 +4578,17 @@ async function runValidateCommand(args, env = process.env) {
4533
4578
 
4534
4579
  // src/commands/dmarc/dmarc.ts
4535
4580
  var DMARC_APPLY_PROVIDERS = ["cloudflare", "vercel", "godaddy", "netlify", "digitalocean", "dnsimple"];
4536
- function readFlag24(args, flag) {
4581
+ function readFlag25(args, flag) {
4537
4582
  const index = args.indexOf(flag);
4538
4583
  if (index === -1) return void 0;
4539
4584
  return args[index + 1];
4540
4585
  }
4541
- var VALUE_FLAGS4 = ["--api-key", "--base-url", "--domain", "--apply"];
4586
+ var VALUE_FLAGS5 = ["--api-key", "--base-url", "--domain", "--apply"];
4542
4587
  function readFirstPositional15(args) {
4543
4588
  for (let i = 0; i < args.length; i += 1) {
4544
4589
  const arg = args[i];
4545
4590
  if (arg.startsWith("--")) {
4546
- if (VALUE_FLAGS4.includes(arg)) i += 1;
4591
+ if (VALUE_FLAGS5.includes(arg)) i += 1;
4547
4592
  continue;
4548
4593
  }
4549
4594
  return arg;
@@ -4590,23 +4635,23 @@ function formatDmarcStatus(dmarc) {
4590
4635
  return lines.join("\n");
4591
4636
  }
4592
4637
  async function runDmarcCommand(subcommand, args, env = process.env) {
4593
- const apiKey = readFlag24(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4638
+ const apiKey = readFlag25(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4594
4639
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Run groundmail login, set GROUNDMAIL_API_KEY or pass --api-key." };
4595
- const domain = readFlag24(args, "--domain") || readFirstPositional15(args);
4640
+ const domain = readFlag25(args, "--domain") || readFirstPositional15(args);
4596
4641
  if (!subcommand || !["status", "enable", "disable", "digest"].includes(subcommand)) {
4597
4642
  return { exitCode: 1, error: "Usage: groundmail dmarc status|enable|disable|digest <domain>" };
4598
4643
  }
4599
4644
  if (!domain) return { exitCode: 1, error: `Missing domain. Usage: groundmail dmarc ${subcommand} example.com` };
4600
4645
  const json = args.includes("--json");
4601
4646
  try {
4602
- const client2 = await createDmarcClient(apiKey, readFlag24(args, "--base-url"));
4647
+ const client2 = await createDmarcClient(apiKey, readFlag25(args, "--base-url"));
4603
4648
  if (subcommand === "status") {
4604
4649
  const result2 = await client2.dmarc.get(domain);
4605
4650
  console.log(json ? JSON.stringify(result2) : formatDmarcStatus(result2.dmarc));
4606
4651
  return { exitCode: 0 };
4607
4652
  }
4608
4653
  if (subcommand === "enable") {
4609
- const apply = readFlag24(args, "--apply");
4654
+ const apply = readFlag25(args, "--apply");
4610
4655
  if (apply && !DMARC_APPLY_PROVIDERS.includes(apply)) {
4611
4656
  return { exitCode: 1, error: `--apply must be one of: ${DMARC_APPLY_PROVIDERS.join(", ")}` };
4612
4657
  }
@@ -4636,7 +4681,7 @@ Updated the DMARC record with ${result2.applied.provider}.`);
4636
4681
  }
4637
4682
 
4638
4683
  // src/commands/test-inbox/test-inbox.ts
4639
- function readFlag25(args, flag) {
4684
+ function readFlag26(args, flag) {
4640
4685
  const index = args.indexOf(flag);
4641
4686
  if (index === -1) return void 0;
4642
4687
  return args[index + 1];
@@ -4664,20 +4709,20 @@ function formatTestEmail(email) {
4664
4709
  var USAGE = "Usage: groundmail test-inbox address [--prefix signup] | wait --to <address> [--timeout 30] [--since <iso>] [--json] | list [--to <address>] [--json]";
4665
4710
  async function runTestInboxCommand(subcommand, args, env = process.env) {
4666
4711
  if (!subcommand || !["address", "wait", "list"].includes(subcommand)) return { exitCode: 1, error: USAGE };
4667
- const apiKey = readFlag25(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4712
+ const apiKey = readFlag26(args, "--api-key") || env.GROUNDMAIL_API_KEY;
4668
4713
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Run groundmail login, set GROUNDMAIL_API_KEY or pass --api-key." };
4669
4714
  const json = args.includes("--json");
4670
4715
  try {
4671
- const client2 = await createTestInboxClient(apiKey, readFlag25(args, "--base-url"));
4716
+ const client2 = await createTestInboxClient(apiKey, readFlag26(args, "--base-url"));
4672
4717
  if (subcommand === "address") {
4673
- console.log(await client2.testInbox.address({ prefix: readFlag25(args, "--prefix") }));
4718
+ console.log(await client2.testInbox.address({ prefix: readFlag26(args, "--prefix") }));
4674
4719
  return { exitCode: 0 };
4675
4720
  }
4676
4721
  if (subcommand === "list") {
4677
4722
  const result = await client2.testInbox.list({
4678
- to: readFlag25(args, "--to"),
4679
- since: readFlag25(args, "--since"),
4680
- limit: readFlag25(args, "--limit") ? Number(readFlag25(args, "--limit")) : void 0
4723
+ to: readFlag26(args, "--to"),
4724
+ since: readFlag26(args, "--since"),
4725
+ limit: readFlag26(args, "--limit") ? Number(readFlag26(args, "--limit")) : void 0
4681
4726
  });
4682
4727
  if (json) console.log(JSON.stringify(result));
4683
4728
  else if (!result.emails.length) console.log("No test emails yet.");
@@ -4688,13 +4733,13 @@ async function runTestInboxCommand(subcommand, args, env = process.env) {
4688
4733
  }
4689
4734
  return { exitCode: 0 };
4690
4735
  }
4691
- const to = readFlag25(args, "--to");
4736
+ const to = readFlag26(args, "--to");
4692
4737
  if (!to) return { exitCode: 1, error: "Missing --to. Usage: groundmail test-inbox wait --to signup-k3m9x2pq@acme.test.groundmail.dev" };
4693
- const timeoutRaw = readFlag25(args, "--timeout");
4738
+ const timeoutRaw = readFlag26(args, "--timeout");
4694
4739
  const seconds = timeoutRaw === void 0 ? 30 : Number(timeoutRaw);
4695
4740
  if (!Number.isFinite(seconds) || seconds < 0) return { exitCode: 1, error: "--timeout must be a number of seconds" };
4696
4741
  try {
4697
- const email = await client2.testInbox.waitFor({ to, timeout: seconds * 1e3, since: readFlag25(args, "--since") });
4742
+ const email = await client2.testInbox.waitFor({ to, timeout: seconds * 1e3, since: readFlag26(args, "--since") });
4698
4743
  console.log(json ? JSON.stringify({ email }) : formatTestEmail(email));
4699
4744
  return { exitCode: 0 };
4700
4745
  } catch (error) {
@@ -4742,6 +4787,8 @@ var USAGE_LINES = [
4742
4787
  " groundmail emails insights [--window 7d|30d]",
4743
4788
  " groundmail emails get --id msg_\u2026 [--watch [--timeout 60] [--json]] --watch: follow an email you already sent until it lands",
4744
4789
  " groundmail emails cancel --id msg_\u2026",
4790
+ " groundmail batches get <batch_id> an emails batch's status counts (the batch_id `emails batch` returned)",
4791
+ " groundmail batches cancel <batch_id> cancel the batch's emails that are still scheduled; safe to repeat",
4745
4792
  " groundmail emails resend --id msg_\u2026",
4746
4793
  ` groundmail events send --name user.created --email user@example.com --data '{"name":"Ada"}'`,
4747
4794
  " groundmail automations list",
@@ -5182,6 +5229,10 @@ async function main() {
5182
5229
  if (subcommand === "get") await finish(await runGetCommand9(rest));
5183
5230
  if (subcommand === "set" || subcommand === "update") await finish(await runSetCommand(rest));
5184
5231
  }
5232
+ if (command === "batches") {
5233
+ if (subcommand === "get") await finish(await runGetCommand10(rest));
5234
+ if (subcommand === "cancel") await finish(await runCancelCommand2(rest));
5235
+ }
5185
5236
  if (command === "senders") {
5186
5237
  if (subcommand === "list") await finish(await runListCommand9(rest));
5187
5238
  if (subcommand === "create" || subcommand === "add") await finish(await runCreateCommand5(rest));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groundmail-cli",
3
- "version": "0.35.1",
3
+ "version": "0.36.0",
4
4
  "description": "Groundmail CLI — send transactional email from the terminal",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -38,7 +38,7 @@
38
38
  "prepublishOnly": "npm run build"
39
39
  },
40
40
  "dependencies": {
41
- "groundmail": "0.37.0"
41
+ "groundmail": "0.38.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "tsup": "^8.5.0",