groundmail-cli 0.20.0 → 0.22.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 +18 -0
  2. package/dist/cli.js +540 -156
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -43,6 +43,7 @@ function parseSendCommandArgs(args) {
43
43
  scheduledAt: readFlag(args, "--schedule"),
44
44
  category,
45
45
  unsubscribe: args.includes("--unsubscribe") ? true : void 0,
46
+ tenant: readFlag(args, "--tenant"),
46
47
  apiKey: readFlag(args, "--api-key"),
47
48
  baseUrl: readFlag(args, "--base-url")
48
49
  };
@@ -66,7 +67,8 @@ async function runSendCommand(args, deps) {
66
67
  tags: options.tags,
67
68
  scheduledAt: options.scheduledAt,
68
69
  category: options.category,
69
- unsubscribe: options.unsubscribe
70
+ unsubscribe: options.unsubscribe,
71
+ ...options.tenant ? { tenant: options.tenant } : {}
70
72
  });
71
73
  stdout(JSON.stringify(result));
72
74
  if (result.test) {
@@ -104,6 +106,7 @@ function parseSendCommandOptions(args, env) {
104
106
  scheduledAt: parsed.scheduledAt,
105
107
  category: parsed.category,
106
108
  unsubscribe: parsed.unsubscribe,
109
+ tenant: parsed.tenant,
107
110
  apiKey,
108
111
  baseUrl: parsed.baseUrl
109
112
  };
@@ -138,7 +141,7 @@ function readFirstPositional(args) {
138
141
  for (let index = 0; index < args.length; index += 1) {
139
142
  const arg = args[index];
140
143
  if (arg.startsWith("--")) {
141
- if (arg === "--api-key" || arg === "--base-url" || arg === "--file") index += 1;
144
+ if (arg === "--api-key" || arg === "--base-url" || arg === "--file" || arg === "--tenant") index += 1;
142
145
  continue;
143
146
  }
144
147
  return arg;
@@ -167,7 +170,9 @@ async function runBatchCommand(args, deps) {
167
170
  stderr(payload.error);
168
171
  return { exitCode: 1, error: payload.error };
169
172
  }
170
- const result = await deps.sendBatch(payload.emails);
173
+ const tenant = readFlag2(args, "--tenant");
174
+ const emails = tenant ? payload.emails.map((email) => email.tenant ? email : { ...email, tenant }) : payload.emails;
175
+ const result = await deps.sendBatch(emails);
171
176
  stdout(JSON.stringify(result));
172
177
  return { exitCode: 0 };
173
178
  } catch (error) {
@@ -397,11 +402,13 @@ async function runListCommand(args, deps) {
397
402
  return { exitCode: 1, error: "conflicting flags" };
398
403
  }
399
404
  const test = args.includes("--test") ? true : args.includes("--live") ? false : void 0;
405
+ const tenant = readFlag7(args, "--tenant");
400
406
  try {
401
407
  const result = await deps.listEmails({
402
408
  ...limit != null && Number.isFinite(limit) ? { limit } : {},
403
409
  ...cursor ? { cursor } : {},
404
- ...test !== void 0 ? { test } : {}
410
+ ...test !== void 0 ? { test } : {},
411
+ ...tenant ? { tenant } : {}
405
412
  });
406
413
  stdout(JSON.stringify(result));
407
414
  return { exitCode: 0 };
@@ -708,7 +715,8 @@ function parseDomainsCommonArgs(args) {
708
715
  apiKey: readFlag10(args, "--api-key"),
709
716
  baseUrl: readFlag10(args, "--base-url"),
710
717
  name: readFlag10(args, "--name") || readFlag10(args, "--domain"),
711
- id: readFlag10(args, "--id")
718
+ id: readFlag10(args, "--id"),
719
+ tenant: readFlag10(args, "--tenant")
712
720
  };
713
721
  }
714
722
  function resolveApiKey3(options, env) {
@@ -741,7 +749,7 @@ async function runAddCommand(args, env = process.env) {
741
749
  if (!apiKey) {
742
750
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
743
751
  }
744
- const name = options.name || args.find((arg) => !arg.startsWith("--") && arg.includes("."));
752
+ const name = options.name || args.find((arg, i) => !arg.startsWith("--") && arg.includes(".") && args[i - 1] !== "--tenant");
745
753
  if (!name) {
746
754
  return {
747
755
  exitCode: 1,
@@ -753,11 +761,14 @@ async function runAddCommand(args, env = process.env) {
753
761
  const inbound = readFlag10(args, "--inbound");
754
762
  const result = await client2.domains.create({
755
763
  name,
756
- ...inbound === "true" || inbound === "1" ? { inbound_enabled: true } : {}
764
+ ...inbound === "true" || inbound === "1" ? { inbound_enabled: true } : {},
765
+ ...options.tenant ? { tenant: options.tenant } : {}
757
766
  });
758
767
  console.log(JSON.stringify(result));
759
768
  console.error("");
760
- console.error(`Domain ${result.domain.name} added (${result.domain.status}).`);
769
+ console.error(
770
+ `Domain ${result.domain.name} added (${result.domain.status})${options.tenant ? ` for tenant ${options.tenant}` : ""}.`
771
+ );
761
772
  console.error(formatDnsRecords(result.records));
762
773
  console.error("");
763
774
  console.error(`Then: groundmail domains verify ${result.domain.name}`);
@@ -892,7 +903,7 @@ async function runListCommand3(args, env = process.env) {
892
903
  }
893
904
  try {
894
905
  const client2 = await createDomainsClient(apiKey, options.baseUrl);
895
- const result = await client2.domains.list();
906
+ const result = await client2.domains.list(options.tenant ? { tenant: options.tenant } : {});
896
907
  console.log(JSON.stringify(result));
897
908
  return { exitCode: 0 };
898
909
  } catch (error) {
@@ -1075,13 +1086,46 @@ async function runListCommand4(args, env = process.env) {
1075
1086
  }
1076
1087
  }
1077
1088
 
1078
- // src/commands/webhooks/shared.ts
1089
+ // src/commands/tenants/shared.ts
1090
+ var TENANT_VALUE_FLAGS = [
1091
+ "--api-key",
1092
+ "--base-url",
1093
+ "--tenant",
1094
+ "--id",
1095
+ "--external-id",
1096
+ "--name",
1097
+ "--default-from-domain",
1098
+ "--stream-policy",
1099
+ "--daily-limit",
1100
+ "--metadata",
1101
+ "--status",
1102
+ "--reason",
1103
+ "--limit",
1104
+ "--cursor",
1105
+ "--days",
1106
+ "--domain"
1107
+ ];
1079
1108
  function readFlag12(args, flag) {
1080
1109
  const index = args.indexOf(flag);
1081
1110
  if (index === -1) return void 0;
1082
1111
  return args[index + 1];
1083
1112
  }
1084
- function parseWebhooksCommonArgs(args) {
1113
+ function hasFlag(args, flag) {
1114
+ return args.includes(flag);
1115
+ }
1116
+ function positionals(args, valueFlags = TENANT_VALUE_FLAGS) {
1117
+ const out = [];
1118
+ for (let i = 0; i < args.length; i += 1) {
1119
+ const arg = args[i];
1120
+ if (arg.startsWith("--")) {
1121
+ if (valueFlags.includes(arg)) i += 1;
1122
+ continue;
1123
+ }
1124
+ out.push(arg);
1125
+ }
1126
+ return out;
1127
+ }
1128
+ function parseTenantsCommonArgs(args) {
1085
1129
  return {
1086
1130
  apiKey: readFlag12(args, "--api-key"),
1087
1131
  baseUrl: readFlag12(args, "--base-url")
@@ -1090,6 +1134,82 @@ function parseWebhooksCommonArgs(args) {
1090
1134
  function resolveApiKey5(options, env) {
1091
1135
  return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1092
1136
  }
1137
+ async function createTenantsClient(apiKey, baseUrl) {
1138
+ const { Groundmail } = await import("groundmail");
1139
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1140
+ }
1141
+ var MISSING_KEY = "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.";
1142
+ function failure(error) {
1143
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1144
+ }
1145
+ function parseDailyLimit(value) {
1146
+ if (value === void 0) return {};
1147
+ if (value === "none" || value === "null") return { value: null };
1148
+ const n2 = Number(value);
1149
+ if (!Number.isInteger(n2) || n2 < 0) return { error: "--daily-limit must be a whole number, or none" };
1150
+ return { value: n2 };
1151
+ }
1152
+ function parseMetadata(value) {
1153
+ if (value === void 0) return {};
1154
+ if (value === "null") return { value: null };
1155
+ try {
1156
+ const parsed = JSON.parse(value);
1157
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1158
+ return { error: "--metadata must be a JSON object" };
1159
+ }
1160
+ return { value: parsed };
1161
+ } catch {
1162
+ return { error: "--metadata must be valid JSON" };
1163
+ }
1164
+ }
1165
+ function parseStreamPolicy(value) {
1166
+ if (value === void 0) return {};
1167
+ if (value === "all" || value === "transactional_only") return { value };
1168
+ return { error: "--stream-policy must be all or transactional_only" };
1169
+ }
1170
+ function parseTenantSettings(args) {
1171
+ const dailyLimit = parseDailyLimit(readFlag12(args, "--daily-limit"));
1172
+ if ("error" in dailyLimit) return dailyLimit;
1173
+ const metadata = parseMetadata(readFlag12(args, "--metadata"));
1174
+ if ("error" in metadata) return metadata;
1175
+ const streamPolicy = parseStreamPolicy(readFlag12(args, "--stream-policy"));
1176
+ if ("error" in streamPolicy) return streamPolicy;
1177
+ const name = readFlag12(args, "--name");
1178
+ const fromDomain = readFlag12(args, "--default-from-domain");
1179
+ return {
1180
+ value: {
1181
+ ...name !== void 0 ? { name } : {},
1182
+ ...fromDomain !== void 0 ? { default_from_domain: fromDomain === "none" ? null : fromDomain } : {},
1183
+ ...streamPolicy.value !== void 0 ? { stream_policy: streamPolicy.value } : {},
1184
+ ..."value" in dailyLimit ? { daily_limit: dailyLimit.value } : {},
1185
+ ..."value" in metadata ? { metadata: metadata.value } : {}
1186
+ }
1187
+ };
1188
+ }
1189
+ function tenantRef(args) {
1190
+ return readFlag12(args, "--tenant") || readFlag12(args, "--id") || positionals(args)[0];
1191
+ }
1192
+ function parseTenantsList(value) {
1193
+ if (value === void 0) return void 0;
1194
+ if (value === "all" || value === "none" || value === "") return null;
1195
+ return value.split(/[\s,]+/).map((v) => v.trim()).filter(Boolean);
1196
+ }
1197
+
1198
+ // src/commands/webhooks/shared.ts
1199
+ function readFlag13(args, flag) {
1200
+ const index = args.indexOf(flag);
1201
+ if (index === -1) return void 0;
1202
+ return args[index + 1];
1203
+ }
1204
+ function parseWebhooksCommonArgs(args) {
1205
+ return {
1206
+ apiKey: readFlag13(args, "--api-key"),
1207
+ baseUrl: readFlag13(args, "--base-url")
1208
+ };
1209
+ }
1210
+ function resolveApiKey6(options, env) {
1211
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1212
+ }
1093
1213
  async function createWebhooksClient(apiKey, baseUrl) {
1094
1214
  const { Groundmail } = await import("groundmail");
1095
1215
  return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
@@ -1098,17 +1218,18 @@ async function createWebhooksClient(apiKey, baseUrl) {
1098
1218
  // src/commands/webhooks/create.ts
1099
1219
  async function runCreateCommand2(args, env = process.env) {
1100
1220
  const options = parseWebhooksCommonArgs(args);
1101
- const apiKey = resolveApiKey5(options, env);
1221
+ const apiKey = resolveApiKey6(options, env);
1102
1222
  if (!apiKey) {
1103
1223
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1104
1224
  }
1105
- const url = readFlag12(args, "--url");
1225
+ const url = readFlag13(args, "--url");
1106
1226
  if (!url) {
1107
1227
  return { exitCode: 1, error: "Required flag: --url" };
1108
1228
  }
1109
1229
  try {
1110
1230
  const client2 = await createWebhooksClient(apiKey, options.baseUrl);
1111
- const result = await client2.webhooks.create({ url });
1231
+ const tenants = parseTenantsList(readFlag13(args, "--tenants"));
1232
+ const result = await client2.webhooks.create({ url, ...tenants?.length ? { tenants } : {} });
1112
1233
  console.log(JSON.stringify(result));
1113
1234
  return { exitCode: 0 };
1114
1235
  } catch (error) {
@@ -1120,9 +1241,9 @@ async function runCreateCommand2(args, env = process.env) {
1120
1241
  var POSITIONAL_FLAGS5 = ["--api-key", "--base-url", "--id"];
1121
1242
  async function runGetCommand5(args, env = process.env) {
1122
1243
  const options = parseWebhooksCommonArgs(args);
1123
- const apiKey = resolveApiKey5(options, env);
1244
+ const apiKey = resolveApiKey6(options, env);
1124
1245
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1125
- const id = readFlag13(args, "--id") || readFirstPositional6(args);
1246
+ const id = readFlag14(args, "--id") || readFirstPositional6(args);
1126
1247
  if (!id) return { exitCode: 1, error: "Missing webhook id. Pass --id wh_\u2026" };
1127
1248
  try {
1128
1249
  const client2 = await createWebhooksClient(apiKey, options.baseUrl);
@@ -1132,7 +1253,7 @@ async function runGetCommand5(args, env = process.env) {
1132
1253
  return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1133
1254
  }
1134
1255
  }
1135
- function readFlag13(args, flag) {
1256
+ function readFlag14(args, flag) {
1136
1257
  const index = args.indexOf(flag);
1137
1258
  return index === -1 ? void 0 : args[index + 1];
1138
1259
  }
@@ -1151,11 +1272,11 @@ function readFirstPositional6(args) {
1151
1272
  // src/commands/webhooks/delete.ts
1152
1273
  async function runDeleteCommand3(args, env = process.env) {
1153
1274
  const options = parseWebhooksCommonArgs(args);
1154
- const apiKey = resolveApiKey5(options, env);
1275
+ const apiKey = resolveApiKey6(options, env);
1155
1276
  if (!apiKey) {
1156
1277
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1157
1278
  }
1158
- const id = readFlag12(args, "--id");
1279
+ const id = readFlag13(args, "--id");
1159
1280
  if (!id) {
1160
1281
  return { exitCode: 1, error: "Required flag: --id" };
1161
1282
  }
@@ -1172,7 +1293,7 @@ async function runDeleteCommand3(args, env = process.env) {
1172
1293
  // src/commands/webhooks/list.ts
1173
1294
  async function runListCommand5(args, env = process.env) {
1174
1295
  const options = parseWebhooksCommonArgs(args);
1175
- const apiKey = resolveApiKey5(options, env);
1296
+ const apiKey = resolveApiKey6(options, env);
1176
1297
  if (!apiKey) {
1177
1298
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1178
1299
  }
@@ -1187,24 +1308,26 @@ async function runListCommand5(args, env = process.env) {
1187
1308
  }
1188
1309
 
1189
1310
  // src/commands/webhooks/update.ts
1190
- var POSITIONAL_FLAGS6 = ["--api-key", "--base-url", "--id", "--url", "--event", "--enabled"];
1311
+ var POSITIONAL_FLAGS6 = ["--api-key", "--base-url", "--id", "--url", "--event", "--enabled", "--tenants"];
1191
1312
  async function runUpdateCommand3(args, env = process.env) {
1192
1313
  const options = parseWebhooksCommonArgs(args);
1193
- const apiKey = resolveApiKey5(options, env);
1314
+ const apiKey = resolveApiKey6(options, env);
1194
1315
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1195
- const id = readFlag14(args, "--id") || readFirstPositional7(args);
1316
+ const id = readFlag15(args, "--id") || readFirstPositional7(args);
1196
1317
  if (!id) return { exitCode: 1, error: "Missing webhook id. Pass --id wh_\u2026" };
1197
- const url = readFlag14(args, "--url");
1318
+ const url = readFlag15(args, "--url");
1198
1319
  const events = readFlags2(args, "--event");
1199
- const enabled = parseEnabledFlag(readFlag14(args, "--enabled"));
1320
+ const enabled = parseEnabledFlag(readFlag15(args, "--enabled"));
1200
1321
  if ("error" in enabled) return { exitCode: 1, error: enabled.error };
1201
- if (!url && events.length === 0 && enabled.value === void 0) {
1202
- return { exitCode: 1, error: "Nothing to update. Pass --url, --event, or --enabled true|false." };
1322
+ const tenants = parseTenantsList(readFlag15(args, "--tenants"));
1323
+ if (!url && events.length === 0 && enabled.value === void 0 && tenants === void 0) {
1324
+ return { exitCode: 1, error: "Nothing to update. Pass --url, --event, --enabled true|false, or --tenants." };
1203
1325
  }
1204
1326
  const payload = {
1205
1327
  ...url ? { url } : {},
1206
1328
  ...events.length > 0 ? { events } : {},
1207
- ...enabled.value !== void 0 ? { enabled: enabled.value } : {}
1329
+ ...enabled.value !== void 0 ? { enabled: enabled.value } : {},
1330
+ ...tenants !== void 0 ? { tenants } : {}
1208
1331
  };
1209
1332
  try {
1210
1333
  const client2 = await createWebhooksClient(apiKey, options.baseUrl);
@@ -1214,7 +1337,7 @@ async function runUpdateCommand3(args, env = process.env) {
1214
1337
  return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1215
1338
  }
1216
1339
  }
1217
- function readFlag14(args, flag) {
1340
+ function readFlag15(args, flag) {
1218
1341
  const index = args.indexOf(flag);
1219
1342
  return index === -1 ? void 0 : args[index + 1];
1220
1343
  }
@@ -1244,22 +1367,22 @@ function parseEnabledFlag(value) {
1244
1367
  }
1245
1368
 
1246
1369
  // src/commands/keys/list.ts
1247
- function readFlag15(args, flag) {
1370
+ function readFlag16(args, flag) {
1248
1371
  const index = args.indexOf(flag);
1249
1372
  if (index === -1) return void 0;
1250
1373
  return args[index + 1];
1251
1374
  }
1252
1375
  async function runListKeysCommandWithClient(args, env = process.env) {
1253
- const apiKey = readFlag15(args, "--api-key") || env.GROUNDMAIL_API_KEY;
1254
- const baseUrl = readFlag15(args, "--base-url");
1376
+ const apiKey = readFlag16(args, "--api-key") || env.GROUNDMAIL_API_KEY;
1377
+ const baseUrl = readFlag16(args, "--base-url");
1255
1378
  if (!apiKey) {
1256
1379
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1257
1380
  }
1258
1381
  const { Groundmail } = await import("groundmail");
1259
1382
  const client2 = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1260
1383
  try {
1261
- const limitRaw = readFlag15(args, "--limit");
1262
- const cursor = readFlag15(args, "--cursor");
1384
+ const limitRaw = readFlag16(args, "--limit");
1385
+ const cursor = readFlag16(args, "--cursor");
1263
1386
  const result = await client2.apiKeys.list({
1264
1387
  ...limitRaw ? { limit: Number(limitRaw) } : {},
1265
1388
  ...cursor ? { cursor } : {}
@@ -1297,7 +1420,7 @@ function trimUrl(value) {
1297
1420
  }
1298
1421
 
1299
1422
  // package.json
1300
- var version = "0.20.0";
1423
+ var version = "0.22.0";
1301
1424
 
1302
1425
  // src/user-agent.ts
1303
1426
  function buildUserAgent(own) {
@@ -1381,15 +1504,15 @@ function parseArgs(argv, spec) {
1381
1504
  const booleanFlags = new Set(spec.booleans ?? []);
1382
1505
  const values = {};
1383
1506
  const booleans = {};
1384
- const positionals = [];
1507
+ const positionals2 = [];
1385
1508
  for (let i = 0; i < argv.length; i++) {
1386
1509
  const arg = argv[i];
1387
1510
  if (arg === "--") {
1388
- positionals.push(...argv.slice(i + 1));
1511
+ positionals2.push(...argv.slice(i + 1));
1389
1512
  break;
1390
1513
  }
1391
1514
  if (!arg.startsWith("--") || arg === "-") {
1392
- positionals.push(arg);
1515
+ positionals2.push(arg);
1393
1516
  continue;
1394
1517
  }
1395
1518
  const eq = arg.indexOf("=");
@@ -1415,7 +1538,7 @@ function parseArgs(argv, spec) {
1415
1538
  const known = [...valueFlags, ...booleanFlags].sort().join(", ");
1416
1539
  return { ok: false, error: `Unknown flag ${name}.${known ? ` This command takes: ${known}.` : ""}` };
1417
1540
  }
1418
- return { ok: true, args: { values, booleans, positionals } };
1541
+ return { ok: true, args: { values, booleans, positionals: positionals2 } };
1419
1542
  }
1420
1543
  function wantsJson(args, stdout = process.stdout) {
1421
1544
  if (args.booleans["--json"] !== void 0) return args.booleans["--json"];
@@ -1723,10 +1846,10 @@ async function resolveAuth(flags, env = process.env, config = loadConfig(env)) {
1723
1846
  return fromSaved(current.workspace);
1724
1847
  }
1725
1848
  async function applySavedSession(argv, env = process.env, config) {
1726
- const hasFlag = (flag) => argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
1849
+ const hasFlag2 = (flag) => argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
1727
1850
  let workspace = null;
1728
1851
  let notice;
1729
- if (!hasFlag("--api-key") && !envApiKey(env)) {
1852
+ if (!hasFlag2("--api-key") && !envApiKey(env)) {
1730
1853
  const current = currentSavedWorkspace(config ?? loadConfig(env), env);
1731
1854
  if (current.ok) {
1732
1855
  workspace = current.workspace;
@@ -1737,7 +1860,7 @@ async function applySavedSession(argv, env = process.env, config) {
1737
1860
  notice = current.error;
1738
1861
  }
1739
1862
  }
1740
- if (hasFlag("--base-url")) return { argv, notice };
1863
+ if (hasFlag2("--base-url")) return { argv, notice };
1741
1864
  const url = explicitApiUrl(env) || trimUrl(workspace?.apiUrl) || trimUrl(env.GROUNDMAIL_DEFAULT_API_URL);
1742
1865
  return { argv: url ? [...argv, "--base-url", url] : argv, notice };
1743
1866
  }
@@ -2134,28 +2257,29 @@ Usage: ${brand.bin} whoami [--workspace <name>] [--json]` };
2134
2257
  }
2135
2258
 
2136
2259
  // src/commands/keys/create.ts
2137
- function readFlag16(args, flag) {
2260
+ function readFlag17(args, flag) {
2138
2261
  const index = args.indexOf(flag);
2139
2262
  if (index === -1) return void 0;
2140
2263
  return args[index + 1];
2141
2264
  }
2142
2265
  async function runCreateKeyCommandWithClient(args, env = process.env) {
2143
- const apiKey = readFlag16(args, "--api-key") || env.GROUNDMAIL_API_KEY;
2144
- const baseUrl = readFlag16(args, "--base-url") || defaultApiUrl(env);
2266
+ const apiKey = readFlag17(args, "--api-key") || env.GROUNDMAIL_API_KEY;
2267
+ const baseUrl = readFlag17(args, "--base-url") || defaultApiUrl(env);
2145
2268
  if (!apiKey) {
2146
2269
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2147
2270
  }
2148
- const name = readFlag16(args, "--name");
2149
- const scope = readFlag16(args, "--scope");
2271
+ const name = readFlag17(args, "--name");
2272
+ const scope = readFlag17(args, "--scope");
2150
2273
  if (scope && scope !== "full" && scope !== "sending") {
2151
2274
  return { exitCode: 1, error: "--scope must be full or sending (or use --scopes for fine-grained scopes)" };
2152
2275
  }
2153
- const scopesFlag = readFlag16(args, "--scopes");
2276
+ const scopesFlag = readFlag17(args, "--scopes");
2154
2277
  const scopes = scopesFlag !== void 0 ? parseScopeFlag(scopesFlag) : null;
2155
2278
  if (scopes && !scopes.ok) return { exitCode: 1, error: scopes.error };
2156
- const domainsFlag = readFlag16(args, "--allowed-domains");
2279
+ const domainsFlag = readFlag17(args, "--allowed-domains");
2157
2280
  const allowedDomains = domainsFlag?.split(/[\s,]+/).map((domain) => domain.trim()).filter(Boolean);
2158
2281
  const test = args.includes("--test");
2282
+ const tenant = readFlag17(args, "--tenant");
2159
2283
  try {
2160
2284
  const response = await apiRequest(baseUrl, "/api-keys", {
2161
2285
  apiKey,
@@ -2165,7 +2289,8 @@ async function runCreateKeyCommandWithClient(args, env = process.env) {
2165
2289
  ...scope && !scopes ? { scope } : {},
2166
2290
  ...scopes?.ok ? { scopes: scopes.scope.split(" ") } : {},
2167
2291
  ...allowedDomains?.length ? { allowed_domains: allowedDomains } : {},
2168
- ...test ? { test: true } : {}
2292
+ ...test ? { test: true } : {},
2293
+ ...tenant ? { tenant } : {}
2169
2294
  }
2170
2295
  });
2171
2296
  if (!response.ok) {
@@ -2182,15 +2307,15 @@ async function runCreateKeyCommandWithClient(args, env = process.env) {
2182
2307
  }
2183
2308
 
2184
2309
  // src/commands/keys/delete.ts
2185
- function readFlag17(args, flag) {
2310
+ function readFlag18(args, flag) {
2186
2311
  const index = args.indexOf(flag);
2187
2312
  if (index === -1) return void 0;
2188
2313
  return args[index + 1];
2189
2314
  }
2190
2315
  async function runDeleteKeyCommandWithClient(args, env = process.env) {
2191
- const apiKey = readFlag17(args, "--api-key") || env.GROUNDMAIL_API_KEY;
2192
- const baseUrl = readFlag17(args, "--base-url");
2193
- const id = readFlag17(args, "--id");
2316
+ const apiKey = readFlag18(args, "--api-key") || env.GROUNDMAIL_API_KEY;
2317
+ const baseUrl = readFlag18(args, "--base-url");
2318
+ const id = readFlag18(args, "--id");
2194
2319
  if (!apiKey) {
2195
2320
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2196
2321
  }
@@ -2211,18 +2336,18 @@ async function runDeleteKeyCommandWithClient(args, env = process.env) {
2211
2336
  }
2212
2337
 
2213
2338
  // src/commands/suppressions/shared.ts
2214
- function readFlag18(args, flag) {
2339
+ function readFlag19(args, flag) {
2215
2340
  const index = args.indexOf(flag);
2216
2341
  if (index === -1) return void 0;
2217
2342
  return args[index + 1];
2218
2343
  }
2219
2344
  function parseSuppressionsCommonArgs(args) {
2220
2345
  return {
2221
- apiKey: readFlag18(args, "--api-key"),
2222
- baseUrl: readFlag18(args, "--base-url")
2346
+ apiKey: readFlag19(args, "--api-key"),
2347
+ baseUrl: readFlag19(args, "--base-url")
2223
2348
  };
2224
2349
  }
2225
- function resolveApiKey6(options, env) {
2350
+ function resolveApiKey7(options, env) {
2226
2351
  return options.apiKey || env.GROUNDMAIL_API_KEY || null;
2227
2352
  }
2228
2353
  async function createSuppressionsClient(apiKey, baseUrl) {
@@ -2233,19 +2358,21 @@ async function createSuppressionsClient(apiKey, baseUrl) {
2233
2358
  // src/commands/suppressions/list.ts
2234
2359
  async function runListCommand6(args, env = process.env) {
2235
2360
  const options = parseSuppressionsCommonArgs(args);
2236
- const apiKey = resolveApiKey6(options, env);
2361
+ const apiKey = resolveApiKey7(options, env);
2237
2362
  if (!apiKey) {
2238
2363
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2239
2364
  }
2240
2365
  try {
2241
2366
  const client2 = await createSuppressionsClient(apiKey, options.baseUrl);
2242
- const limitRaw = readFlag18(args, "--limit");
2243
- const cursor = readFlag18(args, "--cursor");
2244
- const email = readFlag18(args, "--email");
2367
+ const limitRaw = readFlag19(args, "--limit");
2368
+ const cursor = readFlag19(args, "--cursor");
2369
+ const email = readFlag19(args, "--email");
2370
+ const tenant = readFlag19(args, "--tenant");
2245
2371
  const result = await client2.suppressions.list({
2246
2372
  ...limitRaw ? { limit: Number(limitRaw) } : {},
2247
2373
  ...cursor ? { cursor } : {},
2248
- ...email ? { email } : {}
2374
+ ...email ? { email } : {},
2375
+ ...tenant ? { tenant } : {}
2249
2376
  });
2250
2377
  console.log(JSON.stringify(result));
2251
2378
  return { exitCode: 0 };
@@ -2257,20 +2384,22 @@ async function runListCommand6(args, env = process.env) {
2257
2384
  // src/commands/suppressions/add.ts
2258
2385
  async function runAddCommand2(args, env = process.env) {
2259
2386
  const options = parseSuppressionsCommonArgs(args);
2260
- const apiKey = resolveApiKey6(options, env);
2387
+ const apiKey = resolveApiKey7(options, env);
2261
2388
  if (!apiKey) {
2262
2389
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2263
2390
  }
2264
- const email = readFlag18(args, "--email") || args.find((a) => a.includes("@") && !a.startsWith("-"));
2391
+ const tenant = readFlag19(args, "--tenant");
2392
+ const email = readFlag19(args, "--email") || args.find((a, i) => a.includes("@") && !a.startsWith("-") && args[i - 1] !== "--tenant");
2265
2393
  if (!email) {
2266
2394
  return { exitCode: 1, error: "Missing email. Pass --email user@example.com" };
2267
2395
  }
2268
2396
  try {
2269
2397
  const client2 = await createSuppressionsClient(apiKey, options.baseUrl);
2270
- const reason = readFlag18(args, "--reason");
2398
+ const reason = readFlag19(args, "--reason");
2271
2399
  const result = await client2.suppressions.create({
2272
2400
  email,
2273
- ...reason ? { reason } : {}
2401
+ ...reason ? { reason } : {},
2402
+ ...tenant ? { tenant } : {}
2274
2403
  });
2275
2404
  console.log(JSON.stringify(result));
2276
2405
  return { exitCode: 0 };
@@ -2282,17 +2411,20 @@ async function runAddCommand2(args, env = process.env) {
2282
2411
  // src/commands/suppressions/remove.ts
2283
2412
  async function runRemoveCommand(args, env = process.env) {
2284
2413
  const options = parseSuppressionsCommonArgs(args);
2285
- const apiKey = resolveApiKey6(options, env);
2414
+ const apiKey = resolveApiKey7(options, env);
2286
2415
  if (!apiKey) {
2287
2416
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2288
2417
  }
2289
- const idOrEmail = readFlag18(args, "--id") || readFlag18(args, "--email") || args.find((a) => !a.startsWith("-") && a !== "remove" && a !== "delete");
2418
+ const tenant = readFlag19(args, "--tenant");
2419
+ const idOrEmail = readFlag19(args, "--id") || readFlag19(args, "--email") || args.find(
2420
+ (a, i) => !a.startsWith("-") && a !== "remove" && a !== "delete" && !["--tenant", "--api-key", "--base-url"].includes(args[i - 1] ?? "")
2421
+ );
2290
2422
  if (!idOrEmail) {
2291
2423
  return { exitCode: 1, error: "Missing id or email. Pass --id <uuid> or --email user@example.com" };
2292
2424
  }
2293
2425
  try {
2294
2426
  const client2 = await createSuppressionsClient(apiKey, options.baseUrl);
2295
- const result = await client2.suppressions.remove(idOrEmail);
2427
+ const result = tenant ? await client2.suppressions.remove(idOrEmail, { tenant }) : await client2.suppressions.remove(idOrEmail);
2296
2428
  console.log(JSON.stringify(result));
2297
2429
  return { exitCode: 0 };
2298
2430
  } catch (error) {
@@ -2301,18 +2433,18 @@ async function runRemoveCommand(args, env = process.env) {
2301
2433
  }
2302
2434
 
2303
2435
  // src/commands/templates/shared.ts
2304
- function readFlag19(args, flag) {
2436
+ function readFlag20(args, flag) {
2305
2437
  const index = args.indexOf(flag);
2306
2438
  if (index === -1) return void 0;
2307
2439
  return args[index + 1];
2308
2440
  }
2309
2441
  function parseTemplatesCommonArgs(args) {
2310
2442
  return {
2311
- apiKey: readFlag19(args, "--api-key"),
2312
- baseUrl: readFlag19(args, "--base-url")
2443
+ apiKey: readFlag20(args, "--api-key"),
2444
+ baseUrl: readFlag20(args, "--base-url")
2313
2445
  };
2314
2446
  }
2315
- function resolveApiKey7(options, env) {
2447
+ function resolveApiKey8(options, env) {
2316
2448
  return options.apiKey || env.GROUNDMAIL_API_KEY || null;
2317
2449
  }
2318
2450
  async function createTemplatesClient(apiKey, baseUrl) {
@@ -2324,9 +2456,9 @@ async function createTemplatesClient(apiKey, baseUrl) {
2324
2456
  var POSITIONAL_FLAGS7 = ["--api-key", "--base-url", "--id", "--alias"];
2325
2457
  async function runDeleteCommand4(args, env = process.env) {
2326
2458
  const options = parseTemplatesCommonArgs(args);
2327
- const apiKey = resolveApiKey7(options, env);
2459
+ const apiKey = resolveApiKey8(options, env);
2328
2460
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2329
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional8(args);
2461
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional8(args);
2330
2462
  if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2331
2463
  try {
2332
2464
  const client2 = await createTemplatesClient(apiKey, options.baseUrl);
@@ -2352,11 +2484,11 @@ function readFirstPositional8(args) {
2352
2484
  var POSITIONAL_FLAGS8 = ["--api-key", "--base-url", "--id", "--alias", "--name"];
2353
2485
  async function runDuplicateCommand(args, env = process.env) {
2354
2486
  const options = parseTemplatesCommonArgs(args);
2355
- const apiKey = resolveApiKey7(options, env);
2487
+ const apiKey = resolveApiKey8(options, env);
2356
2488
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2357
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional9(args);
2489
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional9(args);
2358
2490
  if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2359
- const name = readFlag19(args, "--name");
2491
+ const name = readFlag20(args, "--name");
2360
2492
  try {
2361
2493
  const client2 = await createTemplatesClient(apiKey, options.baseUrl);
2362
2494
  console.log(JSON.stringify(await client2.templates.duplicate(idOrAlias, name ? { name } : {})));
@@ -2381,9 +2513,9 @@ function readFirstPositional9(args) {
2381
2513
  var POSITIONAL_FLAGS9 = ["--api-key", "--base-url", "--id", "--alias"];
2382
2514
  async function runGetCommand6(args, env = process.env) {
2383
2515
  const options = parseTemplatesCommonArgs(args);
2384
- const apiKey = resolveApiKey7(options, env);
2516
+ const apiKey = resolveApiKey8(options, env);
2385
2517
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2386
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional10(args);
2518
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional10(args);
2387
2519
  if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2388
2520
  try {
2389
2521
  const client2 = await createTemplatesClient(apiKey, options.baseUrl);
@@ -2408,15 +2540,15 @@ function readFirstPositional10(args) {
2408
2540
  // src/commands/templates/list.ts
2409
2541
  async function runListCommand7(args, env = process.env) {
2410
2542
  const options = parseTemplatesCommonArgs(args);
2411
- const apiKey = resolveApiKey7(options, env);
2543
+ const apiKey = resolveApiKey8(options, env);
2412
2544
  if (!apiKey) {
2413
2545
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2414
2546
  }
2415
2547
  try {
2416
2548
  const client2 = await createTemplatesClient(apiKey, options.baseUrl);
2417
- const limitRaw = readFlag19(args, "--limit");
2418
- const cursor = readFlag19(args, "--cursor");
2419
- const status = readFlag19(args, "--status");
2549
+ const limitRaw = readFlag20(args, "--limit");
2550
+ const cursor = readFlag20(args, "--cursor");
2551
+ const status = readFlag20(args, "--status");
2420
2552
  const result = await client2.templates.list({
2421
2553
  ...limitRaw ? { limit: Number(limitRaw) } : {},
2422
2554
  ...cursor ? { cursor } : {},
@@ -2433,9 +2565,9 @@ async function runListCommand7(args, env = process.env) {
2433
2565
  var POSITIONAL_FLAGS10 = ["--api-key", "--base-url", "--id", "--alias"];
2434
2566
  async function runPublishCommand(args, env = process.env) {
2435
2567
  const options = parseTemplatesCommonArgs(args);
2436
- const apiKey = resolveApiKey7(options, env);
2568
+ const apiKey = resolveApiKey8(options, env);
2437
2569
  if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2438
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional11(args);
2570
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional11(args);
2439
2571
  if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2440
2572
  try {
2441
2573
  const client2 = await createTemplatesClient(apiKey, options.baseUrl);
@@ -2574,23 +2706,23 @@ function statusOf(error) {
2574
2706
  }
2575
2707
  async function runPushCommand(args, env = process.env, deps = {}) {
2576
2708
  const options = parseTemplatesCommonArgs(args);
2577
- const apiKey = resolveApiKey7(options, env);
2709
+ const apiKey = resolveApiKey8(options, env);
2578
2710
  if (!apiKey) {
2579
2711
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2580
2712
  }
2581
- const file = readFlag19(args, "--file") ?? readPositional(args);
2713
+ const file = readFlag20(args, "--file") ?? readPositional(args);
2582
2714
  if (!file) {
2583
2715
  return { exitCode: 1, error: "Missing template file. Usage: templates push <file> --alias <alias>" };
2584
2716
  }
2585
- const alias = readFlag19(args, "--alias");
2717
+ const alias = readFlag20(args, "--alias");
2586
2718
  if (!alias) {
2587
2719
  return { exitCode: 1, error: "Missing --alias. The alias identifies which template to update." };
2588
2720
  }
2589
- const subject = readFlag19(args, "--subject");
2590
- const name = readFlag19(args, "--name");
2591
- const preheader = readFlag19(args, "--preheader");
2592
- const textFile = readFlag19(args, "--text");
2593
- const propsRaw = readFlag19(args, "--props");
2721
+ const subject = readFlag20(args, "--subject");
2722
+ const name = readFlag20(args, "--name");
2723
+ const preheader = readFlag20(args, "--preheader");
2724
+ const textFile = readFlag20(args, "--text");
2725
+ const propsRaw = readFlag20(args, "--props");
2594
2726
  const shouldPublish = args.includes("--publish");
2595
2727
  let props = {};
2596
2728
  if (propsRaw) {
@@ -2660,16 +2792,16 @@ async function runPushCommand(args, env = process.env, deps = {}) {
2660
2792
  // src/commands/templates/create.ts
2661
2793
  async function runCreateCommand3(args, env = process.env) {
2662
2794
  const options = parseTemplatesCommonArgs(args);
2663
- const apiKey = resolveApiKey7(options, env);
2795
+ const apiKey = resolveApiKey8(options, env);
2664
2796
  if (!apiKey) {
2665
2797
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2666
2798
  }
2667
- const name = readFlag19(args, "--name");
2668
- const subject = readFlag19(args, "--subject");
2669
- const html = readFlag19(args, "--html");
2670
- const text = readFlag19(args, "--text");
2671
- const alias = readFlag19(args, "--alias");
2672
- const category = readFlag19(args, "--category");
2799
+ const name = readFlag20(args, "--name");
2800
+ const subject = readFlag20(args, "--subject");
2801
+ const html = readFlag20(args, "--html");
2802
+ const text = readFlag20(args, "--text");
2803
+ const alias = readFlag20(args, "--alias");
2804
+ const category = readFlag20(args, "--category");
2673
2805
  const unsubscribeEnabled = args.includes("--unsubscribe-enabled");
2674
2806
  if (!name) {
2675
2807
  return { exitCode: 1, error: 'Missing name. Pass --name "Welcome"' };
@@ -2713,21 +2845,21 @@ var POSITIONAL_FLAGS11 = [
2713
2845
  ];
2714
2846
  async function runUpdateCommand4(args, env = process.env) {
2715
2847
  const options = parseTemplatesCommonArgs(args);
2716
- const apiKey = resolveApiKey7(options, env);
2848
+ const apiKey = resolveApiKey8(options, env);
2717
2849
  if (!apiKey) {
2718
2850
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2719
2851
  }
2720
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional12(args);
2852
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional12(args);
2721
2853
  if (!idOrAlias) {
2722
2854
  return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2723
2855
  }
2724
- const name = readFlag19(args, "--name");
2725
- const subject = readFlag19(args, "--subject");
2726
- const html = readFlag19(args, "--html");
2727
- const text = readFlag19(args, "--text");
2728
- const alias = readFlag19(args, "--set-alias");
2856
+ const name = readFlag20(args, "--name");
2857
+ const subject = readFlag20(args, "--subject");
2858
+ const html = readFlag20(args, "--html");
2859
+ const text = readFlag20(args, "--text");
2860
+ const alias = readFlag20(args, "--set-alias");
2729
2861
  const variables = readFlags3(args, "--variable");
2730
- const category = readFlag19(args, "--category");
2862
+ const category = readFlag20(args, "--category");
2731
2863
  const unsubscribeEnabled = args.includes("--unsubscribe-enabled");
2732
2864
  const unsubscribeDisabled = args.includes("--no-unsubscribe-enabled");
2733
2865
  if (!name && !subject && !html && !text && !alias && variables.length === 0 && !category && !unsubscribeEnabled && !unsubscribeDisabled) {
@@ -2789,11 +2921,11 @@ function readFirstPositional13(args) {
2789
2921
  }
2790
2922
  async function runFromStarterCommand(args, env = process.env) {
2791
2923
  const options = parseTemplatesCommonArgs(args);
2792
- const apiKey = resolveApiKey7(options, env);
2924
+ const apiKey = resolveApiKey8(options, env);
2793
2925
  if (!apiKey) {
2794
2926
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2795
2927
  }
2796
- const alias = readFlag19(args, "--alias") || readFirstPositional13(args);
2928
+ const alias = readFlag20(args, "--alias") || readFirstPositional13(args);
2797
2929
  if (!alias) {
2798
2930
  return {
2799
2931
  exitCode: 1,
@@ -2810,7 +2942,7 @@ async function runFromStarterCommand(args, env = process.env) {
2810
2942
  }
2811
2943
  async function runListStartersCommand(args, env = process.env) {
2812
2944
  const options = parseTemplatesCommonArgs(args);
2813
- const apiKey = resolveApiKey7(options, env);
2945
+ const apiKey = resolveApiKey8(options, env);
2814
2946
  if (!apiKey) {
2815
2947
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2816
2948
  }
@@ -2838,11 +2970,11 @@ function readFirstPositional14(args) {
2838
2970
  }
2839
2971
  async function runVersionsCommand(args, env = process.env) {
2840
2972
  const options = parseTemplatesCommonArgs(args);
2841
- const apiKey = resolveApiKey7(options, env);
2973
+ const apiKey = resolveApiKey8(options, env);
2842
2974
  if (!apiKey) {
2843
2975
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2844
2976
  }
2845
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
2977
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional14(args);
2846
2978
  if (!idOrAlias) {
2847
2979
  return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
2848
2980
  }
@@ -2856,12 +2988,12 @@ async function runVersionsCommand(args, env = process.env) {
2856
2988
  }
2857
2989
  async function runRestoreCommand(args, env = process.env) {
2858
2990
  const options = parseTemplatesCommonArgs(args);
2859
- const apiKey = resolveApiKey7(options, env);
2991
+ const apiKey = resolveApiKey8(options, env);
2860
2992
  if (!apiKey) {
2861
2993
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2862
2994
  }
2863
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
2864
- const versionRaw = readFlag19(args, "--version");
2995
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional14(args);
2996
+ const versionRaw = readFlag20(args, "--version");
2865
2997
  const version2 = versionRaw ? Number.parseInt(versionRaw, 10) : NaN;
2866
2998
  if (!idOrAlias || !Number.isFinite(version2) || version2 < 1) {
2867
2999
  return {
@@ -2879,13 +3011,13 @@ async function runRestoreCommand(args, env = process.env) {
2879
3011
  }
2880
3012
  async function runTestSendCommand(args, env = process.env) {
2881
3013
  const options = parseTemplatesCommonArgs(args);
2882
- const apiKey = resolveApiKey7(options, env);
3014
+ const apiKey = resolveApiKey8(options, env);
2883
3015
  if (!apiKey) {
2884
3016
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2885
3017
  }
2886
- const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
2887
- const from = readFlag19(args, "--from");
2888
- const to = readFlag19(args, "--to");
3018
+ const idOrAlias = readFlag20(args, "--id") || readFlag20(args, "--alias") || readFirstPositional14(args);
3019
+ const from = readFlag20(args, "--from");
3020
+ const to = readFlag20(args, "--to");
2889
3021
  if (!idOrAlias || !from || !to) {
2890
3022
  return {
2891
3023
  exitCode: 1,
@@ -2902,18 +3034,18 @@ async function runTestSendCommand(args, env = process.env) {
2902
3034
  }
2903
3035
 
2904
3036
  // src/commands/integrations/shared.ts
2905
- function readFlag20(args, flag) {
3037
+ function readFlag21(args, flag) {
2906
3038
  const index = args.indexOf(flag);
2907
3039
  if (index === -1) return void 0;
2908
3040
  return args[index + 1];
2909
3041
  }
2910
3042
  function parseIntegrationsCommonArgs(args) {
2911
3043
  return {
2912
- apiKey: readFlag20(args, "--api-key"),
2913
- baseUrl: readFlag20(args, "--base-url")
3044
+ apiKey: readFlag21(args, "--api-key"),
3045
+ baseUrl: readFlag21(args, "--base-url")
2914
3046
  };
2915
3047
  }
2916
- function resolveApiKey8(options, env) {
3048
+ function resolveApiKey9(options, env) {
2917
3049
  return options.apiKey || env.GROUNDMAIL_API_KEY || null;
2918
3050
  }
2919
3051
  async function createIntegrationsClient(apiKey, baseUrl) {
@@ -2924,7 +3056,7 @@ async function createIntegrationsClient(apiKey, baseUrl) {
2924
3056
  // src/commands/integrations/twilio.ts
2925
3057
  async function runTwilioStatusCommand(args, env = process.env) {
2926
3058
  const options = parseIntegrationsCommonArgs(args);
2927
- const apiKey = resolveApiKey8(options, env);
3059
+ const apiKey = resolveApiKey9(options, env);
2928
3060
  if (!apiKey) {
2929
3061
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2930
3062
  }
@@ -2939,14 +3071,14 @@ async function runTwilioStatusCommand(args, env = process.env) {
2939
3071
  }
2940
3072
  async function runTwilioConnectCommand(args, env = process.env) {
2941
3073
  const options = parseIntegrationsCommonArgs(args);
2942
- const apiKey = resolveApiKey8(options, env);
3074
+ const apiKey = resolveApiKey9(options, env);
2943
3075
  if (!apiKey) {
2944
3076
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2945
3077
  }
2946
- const accountSid = readFlag20(args, "--account-sid") || env.TWILIO_ACCOUNT_SID || env.TWILIO_SID || "";
2947
- const authToken = readFlag20(args, "--auth-token") || env.TWILIO_AUTH_TOKEN || env.TWILIO_TOKEN || "";
2948
- const defaultFrom = readFlag20(args, "--from") || readFlag20(args, "--default-from") || env.TWILIO_DEFAULT_FROM || "";
2949
- const messagingServiceSid = readFlag20(args, "--messaging-service-sid") || readFlag20(args, "--messaging-sid") || env.TWILIO_MESSAGING_SERVICE_SID || "";
3078
+ const accountSid = readFlag21(args, "--account-sid") || env.TWILIO_ACCOUNT_SID || env.TWILIO_SID || "";
3079
+ const authToken = readFlag21(args, "--auth-token") || env.TWILIO_AUTH_TOKEN || env.TWILIO_TOKEN || "";
3080
+ const defaultFrom = readFlag21(args, "--from") || readFlag21(args, "--default-from") || env.TWILIO_DEFAULT_FROM || "";
3081
+ const messagingServiceSid = readFlag21(args, "--messaging-service-sid") || readFlag21(args, "--messaging-sid") || env.TWILIO_MESSAGING_SERVICE_SID || "";
2950
3082
  if (!accountSid.trim() || !authToken.trim()) {
2951
3083
  return {
2952
3084
  exitCode: 1,
@@ -2975,7 +3107,7 @@ async function runTwilioConnectCommand(args, env = process.env) {
2975
3107
  }
2976
3108
  async function runTwilioDisconnectCommand(args, env = process.env) {
2977
3109
  const options = parseIntegrationsCommonArgs(args);
2978
- const apiKey = resolveApiKey8(options, env);
3110
+ const apiKey = resolveApiKey9(options, env);
2979
3111
  if (!apiKey) {
2980
3112
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2981
3113
  }
@@ -2989,6 +3121,125 @@ async function runTwilioDisconnectCommand(args, env = process.env) {
2989
3121
  }
2990
3122
  }
2991
3123
 
3124
+ // src/commands/tenants/commands.ts
3125
+ async function withClient(args, env, run) {
3126
+ const options = parseTenantsCommonArgs(args);
3127
+ const apiKey = resolveApiKey5(options, env);
3128
+ if (!apiKey) return { exitCode: 1, error: MISSING_KEY };
3129
+ try {
3130
+ const client2 = await createTenantsClient(apiKey, options.baseUrl);
3131
+ console.log(JSON.stringify(await run(client2)));
3132
+ return { exitCode: 0 };
3133
+ } catch (error) {
3134
+ return failure(error);
3135
+ }
3136
+ }
3137
+ function missingTenant(usage) {
3138
+ return { exitCode: 1, error: `Missing tenant. Usage: ${usage}` };
3139
+ }
3140
+ async function runListCommand8(args, env = process.env) {
3141
+ const status = readFlag12(args, "--status");
3142
+ if (status !== void 0 && status !== "active" && status !== "paused") {
3143
+ return { exitCode: 1, error: "--status must be active or paused" };
3144
+ }
3145
+ const limitRaw = readFlag12(args, "--limit");
3146
+ const cursor = readFlag12(args, "--cursor");
3147
+ return withClient(
3148
+ args,
3149
+ env,
3150
+ (client2) => client2.tenants.list({
3151
+ ...limitRaw ? { limit: Number(limitRaw) } : {},
3152
+ ...cursor ? { cursor } : {},
3153
+ ...status ? { status } : {}
3154
+ })
3155
+ );
3156
+ }
3157
+ async function runCreateCommand4(args, env = process.env) {
3158
+ const externalId = readFlag12(args, "--external-id") || positionals(args)[0];
3159
+ if (!externalId) {
3160
+ return { exitCode: 1, error: "Missing external id. Usage: groundmail tenants create <external-id> [--name \u2026]" };
3161
+ }
3162
+ const settings = parseTenantSettings(args);
3163
+ if ("error" in settings) return { exitCode: 1, error: settings.error };
3164
+ return withClient(args, env, (client2) => client2.tenants.create({ external_id: externalId, ...settings.value }));
3165
+ }
3166
+ async function runGetCommand7(args, env = process.env) {
3167
+ const tenant = tenantRef(args);
3168
+ if (!tenant) return missingTenant("groundmail tenants get <tenant>");
3169
+ return withClient(args, env, (client2) => client2.tenants.get(tenant));
3170
+ }
3171
+ async function runUpdateCommand5(args, env = process.env) {
3172
+ const tenant = tenantRef(args);
3173
+ if (!tenant) return missingTenant("groundmail tenants update <tenant> [--name \u2026] [--daily-limit N|none]");
3174
+ const settings = parseTenantSettings(args);
3175
+ if ("error" in settings) return { exitCode: 1, error: settings.error };
3176
+ if (Object.keys(settings.value).length === 0) {
3177
+ return {
3178
+ exitCode: 1,
3179
+ error: "Nothing to update. Pass --name, --default-from-domain, --stream-policy, --daily-limit or --metadata (or use tenants pause / resume)."
3180
+ };
3181
+ }
3182
+ return withClient(args, env, (client2) => client2.tenants.update(tenant, settings.value));
3183
+ }
3184
+ async function runPauseCommand2(args, env = process.env) {
3185
+ const tenant = tenantRef(args);
3186
+ if (!tenant) return missingTenant("groundmail tenants pause <tenant> [--reason \u2026]");
3187
+ const reason = readFlag12(args, "--reason");
3188
+ return withClient(args, env, (client2) => client2.tenants.pause(tenant, reason));
3189
+ }
3190
+ async function runResumeCommand(args, env = process.env) {
3191
+ const tenant = tenantRef(args);
3192
+ if (!tenant) return missingTenant("groundmail tenants resume <tenant>");
3193
+ return withClient(args, env, (client2) => client2.tenants.resume(tenant));
3194
+ }
3195
+ async function runDeleteCommand5(args, env = process.env) {
3196
+ const tenant = tenantRef(args);
3197
+ if (!tenant) return missingTenant("groundmail tenants delete <tenant> --yes");
3198
+ if (!hasFlag(args, "--yes")) {
3199
+ return {
3200
+ exitCode: 1,
3201
+ error: `This deletes tenant ${tenant} and its suppression list; its domains go back to the account and keys limited to it stop working. Run again with --yes to confirm.`
3202
+ };
3203
+ }
3204
+ return withClient(args, env, (client2) => client2.tenants.delete(tenant));
3205
+ }
3206
+ async function runStatsCommand(args, env = process.env) {
3207
+ const tenant = tenantRef(args);
3208
+ if (!tenant) return missingTenant("groundmail tenants stats <tenant> [--days 7]");
3209
+ const daysRaw = readFlag12(args, "--days");
3210
+ const days = daysRaw !== void 0 ? Number(daysRaw) : void 0;
3211
+ if (days !== void 0 && (!Number.isInteger(days) || days < 1 || days > 90)) {
3212
+ return { exitCode: 1, error: "--days must be a whole number from 1 to 90" };
3213
+ }
3214
+ return withClient(args, env, (client2) => client2.tenants.stats(tenant, days !== void 0 ? { days } : {}));
3215
+ }
3216
+ async function runDomainsCommand(args, env = process.env) {
3217
+ const [action, ...rest] = args;
3218
+ const pos = positionals(rest);
3219
+ const tenant = readFlag12(rest, "--tenant") || readFlag12(rest, "--id") || pos.shift();
3220
+ const domain = readFlag12(rest, "--domain") || pos.shift();
3221
+ if (action === "list") {
3222
+ if (!tenant) return missingTenant("groundmail tenants domains list <tenant>");
3223
+ return withClient(rest, env, (client2) => client2.tenants.domains.list(tenant));
3224
+ }
3225
+ if (action === "add" || action === "assign") {
3226
+ if (!tenant || !domain) {
3227
+ return { exitCode: 1, error: "Usage: groundmail tenants domains add <tenant> <domain>" };
3228
+ }
3229
+ return withClient(rest, env, (client2) => client2.tenants.domains.assign(tenant, domain));
3230
+ }
3231
+ if (action === "remove" || action === "unassign" || action === "delete") {
3232
+ if (!tenant || !domain) {
3233
+ return { exitCode: 1, error: "Usage: groundmail tenants domains remove <tenant> <domain>" };
3234
+ }
3235
+ return withClient(rest, env, (client2) => client2.tenants.domains.unassign(tenant, domain));
3236
+ }
3237
+ return {
3238
+ exitCode: 1,
3239
+ error: "Usage: groundmail tenants domains list|add|remove <tenant> [<domain>]"
3240
+ };
3241
+ }
3242
+
2992
3243
  // src/commands/auth.ts
2993
3244
  async function runAuthCommand(subcommand, argv, deps = {}) {
2994
3245
  const env = deps.env ?? process.env;
@@ -3135,7 +3386,7 @@ var KEY_ENV = {
3135
3386
  };
3136
3387
  var LABELS = { sendgrid: "SendGrid", postmark: "Postmark", mailgun: "Mailgun" };
3137
3388
  var VALUE_FLAGS2 = /* @__PURE__ */ new Set(["--api-key", "--base-url"]);
3138
- function readFlag21(args, flag) {
3389
+ function readFlag22(args, flag) {
3139
3390
  const index = args.indexOf(flag);
3140
3391
  if (index === -1) return void 0;
3141
3392
  return args[index + 1];
@@ -3204,10 +3455,10 @@ function formatMigrationSummary(m) {
3204
3455
  return lines.join("\n");
3205
3456
  }
3206
3457
  async function client(args, env) {
3207
- const apiKey = readFlag21(args, "--api-key") || env.GROUNDMAIL_API_KEY;
3458
+ const apiKey = readFlag22(args, "--api-key") || env.GROUNDMAIL_API_KEY;
3208
3459
  if (!apiKey) return null;
3209
3460
  const { Groundmail } = await import("groundmail");
3210
- const baseUrl = readFlag21(args, "--base-url");
3461
+ const baseUrl = readFlag22(args, "--base-url");
3211
3462
  return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
3212
3463
  }
3213
3464
  async function runStoredCommand(sub, args, env) {
@@ -3244,11 +3495,11 @@ async function runMigrateCommand(provider, args, env = process.env) {
3244
3495
  };
3245
3496
  }
3246
3497
  const id = provider;
3247
- const apiKey = readFlag21(args, "--api-key") || env.GROUNDMAIL_API_KEY;
3498
+ const apiKey = readFlag22(args, "--api-key") || env.GROUNDMAIL_API_KEY;
3248
3499
  if (!apiKey) {
3249
3500
  return { exitCode: 1, error: "Not signed in. Run `groundmail login`, or set GROUNDMAIL_API_KEY." };
3250
3501
  }
3251
- const providerKey = readFlag21(args, "--key") || env[KEY_ENV[id]];
3502
+ const providerKey = readFlag22(args, "--key") || env[KEY_ENV[id]];
3252
3503
  if (!providerKey) {
3253
3504
  return {
3254
3505
  exitCode: 1,
@@ -3257,14 +3508,14 @@ async function runMigrateCommand(provider, args, env = process.env) {
3257
3508
  }
3258
3509
  const params = { provider: id, api_key: providerKey };
3259
3510
  if (id === "postmark") {
3260
- const accountToken = readFlag21(args, "--account-token") || env.POSTMARK_ACCOUNT_TOKEN;
3511
+ const accountToken = readFlag22(args, "--account-token") || env.POSTMARK_ACCOUNT_TOKEN;
3261
3512
  if (accountToken) params.account_api_key = accountToken;
3262
3513
  } else {
3263
- const region = readFlag21(args, "--region");
3514
+ const region = readFlag22(args, "--region");
3264
3515
  if (region === "us" || region === "eu") params.region = region;
3265
3516
  else if (region) return { exitCode: 1, error: "--region must be us or eu" };
3266
3517
  }
3267
- const only = readFlag21(args, "--only");
3518
+ const only = readFlag22(args, "--only");
3268
3519
  if (only) {
3269
3520
  const list = only.split(",").map((s) => s.trim()).filter(Boolean);
3270
3521
  const bad = list.filter((r) => !RESOURCES.includes(r));
@@ -3276,7 +3527,7 @@ async function runMigrateCommand(provider, args, env = process.env) {
3276
3527
  if (args.includes("--dry-run")) params.dry_run = true;
3277
3528
  try {
3278
3529
  const { Groundmail } = await import("groundmail");
3279
- const baseUrl = readFlag21(args, "--base-url");
3530
+ const baseUrl = readFlag22(args, "--base-url");
3280
3531
  const client2 = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
3281
3532
  console.error(`${params.dry_run ? "Previewing" : "Importing"} from ${LABELS[id]} (Beta)\u2026`);
3282
3533
  const report = await client2.migrations.run(params, {
@@ -3299,12 +3550,12 @@ async function runMigrateCommand(provider, args, env = process.env) {
3299
3550
  // src/commands/validate.ts
3300
3551
  async function runValidateCommand(args, env = process.env) {
3301
3552
  const options = parseSuppressionsCommonArgs(args);
3302
- const apiKey = resolveApiKey6(options, env);
3553
+ const apiKey = resolveApiKey7(options, env);
3303
3554
  if (!apiKey) {
3304
3555
  return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY, pass --api-key, or run `groundmail login`." };
3305
3556
  }
3306
3557
  const flagValues = new Set([options.apiKey, options.baseUrl].filter(Boolean));
3307
- const email = readFlag18(args, "--email") || args.find((arg) => arg.includes("@") && !arg.startsWith("-") && !flagValues.has(arg));
3558
+ const email = readFlag19(args, "--email") || args.find((arg) => arg.includes("@") && !arg.startsWith("-") && !flagValues.has(arg));
3308
3559
  if (!email) {
3309
3560
  return { exitCode: 1, error: "Missing email. Usage: groundmail validate user@example.com" };
3310
3561
  }
@@ -3318,6 +3569,109 @@ async function runValidateCommand(args, env = process.env) {
3318
3569
  }
3319
3570
  }
3320
3571
 
3572
+ // src/commands/dmarc/dmarc.ts
3573
+ function readFlag23(args, flag) {
3574
+ const index = args.indexOf(flag);
3575
+ if (index === -1) return void 0;
3576
+ return args[index + 1];
3577
+ }
3578
+ var VALUE_FLAGS3 = ["--api-key", "--base-url", "--domain", "--apply"];
3579
+ function readFirstPositional15(args) {
3580
+ for (let i = 0; i < args.length; i += 1) {
3581
+ const arg = args[i];
3582
+ if (arg.startsWith("--")) {
3583
+ if (VALUE_FLAGS3.includes(arg)) i += 1;
3584
+ continue;
3585
+ }
3586
+ return arg;
3587
+ }
3588
+ return void 0;
3589
+ }
3590
+ async function createDmarcClient(apiKey, baseUrl) {
3591
+ const { Groundmail } = await import("groundmail");
3592
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
3593
+ }
3594
+ function pct(rate) {
3595
+ const value = rate * 100;
3596
+ return value === 100 ? "100%" : `${value.toFixed(1).replace(/\.0$/, "")}%`;
3597
+ }
3598
+ function formatDmarcStatus(dmarc) {
3599
+ if (!dmarc.enabled) {
3600
+ return [
3601
+ `DMARC monitoring for ${dmarc.domain}: off`,
3602
+ ` Current record (${dmarc.dns.host}): ${dmarc.dns.record ?? "none"}`,
3603
+ "",
3604
+ `Turn it on: groundmail dmarc enable ${dmarc.domain}`
3605
+ ].join("\n");
3606
+ }
3607
+ const lines = [
3608
+ `DMARC monitoring for ${dmarc.domain}: ${dmarc.status === "waiting" ? "waiting for the first report" : "receiving reports"}`,
3609
+ ` Report address: ${dmarc.report_address}`
3610
+ ];
3611
+ if (!dmarc.dns.rua_present) {
3612
+ lines.push("", ` Add the address to your DMARC record. TXT ${dmarc.dns.host}:`, ` ${dmarc.dns.suggested_record}`);
3613
+ }
3614
+ lines.push(
3615
+ "",
3616
+ ` Last ${dmarc.window_days} days: ${dmarc.summary.messages.toLocaleString("en-US")} messages, ${pct(dmarc.summary.pass_rate)} passed DMARC, ${dmarc.summary.reports} reports`,
3617
+ ` Readiness: ${dmarc.readiness.label}. ${dmarc.readiness.detail}`
3618
+ );
3619
+ if (dmarc.sources.length) {
3620
+ lines.push("", " Sources:");
3621
+ for (const source of dmarc.sources.slice(0, 15)) {
3622
+ lines.push(
3623
+ ` ${source.name.padEnd(26)} ${source.status.padEnd(8)} ${String(source.messages).padStart(9)} msgs ${pct(source.pass_rate).padStart(6)} pass`
3624
+ );
3625
+ }
3626
+ }
3627
+ return lines.join("\n");
3628
+ }
3629
+ async function runDmarcCommand(subcommand, args, env = process.env) {
3630
+ const apiKey = readFlag23(args, "--api-key") || env.GROUNDMAIL_API_KEY;
3631
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Run groundmail login, set GROUNDMAIL_API_KEY or pass --api-key." };
3632
+ const domain = readFlag23(args, "--domain") || readFirstPositional15(args);
3633
+ if (!subcommand || !["status", "enable", "disable", "digest"].includes(subcommand)) {
3634
+ return { exitCode: 1, error: "Usage: groundmail dmarc status|enable|disable|digest <domain>" };
3635
+ }
3636
+ if (!domain) return { exitCode: 1, error: `Missing domain. Usage: groundmail dmarc ${subcommand} example.com` };
3637
+ const json = args.includes("--json");
3638
+ try {
3639
+ const client2 = await createDmarcClient(apiKey, readFlag23(args, "--base-url"));
3640
+ if (subcommand === "status") {
3641
+ const result2 = await client2.dmarc.get(domain);
3642
+ console.log(json ? JSON.stringify(result2) : formatDmarcStatus(result2.dmarc));
3643
+ return { exitCode: 0 };
3644
+ }
3645
+ if (subcommand === "enable") {
3646
+ const apply = readFlag23(args, "--apply");
3647
+ if (apply && apply !== "cloudflare" && apply !== "vercel" && apply !== "godaddy") {
3648
+ return { exitCode: 1, error: "--apply must be cloudflare, vercel or godaddy" };
3649
+ }
3650
+ const result2 = await client2.dmarc.enable(domain, apply ? { apply } : {});
3651
+ if (json) console.log(JSON.stringify(result2));
3652
+ else {
3653
+ console.log(formatDmarcStatus(result2.dmarc));
3654
+ if (result2.applied) console.log(`
3655
+ Updated the DMARC record with ${result2.applied.provider}.`);
3656
+ }
3657
+ if (result2.apply_error) return { exitCode: 1, error: result2.apply_error };
3658
+ return { exitCode: 0 };
3659
+ }
3660
+ if (subcommand === "disable") {
3661
+ const result2 = await client2.dmarc.disable(domain);
3662
+ console.log(json ? JSON.stringify(result2) : `DMARC monitoring for ${domain} is off. Remove the report address from your DMARC record's rua= tag too.`);
3663
+ return { exitCode: 0 };
3664
+ }
3665
+ const value = args.includes("--off") ? false : args.includes("--on") ? true : void 0;
3666
+ if (value === void 0) return { exitCode: 1, error: "Usage: groundmail dmarc digest example.com --on|--off" };
3667
+ const result = await client2.dmarc.update(domain, { digest_enabled: value });
3668
+ console.log(json ? JSON.stringify(result) : `Weekly DMARC digest for ${domain} is ${value ? "on" : "off"}.`);
3669
+ return { exitCode: 0 };
3670
+ } catch (error) {
3671
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
3672
+ }
3673
+ }
3674
+
3321
3675
  // src/help.ts
3322
3676
  var USAGE_LINES = [
3323
3677
  " groundmail login [--scope <scopes>] [--workspace <name>] sign in through the browser (OAuth; no key to copy)",
@@ -3326,20 +3680,24 @@ var USAGE_LINES = [
3326
3680
  " groundmail auth token [--scope <scopes>] print a short-lived access token (for agents and scripts)",
3327
3681
  " groundmail workspaces list",
3328
3682
  " groundmail workspaces use <name|id>",
3329
- " groundmail domains add example.com",
3683
+ " groundmail domains add example.com [--tenant <tenant>]",
3330
3684
  " groundmail domains apply example.com --provider cloudflare",
3331
3685
  " groundmail domains apply example.com --provider vercel",
3332
3686
  " groundmail domains apply example.com --provider godaddy",
3333
- " groundmail domains list",
3687
+ " groundmail domains list [--tenant <tenant>]",
3334
3688
  " groundmail domains get example.com",
3335
3689
  " groundmail domains update example.com --inbound true",
3336
3690
  " groundmail domains verify example.com",
3337
3691
  " groundmail domains delete example.com",
3692
+ " groundmail dmarc status example.com [--json] DMARC monitoring: sources, pass rates, readiness",
3693
+ " groundmail dmarc enable example.com [--apply cloudflare|vercel|godaddy] report address and the record to publish",
3694
+ " groundmail dmarc digest example.com --on|--off weekly digest email",
3695
+ " groundmail dmarc disable example.com",
3338
3696
  " groundmail received-emails list [--domain inbound.example.com]",
3339
3697
  " groundmail received-emails get inb_...",
3340
- ' groundmail emails send --from you@domain.com --to user@example.com --subject "Hello" --html "<p>Hi</p>" [--category transactional|product] [--unsubscribe]',
3341
- " groundmail emails batch --file ./emails.json",
3342
- " groundmail emails list [--limit 25] [--cursor \u2026] [--test | --live]",
3698
+ ' groundmail emails send --from you@domain.com --to user@example.com --subject "Hello" --html "<p>Hi</p>" [--category transactional|product] [--unsubscribe] [--tenant <tenant>]',
3699
+ " groundmail emails batch --file ./emails.json [--tenant <tenant>]",
3700
+ " groundmail emails list [--limit 25] [--cursor \u2026] [--test | --live] [--tenant <tenant>]",
3343
3701
  " groundmail emails insights [--window 7d|30d]",
3344
3702
  " groundmail emails get --id msg_\u2026",
3345
3703
  " groundmail emails cancel --id msg_\u2026",
@@ -3355,14 +3713,14 @@ var USAGE_LINES = [
3355
3713
  " groundmail automations pause --id <automation-id>",
3356
3714
  " groundmail automations delete --id <automation-id>",
3357
3715
  " groundmail webhooks list",
3358
- " groundmail webhooks create --url https://yourapp.com/hooks",
3716
+ " groundmail webhooks create --url https://yourapp.com/hooks [--tenants a,b] --tenants: only these tenants' email events",
3359
3717
  " groundmail webhooks get --id wh_\u2026",
3360
- " groundmail webhooks update --id wh_\u2026 [--url \u2026] [--event email.sent] [--enabled true|false]",
3718
+ " groundmail webhooks update --id wh_\u2026 [--url \u2026] [--event email.sent] [--enabled true|false] [--tenants a,b|all]",
3361
3719
  " groundmail webhooks delete --id <webhook-id>",
3362
3720
  " groundmail validate user@example.com Groundmail validation: verdict, reasons, typo suggestion (exit 2 when invalid)",
3363
- " groundmail suppressions list",
3364
- " groundmail suppressions add --email user@example.com [--reason \u2026]",
3365
- " groundmail suppressions remove --id <id> | --email user@example.com",
3721
+ " groundmail suppressions list [--tenant <tenant>]",
3722
+ " groundmail suppressions add --email user@example.com [--reason \u2026] [--tenant <tenant>]",
3723
+ " groundmail suppressions remove --id <id> | --email user@example.com [--tenant <tenant>]",
3366
3724
  " groundmail templates list [--status draft|published]",
3367
3725
  " groundmail templates starters",
3368
3726
  " groundmail templates from-starter password-reset",
@@ -3376,8 +3734,19 @@ var USAGE_LINES = [
3376
3734
  " groundmail templates test-send --id tpl_\u2026 --from you@domain.com --to you@domain.com",
3377
3735
  ' groundmail templates duplicate --id tpl_\u2026 [--name "Copy"]',
3378
3736
  " groundmail templates delete --id tpl_\u2026",
3737
+ " groundmail tenants list [--status active|paused] [--limit 25] [--cursor \u2026] your customers, each with its own domains, suppressions and limits",
3738
+ ` groundmail tenants create <external-id> [--name \u2026] [--default-from-domain \u2026] [--stream-policy all|transactional_only] [--daily-limit N] [--metadata '{"plan":"pro"}']`,
3739
+ " groundmail tenants get <tenant>",
3740
+ " groundmail tenants update <tenant> [--name \u2026] [--default-from-domain \u2026|none] [--stream-policy \u2026] [--daily-limit N|none] [--metadata JSON|null]",
3741
+ " groundmail tenants pause <tenant> [--reason \u2026] stops the tenant's new sends",
3742
+ " groundmail tenants resume <tenant>",
3743
+ " groundmail tenants delete <tenant> --yes",
3744
+ " groundmail tenants stats <tenant> [--days 7]",
3745
+ " groundmail tenants domains list <tenant>",
3746
+ " groundmail tenants domains add <tenant> example.com only this tenant can then send from it",
3747
+ " groundmail tenants domains remove <tenant> example.com gives the domain back to the account",
3379
3748
  " groundmail keys list",
3380
- " groundmail keys create [--name Default] [--scopes emails:send,domains:read] [--allowed-domains example.com] [--test] --test: a gm_test_ key, sends are simulated",
3749
+ " groundmail keys create [--name Default] [--scopes emails:send,domains:read] [--allowed-domains example.com] [--test] [--tenant <tenant>] --test: a gm_test_ key, sends are simulated; --tenant: a key limited to one tenant",
3381
3750
  " groundmail keys delete --id <api-key-id>",
3382
3751
  " groundmail migrate sendgrid [--dry-run] [--only templates,suppressions,domains,webhooks] [--region eu] import from SendGrid (Beta)",
3383
3752
  " groundmail migrate postmark [--dry-run] [--only \u2026] import from Postmark (Beta)",
@@ -3401,6 +3770,8 @@ var FOOTER_LINES = [
3401
3770
  "Scopes: full, emails:send, emails:read, domains:read, domains:write, webhooks:write, templates:write,",
3402
3771
  " suppressions:write, account:read",
3403
3772
  "",
3773
+ "<tenant>: the tenant's external id (your id for that customer) or its Groundmail id.",
3774
+ "",
3404
3775
  "Add --help to any command for just its usage. --version prints the CLI version."
3405
3776
  ];
3406
3777
  var CLI_VERSION = version;
@@ -3410,7 +3781,8 @@ var ALIASES = {
3410
3781
  events: { trigger: "send" },
3411
3782
  automations: { add: "create", remove: "delete" },
3412
3783
  suppressions: { create: "add", delete: "remove" },
3413
- templates: { add: "create", remove: "delete" }
3784
+ templates: { add: "create", remove: "delete" },
3785
+ tenants: { add: "create", remove: "delete" }
3414
3786
  };
3415
3787
  function words(line) {
3416
3788
  return line.trim().split(/\s+/);
@@ -3474,6 +3846,7 @@ async function main() {
3474
3846
  const rest = session.argv;
3475
3847
  if (command === "migrate") await finish(await runMigrateCommand(subcommand, rest));
3476
3848
  if (command === "validate") await finish(await runValidateCommand([...subcommand ? [subcommand] : [], ...rest]));
3849
+ if (command === "dmarc") await finish(await runDmarcCommand(subcommand, rest));
3477
3850
  if (command === "domains") {
3478
3851
  if (subcommand === "add" || subcommand === "create") {
3479
3852
  const result = await runAddCommand(rest);
@@ -3735,6 +4108,17 @@ async function main() {
3735
4108
  }
3736
4109
  }
3737
4110
  }
4111
+ if (command === "tenants") {
4112
+ if (subcommand === "list") await finish(await runListCommand8(rest));
4113
+ if (subcommand === "create" || subcommand === "add") await finish(await runCreateCommand4(rest));
4114
+ if (subcommand === "get") await finish(await runGetCommand7(rest));
4115
+ if (subcommand === "update") await finish(await runUpdateCommand5(rest));
4116
+ if (subcommand === "pause") await finish(await runPauseCommand2(rest));
4117
+ if (subcommand === "resume") await finish(await runResumeCommand(rest));
4118
+ if (subcommand === "delete" || subcommand === "remove") await finish(await runDeleteCommand5(rest));
4119
+ if (subcommand === "stats") await finish(await runStatsCommand(rest));
4120
+ if (subcommand === "domains") await finish(await runDomainsCommand(rest));
4121
+ }
3738
4122
  if (command === "keys") {
3739
4123
  if (subcommand === "list") {
3740
4124
  const result = await runListKeysCommandWithClient(rest);