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.
- package/README.md +2 -0
- package/dist/cli.js +81 -30
- 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.
|
|
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 =
|
|
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
|
|
4337
|
-
function
|
|
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 =
|
|
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 =
|
|
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("--") && !
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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,
|
|
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 =
|
|
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
|
|
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 =
|
|
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,
|
|
4716
|
+
const client2 = await createTestInboxClient(apiKey, readFlag26(args, "--base-url"));
|
|
4672
4717
|
if (subcommand === "address") {
|
|
4673
|
-
console.log(await client2.testInbox.address({ 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:
|
|
4679
|
-
since:
|
|
4680
|
-
limit:
|
|
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 =
|
|
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 =
|
|
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:
|
|
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.
|
|
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.
|
|
41
|
+
"groundmail": "0.38.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"tsup": "^8.5.0",
|