groundmail-cli 0.0.0-stage → 0.15.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/dist/cli.js ADDED
@@ -0,0 +1,3158 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-4SSJDDBV.js";
3
+
4
+ // src/commands/emails/send.ts
5
+ function readFlag(args, flag) {
6
+ const index = args.indexOf(flag);
7
+ if (index === -1) return void 0;
8
+ return args[index + 1];
9
+ }
10
+ function readFlags(args, flag) {
11
+ const values = [];
12
+ for (let index = 0; index < args.length; index += 1) {
13
+ if (args[index] === flag && args[index + 1]) values.push(args[index + 1]);
14
+ }
15
+ return values;
16
+ }
17
+ function parseTags(values) {
18
+ const tags = values.map((value) => {
19
+ const separator = value.indexOf("=");
20
+ if (separator <= 0) {
21
+ return null;
22
+ }
23
+ const name = value.slice(0, separator).trim();
24
+ const tagValue = value.slice(separator + 1).trim();
25
+ if (!name || !tagValue) return null;
26
+ return { name, value: tagValue };
27
+ });
28
+ if (tags.some((tag) => tag == null)) {
29
+ return { error: "--tag must be in name=value format" };
30
+ }
31
+ return tags;
32
+ }
33
+ function parseSendCommandArgs(args) {
34
+ const parsedTags = parseTags(readFlags(args, "--tag"));
35
+ const category = readFlag(args, "--category");
36
+ return {
37
+ from: readFlag(args, "--from"),
38
+ to: readFlag(args, "--to"),
39
+ subject: readFlag(args, "--subject"),
40
+ html: readFlag(args, "--html"),
41
+ text: readFlag(args, "--text"),
42
+ tags: Array.isArray(parsedTags) ? parsedTags : void 0,
43
+ scheduledAt: readFlag(args, "--schedule"),
44
+ category,
45
+ unsubscribe: args.includes("--unsubscribe") ? true : void 0,
46
+ apiKey: readFlag(args, "--api-key"),
47
+ baseUrl: readFlag(args, "--base-url")
48
+ };
49
+ }
50
+ async function runSendCommand(args, deps) {
51
+ const env = deps.env ?? process.env;
52
+ const stdout = deps.stdout ?? ((line) => console.log(line));
53
+ const stderr = deps.stderr ?? ((line) => console.error(line));
54
+ const options = parseSendCommandOptions(args, env);
55
+ if ("error" in options) {
56
+ stderr(options.error);
57
+ return 1;
58
+ }
59
+ try {
60
+ const result = await deps.sendEmail({
61
+ from: options.from,
62
+ to: options.to,
63
+ subject: options.subject,
64
+ html: options.html,
65
+ text: options.text,
66
+ tags: options.tags,
67
+ scheduledAt: options.scheduledAt,
68
+ category: options.category,
69
+ unsubscribe: options.unsubscribe
70
+ });
71
+ stdout(JSON.stringify(result));
72
+ return 0;
73
+ } catch (error) {
74
+ stderr(error instanceof Error ? error.message : String(error));
75
+ return 1;
76
+ }
77
+ }
78
+ function parseSendCommandOptions(args, env) {
79
+ const parsed = parseSendCommandArgs(args);
80
+ const apiKey = parsed.apiKey || env.GROUNDMAIL_API_KEY;
81
+ const parsedTags = parseTags(readFlags(args, "--tag"));
82
+ if (!apiKey) {
83
+ return { error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
84
+ }
85
+ if ("error" in parsedTags) {
86
+ return { error: parsedTags.error };
87
+ }
88
+ if (!parsed.from || !parsed.to || !parsed.subject) {
89
+ return { error: "Required flags: --from --to --subject (and --html or --text)" };
90
+ }
91
+ if (!parsed.html && !parsed.text) {
92
+ return { error: "Provide --html or --text" };
93
+ }
94
+ return {
95
+ from: parsed.from,
96
+ to: parsed.to,
97
+ subject: parsed.subject,
98
+ html: parsed.html,
99
+ text: parsed.text,
100
+ tags: parsedTags.length ? parsedTags : void 0,
101
+ scheduledAt: parsed.scheduledAt,
102
+ category: parsed.category,
103
+ unsubscribe: parsed.unsubscribe,
104
+ apiKey,
105
+ baseUrl: parsed.baseUrl
106
+ };
107
+ }
108
+ function createDefaultSendDeps(apiKey, baseUrl) {
109
+ return {
110
+ sendEmail: async (params) => {
111
+ const { Groundmail } = await import("groundmail");
112
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
113
+ return client.emails.send(params);
114
+ }
115
+ };
116
+ }
117
+ async function runSendCommandWithClient(args, env = process.env) {
118
+ const parsed = parseSendCommandOptions(args, env);
119
+ if ("error" in parsed) {
120
+ return { exitCode: 1, error: parsed.error };
121
+ }
122
+ const deps = createDefaultSendDeps(parsed.apiKey, parsed.baseUrl);
123
+ const exitCode = await runSendCommand(args, { ...deps, env });
124
+ return { exitCode };
125
+ }
126
+
127
+ // src/commands/emails/batch.ts
128
+ import { readFile } from "fs/promises";
129
+ function readFlag2(args, flag) {
130
+ const index = args.indexOf(flag);
131
+ if (index === -1) return void 0;
132
+ return args[index + 1];
133
+ }
134
+ function readFirstPositional(args) {
135
+ for (let index = 0; index < args.length; index += 1) {
136
+ const arg = args[index];
137
+ if (arg.startsWith("--")) {
138
+ if (arg === "--api-key" || arg === "--base-url" || arg === "--file") index += 1;
139
+ continue;
140
+ }
141
+ return arg;
142
+ }
143
+ return void 0;
144
+ }
145
+ async function runBatchCommand(args, deps) {
146
+ const env = deps.env ?? process.env;
147
+ const stdout = deps.stdout ?? ((line) => console.log(line));
148
+ const stderr = deps.stderr ?? ((line) => console.error(line));
149
+ const apiKey = readFlag2(args, "--api-key") || env.GROUNDMAIL_API_KEY;
150
+ if (!apiKey) {
151
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
152
+ return { exitCode: 1, error: "missing key" };
153
+ }
154
+ const filePath = readFlag2(args, "--file") || readFirstPositional(args);
155
+ if (!filePath) {
156
+ stderr("Required: --file <emails.json>");
157
+ return { exitCode: 1, error: "missing file" };
158
+ }
159
+ try {
160
+ const readTextFile = deps.readTextFile ?? ((path) => readFile(path, "utf8"));
161
+ const source = await readTextFile(filePath);
162
+ const payload = parseBatchPayload(source);
163
+ if ("error" in payload) {
164
+ stderr(payload.error);
165
+ return { exitCode: 1, error: payload.error };
166
+ }
167
+ const result = await deps.sendBatch(payload.emails);
168
+ stdout(JSON.stringify(result));
169
+ return { exitCode: 0 };
170
+ } catch (error) {
171
+ stderr(error instanceof Error ? error.message : String(error));
172
+ return { exitCode: 1, error: String(error) };
173
+ }
174
+ }
175
+ async function runBatchCommandWithClient(args, env = process.env) {
176
+ const apiKey = readFlag2(args, "--api-key") || env.GROUNDMAIL_API_KEY;
177
+ const baseUrl = readFlag2(args, "--base-url");
178
+ if (!apiKey) {
179
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
180
+ }
181
+ const { Groundmail } = await import("groundmail");
182
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
183
+ return runBatchCommand(args, {
184
+ env,
185
+ sendBatch: (emails) => client.emails.batch(emails)
186
+ });
187
+ }
188
+ function parseBatchPayload(source) {
189
+ let parsed;
190
+ try {
191
+ parsed = JSON.parse(source);
192
+ } catch {
193
+ return { error: "Batch file must be valid JSON." };
194
+ }
195
+ const emails = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && "emails" in parsed && Array.isArray(parsed.emails) ? parsed.emails : null;
196
+ if (!emails || emails.length === 0) {
197
+ return { error: "Batch file must contain a non-empty array of emails." };
198
+ }
199
+ return { emails };
200
+ }
201
+
202
+ // src/commands/emails/cancel.ts
203
+ function readFlag3(args, flag) {
204
+ const index = args.indexOf(flag);
205
+ if (index === -1) return void 0;
206
+ return args[index + 1];
207
+ }
208
+ async function runCancelCommand(args, deps) {
209
+ const env = deps.env ?? process.env;
210
+ const stdout = deps.stdout ?? ((line) => console.log(line));
211
+ const stderr = deps.stderr ?? ((line) => console.error(line));
212
+ const apiKey = readFlag3(args, "--api-key") || env.GROUNDMAIL_API_KEY;
213
+ const id = readFlag3(args, "--id") || args.find((arg) => !arg.startsWith("--"));
214
+ if (!apiKey) {
215
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
216
+ return { exitCode: 1, error: "missing key" };
217
+ }
218
+ if (!id) {
219
+ stderr("Required: --id <msg_\u2026>");
220
+ return { exitCode: 1, error: "missing id" };
221
+ }
222
+ try {
223
+ const result = await deps.cancelEmail(id);
224
+ stdout(JSON.stringify(result));
225
+ return { exitCode: 0 };
226
+ } catch (error) {
227
+ stderr(error instanceof Error ? error.message : String(error));
228
+ return { exitCode: 1, error: String(error) };
229
+ }
230
+ }
231
+ async function runCancelCommandWithClient(args, env = process.env) {
232
+ const apiKey = readFlag3(args, "--api-key") || env.GROUNDMAIL_API_KEY;
233
+ const baseUrl = readFlag3(args, "--base-url");
234
+ if (!apiKey) {
235
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
236
+ }
237
+ const { Groundmail } = await import("groundmail");
238
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
239
+ return runCancelCommand(args, {
240
+ env,
241
+ cancelEmail: (id) => client.emails.cancel(id)
242
+ });
243
+ }
244
+
245
+ // src/commands/emails/resend.ts
246
+ function readFlag4(args, flag) {
247
+ const index = args.indexOf(flag);
248
+ if (index === -1) return void 0;
249
+ return args[index + 1];
250
+ }
251
+ async function runResendCommand(args, deps) {
252
+ const env = deps.env ?? process.env;
253
+ const stdout = deps.stdout ?? ((line) => console.log(line));
254
+ const stderr = deps.stderr ?? ((line) => console.error(line));
255
+ const apiKey = readFlag4(args, "--api-key") || env.GROUNDMAIL_API_KEY;
256
+ const id = readFlag4(args, "--id") || args.find((arg) => !arg.startsWith("--"));
257
+ if (!apiKey) {
258
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
259
+ return { exitCode: 1, error: "missing key" };
260
+ }
261
+ if (!id) {
262
+ stderr("Required: --id <msg_\u2026>");
263
+ return { exitCode: 1, error: "missing id" };
264
+ }
265
+ try {
266
+ const result = await deps.resendEmail(id);
267
+ stdout(JSON.stringify(result));
268
+ return { exitCode: 0 };
269
+ } catch (error) {
270
+ stderr(error instanceof Error ? error.message : String(error));
271
+ return { exitCode: 1, error: String(error) };
272
+ }
273
+ }
274
+ async function runResendCommandWithClient(args, env = process.env) {
275
+ const apiKey = readFlag4(args, "--api-key") || env.GROUNDMAIL_API_KEY;
276
+ const baseUrl = readFlag4(args, "--base-url");
277
+ if (!apiKey) {
278
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
279
+ }
280
+ const { Groundmail } = await import("groundmail");
281
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
282
+ return runResendCommand(args, {
283
+ env,
284
+ resendEmail: (id) => client.emails.resend(id)
285
+ });
286
+ }
287
+
288
+ // src/commands/emails/get.ts
289
+ function readFlag5(args, flag) {
290
+ const index = args.indexOf(flag);
291
+ if (index === -1) return void 0;
292
+ return args[index + 1];
293
+ }
294
+ async function runGetCommand(args, deps) {
295
+ const env = deps.env ?? process.env;
296
+ const stdout = deps.stdout ?? ((line) => console.log(line));
297
+ const stderr = deps.stderr ?? ((line) => console.error(line));
298
+ const id = readFlag5(args, "--id") || args.find((a) => !a.startsWith("--"));
299
+ const apiKey = readFlag5(args, "--api-key") || env.GROUNDMAIL_API_KEY;
300
+ if (!apiKey) {
301
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
302
+ return { exitCode: 1, error: "missing key" };
303
+ }
304
+ if (!id) {
305
+ stderr("Required: --id <msg_\u2026>");
306
+ return { exitCode: 1, error: "missing id" };
307
+ }
308
+ try {
309
+ const result = await deps.getEmail(id);
310
+ stdout(JSON.stringify(result));
311
+ return { exitCode: 0 };
312
+ } catch (error) {
313
+ stderr(error instanceof Error ? error.message : String(error));
314
+ return { exitCode: 1, error: String(error) };
315
+ }
316
+ }
317
+ async function runGetCommandWithClient(args, env = process.env) {
318
+ const apiKey = readFlag5(args, "--api-key") || env.GROUNDMAIL_API_KEY;
319
+ const baseUrl = readFlag5(args, "--base-url");
320
+ if (!apiKey) {
321
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
322
+ }
323
+ const { Groundmail } = await import("groundmail");
324
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
325
+ return runGetCommand(args, {
326
+ env,
327
+ getEmail: (id) => client.emails.get(id)
328
+ });
329
+ }
330
+
331
+ // src/commands/emails/insights.ts
332
+ function readFlag6(args, flag) {
333
+ const index = args.indexOf(flag);
334
+ if (index === -1) return void 0;
335
+ return args[index + 1];
336
+ }
337
+ async function runInsightsCommand(args, deps) {
338
+ const env = deps.env ?? process.env;
339
+ const stdout = deps.stdout ?? ((line) => console.log(line));
340
+ const stderr = deps.stderr ?? ((line) => console.error(line));
341
+ const apiKey = readFlag6(args, "--api-key") || env.GROUNDMAIL_API_KEY;
342
+ if (!apiKey) {
343
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
344
+ return { exitCode: 1, error: "missing key" };
345
+ }
346
+ const windowFlag = readFlag6(args, "--window");
347
+ if (windowFlag && windowFlag !== "7d" && windowFlag !== "30d") {
348
+ stderr("Invalid --window. Use 7d or 30d.");
349
+ return { exitCode: 1, error: "invalid window" };
350
+ }
351
+ try {
352
+ const result = await deps.getInsights(windowFlag);
353
+ stdout(JSON.stringify(result));
354
+ return { exitCode: 0 };
355
+ } catch (error) {
356
+ stderr(error instanceof Error ? error.message : String(error));
357
+ return { exitCode: 1, error: String(error) };
358
+ }
359
+ }
360
+ async function runInsightsCommandWithClient(args, env = process.env) {
361
+ const apiKey = readFlag6(args, "--api-key") || env.GROUNDMAIL_API_KEY;
362
+ const baseUrl = readFlag6(args, "--base-url");
363
+ if (!apiKey) {
364
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
365
+ }
366
+ const { Groundmail } = await import("groundmail");
367
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
368
+ return runInsightsCommand(args, {
369
+ env,
370
+ getInsights: (window) => client.emails.insights(window)
371
+ });
372
+ }
373
+
374
+ // src/commands/emails/list.ts
375
+ function readFlag7(args, flag) {
376
+ const index = args.indexOf(flag);
377
+ if (index === -1) return void 0;
378
+ return args[index + 1];
379
+ }
380
+ async function runListCommand(args, deps) {
381
+ const env = deps.env ?? process.env;
382
+ const stdout = deps.stdout ?? ((line) => console.log(line));
383
+ const stderr = deps.stderr ?? ((line) => console.error(line));
384
+ const apiKey = readFlag7(args, "--api-key") || env.GROUNDMAIL_API_KEY;
385
+ if (!apiKey) {
386
+ stderr("Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key.");
387
+ return { exitCode: 1, error: "missing key" };
388
+ }
389
+ const limitRaw = readFlag7(args, "--limit");
390
+ const cursor = readFlag7(args, "--cursor");
391
+ const limit = limitRaw ? Number(limitRaw) : void 0;
392
+ try {
393
+ const result = await deps.listEmails({
394
+ ...limit != null && Number.isFinite(limit) ? { limit } : {},
395
+ ...cursor ? { cursor } : {}
396
+ });
397
+ stdout(JSON.stringify(result));
398
+ return { exitCode: 0 };
399
+ } catch (error) {
400
+ stderr(error instanceof Error ? error.message : String(error));
401
+ return { exitCode: 1, error: String(error) };
402
+ }
403
+ }
404
+ async function runListCommandWithClient(args, env = process.env) {
405
+ const apiKey = readFlag7(args, "--api-key") || env.GROUNDMAIL_API_KEY;
406
+ const baseUrl = readFlag7(args, "--base-url");
407
+ if (!apiKey) {
408
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
409
+ }
410
+ const { Groundmail } = await import("groundmail");
411
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
412
+ return runListCommand(args, {
413
+ env,
414
+ listEmails: (params) => client.emails.list(params)
415
+ });
416
+ }
417
+
418
+ // src/commands/events/send.ts
419
+ function readFlag8(args, flag) {
420
+ const index = args.indexOf(flag);
421
+ if (index === -1) return void 0;
422
+ return args[index + 1];
423
+ }
424
+ function resolveApiKey(args, env) {
425
+ return readFlag8(args, "--api-key") || env.GROUNDMAIL_API_KEY || null;
426
+ }
427
+ async function createClient(apiKey, baseUrl) {
428
+ const { Groundmail } = await import("groundmail");
429
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
430
+ }
431
+ async function runSendEventCommand(args, env = process.env) {
432
+ const apiKey = resolveApiKey(args, env);
433
+ if (!apiKey) {
434
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
435
+ }
436
+ const name = readFlag8(args, "--name") || readFlag8(args, "--type");
437
+ if (!name) {
438
+ return { exitCode: 1, error: "Required flag: --name or --type" };
439
+ }
440
+ const email = readFlag8(args, "--email");
441
+ const userId = readFlag8(args, "--user-id");
442
+ const dataRaw = readFlag8(args, "--data");
443
+ const idempotencyKey = readFlag8(args, "--idempotency-key");
444
+ const baseUrl = readFlag8(args, "--base-url");
445
+ let data;
446
+ if (dataRaw) {
447
+ try {
448
+ const parsed = JSON.parse(dataRaw);
449
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
450
+ return { exitCode: 1, error: "--data must be a JSON object" };
451
+ }
452
+ data = parsed;
453
+ } catch (error) {
454
+ return {
455
+ exitCode: 1,
456
+ error: error instanceof Error ? error.message : "--data must be valid JSON"
457
+ };
458
+ }
459
+ }
460
+ try {
461
+ const client = await createClient(apiKey, baseUrl);
462
+ const result = await client.events.trigger({
463
+ name,
464
+ email,
465
+ user_id: userId,
466
+ data,
467
+ idempotencyKey
468
+ });
469
+ console.log(JSON.stringify(result));
470
+ return { exitCode: 0 };
471
+ } catch (error) {
472
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
473
+ }
474
+ }
475
+
476
+ // src/commands/automations/shared.ts
477
+ import { readFile as readFile2 } from "fs/promises";
478
+ function readFlag9(args, flag) {
479
+ const index = args.indexOf(flag);
480
+ if (index === -1) return void 0;
481
+ return args[index + 1];
482
+ }
483
+ function parseAutomationsCommonArgs(args) {
484
+ return {
485
+ apiKey: readFlag9(args, "--api-key"),
486
+ baseUrl: readFlag9(args, "--base-url")
487
+ };
488
+ }
489
+ function resolveApiKey2(options, env) {
490
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
491
+ }
492
+ async function createAutomationsClient(apiKey, baseUrl) {
493
+ const { Groundmail } = await import("groundmail");
494
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
495
+ }
496
+ async function readAutomationDefinition(args) {
497
+ const file = readFlag9(args, "--file");
498
+ if (file) {
499
+ try {
500
+ const raw = await readFile2(file, "utf8");
501
+ const parsed = JSON.parse(raw);
502
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
503
+ return { ok: false, error: "--file must contain a JSON object" };
504
+ }
505
+ return { ok: true, value: parsed };
506
+ } catch (error) {
507
+ return {
508
+ ok: false,
509
+ error: error instanceof Error ? error.message : "Failed to read --file"
510
+ };
511
+ }
512
+ }
513
+ const name = readFlag9(args, "--name");
514
+ const triggerEvent = readFlag9(args, "--trigger") || readFlag9(args, "--event");
515
+ const stepsRaw = readFlag9(args, "--steps");
516
+ let steps;
517
+ if (stepsRaw) {
518
+ try {
519
+ steps = JSON.parse(stepsRaw);
520
+ } catch (error) {
521
+ return {
522
+ ok: false,
523
+ error: error instanceof Error ? error.message : "--steps must be valid JSON"
524
+ };
525
+ }
526
+ }
527
+ return {
528
+ ok: true,
529
+ value: {
530
+ ...name ? { name } : {},
531
+ ...triggerEvent ? { trigger: { type: "event", event: triggerEvent } } : {},
532
+ ...steps !== void 0 ? { steps } : {}
533
+ }
534
+ };
535
+ }
536
+
537
+ // src/commands/automations/list.ts
538
+ async function runListCommand2(args, env = process.env) {
539
+ const options = parseAutomationsCommonArgs(args);
540
+ const apiKey = resolveApiKey2(options, env);
541
+ if (!apiKey) {
542
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
543
+ }
544
+ try {
545
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
546
+ const result = await client.automations.list();
547
+ console.log(JSON.stringify(result));
548
+ return { exitCode: 0 };
549
+ } catch (error) {
550
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
551
+ }
552
+ }
553
+
554
+ // src/commands/automations/get.ts
555
+ async function runGetCommand2(args, env = process.env) {
556
+ const options = parseAutomationsCommonArgs(args);
557
+ const apiKey = resolveApiKey2(options, env);
558
+ if (!apiKey) {
559
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
560
+ }
561
+ const id = readFlag9(args, "--id");
562
+ if (!id) return { exitCode: 1, error: "Required flag: --id" };
563
+ try {
564
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
565
+ const result = await client.automations.get(id);
566
+ console.log(JSON.stringify(result));
567
+ return { exitCode: 0 };
568
+ } catch (error) {
569
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
570
+ }
571
+ }
572
+
573
+ // src/commands/automations/create.ts
574
+ async function runCreateCommand(args, env = process.env) {
575
+ const options = parseAutomationsCommonArgs(args);
576
+ const apiKey = resolveApiKey2(options, env);
577
+ if (!apiKey) {
578
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
579
+ }
580
+ const definition = await readAutomationDefinition(args);
581
+ if (!definition.ok) return { exitCode: 1, error: definition.error };
582
+ const { name, trigger, steps } = definition.value;
583
+ if (!name || typeof name !== "string") {
584
+ return { exitCode: 1, error: "Required: --name or name in --file" };
585
+ }
586
+ if (!trigger) {
587
+ return { exitCode: 1, error: "Required: --trigger/--event or trigger in --file" };
588
+ }
589
+ if (!steps) {
590
+ return { exitCode: 1, error: "Required: --steps or steps in --file" };
591
+ }
592
+ try {
593
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
594
+ const result = await client.automations.create({
595
+ name,
596
+ trigger,
597
+ steps
598
+ });
599
+ console.log(JSON.stringify(result));
600
+ return { exitCode: 0 };
601
+ } catch (error) {
602
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
603
+ }
604
+ }
605
+
606
+ // src/commands/automations/update.ts
607
+ async function runUpdateCommand(args, env = process.env) {
608
+ const options = parseAutomationsCommonArgs(args);
609
+ const apiKey = resolveApiKey2(options, env);
610
+ if (!apiKey) {
611
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
612
+ }
613
+ const id = readFlag9(args, "--id");
614
+ if (!id) return { exitCode: 1, error: "Required flag: --id" };
615
+ const definition = await readAutomationDefinition(args);
616
+ if (!definition.ok) return { exitCode: 1, error: definition.error };
617
+ const { name, trigger, steps } = definition.value;
618
+ if (!name && !trigger && !steps) {
619
+ return {
620
+ exitCode: 1,
621
+ error: "Nothing to update. Pass --file and/or --name/--trigger/--steps."
622
+ };
623
+ }
624
+ try {
625
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
626
+ const result = await client.automations.update(id, {
627
+ ...name ? { name } : {},
628
+ ...trigger ? { trigger } : {},
629
+ ...steps ? { steps } : {}
630
+ });
631
+ console.log(JSON.stringify(result));
632
+ return { exitCode: 0 };
633
+ } catch (error) {
634
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
635
+ }
636
+ }
637
+
638
+ // src/commands/automations/actions.ts
639
+ async function runActivateCommand(args, env = process.env) {
640
+ const options = parseAutomationsCommonArgs(args);
641
+ const apiKey = resolveApiKey2(options, env);
642
+ if (!apiKey) {
643
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
644
+ }
645
+ const id = readFlag9(args, "--id");
646
+ if (!id) return { exitCode: 1, error: "Required flag: --id" };
647
+ try {
648
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
649
+ const result = await client.automations.activate(id);
650
+ console.log(JSON.stringify(result));
651
+ return { exitCode: 0 };
652
+ } catch (error) {
653
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
654
+ }
655
+ }
656
+ async function runPauseCommand(args, env = process.env) {
657
+ const options = parseAutomationsCommonArgs(args);
658
+ const apiKey = resolveApiKey2(options, env);
659
+ if (!apiKey) {
660
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
661
+ }
662
+ const id = readFlag9(args, "--id");
663
+ if (!id) return { exitCode: 1, error: "Required flag: --id" };
664
+ try {
665
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
666
+ const result = await client.automations.pause(id);
667
+ console.log(JSON.stringify(result));
668
+ return { exitCode: 0 };
669
+ } catch (error) {
670
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
671
+ }
672
+ }
673
+ async function runDeleteCommand(args, env = process.env) {
674
+ const options = parseAutomationsCommonArgs(args);
675
+ const apiKey = resolveApiKey2(options, env);
676
+ if (!apiKey) {
677
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
678
+ }
679
+ const id = readFlag9(args, "--id");
680
+ if (!id) return { exitCode: 1, error: "Required flag: --id" };
681
+ try {
682
+ const client = await createAutomationsClient(apiKey, options.baseUrl);
683
+ const result = await client.automations.remove(id);
684
+ console.log(JSON.stringify(result));
685
+ return { exitCode: 0 };
686
+ } catch (error) {
687
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
688
+ }
689
+ }
690
+
691
+ // src/commands/domains/shared.ts
692
+ function readFlag10(args, flag) {
693
+ const index = args.indexOf(flag);
694
+ if (index === -1) return void 0;
695
+ return args[index + 1];
696
+ }
697
+ function parseDomainsCommonArgs(args) {
698
+ return {
699
+ apiKey: readFlag10(args, "--api-key"),
700
+ baseUrl: readFlag10(args, "--base-url"),
701
+ name: readFlag10(args, "--name") || readFlag10(args, "--domain"),
702
+ id: readFlag10(args, "--id")
703
+ };
704
+ }
705
+ function resolveApiKey3(options, env) {
706
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
707
+ }
708
+ async function createDomainsClient(apiKey, baseUrl) {
709
+ const { Groundmail } = await import("groundmail");
710
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
711
+ }
712
+ function formatDnsRecords(records) {
713
+ const lines = ["DNS records to add:", ""];
714
+ for (const record of records) {
715
+ lines.push(` ${record.type.padEnd(6)} ${record.host}`);
716
+ if (record.type === "MX" && record.priority != null) {
717
+ lines.push(` priority: ${record.priority}`);
718
+ lines.push(` mail server: ${record.value}`);
719
+ } else {
720
+ lines.push(` ${record.value}`);
721
+ }
722
+ lines.push(` (${record.purpose})`);
723
+ lines.push("");
724
+ }
725
+ return lines.join("\n").trimEnd();
726
+ }
727
+
728
+ // src/commands/domains/add.ts
729
+ async function runAddCommand(args, env = process.env) {
730
+ const options = parseDomainsCommonArgs(args);
731
+ const apiKey = resolveApiKey3(options, env);
732
+ if (!apiKey) {
733
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
734
+ }
735
+ const name = options.name || args.find((arg) => !arg.startsWith("--") && arg.includes("."));
736
+ if (!name) {
737
+ return {
738
+ exitCode: 1,
739
+ error: "Missing domain. Usage: groundmail domains add example.com"
740
+ };
741
+ }
742
+ try {
743
+ const client = await createDomainsClient(apiKey, options.baseUrl);
744
+ const inbound = readFlag10(args, "--inbound");
745
+ const result = await client.domains.create({
746
+ name,
747
+ ...inbound === "true" || inbound === "1" ? { inbound_enabled: true } : {}
748
+ });
749
+ console.log(JSON.stringify(result));
750
+ console.error("");
751
+ console.error(`Domain ${result.domain.name} added (${result.domain.status}).`);
752
+ console.error(formatDnsRecords(result.records));
753
+ console.error("");
754
+ console.error(`Then: groundmail domains verify ${result.domain.name}`);
755
+ return { exitCode: 0 };
756
+ } catch (error) {
757
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
758
+ }
759
+ }
760
+
761
+ // src/commands/domains/apply.ts
762
+ async function runApplyCommand(args, env = process.env) {
763
+ const options = parseDomainsCommonArgs(args);
764
+ const apiKey = resolveApiKey3(options, env);
765
+ if (!apiKey) {
766
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
767
+ }
768
+ const providerFlag = args.includes("--provider") ? args[args.indexOf("--provider") + 1] : void 0;
769
+ const provider = (providerFlag || "").toLowerCase();
770
+ if (provider !== "cloudflare" && provider !== "godaddy" && provider !== "vercel") {
771
+ return {
772
+ exitCode: 1,
773
+ error: "Missing or invalid --provider. Use --provider cloudflare, --provider vercel, or --provider godaddy."
774
+ };
775
+ }
776
+ const idOrName = options.id || options.name || args.find((arg, i) => {
777
+ if (arg.startsWith("--")) return false;
778
+ const prev = args[i - 1];
779
+ if (prev === "--provider" || prev === "--api-key" || prev === "--base-url" || prev === "--name" || prev === "--domain" || prev === "--id") {
780
+ return false;
781
+ }
782
+ return arg.includes(".") || arg.length > 8;
783
+ });
784
+ if (!idOrName) {
785
+ return {
786
+ exitCode: 1,
787
+ error: "Missing domain. Usage: groundmail domains apply example.com --provider cloudflare"
788
+ };
789
+ }
790
+ try {
791
+ const client = await createDomainsClient(apiKey, options.baseUrl);
792
+ const localCloudflare = env.CLOUDFLARE_API_TOKEN || env.CLOUDFLARE_API_KEY;
793
+ const localVercel = env.VERCEL_API_TOKEN;
794
+ const useStoredCloudflare = provider === "cloudflare" && !localCloudflare;
795
+ const useStoredVercel = provider === "vercel" && !localVercel;
796
+ const result = useStoredCloudflare || useStoredVercel ? await client.domains.apply(idOrName, { provider }) : await client.domains.applyDns({
797
+ idOrName,
798
+ provider,
799
+ cloudflareApiToken: localCloudflare,
800
+ cloudflareZoneId: env.CLOUDFLARE_ZONE_ID,
801
+ godaddyApiKey: env.GODADDY_API_KEY,
802
+ godaddyApiSecret: env.GODADDY_API_SECRET,
803
+ vercelApiToken: localVercel,
804
+ vercelTeamId: env.VERCEL_TEAM_ID
805
+ });
806
+ console.log(JSON.stringify(result));
807
+ console.error(
808
+ useStoredCloudflare ? `Applied ${result.results.length} DNS change(s) via stored Cloudflare credentials for ${result.domain}.` : useStoredVercel ? `Applied ${result.results.length} DNS change(s) via stored Vercel credentials for ${result.domain}.` : `Applied ${result.results.length} DNS change(s) via ${result.provider} for ${result.domain}.`
809
+ );
810
+ for (const row of result.results) {
811
+ console.error(` ${row.action.padEnd(10)} ${row.purpose} \u2192 ${row.host}`);
812
+ }
813
+ console.error("");
814
+ console.error(`Next: groundmail domains verify ${result.domain}`);
815
+ return { exitCode: 0 };
816
+ } catch (error) {
817
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
818
+ }
819
+ }
820
+
821
+ // src/commands/domains/delete.ts
822
+ var POSITIONAL_FLAGS = ["--api-key", "--base-url", "--name", "--domain", "--id"];
823
+ async function runDeleteCommand2(args, env = process.env) {
824
+ const options = parseDomainsCommonArgs(args);
825
+ const apiKey = resolveApiKey3(options, env);
826
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
827
+ const idOrName = options.id || options.name || readFirstPositional2(args);
828
+ if (!idOrName) return { exitCode: 1, error: "Missing domain. Usage: groundmail domains delete example.com" };
829
+ try {
830
+ const client = await createDomainsClient(apiKey, options.baseUrl);
831
+ console.log(JSON.stringify(await client.domains.delete(idOrName)));
832
+ return { exitCode: 0 };
833
+ } catch (error) {
834
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
835
+ }
836
+ }
837
+ function readFirstPositional2(args) {
838
+ for (let i = 0; i < args.length; i += 1) {
839
+ const arg = args[i];
840
+ if (arg.startsWith("--")) {
841
+ if (POSITIONAL_FLAGS.includes(arg)) i += 1;
842
+ continue;
843
+ }
844
+ return arg;
845
+ }
846
+ return void 0;
847
+ }
848
+
849
+ // src/commands/domains/get.ts
850
+ var POSITIONAL_FLAGS2 = ["--api-key", "--base-url", "--name", "--domain", "--id"];
851
+ async function runGetCommand3(args, env = process.env) {
852
+ const options = parseDomainsCommonArgs(args);
853
+ const apiKey = resolveApiKey3(options, env);
854
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
855
+ const idOrName = options.id || options.name || readFirstPositional3(args);
856
+ if (!idOrName) return { exitCode: 1, error: "Missing domain. Usage: groundmail domains get example.com" };
857
+ try {
858
+ const client = await createDomainsClient(apiKey, options.baseUrl);
859
+ console.log(JSON.stringify(await client.domains.get(idOrName)));
860
+ return { exitCode: 0 };
861
+ } catch (error) {
862
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
863
+ }
864
+ }
865
+ function readFirstPositional3(args) {
866
+ for (let i = 0; i < args.length; i += 1) {
867
+ const arg = args[i];
868
+ if (arg.startsWith("--")) {
869
+ if (POSITIONAL_FLAGS2.includes(arg)) i += 1;
870
+ continue;
871
+ }
872
+ return arg;
873
+ }
874
+ return void 0;
875
+ }
876
+
877
+ // src/commands/domains/list.ts
878
+ async function runListCommand3(args, env = process.env) {
879
+ const options = parseDomainsCommonArgs(args);
880
+ const apiKey = resolveApiKey3(options, env);
881
+ if (!apiKey) {
882
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
883
+ }
884
+ try {
885
+ const client = await createDomainsClient(apiKey, options.baseUrl);
886
+ const result = await client.domains.list();
887
+ console.log(JSON.stringify(result));
888
+ return { exitCode: 0 };
889
+ } catch (error) {
890
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
891
+ }
892
+ }
893
+
894
+ // src/commands/domains/update.ts
895
+ function parseBooleanFlag(value, flag) {
896
+ if (value == null) return void 0;
897
+ if (value === "true" || value === "1") return true;
898
+ if (value === "false" || value === "0") return false;
899
+ throw new Error(`${flag} must be true or false`);
900
+ }
901
+ var POSITIONAL_FLAGS3 = [
902
+ "--api-key",
903
+ "--base-url",
904
+ "--name",
905
+ "--domain",
906
+ "--id",
907
+ "--tls-mode",
908
+ "--open-tracking",
909
+ "--click-tracking",
910
+ "--inbound"
911
+ ];
912
+ function readFirstPositional4(args) {
913
+ for (let i = 0; i < args.length; i += 1) {
914
+ const arg = args[i];
915
+ if (arg.startsWith("--")) {
916
+ if (POSITIONAL_FLAGS3.includes(arg)) i += 1;
917
+ continue;
918
+ }
919
+ return arg;
920
+ }
921
+ return void 0;
922
+ }
923
+ async function runUpdateCommand2(args, env = process.env) {
924
+ const options = parseDomainsCommonArgs(args);
925
+ const apiKey = resolveApiKey3(options, env);
926
+ if (!apiKey) {
927
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
928
+ }
929
+ const idOrName = options.id || options.name || readFirstPositional4(args);
930
+ if (!idOrName) {
931
+ return {
932
+ exitCode: 1,
933
+ error: "Missing domain. Usage: groundmail domains update example.com --inbound true"
934
+ };
935
+ }
936
+ try {
937
+ const payload = {};
938
+ const tlsMode = readFlag10(args, "--tls-mode");
939
+ if (tlsMode) {
940
+ if (tlsMode !== "opportunistic" && tlsMode !== "enforced") {
941
+ return { exitCode: 1, error: "--tls-mode must be opportunistic or enforced" };
942
+ }
943
+ payload.tls_mode = tlsMode;
944
+ }
945
+ const openTracking = parseBooleanFlag(readFlag10(args, "--open-tracking"), "--open-tracking");
946
+ if (openTracking !== void 0) payload.open_tracking = openTracking;
947
+ const clickTracking = parseBooleanFlag(readFlag10(args, "--click-tracking"), "--click-tracking");
948
+ if (clickTracking !== void 0) payload.click_tracking = clickTracking;
949
+ const inbound = parseBooleanFlag(readFlag10(args, "--inbound"), "--inbound");
950
+ if (inbound !== void 0) payload.inbound_enabled = inbound;
951
+ if (!Object.keys(payload).length) {
952
+ return {
953
+ exitCode: 1,
954
+ error: "No updates provided. Pass --inbound true|false, --tls-mode opportunistic|enforced, --open-tracking true|false, or --click-tracking true|false."
955
+ };
956
+ }
957
+ const client = await createDomainsClient(apiKey, options.baseUrl);
958
+ console.log(JSON.stringify(await client.domains.update(idOrName, payload)));
959
+ return { exitCode: 0 };
960
+ } catch (error) {
961
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
962
+ }
963
+ }
964
+
965
+ // src/commands/domains/verify.ts
966
+ async function runVerifyCommand(args, env = process.env) {
967
+ const options = parseDomainsCommonArgs(args);
968
+ const apiKey = resolveApiKey3(options, env);
969
+ if (!apiKey) {
970
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
971
+ }
972
+ const idOrName = options.id || options.name || args.find((arg) => !arg.startsWith("--") && (arg.includes(".") || arg.length > 8));
973
+ if (!idOrName) {
974
+ return {
975
+ exitCode: 1,
976
+ error: "Missing domain. Usage: groundmail domains verify example.com"
977
+ };
978
+ }
979
+ try {
980
+ const client = await createDomainsClient(apiKey, options.baseUrl);
981
+ const result = await client.domains.verify(idOrName);
982
+ console.log(JSON.stringify(result));
983
+ if (result.verified) {
984
+ console.error(`Domain ${result.domain.name} verified.`);
985
+ }
986
+ return { exitCode: 0 };
987
+ } catch (error) {
988
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
989
+ }
990
+ }
991
+
992
+ // src/commands/received-emails/shared.ts
993
+ function readFlag11(args, flag) {
994
+ const index = args.indexOf(flag);
995
+ if (index === -1) return void 0;
996
+ return args[index + 1];
997
+ }
998
+ function parseReceivedEmailsCommonArgs(args) {
999
+ return {
1000
+ apiKey: readFlag11(args, "--api-key"),
1001
+ baseUrl: readFlag11(args, "--base-url"),
1002
+ id: readFlag11(args, "--id")
1003
+ };
1004
+ }
1005
+ function resolveApiKey4(options, env) {
1006
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1007
+ }
1008
+ async function createReceivedEmailsClient(apiKey, baseUrl) {
1009
+ const { Groundmail } = await import("groundmail");
1010
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1011
+ }
1012
+
1013
+ // src/commands/received-emails/get.ts
1014
+ var POSITIONAL_FLAGS4 = ["--api-key", "--base-url", "--id"];
1015
+ function readFirstPositional5(args) {
1016
+ for (let i = 0; i < args.length; i += 1) {
1017
+ const arg = args[i];
1018
+ if (arg.startsWith("--")) {
1019
+ if (POSITIONAL_FLAGS4.includes(arg)) i += 1;
1020
+ continue;
1021
+ }
1022
+ return arg;
1023
+ }
1024
+ return void 0;
1025
+ }
1026
+ async function runGetCommand4(args, env = process.env) {
1027
+ const options = parseReceivedEmailsCommonArgs(args);
1028
+ const apiKey = resolveApiKey4(options, env);
1029
+ if (!apiKey) {
1030
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1031
+ }
1032
+ const id = options.id || readFirstPositional5(args);
1033
+ if (!id) {
1034
+ return { exitCode: 1, error: "Missing id. Usage: groundmail received-emails get inb_..." };
1035
+ }
1036
+ try {
1037
+ const client = await createReceivedEmailsClient(apiKey, options.baseUrl);
1038
+ console.log(JSON.stringify(await client.receivedEmails.get(id)));
1039
+ return { exitCode: 0 };
1040
+ } catch (error) {
1041
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1042
+ }
1043
+ }
1044
+
1045
+ // src/commands/received-emails/list.ts
1046
+ async function runListCommand4(args, env = process.env) {
1047
+ const options = parseReceivedEmailsCommonArgs(args);
1048
+ const apiKey = resolveApiKey4(options, env);
1049
+ if (!apiKey) {
1050
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1051
+ }
1052
+ try {
1053
+ const client = await createReceivedEmailsClient(apiKey, options.baseUrl);
1054
+ console.log(
1055
+ JSON.stringify(
1056
+ await client.receivedEmails.list({
1057
+ limit: readFlag11(args, "--limit") ? Number(readFlag11(args, "--limit")) : void 0,
1058
+ cursor: readFlag11(args, "--cursor"),
1059
+ domain: readFlag11(args, "--domain")
1060
+ })
1061
+ )
1062
+ );
1063
+ return { exitCode: 0 };
1064
+ } catch (error) {
1065
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1066
+ }
1067
+ }
1068
+
1069
+ // src/commands/webhooks/shared.ts
1070
+ function readFlag12(args, flag) {
1071
+ const index = args.indexOf(flag);
1072
+ if (index === -1) return void 0;
1073
+ return args[index + 1];
1074
+ }
1075
+ function parseWebhooksCommonArgs(args) {
1076
+ return {
1077
+ apiKey: readFlag12(args, "--api-key"),
1078
+ baseUrl: readFlag12(args, "--base-url")
1079
+ };
1080
+ }
1081
+ function resolveApiKey5(options, env) {
1082
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1083
+ }
1084
+ async function createWebhooksClient(apiKey, baseUrl) {
1085
+ const { Groundmail } = await import("groundmail");
1086
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1087
+ }
1088
+
1089
+ // src/commands/webhooks/create.ts
1090
+ async function runCreateCommand2(args, env = process.env) {
1091
+ const options = parseWebhooksCommonArgs(args);
1092
+ const apiKey = resolveApiKey5(options, env);
1093
+ if (!apiKey) {
1094
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1095
+ }
1096
+ const url = readFlag12(args, "--url");
1097
+ if (!url) {
1098
+ return { exitCode: 1, error: "Required flag: --url" };
1099
+ }
1100
+ try {
1101
+ const client = await createWebhooksClient(apiKey, options.baseUrl);
1102
+ const result = await client.webhooks.create({ url });
1103
+ console.log(JSON.stringify(result));
1104
+ return { exitCode: 0 };
1105
+ } catch (error) {
1106
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1107
+ }
1108
+ }
1109
+
1110
+ // src/commands/webhooks/get.ts
1111
+ var POSITIONAL_FLAGS5 = ["--api-key", "--base-url", "--id"];
1112
+ async function runGetCommand5(args, env = process.env) {
1113
+ const options = parseWebhooksCommonArgs(args);
1114
+ const apiKey = resolveApiKey5(options, env);
1115
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1116
+ const id = readFlag13(args, "--id") || readFirstPositional6(args);
1117
+ if (!id) return { exitCode: 1, error: "Missing webhook id. Pass --id wh_\u2026" };
1118
+ try {
1119
+ const client = await createWebhooksClient(apiKey, options.baseUrl);
1120
+ console.log(JSON.stringify(await client.webhooks.get(id)));
1121
+ return { exitCode: 0 };
1122
+ } catch (error) {
1123
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1124
+ }
1125
+ }
1126
+ function readFlag13(args, flag) {
1127
+ const index = args.indexOf(flag);
1128
+ return index === -1 ? void 0 : args[index + 1];
1129
+ }
1130
+ function readFirstPositional6(args) {
1131
+ for (let i = 0; i < args.length; i += 1) {
1132
+ const arg = args[i];
1133
+ if (arg.startsWith("--")) {
1134
+ if (POSITIONAL_FLAGS5.includes(arg)) i += 1;
1135
+ continue;
1136
+ }
1137
+ return arg;
1138
+ }
1139
+ return void 0;
1140
+ }
1141
+
1142
+ // src/commands/webhooks/delete.ts
1143
+ async function runDeleteCommand3(args, env = process.env) {
1144
+ const options = parseWebhooksCommonArgs(args);
1145
+ const apiKey = resolveApiKey5(options, env);
1146
+ if (!apiKey) {
1147
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1148
+ }
1149
+ const id = readFlag12(args, "--id");
1150
+ if (!id) {
1151
+ return { exitCode: 1, error: "Required flag: --id" };
1152
+ }
1153
+ try {
1154
+ const client = await createWebhooksClient(apiKey, options.baseUrl);
1155
+ const result = await client.webhooks.delete(id);
1156
+ console.log(JSON.stringify(result));
1157
+ return { exitCode: 0 };
1158
+ } catch (error) {
1159
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1160
+ }
1161
+ }
1162
+
1163
+ // src/commands/webhooks/list.ts
1164
+ async function runListCommand5(args, env = process.env) {
1165
+ const options = parseWebhooksCommonArgs(args);
1166
+ const apiKey = resolveApiKey5(options, env);
1167
+ if (!apiKey) {
1168
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1169
+ }
1170
+ try {
1171
+ const client = await createWebhooksClient(apiKey, options.baseUrl);
1172
+ const result = await client.webhooks.list();
1173
+ console.log(JSON.stringify(result));
1174
+ return { exitCode: 0 };
1175
+ } catch (error) {
1176
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1177
+ }
1178
+ }
1179
+
1180
+ // src/commands/webhooks/update.ts
1181
+ var POSITIONAL_FLAGS6 = ["--api-key", "--base-url", "--id", "--url", "--event", "--enabled"];
1182
+ async function runUpdateCommand3(args, env = process.env) {
1183
+ const options = parseWebhooksCommonArgs(args);
1184
+ const apiKey = resolveApiKey5(options, env);
1185
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1186
+ const id = readFlag14(args, "--id") || readFirstPositional7(args);
1187
+ if (!id) return { exitCode: 1, error: "Missing webhook id. Pass --id wh_\u2026" };
1188
+ const url = readFlag14(args, "--url");
1189
+ const events = readFlags2(args, "--event");
1190
+ const enabled = parseEnabledFlag(readFlag14(args, "--enabled"));
1191
+ if ("error" in enabled) return { exitCode: 1, error: enabled.error };
1192
+ if (!url && events.length === 0 && enabled.value === void 0) {
1193
+ return { exitCode: 1, error: "Nothing to update. Pass --url, --event, or --enabled true|false." };
1194
+ }
1195
+ const payload = {
1196
+ ...url ? { url } : {},
1197
+ ...events.length > 0 ? { events } : {},
1198
+ ...enabled.value !== void 0 ? { enabled: enabled.value } : {}
1199
+ };
1200
+ try {
1201
+ const client = await createWebhooksClient(apiKey, options.baseUrl);
1202
+ console.log(JSON.stringify(await client.webhooks.update(id, payload)));
1203
+ return { exitCode: 0 };
1204
+ } catch (error) {
1205
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1206
+ }
1207
+ }
1208
+ function readFlag14(args, flag) {
1209
+ const index = args.indexOf(flag);
1210
+ return index === -1 ? void 0 : args[index + 1];
1211
+ }
1212
+ function readFlags2(args, flag) {
1213
+ const values = [];
1214
+ for (let i = 0; i < args.length; i += 1) {
1215
+ if (args[i] === flag && args[i + 1]) values.push(args[i + 1]);
1216
+ }
1217
+ return values;
1218
+ }
1219
+ function readFirstPositional7(args) {
1220
+ for (let i = 0; i < args.length; i += 1) {
1221
+ const arg = args[i];
1222
+ if (arg.startsWith("--")) {
1223
+ if (POSITIONAL_FLAGS6.includes(arg)) i += 1;
1224
+ continue;
1225
+ }
1226
+ return arg;
1227
+ }
1228
+ return void 0;
1229
+ }
1230
+ function parseEnabledFlag(value) {
1231
+ if (value === void 0) return { value: void 0 };
1232
+ if (value === "true") return { value: true };
1233
+ if (value === "false") return { value: false };
1234
+ return { error: "--enabled must be true or false" };
1235
+ }
1236
+
1237
+ // src/commands/keys/list.ts
1238
+ function readFlag15(args, flag) {
1239
+ const index = args.indexOf(flag);
1240
+ if (index === -1) return void 0;
1241
+ return args[index + 1];
1242
+ }
1243
+ async function runListKeysCommandWithClient(args, env = process.env) {
1244
+ const apiKey = readFlag15(args, "--api-key") || env.GROUNDMAIL_API_KEY;
1245
+ const baseUrl = readFlag15(args, "--base-url");
1246
+ if (!apiKey) {
1247
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1248
+ }
1249
+ const { Groundmail } = await import("groundmail");
1250
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1251
+ try {
1252
+ const limitRaw = readFlag15(args, "--limit");
1253
+ const cursor = readFlag15(args, "--cursor");
1254
+ const result = await client.apiKeys.list({
1255
+ ...limitRaw ? { limit: Number(limitRaw) } : {},
1256
+ ...cursor ? { cursor } : {}
1257
+ });
1258
+ console.log(JSON.stringify(result));
1259
+ return { exitCode: 0 };
1260
+ } catch (error) {
1261
+ const message = error instanceof Error ? error.message : String(error);
1262
+ console.error(message);
1263
+ return { exitCode: 1, error: message };
1264
+ }
1265
+ }
1266
+
1267
+ // src/commands/keys/create.ts
1268
+ function readFlag16(args, flag) {
1269
+ const index = args.indexOf(flag);
1270
+ if (index === -1) return void 0;
1271
+ return args[index + 1];
1272
+ }
1273
+ async function runCreateKeyCommandWithClient(args, env = process.env) {
1274
+ const apiKey = readFlag16(args, "--api-key") || env.GROUNDMAIL_API_KEY;
1275
+ const baseUrl = readFlag16(args, "--base-url");
1276
+ if (!apiKey) {
1277
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1278
+ }
1279
+ const name = readFlag16(args, "--name");
1280
+ const scope = readFlag16(args, "--scope");
1281
+ if (scope && scope !== "full" && scope !== "sending") {
1282
+ return { exitCode: 1, error: "--scope must be full or sending" };
1283
+ }
1284
+ const { Groundmail } = await import("groundmail");
1285
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1286
+ try {
1287
+ const result = await client.apiKeys.create({
1288
+ ...name ? { name } : {},
1289
+ ...scope ? { scope } : {}
1290
+ });
1291
+ console.log(JSON.stringify(result));
1292
+ return { exitCode: 0 };
1293
+ } catch (error) {
1294
+ const message = error instanceof Error ? error.message : String(error);
1295
+ console.error(message);
1296
+ return { exitCode: 1, error: message };
1297
+ }
1298
+ }
1299
+
1300
+ // src/commands/keys/delete.ts
1301
+ function readFlag17(args, flag) {
1302
+ const index = args.indexOf(flag);
1303
+ if (index === -1) return void 0;
1304
+ return args[index + 1];
1305
+ }
1306
+ async function runDeleteKeyCommandWithClient(args, env = process.env) {
1307
+ const apiKey = readFlag17(args, "--api-key") || env.GROUNDMAIL_API_KEY;
1308
+ const baseUrl = readFlag17(args, "--base-url");
1309
+ const id = readFlag17(args, "--id");
1310
+ if (!apiKey) {
1311
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1312
+ }
1313
+ if (!id) {
1314
+ return { exitCode: 1, error: "Required: --id <api-key-id>" };
1315
+ }
1316
+ const { Groundmail } = await import("groundmail");
1317
+ const client = new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1318
+ try {
1319
+ const result = await client.apiKeys.remove(id);
1320
+ console.log(JSON.stringify(result));
1321
+ return { exitCode: 0 };
1322
+ } catch (error) {
1323
+ const message = error instanceof Error ? error.message : String(error);
1324
+ console.error(message);
1325
+ return { exitCode: 1, error: message };
1326
+ }
1327
+ }
1328
+
1329
+ // src/commands/suppressions/shared.ts
1330
+ function readFlag18(args, flag) {
1331
+ const index = args.indexOf(flag);
1332
+ if (index === -1) return void 0;
1333
+ return args[index + 1];
1334
+ }
1335
+ function parseSuppressionsCommonArgs(args) {
1336
+ return {
1337
+ apiKey: readFlag18(args, "--api-key"),
1338
+ baseUrl: readFlag18(args, "--base-url")
1339
+ };
1340
+ }
1341
+ function resolveApiKey6(options, env) {
1342
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1343
+ }
1344
+ async function createSuppressionsClient(apiKey, baseUrl) {
1345
+ const { Groundmail } = await import("groundmail");
1346
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1347
+ }
1348
+
1349
+ // src/commands/suppressions/list.ts
1350
+ async function runListCommand6(args, env = process.env) {
1351
+ const options = parseSuppressionsCommonArgs(args);
1352
+ const apiKey = resolveApiKey6(options, env);
1353
+ if (!apiKey) {
1354
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1355
+ }
1356
+ try {
1357
+ const client = await createSuppressionsClient(apiKey, options.baseUrl);
1358
+ const limitRaw = readFlag18(args, "--limit");
1359
+ const cursor = readFlag18(args, "--cursor");
1360
+ const email = readFlag18(args, "--email");
1361
+ const result = await client.suppressions.list({
1362
+ ...limitRaw ? { limit: Number(limitRaw) } : {},
1363
+ ...cursor ? { cursor } : {},
1364
+ ...email ? { email } : {}
1365
+ });
1366
+ console.log(JSON.stringify(result));
1367
+ return { exitCode: 0 };
1368
+ } catch (error) {
1369
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1370
+ }
1371
+ }
1372
+
1373
+ // src/commands/suppressions/add.ts
1374
+ async function runAddCommand2(args, env = process.env) {
1375
+ const options = parseSuppressionsCommonArgs(args);
1376
+ const apiKey = resolveApiKey6(options, env);
1377
+ if (!apiKey) {
1378
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1379
+ }
1380
+ const email = readFlag18(args, "--email") || args.find((a) => a.includes("@") && !a.startsWith("-"));
1381
+ if (!email) {
1382
+ return { exitCode: 1, error: "Missing email. Pass --email user@example.com" };
1383
+ }
1384
+ try {
1385
+ const client = await createSuppressionsClient(apiKey, options.baseUrl);
1386
+ const reason = readFlag18(args, "--reason");
1387
+ const result = await client.suppressions.create({
1388
+ email,
1389
+ ...reason ? { reason } : {}
1390
+ });
1391
+ console.log(JSON.stringify(result));
1392
+ return { exitCode: 0 };
1393
+ } catch (error) {
1394
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1395
+ }
1396
+ }
1397
+
1398
+ // src/commands/suppressions/remove.ts
1399
+ async function runRemoveCommand(args, env = process.env) {
1400
+ const options = parseSuppressionsCommonArgs(args);
1401
+ const apiKey = resolveApiKey6(options, env);
1402
+ if (!apiKey) {
1403
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1404
+ }
1405
+ const idOrEmail = readFlag18(args, "--id") || readFlag18(args, "--email") || args.find((a) => !a.startsWith("-") && a !== "remove" && a !== "delete");
1406
+ if (!idOrEmail) {
1407
+ return { exitCode: 1, error: "Missing id or email. Pass --id <uuid> or --email user@example.com" };
1408
+ }
1409
+ try {
1410
+ const client = await createSuppressionsClient(apiKey, options.baseUrl);
1411
+ const result = await client.suppressions.remove(idOrEmail);
1412
+ console.log(JSON.stringify(result));
1413
+ return { exitCode: 0 };
1414
+ } catch (error) {
1415
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1416
+ }
1417
+ }
1418
+
1419
+ // src/commands/templates/shared.ts
1420
+ function readFlag19(args, flag) {
1421
+ const index = args.indexOf(flag);
1422
+ if (index === -1) return void 0;
1423
+ return args[index + 1];
1424
+ }
1425
+ function parseTemplatesCommonArgs(args) {
1426
+ return {
1427
+ apiKey: readFlag19(args, "--api-key"),
1428
+ baseUrl: readFlag19(args, "--base-url")
1429
+ };
1430
+ }
1431
+ function resolveApiKey7(options, env) {
1432
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
1433
+ }
1434
+ async function createTemplatesClient(apiKey, baseUrl) {
1435
+ const { Groundmail } = await import("groundmail");
1436
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
1437
+ }
1438
+
1439
+ // src/commands/templates/delete.ts
1440
+ var POSITIONAL_FLAGS7 = ["--api-key", "--base-url", "--id", "--alias"];
1441
+ async function runDeleteCommand4(args, env = process.env) {
1442
+ const options = parseTemplatesCommonArgs(args);
1443
+ const apiKey = resolveApiKey7(options, env);
1444
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1445
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional8(args);
1446
+ if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1447
+ try {
1448
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1449
+ console.log(JSON.stringify(await client.templates.remove(idOrAlias)));
1450
+ return { exitCode: 0 };
1451
+ } catch (error) {
1452
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1453
+ }
1454
+ }
1455
+ function readFirstPositional8(args) {
1456
+ for (let i = 0; i < args.length; i += 1) {
1457
+ const arg = args[i];
1458
+ if (arg.startsWith("--")) {
1459
+ if (POSITIONAL_FLAGS7.includes(arg)) i += 1;
1460
+ continue;
1461
+ }
1462
+ return arg;
1463
+ }
1464
+ return void 0;
1465
+ }
1466
+
1467
+ // src/commands/templates/duplicate.ts
1468
+ var POSITIONAL_FLAGS8 = ["--api-key", "--base-url", "--id", "--alias", "--name"];
1469
+ async function runDuplicateCommand(args, env = process.env) {
1470
+ const options = parseTemplatesCommonArgs(args);
1471
+ const apiKey = resolveApiKey7(options, env);
1472
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1473
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional9(args);
1474
+ if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1475
+ const name = readFlag19(args, "--name");
1476
+ try {
1477
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1478
+ console.log(JSON.stringify(await client.templates.duplicate(idOrAlias, name ? { name } : {})));
1479
+ return { exitCode: 0 };
1480
+ } catch (error) {
1481
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1482
+ }
1483
+ }
1484
+ function readFirstPositional9(args) {
1485
+ for (let i = 0; i < args.length; i += 1) {
1486
+ const arg = args[i];
1487
+ if (arg.startsWith("--")) {
1488
+ if (POSITIONAL_FLAGS8.includes(arg)) i += 1;
1489
+ continue;
1490
+ }
1491
+ return arg;
1492
+ }
1493
+ return void 0;
1494
+ }
1495
+
1496
+ // src/commands/templates/get.ts
1497
+ var POSITIONAL_FLAGS9 = ["--api-key", "--base-url", "--id", "--alias"];
1498
+ async function runGetCommand6(args, env = process.env) {
1499
+ const options = parseTemplatesCommonArgs(args);
1500
+ const apiKey = resolveApiKey7(options, env);
1501
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1502
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional10(args);
1503
+ if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1504
+ try {
1505
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1506
+ console.log(JSON.stringify(await client.templates.get(idOrAlias)));
1507
+ return { exitCode: 0 };
1508
+ } catch (error) {
1509
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1510
+ }
1511
+ }
1512
+ function readFirstPositional10(args) {
1513
+ for (let i = 0; i < args.length; i += 1) {
1514
+ const arg = args[i];
1515
+ if (arg.startsWith("--")) {
1516
+ if (POSITIONAL_FLAGS9.includes(arg)) i += 1;
1517
+ continue;
1518
+ }
1519
+ return arg;
1520
+ }
1521
+ return void 0;
1522
+ }
1523
+
1524
+ // src/commands/templates/list.ts
1525
+ async function runListCommand7(args, env = process.env) {
1526
+ const options = parseTemplatesCommonArgs(args);
1527
+ const apiKey = resolveApiKey7(options, env);
1528
+ if (!apiKey) {
1529
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1530
+ }
1531
+ try {
1532
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1533
+ const limitRaw = readFlag19(args, "--limit");
1534
+ const cursor = readFlag19(args, "--cursor");
1535
+ const status = readFlag19(args, "--status");
1536
+ const result = await client.templates.list({
1537
+ ...limitRaw ? { limit: Number(limitRaw) } : {},
1538
+ ...cursor ? { cursor } : {},
1539
+ ...status ? { status } : {}
1540
+ });
1541
+ console.log(JSON.stringify(result));
1542
+ return { exitCode: 0 };
1543
+ } catch (error) {
1544
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1545
+ }
1546
+ }
1547
+
1548
+ // src/commands/templates/publish.ts
1549
+ var POSITIONAL_FLAGS10 = ["--api-key", "--base-url", "--id", "--alias"];
1550
+ async function runPublishCommand(args, env = process.env) {
1551
+ const options = parseTemplatesCommonArgs(args);
1552
+ const apiKey = resolveApiKey7(options, env);
1553
+ if (!apiKey) return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1554
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional11(args);
1555
+ if (!idOrAlias) return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1556
+ try {
1557
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1558
+ console.log(JSON.stringify(await client.templates.publish(idOrAlias)));
1559
+ return { exitCode: 0 };
1560
+ } catch (error) {
1561
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1562
+ }
1563
+ }
1564
+ function readFirstPositional11(args) {
1565
+ for (let i = 0; i < args.length; i += 1) {
1566
+ const arg = args[i];
1567
+ if (arg.startsWith("--")) {
1568
+ if (POSITIONAL_FLAGS10.includes(arg)) i += 1;
1569
+ continue;
1570
+ }
1571
+ return arg;
1572
+ }
1573
+ return void 0;
1574
+ }
1575
+
1576
+ // src/commands/templates/render-source.ts
1577
+ var HTML_EXTENSIONS = [".html", ".htm"];
1578
+ var TEXT_EXTENSIONS = [".txt", ".text"];
1579
+ var MODULE_EXTENSIONS = [".js", ".mjs", ".cjs", ".jsx", ".ts", ".tsx"];
1580
+ var TYPESCRIPT_EXTENSIONS = [".ts", ".tsx", ".jsx"];
1581
+ function extensionOf(filePath) {
1582
+ const match = /\.[^.\/\\]+$/.exec(filePath);
1583
+ return match ? match[0].toLowerCase() : "";
1584
+ }
1585
+ async function defaultReadFile(filePath) {
1586
+ const { readFile: readFile3 } = await import("fs/promises");
1587
+ return readFile3(filePath, "utf8");
1588
+ }
1589
+ async function defaultImportModule(filePath) {
1590
+ const { pathToFileURL } = await import("url");
1591
+ const { resolve } = await import("path");
1592
+ const url = pathToFileURL(resolve(filePath)).href;
1593
+ try {
1594
+ return await import(url);
1595
+ } catch (error) {
1596
+ if (!TYPESCRIPT_EXTENSIONS.includes(extensionOf(filePath))) throw error;
1597
+ try {
1598
+ const specifier = "tsx/esm/api";
1599
+ const tsx = await import(specifier);
1600
+ tsx.register();
1601
+ } catch {
1602
+ throw new Error(
1603
+ `Cannot import ${filePath} directly. Install tsx to push TypeScript or JSX templates (npm install -D tsx), or pre-render the file to .html.`
1604
+ );
1605
+ }
1606
+ return import(url);
1607
+ }
1608
+ }
1609
+ async function loadReactEmailRender() {
1610
+ try {
1611
+ const mod = await import("@react-email/render");
1612
+ const render = mod.render ?? mod.default?.render;
1613
+ if (typeof render !== "function") throw new Error("missing render export");
1614
+ return render;
1615
+ } catch {
1616
+ throw new Error(
1617
+ "Rendering a React email requires @react-email/render. Install it with: npm install @react-email/render react"
1618
+ );
1619
+ }
1620
+ }
1621
+ async function toElement(mod, props) {
1622
+ const record = mod;
1623
+ const exported = record?.default ?? mod;
1624
+ if (typeof exported === "function") {
1625
+ const react = await import("./react-IXBRBSFN.js");
1626
+ const createElement = react.createElement ?? react.default?.createElement;
1627
+ if (typeof createElement !== "function") {
1628
+ throw new Error("Rendering a React email requires react. Install it with: npm install react");
1629
+ }
1630
+ return createElement(exported, props);
1631
+ }
1632
+ if (!exported) {
1633
+ throw new Error("The template module must export a React component as its default export.");
1634
+ }
1635
+ return exported;
1636
+ }
1637
+ async function loadTemplateSource(filePath, options = {}, deps = {}) {
1638
+ const readFile3 = deps.readFile ?? defaultReadFile;
1639
+ const importModule = deps.importModule ?? defaultImportModule;
1640
+ const extension = extensionOf(filePath);
1641
+ if (HTML_EXTENSIONS.includes(extension)) {
1642
+ return { html: await readFile3(filePath) };
1643
+ }
1644
+ if (TEXT_EXTENSIONS.includes(extension)) {
1645
+ return { text: await readFile3(filePath) };
1646
+ }
1647
+ if (!MODULE_EXTENSIONS.includes(extension)) {
1648
+ throw new Error(
1649
+ `Unsupported template file "${filePath}". Use .html, .txt, or a module exporting a React component (${MODULE_EXTENSIONS.join(", ")}).`
1650
+ );
1651
+ }
1652
+ const mod = await importModule(filePath);
1653
+ const element = await toElement(mod, options.props ?? {});
1654
+ const render = await loadReactEmailRender();
1655
+ const html = await render(element);
1656
+ let text;
1657
+ try {
1658
+ text = await render(element, { plainText: true });
1659
+ } catch {
1660
+ text = void 0;
1661
+ }
1662
+ return { html, ...text ? { text } : {} };
1663
+ }
1664
+
1665
+ // src/commands/templates/push.ts
1666
+ var VALUE_FLAGS = /* @__PURE__ */ new Set([
1667
+ "--alias",
1668
+ "--subject",
1669
+ "--name",
1670
+ "--text",
1671
+ "--preheader",
1672
+ "--props",
1673
+ "--api-key",
1674
+ "--base-url"
1675
+ ]);
1676
+ function readPositional(args) {
1677
+ for (let index = 0; index < args.length; index += 1) {
1678
+ const arg = args[index];
1679
+ if (arg.startsWith("--")) {
1680
+ if (VALUE_FLAGS.has(arg)) index += 1;
1681
+ continue;
1682
+ }
1683
+ return arg;
1684
+ }
1685
+ return void 0;
1686
+ }
1687
+ function statusOf(error) {
1688
+ const status = error?.status;
1689
+ return typeof status === "number" ? status : void 0;
1690
+ }
1691
+ async function runPushCommand(args, env = process.env, deps = {}) {
1692
+ const options = parseTemplatesCommonArgs(args);
1693
+ const apiKey = resolveApiKey7(options, env);
1694
+ if (!apiKey) {
1695
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1696
+ }
1697
+ const file = readFlag19(args, "--file") ?? readPositional(args);
1698
+ if (!file) {
1699
+ return { exitCode: 1, error: "Missing template file. Usage: templates push <file> --alias <alias>" };
1700
+ }
1701
+ const alias = readFlag19(args, "--alias");
1702
+ if (!alias) {
1703
+ return { exitCode: 1, error: "Missing --alias. The alias identifies which template to update." };
1704
+ }
1705
+ const subject = readFlag19(args, "--subject");
1706
+ const name = readFlag19(args, "--name");
1707
+ const preheader = readFlag19(args, "--preheader");
1708
+ const textFile = readFlag19(args, "--text");
1709
+ const propsRaw = readFlag19(args, "--props");
1710
+ const shouldPublish = args.includes("--publish");
1711
+ let props = {};
1712
+ if (propsRaw) {
1713
+ try {
1714
+ const parsed = JSON.parse(propsRaw);
1715
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1716
+ throw new Error("not an object");
1717
+ }
1718
+ props = parsed;
1719
+ } catch {
1720
+ return { exitCode: 1, error: `--props must be a JSON object, e.g. --props '{"name":"Ada"}'` };
1721
+ }
1722
+ }
1723
+ try {
1724
+ const source = await loadTemplateSource(file, { props }, deps);
1725
+ if (textFile) {
1726
+ const textSource = await loadTemplateSource(textFile, { props }, deps);
1727
+ source.text = textSource.text ?? textSource.html;
1728
+ }
1729
+ if (!source.html && !source.text) {
1730
+ return { exitCode: 1, error: `${file} produced no content to push.` };
1731
+ }
1732
+ const createClient2 = deps.createClient ?? createTemplatesClient;
1733
+ const client = await createClient2(apiKey, options.baseUrl);
1734
+ let existed = true;
1735
+ try {
1736
+ await client.templates.get(alias);
1737
+ } catch (error) {
1738
+ if (statusOf(error) !== 404) throw error;
1739
+ existed = false;
1740
+ }
1741
+ const body = {
1742
+ format: "html",
1743
+ ...source.html ? { html: source.html } : {},
1744
+ ...source.text ? { text: source.text } : {},
1745
+ ...subject ? { subject } : {},
1746
+ ...preheader ? { preheader } : {},
1747
+ ...name ? { name } : {}
1748
+ };
1749
+ let result;
1750
+ if (existed) {
1751
+ result = await client.templates.update(alias, body);
1752
+ } else {
1753
+ if (!subject) {
1754
+ return {
1755
+ exitCode: 1,
1756
+ error: `Template "${alias}" does not exist yet. Pass --subject to create it.`
1757
+ };
1758
+ }
1759
+ result = await client.templates.create({
1760
+ name: name || alias,
1761
+ subject,
1762
+ alias,
1763
+ ...body
1764
+ });
1765
+ }
1766
+ if (shouldPublish) {
1767
+ result = await client.templates.publish(alias);
1768
+ }
1769
+ console.log(JSON.stringify({ ...result, pushed: { file, alias, created: !existed } }));
1770
+ return { exitCode: 0 };
1771
+ } catch (error) {
1772
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1773
+ }
1774
+ }
1775
+
1776
+ // src/commands/templates/create.ts
1777
+ async function runCreateCommand3(args, env = process.env) {
1778
+ const options = parseTemplatesCommonArgs(args);
1779
+ const apiKey = resolveApiKey7(options, env);
1780
+ if (!apiKey) {
1781
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1782
+ }
1783
+ const name = readFlag19(args, "--name");
1784
+ const subject = readFlag19(args, "--subject");
1785
+ const html = readFlag19(args, "--html");
1786
+ const text = readFlag19(args, "--text");
1787
+ const alias = readFlag19(args, "--alias");
1788
+ const category = readFlag19(args, "--category");
1789
+ const unsubscribeEnabled = args.includes("--unsubscribe-enabled");
1790
+ if (!name) {
1791
+ return { exitCode: 1, error: 'Missing name. Pass --name "Welcome"' };
1792
+ }
1793
+ if (!subject) {
1794
+ return { exitCode: 1, error: 'Missing subject. Pass --subject "Hello {{name}}"' };
1795
+ }
1796
+ if (!html && !text) {
1797
+ return { exitCode: 1, error: 'Missing body. Pass --html "<p>Hi</p>" or --text "Hi"' };
1798
+ }
1799
+ try {
1800
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1801
+ const result = await client.templates.create({
1802
+ name,
1803
+ subject,
1804
+ ...html ? { html } : {},
1805
+ ...text ? { text } : {},
1806
+ ...alias ? { alias } : {},
1807
+ ...category ? { category } : {},
1808
+ ...unsubscribeEnabled ? { unsubscribe_enabled: true } : {}
1809
+ });
1810
+ console.log(JSON.stringify(result));
1811
+ return { exitCode: 0 };
1812
+ } catch (error) {
1813
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1814
+ }
1815
+ }
1816
+
1817
+ // src/commands/templates/update.ts
1818
+ var POSITIONAL_FLAGS11 = [
1819
+ "--api-key",
1820
+ "--base-url",
1821
+ "--id",
1822
+ "--alias",
1823
+ "--set-alias",
1824
+ "--name",
1825
+ "--subject",
1826
+ "--html",
1827
+ "--text",
1828
+ "--variable"
1829
+ ];
1830
+ async function runUpdateCommand4(args, env = process.env) {
1831
+ const options = parseTemplatesCommonArgs(args);
1832
+ const apiKey = resolveApiKey7(options, env);
1833
+ if (!apiKey) {
1834
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1835
+ }
1836
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional12(args);
1837
+ if (!idOrAlias) {
1838
+ return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1839
+ }
1840
+ const name = readFlag19(args, "--name");
1841
+ const subject = readFlag19(args, "--subject");
1842
+ const html = readFlag19(args, "--html");
1843
+ const text = readFlag19(args, "--text");
1844
+ const alias = readFlag19(args, "--set-alias");
1845
+ const variables = readFlags3(args, "--variable");
1846
+ const category = readFlag19(args, "--category");
1847
+ const unsubscribeEnabled = args.includes("--unsubscribe-enabled");
1848
+ const unsubscribeDisabled = args.includes("--no-unsubscribe-enabled");
1849
+ if (!name && !subject && !html && !text && !alias && variables.length === 0 && !category && !unsubscribeEnabled && !unsubscribeDisabled) {
1850
+ return {
1851
+ exitCode: 1,
1852
+ error: "Nothing to update. Pass --name, --subject, --html, --text, --set-alias, --category, --variable, or unsubscribe flags."
1853
+ };
1854
+ }
1855
+ try {
1856
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1857
+ const result = await client.templates.update(idOrAlias, {
1858
+ ...name ? { name } : {},
1859
+ ...subject ? { subject } : {},
1860
+ ...html ? { html } : {},
1861
+ ...text ? { text } : {},
1862
+ ...alias ? { alias } : {},
1863
+ ...variables.length > 0 ? { variables } : {},
1864
+ ...category ? { category } : {},
1865
+ ...unsubscribeEnabled ? { unsubscribe_enabled: true } : {},
1866
+ ...unsubscribeDisabled ? { unsubscribe_enabled: false } : {}
1867
+ });
1868
+ console.log(JSON.stringify(result));
1869
+ return { exitCode: 0 };
1870
+ } catch (error) {
1871
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1872
+ }
1873
+ }
1874
+ function readFlags3(args, flag) {
1875
+ const values = [];
1876
+ for (let i = 0; i < args.length; i += 1) {
1877
+ if (args[i] === flag && args[i + 1]) values.push(args[i + 1]);
1878
+ }
1879
+ return values;
1880
+ }
1881
+ function readFirstPositional12(args) {
1882
+ for (let i = 0; i < args.length; i += 1) {
1883
+ const arg = args[i];
1884
+ if (arg.startsWith("--")) {
1885
+ if (POSITIONAL_FLAGS11.includes(arg)) i += 1;
1886
+ continue;
1887
+ }
1888
+ return arg;
1889
+ }
1890
+ return void 0;
1891
+ }
1892
+
1893
+ // src/commands/templates/from-starter.ts
1894
+ var POSITIONAL_FLAGS12 = ["--api-key", "--base-url", "--alias"];
1895
+ function readFirstPositional13(args) {
1896
+ for (let i = 0; i < args.length; i += 1) {
1897
+ const arg = args[i];
1898
+ if (arg.startsWith("--")) {
1899
+ if (POSITIONAL_FLAGS12.includes(arg)) i += 1;
1900
+ continue;
1901
+ }
1902
+ return arg;
1903
+ }
1904
+ return void 0;
1905
+ }
1906
+ async function runFromStarterCommand(args, env = process.env) {
1907
+ const options = parseTemplatesCommonArgs(args);
1908
+ const apiKey = resolveApiKey7(options, env);
1909
+ if (!apiKey) {
1910
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1911
+ }
1912
+ const alias = readFlag19(args, "--alias") || readFirstPositional13(args);
1913
+ if (!alias) {
1914
+ return {
1915
+ exitCode: 1,
1916
+ error: "Missing starter alias. Pass password-reset (or --alias welcome). List: groundmail templates starters"
1917
+ };
1918
+ }
1919
+ try {
1920
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1921
+ console.log(JSON.stringify(await client.templates.fromStarter(alias)));
1922
+ return { exitCode: 0 };
1923
+ } catch (error) {
1924
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1925
+ }
1926
+ }
1927
+ async function runListStartersCommand(args, env = process.env) {
1928
+ const options = parseTemplatesCommonArgs(args);
1929
+ const apiKey = resolveApiKey7(options, env);
1930
+ if (!apiKey) {
1931
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1932
+ }
1933
+ try {
1934
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1935
+ console.log(JSON.stringify(await client.templates.listStarters()));
1936
+ return { exitCode: 0 };
1937
+ } catch (error) {
1938
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1939
+ }
1940
+ }
1941
+
1942
+ // src/commands/templates/versions.ts
1943
+ var POSITIONAL_FLAGS13 = ["--api-key", "--base-url", "--id", "--alias", "--version", "--from", "--to"];
1944
+ function readFirstPositional14(args) {
1945
+ for (let i = 0; i < args.length; i += 1) {
1946
+ const arg = args[i];
1947
+ if (arg.startsWith("--")) {
1948
+ if (POSITIONAL_FLAGS13.includes(arg)) i += 1;
1949
+ continue;
1950
+ }
1951
+ return arg;
1952
+ }
1953
+ return void 0;
1954
+ }
1955
+ async function runVersionsCommand(args, env = process.env) {
1956
+ const options = parseTemplatesCommonArgs(args);
1957
+ const apiKey = resolveApiKey7(options, env);
1958
+ if (!apiKey) {
1959
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1960
+ }
1961
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
1962
+ if (!idOrAlias) {
1963
+ return { exitCode: 1, error: "Missing template id or alias. Pass --id tpl_\u2026 or --alias welcome" };
1964
+ }
1965
+ try {
1966
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1967
+ console.log(JSON.stringify(await client.templates.listVersions(idOrAlias)));
1968
+ return { exitCode: 0 };
1969
+ } catch (error) {
1970
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1971
+ }
1972
+ }
1973
+ async function runRestoreCommand(args, env = process.env) {
1974
+ const options = parseTemplatesCommonArgs(args);
1975
+ const apiKey = resolveApiKey7(options, env);
1976
+ if (!apiKey) {
1977
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
1978
+ }
1979
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
1980
+ const versionRaw = readFlag19(args, "--version");
1981
+ const version2 = versionRaw ? Number.parseInt(versionRaw, 10) : NaN;
1982
+ if (!idOrAlias || !Number.isFinite(version2) || version2 < 1) {
1983
+ return {
1984
+ exitCode: 1,
1985
+ error: "Usage: groundmail templates restore --id <id|alias> --version <n>"
1986
+ };
1987
+ }
1988
+ try {
1989
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
1990
+ console.log(JSON.stringify(await client.templates.restoreVersion(idOrAlias, version2)));
1991
+ return { exitCode: 0 };
1992
+ } catch (error) {
1993
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
1994
+ }
1995
+ }
1996
+ async function runTestSendCommand(args, env = process.env) {
1997
+ const options = parseTemplatesCommonArgs(args);
1998
+ const apiKey = resolveApiKey7(options, env);
1999
+ if (!apiKey) {
2000
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2001
+ }
2002
+ const idOrAlias = readFlag19(args, "--id") || readFlag19(args, "--alias") || readFirstPositional14(args);
2003
+ const from = readFlag19(args, "--from");
2004
+ const to = readFlag19(args, "--to");
2005
+ if (!idOrAlias || !from || !to) {
2006
+ return {
2007
+ exitCode: 1,
2008
+ error: "Usage: groundmail templates test-send --id <id|alias> --from <email> --to <email>"
2009
+ };
2010
+ }
2011
+ try {
2012
+ const client = await createTemplatesClient(apiKey, options.baseUrl);
2013
+ console.log(JSON.stringify(await client.templates.testSend(idOrAlias, { from, to })));
2014
+ return { exitCode: 0 };
2015
+ } catch (error) {
2016
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
2017
+ }
2018
+ }
2019
+
2020
+ // src/commands/integrations/shared.ts
2021
+ function readFlag20(args, flag) {
2022
+ const index = args.indexOf(flag);
2023
+ if (index === -1) return void 0;
2024
+ return args[index + 1];
2025
+ }
2026
+ function parseIntegrationsCommonArgs(args) {
2027
+ return {
2028
+ apiKey: readFlag20(args, "--api-key"),
2029
+ baseUrl: readFlag20(args, "--base-url")
2030
+ };
2031
+ }
2032
+ function resolveApiKey8(options, env) {
2033
+ return options.apiKey || env.GROUNDMAIL_API_KEY || null;
2034
+ }
2035
+ async function createIntegrationsClient(apiKey, baseUrl) {
2036
+ const { Groundmail } = await import("groundmail");
2037
+ return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
2038
+ }
2039
+
2040
+ // src/commands/integrations/twilio.ts
2041
+ async function runTwilioStatusCommand(args, env = process.env) {
2042
+ const options = parseIntegrationsCommonArgs(args);
2043
+ const apiKey = resolveApiKey8(options, env);
2044
+ if (!apiKey) {
2045
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2046
+ }
2047
+ try {
2048
+ const client = await createIntegrationsClient(apiKey, options.baseUrl);
2049
+ const result = await client.integrations.getTwilio();
2050
+ console.log(JSON.stringify(result));
2051
+ return { exitCode: 0 };
2052
+ } catch (error) {
2053
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
2054
+ }
2055
+ }
2056
+ async function runTwilioConnectCommand(args, env = process.env) {
2057
+ const options = parseIntegrationsCommonArgs(args);
2058
+ const apiKey = resolveApiKey8(options, env);
2059
+ if (!apiKey) {
2060
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2061
+ }
2062
+ const accountSid = readFlag20(args, "--account-sid") || env.TWILIO_ACCOUNT_SID || env.TWILIO_SID || "";
2063
+ const authToken = readFlag20(args, "--auth-token") || env.TWILIO_AUTH_TOKEN || env.TWILIO_TOKEN || "";
2064
+ const defaultFrom = readFlag20(args, "--from") || readFlag20(args, "--default-from") || env.TWILIO_DEFAULT_FROM || "";
2065
+ const messagingServiceSid = readFlag20(args, "--messaging-service-sid") || readFlag20(args, "--messaging-sid") || env.TWILIO_MESSAGING_SERVICE_SID || "";
2066
+ if (!accountSid.trim() || !authToken.trim()) {
2067
+ return {
2068
+ exitCode: 1,
2069
+ error: "Required: --account-sid and --auth-token (or TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN)."
2070
+ };
2071
+ }
2072
+ if (!defaultFrom.trim() && !messagingServiceSid.trim()) {
2073
+ return {
2074
+ exitCode: 1,
2075
+ error: "Required: --from or --messaging-service-sid (or TWILIO_DEFAULT_FROM / TWILIO_MESSAGING_SERVICE_SID)."
2076
+ };
2077
+ }
2078
+ try {
2079
+ const client = await createIntegrationsClient(apiKey, options.baseUrl);
2080
+ const result = await client.integrations.connectTwilio({
2081
+ accountSid: accountSid.trim(),
2082
+ authToken: authToken.trim(),
2083
+ ...defaultFrom.trim() ? { defaultFrom: defaultFrom.trim() } : {},
2084
+ ...messagingServiceSid.trim() ? { messagingServiceSid: messagingServiceSid.trim() } : {}
2085
+ });
2086
+ console.log(JSON.stringify(result));
2087
+ return { exitCode: 0 };
2088
+ } catch (error) {
2089
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
2090
+ }
2091
+ }
2092
+ async function runTwilioDisconnectCommand(args, env = process.env) {
2093
+ const options = parseIntegrationsCommonArgs(args);
2094
+ const apiKey = resolveApiKey8(options, env);
2095
+ if (!apiKey) {
2096
+ return { exitCode: 1, error: "Missing API key. Set GROUNDMAIL_API_KEY or pass --api-key." };
2097
+ }
2098
+ try {
2099
+ const client = await createIntegrationsClient(apiKey, options.baseUrl);
2100
+ const result = await client.integrations.disconnectTwilio();
2101
+ console.log(JSON.stringify(result));
2102
+ return { exitCode: 0 };
2103
+ } catch (error) {
2104
+ return { exitCode: 1, error: error instanceof Error ? error.message : String(error) };
2105
+ }
2106
+ }
2107
+
2108
+ // src/commands/login.ts
2109
+ import { spawn } from "child_process";
2110
+
2111
+ // src/session/args.ts
2112
+ var COMMON_VALUE_FLAGS = ["--api-key", "--base-url", "--workspace"];
2113
+ var COMMON_BOOLEAN_FLAGS = ["--json"];
2114
+ function parseArgs(argv, spec) {
2115
+ const valueFlags = new Set(spec.values ?? []);
2116
+ const booleanFlags = new Set(spec.booleans ?? []);
2117
+ const values = {};
2118
+ const booleans = {};
2119
+ const positionals = [];
2120
+ for (let i = 0; i < argv.length; i++) {
2121
+ const arg = argv[i];
2122
+ if (arg === "--") {
2123
+ positionals.push(...argv.slice(i + 1));
2124
+ break;
2125
+ }
2126
+ if (!arg.startsWith("--") || arg === "-") {
2127
+ positionals.push(arg);
2128
+ continue;
2129
+ }
2130
+ const eq = arg.indexOf("=");
2131
+ const name = eq === -1 ? arg : arg.slice(0, eq);
2132
+ if (valueFlags.has(name)) {
2133
+ const value = eq === -1 ? argv[i + 1] : arg.slice(eq + 1);
2134
+ if (value === void 0 || eq === -1 && value.startsWith("--")) {
2135
+ return { ok: false, error: `${name} needs a value.` };
2136
+ }
2137
+ values[name] = value;
2138
+ if (eq === -1) i++;
2139
+ continue;
2140
+ }
2141
+ if (booleanFlags.has(name) && eq === -1) {
2142
+ booleans[name] = true;
2143
+ continue;
2144
+ }
2145
+ const negated = name.startsWith("--no-") ? `--${name.slice("--no-".length)}` : null;
2146
+ if (negated && booleanFlags.has(negated) && eq === -1) {
2147
+ booleans[negated] = false;
2148
+ continue;
2149
+ }
2150
+ const known = [...valueFlags, ...booleanFlags].sort().join(", ");
2151
+ return { ok: false, error: `Unknown flag ${name}.${known ? ` This command takes: ${known}.` : ""}` };
2152
+ }
2153
+ return { ok: true, args: { values, booleans, positionals } };
2154
+ }
2155
+ function wantsJson(args, stdout = process.stdout) {
2156
+ if (args.booleans["--json"] !== void 0) return args.booleans["--json"];
2157
+ return !stdout.isTTY;
2158
+ }
2159
+ var EXIT_OK = 0;
2160
+ var EXIT_FAILED = 1;
2161
+ var EXIT_USAGE = 2;
2162
+
2163
+ // src/session/brand.ts
2164
+ var GROUNDMAIL = {
2165
+ bin: "groundmail",
2166
+ product: "Groundmail",
2167
+ configDirName: "groundmail",
2168
+ keyEnvVar: "GROUNDMAIL_API_KEY",
2169
+ npx: "npx -y groundmail-cli@latest"
2170
+ };
2171
+ function cliBrand(_env = process.env) {
2172
+ return GROUNDMAIL;
2173
+ }
2174
+ var SDK_DEFAULT_API_URL = "https://api.groundmail.dev";
2175
+ var DEFAULT_API_URL_ENV = "GROUNDMAIL_DEFAULT_API_URL";
2176
+ function defaultApiUrl(env = process.env) {
2177
+ return trimUrl(env[DEFAULT_API_URL_ENV]) || SDK_DEFAULT_API_URL;
2178
+ }
2179
+ function explicitApiUrl(env = process.env) {
2180
+ return trimUrl(env.GROUNDMAIL_API_URL) || null;
2181
+ }
2182
+ function trimUrl(value) {
2183
+ return (value ?? "").trim().replace(/\/+$/, "");
2184
+ }
2185
+
2186
+ // src/session/config.ts
2187
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
2188
+ import { homedir } from "os";
2189
+ import { dirname, join } from "path";
2190
+ function configDir(env = process.env) {
2191
+ const override = env.GROUNDMAIL_CONFIG_DIR?.trim();
2192
+ if (override) return override;
2193
+ const base = env.XDG_CONFIG_HOME?.trim() || (process.platform === "win32" ? env.APPDATA?.trim() || join(homedir(), "AppData", "Roaming") : "") || join(homedir(), ".config");
2194
+ return join(base, cliBrand(env).configDirName);
2195
+ }
2196
+ function configPath(env = process.env) {
2197
+ return join(configDir(env), "config.json");
2198
+ }
2199
+ function loadConfig(env = process.env) {
2200
+ try {
2201
+ const parsed = JSON.parse(readFileSync(configPath(env), "utf8"));
2202
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
2203
+ const record = parsed;
2204
+ const workspaces = {};
2205
+ for (const [id, entry] of Object.entries(record.workspaces ?? {})) {
2206
+ if (entry && typeof entry.apiKey === "string" && entry.apiKey && typeof entry.id === "string") {
2207
+ workspaces[id] = entry;
2208
+ }
2209
+ }
2210
+ return {
2211
+ ...typeof record.current === "string" && workspaces[record.current] ? { current: record.current } : {},
2212
+ workspaces,
2213
+ ...record.pendingLogin && typeof record.pendingLogin.deviceCode === "string" ? { pendingLogin: record.pendingLogin } : {}
2214
+ };
2215
+ } catch {
2216
+ return {};
2217
+ }
2218
+ }
2219
+ function saveConfig(config, env = process.env) {
2220
+ const file = configPath(env);
2221
+ mkdirSync(dirname(file), { recursive: true, mode: 448 });
2222
+ const tmp = `${file}.${process.pid}.tmp`;
2223
+ writeFileSync(tmp, `${JSON.stringify(config, null, 2)}
2224
+ `, { mode: 384 });
2225
+ renameSync(tmp, file);
2226
+ try {
2227
+ chmodSync(file, 384);
2228
+ } catch {
2229
+ }
2230
+ }
2231
+ function updateConfig(change, env = process.env) {
2232
+ const next = change(loadConfig(env));
2233
+ saveConfig(next, env);
2234
+ return next;
2235
+ }
2236
+ function savedWorkspaces(config) {
2237
+ return Object.values(config.workspaces ?? {}).sort((a, b) => a.name.localeCompare(b.name));
2238
+ }
2239
+ function findSavedWorkspace(config, wanted) {
2240
+ const all = savedWorkspaces(config);
2241
+ const key = wanted.trim();
2242
+ const byId = all.find((workspace) => workspace.id === key);
2243
+ if (byId) return { ok: true, workspace: byId };
2244
+ const byName = all.filter((workspace) => workspace.name.trim().toLowerCase() === key.toLowerCase());
2245
+ if (byName.length === 1) return { ok: true, workspace: byName[0] };
2246
+ return { ok: false, reason: byName.length ? "ambiguous" : "none", matches: byName };
2247
+ }
2248
+
2249
+ // src/session/credentials.ts
2250
+ function envApiKey(env = process.env) {
2251
+ return env.GROUNDMAIL_API_KEY?.trim() || null;
2252
+ }
2253
+ function currentSavedWorkspace(config, env = process.env) {
2254
+ const brand = cliBrand(env);
2255
+ const all = savedWorkspaces(config);
2256
+ if (config.current && config.workspaces?.[config.current]) {
2257
+ return { ok: true, workspace: config.workspaces[config.current] };
2258
+ }
2259
+ if (all.length === 1) return { ok: true, workspace: all[0] };
2260
+ if (all.length === 0) {
2261
+ return {
2262
+ ok: false,
2263
+ reason: "none",
2264
+ error: `Not signed in. Run: ${brand.bin} login (it prints a link to approve in the browser). Or set ${brand.keyEnvVar}.`
2265
+ };
2266
+ }
2267
+ return {
2268
+ ok: false,
2269
+ reason: "ambiguous",
2270
+ error: `Signed in to ${all.length} workspaces on this computer and none is picked: ${all.map((workspace) => `"${workspace.name}"`).join(", ")}. Pick one: ${brand.bin} workspaces use <name>, or pass --workspace <name>.`
2271
+ };
2272
+ }
2273
+ function resolveAuth(flags, env = process.env, config = loadConfig(env)) {
2274
+ const brand = cliBrand(env);
2275
+ const flagUrl = trimUrl(flags.baseUrl) || null;
2276
+ const urlFor = (workspace) => flagUrl || explicitApiUrl(env) || trimUrl(workspace?.apiUrl) || defaultApiUrl(env);
2277
+ const flagKey = flags.apiKey?.trim();
2278
+ if (flagKey) return { ok: true, auth: { apiKey: flagKey, baseUrl: urlFor(null), source: "flag", workspace: null } };
2279
+ if (flags.workspace?.trim()) {
2280
+ const match = findSavedWorkspace(config, flags.workspace);
2281
+ if (!match.ok) {
2282
+ const saved = savedWorkspaces(config);
2283
+ return {
2284
+ ok: false,
2285
+ error: match.reason === "ambiguous" ? `More than one saved workspace is called "${flags.workspace}". Use its id: ${match.matches.map((w) => w.id).join(", ")}.` : `Not signed in to "${flags.workspace}" on this computer.${saved.length ? ` Signed in: ${saved.map((w) => `"${w.name}"`).join(", ")}.` : ""} To add it: ${brand.bin} login --workspace "${flags.workspace}".`
2286
+ };
2287
+ }
2288
+ return {
2289
+ ok: true,
2290
+ auth: { apiKey: match.workspace.apiKey, baseUrl: urlFor(match.workspace), source: "saved", workspace: match.workspace }
2291
+ };
2292
+ }
2293
+ const fromEnv = envApiKey(env);
2294
+ if (fromEnv) return { ok: true, auth: { apiKey: fromEnv, baseUrl: urlFor(null), source: "env", workspace: null } };
2295
+ const current = currentSavedWorkspace(config, env);
2296
+ if (!current.ok) return { ok: false, error: current.error };
2297
+ return {
2298
+ ok: true,
2299
+ auth: { apiKey: current.workspace.apiKey, baseUrl: urlFor(current.workspace), source: "saved", workspace: current.workspace }
2300
+ };
2301
+ }
2302
+ function applySavedSession(argv, env = process.env, config) {
2303
+ const hasFlag = (flag) => argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
2304
+ let workspace = null;
2305
+ let notice;
2306
+ if (!hasFlag("--api-key") && !envApiKey(env)) {
2307
+ const current = currentSavedWorkspace(config ?? loadConfig(env), env);
2308
+ if (current.ok) {
2309
+ workspace = current.workspace;
2310
+ env.GROUNDMAIL_API_KEY = current.workspace.apiKey;
2311
+ } else if (current.reason === "ambiguous") {
2312
+ notice = current.error;
2313
+ }
2314
+ }
2315
+ if (hasFlag("--base-url")) return { argv, notice };
2316
+ const url = explicitApiUrl(env) || trimUrl(workspace?.apiUrl) || trimUrl(env.GROUNDMAIL_DEFAULT_API_URL);
2317
+ return { argv: url ? [...argv, "--base-url", url] : argv, notice };
2318
+ }
2319
+
2320
+ // package.json
2321
+ var version = "0.15.0";
2322
+
2323
+ // src/user-agent.ts
2324
+ function buildUserAgent(own) {
2325
+ return `${own.name}/${own.version} node/${process.versions.node}`;
2326
+ }
2327
+ function withUserAgent(init, userAgent) {
2328
+ const headers = init?.headers;
2329
+ if (headers instanceof Headers) {
2330
+ const next = new Headers(headers);
2331
+ if (!next.has("user-agent")) next.set("User-Agent", userAgent);
2332
+ return { ...init, headers: next };
2333
+ }
2334
+ if (Array.isArray(headers)) {
2335
+ const has2 = headers.some(([key]) => key.toLowerCase() === "user-agent");
2336
+ return { ...init, headers: has2 ? headers : [...headers, ["User-Agent", userAgent]] };
2337
+ }
2338
+ const record = headers ?? {};
2339
+ const has = Object.keys(record).some((key) => key.toLowerCase() === "user-agent");
2340
+ return { ...init, headers: has ? record : { ...record, "User-Agent": userAgent } };
2341
+ }
2342
+ function fetchWithUserAgent(userAgent) {
2343
+ return ((input, init) => globalThis.fetch(input, withUserAgent(init, userAgent)));
2344
+ }
2345
+
2346
+ // src/client-info.ts
2347
+ var CLI_PACKAGE = { name: "groundmail-cli", version };
2348
+
2349
+ // src/session/http.ts
2350
+ var CliRequestError = class extends Error {
2351
+ };
2352
+ async function apiRequest(baseUrl, path, options = {}) {
2353
+ const doFetch = fetchWithUserAgent(buildUserAgent(CLI_PACKAGE));
2354
+ const url = `${baseUrl.replace(/\/+$/, "")}${path}`;
2355
+ let response;
2356
+ try {
2357
+ response = await doFetch(url, {
2358
+ method: options.method ?? (options.body === void 0 ? "GET" : "POST"),
2359
+ headers: {
2360
+ Accept: "application/json",
2361
+ ...options.body === void 0 ? {} : { "Content-Type": "application/json" },
2362
+ ...options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {}
2363
+ },
2364
+ ...options.body === void 0 ? {} : { body: JSON.stringify(options.body) }
2365
+ });
2366
+ } catch (error) {
2367
+ const reason = error instanceof Error ? error.message : String(error);
2368
+ throw new CliRequestError(`Could not reach ${baseUrl}: ${reason}`);
2369
+ }
2370
+ const text = await response.text();
2371
+ let body = {};
2372
+ try {
2373
+ const parsed = text ? JSON.parse(text) : {};
2374
+ body = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : { value: parsed };
2375
+ } catch {
2376
+ body = { error: text.slice(0, 300) || `HTTP ${response.status}` };
2377
+ }
2378
+ return { ok: response.ok, status: response.status, body };
2379
+ }
2380
+ function sentence(text) {
2381
+ return /[.!?…)]$/.test(text.trim()) ? text.trim() : `${text.trim()}.`;
2382
+ }
2383
+ function errorMessage(response, fallback) {
2384
+ const error = response.body.error;
2385
+ if (typeof error === "string" && error.trim()) return error.trim();
2386
+ if (error && typeof error === "object") {
2387
+ const message = error.message;
2388
+ if (typeof message === "string" && message.trim()) return message.trim();
2389
+ }
2390
+ return `${fallback} (HTTP ${response.status}).`;
2391
+ }
2392
+
2393
+ // src/session/io.ts
2394
+ var processIo = {
2395
+ out: (text) => process.stdout.write(text.endsWith("\n") ? text : `${text}
2396
+ `),
2397
+ err: (text) => process.stderr.write(text.endsWith("\n") ? text : `${text}
2398
+ `),
2399
+ get isTTY() {
2400
+ return Boolean(process.stdout.isTTY);
2401
+ }
2402
+ };
2403
+ function printJson(io, value) {
2404
+ io.out(JSON.stringify(value, null, 2));
2405
+ }
2406
+
2407
+ // src/commands/login.ts
2408
+ var realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2409
+ function openInBrowser(url) {
2410
+ const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
2411
+ try {
2412
+ const child = spawn(cmd, args, { stdio: "ignore", detached: true });
2413
+ child.on("error", () => {
2414
+ });
2415
+ child.unref();
2416
+ } catch {
2417
+ }
2418
+ }
2419
+ function sourceLabel(source, env) {
2420
+ if (source === "flag") return "--api-key";
2421
+ if (source === "env") return cliBrand(env).keyEnvVar;
2422
+ return "saved login";
2423
+ }
2424
+ async function runLoginCommand(argv, deps = {}) {
2425
+ const io = deps.io ?? processIo;
2426
+ const env = deps.env ?? process.env;
2427
+ const sleep = deps.sleep ?? realSleep;
2428
+ const now = deps.now ?? Date.now;
2429
+ const brand = cliBrand(env);
2430
+ const parsed = parseArgs(argv, {
2431
+ values: ["--base-url", "--workspace"],
2432
+ booleans: ["--json", "--browser", "--wait", "--new"]
2433
+ });
2434
+ if (!parsed.ok) return { exitCode: EXIT_USAGE, error: `${parsed.error}
2435
+ Usage: ${brand.bin} login [--workspace <name>] [--new] [--no-browser] [--wait|--no-wait] [--json]` };
2436
+ const { args } = parsed;
2437
+ if (args.positionals.length) {
2438
+ return { exitCode: EXIT_USAGE, error: `${brand.bin} login takes no arguments. To sign in to a workspace by name: ${brand.bin} login --workspace "<name>".` };
2439
+ }
2440
+ const json = wantsJson(args, io);
2441
+ const wait = args.booleans["--wait"] ?? io.isTTY;
2442
+ const browser = args.booleans["--browser"] ?? true;
2443
+ const apiUrl = trimUrl(args.values["--base-url"]) || explicitApiUrl(env) || defaultApiUrl(env);
2444
+ const workspaceHint = args.values["--workspace"]?.trim() || null;
2445
+ try {
2446
+ const config = loadConfig(env);
2447
+ let login = config.pendingLogin;
2448
+ const resumed = Boolean(
2449
+ !args.booleans["--new"] && login && login.apiUrl === apiUrl && login.expiresAt > now() + 5e3 && (login.workspace ?? null) === workspaceHint
2450
+ );
2451
+ if (!resumed && !workspaceHint && !args.booleans["--new"]) {
2452
+ const current = currentSavedWorkspace(config, env);
2453
+ if (current.ok && (trimUrl(current.workspace.apiUrl) || defaultApiUrl(env)) === apiUrl) {
2454
+ const next = `To sign in to another workspace: ${brand.bin} login --workspace "<name>". To sign in as someone else: ${brand.bin} logout, then ${brand.bin} login.`;
2455
+ if (json) {
2456
+ printJson(io, {
2457
+ status: "signed_in",
2458
+ already: true,
2459
+ workspace: { id: current.workspace.id, name: current.workspace.name },
2460
+ email: current.workspace.email ?? null,
2461
+ config_path: configPath(env),
2462
+ next
2463
+ });
2464
+ } else {
2465
+ io.out(`Already signed in${current.workspace.email ? ` as ${current.workspace.email}` : ""} to ${current.workspace.name}.
2466
+ ${next}`);
2467
+ }
2468
+ return { exitCode: EXIT_OK };
2469
+ }
2470
+ }
2471
+ if (!resumed) {
2472
+ const start = await apiRequest(apiUrl, "/cli/login", { body: workspaceHint ? { workspace: workspaceHint } : {}, env });
2473
+ if (!start.ok) return { exitCode: EXIT_FAILED, error: errorMessage(start, "Could not start the sign-in") };
2474
+ const body = start.body;
2475
+ if (typeof body.device_code !== "string" || typeof body.user_code !== "string" || typeof body.verification_url !== "string") {
2476
+ return { exitCode: EXIT_FAILED, error: `Unexpected answer from ${apiUrl}/cli/login. Is --base-url right?` };
2477
+ }
2478
+ login = {
2479
+ deviceCode: body.device_code,
2480
+ userCode: body.user_code,
2481
+ url: body.verification_url,
2482
+ interval: Math.max(1, Number(body.interval) || 2),
2483
+ expiresAt: now() + (Number(body.expires_in) || 600) * 1e3,
2484
+ apiUrl,
2485
+ workspace: workspaceHint
2486
+ };
2487
+ const pending = login;
2488
+ updateConfig((current) => ({ ...current, pendingLogin: pending }), env);
2489
+ }
2490
+ const active = login;
2491
+ const link = `${resumed ? "Still waiting for approval" : `Sign in to ${brand.product}`}: open this link and approve code ${active.userCode}
2492
+ ${active.url}`;
2493
+ if (!json) {
2494
+ io.out(`${link}${wait ? "\nWaiting\u2026 (Ctrl-C to stop; run the same command again to pick up where you left off)" : ""}`);
2495
+ } else if (wait) {
2496
+ io.err(link);
2497
+ }
2498
+ if (browser && !resumed && !env.CI) (deps.openBrowser ?? openInBrowser)(active.url);
2499
+ for (; ; ) {
2500
+ const poll = await apiRequest(apiUrl, "/cli/login/token", { body: { device_code: active.deviceCode }, env });
2501
+ if (!poll.ok) {
2502
+ if (poll.status < 500 && poll.status !== 429) {
2503
+ updateConfig(({ pendingLogin: _drop, ...rest }) => rest, env);
2504
+ }
2505
+ return { exitCode: EXIT_FAILED, error: errorMessage(poll, "The sign-in check failed") };
2506
+ }
2507
+ const status = poll.body.status;
2508
+ if (status === "approved" && typeof poll.body.api_key === "string") {
2509
+ return finishLogin(poll.body, active, { io, env, json });
2510
+ }
2511
+ if (status === "denied") {
2512
+ updateConfig(({ pendingLogin: _drop, ...rest }) => rest, env);
2513
+ return { exitCode: EXIT_FAILED, error: `The sign-in was canceled in the browser. Run ${brand.bin} login to start again.` };
2514
+ }
2515
+ if (status !== "pending") {
2516
+ updateConfig(({ pendingLogin: _drop, ...rest }) => rest, env);
2517
+ return { exitCode: EXIT_FAILED, error: `The sign-in code expired or was already used. Run ${brand.bin} login again.` };
2518
+ }
2519
+ if (!wait || now() + active.interval * 1e3 > active.expiresAt) {
2520
+ const next = `Not signed in yet. Approve code ${active.userCode} in the browser, then run ${brand.bin} login again to finish.`;
2521
+ if (json) {
2522
+ printJson(io, {
2523
+ status: "pending",
2524
+ user_code: active.userCode,
2525
+ verification_url: active.url,
2526
+ expires_at: new Date(active.expiresAt).toISOString(),
2527
+ next
2528
+ });
2529
+ } else {
2530
+ io.out(next);
2531
+ }
2532
+ return { exitCode: EXIT_OK };
2533
+ }
2534
+ await sleep(active.interval * 1e3);
2535
+ }
2536
+ } catch (error) {
2537
+ if (error instanceof CliRequestError) return { exitCode: EXIT_FAILED, error: error.message };
2538
+ throw error;
2539
+ }
2540
+ }
2541
+ function finishLogin(body, login, { io, env, json }) {
2542
+ const brand = cliBrand(env);
2543
+ const workspace = body.workspace ?? {};
2544
+ const user = body.user ?? {};
2545
+ const key = body.key ?? {};
2546
+ const id = typeof workspace.id === "string" && workspace.id ? workspace.id : "default";
2547
+ const saved = {
2548
+ id,
2549
+ name: typeof workspace.name === "string" && workspace.name ? workspace.name : "Workspace",
2550
+ apiKey: body.api_key,
2551
+ ...typeof key.id === "string" ? { keyId: key.id } : {},
2552
+ ...typeof key.prefix === "string" ? { keyPrefix: key.prefix } : {},
2553
+ ...login.apiUrl !== defaultApiUrl(env) ? { apiUrl: login.apiUrl } : {},
2554
+ email: typeof user.email === "string" ? user.email : null,
2555
+ savedAt: (/* @__PURE__ */ new Date()).toISOString()
2556
+ };
2557
+ const config = updateConfig(({ pendingLogin: _drop, ...rest }) => ({
2558
+ ...rest,
2559
+ workspaces: { ...rest.workspaces ?? {}, [id]: saved },
2560
+ current: id
2561
+ }), env);
2562
+ const others = savedWorkspaces(config).filter((entry) => entry.id !== id);
2563
+ const envKey = envApiKey(env);
2564
+ const envNote = envKey ? `${sourceLabel("env", env)} is set in this environment and is used instead of the saved key until you unset it.` : null;
2565
+ if (json) {
2566
+ printJson(io, {
2567
+ status: "signed_in",
2568
+ user: body.user ?? null,
2569
+ workspace: { id: saved.id, name: saved.name },
2570
+ key: { id: saved.keyId ?? null, prefix: saved.keyPrefix ?? null },
2571
+ config_path: configPath(env),
2572
+ other_workspaces: others.map((entry) => ({ id: entry.id, name: entry.name })),
2573
+ ...envNote ? { note: envNote } : {}
2574
+ });
2575
+ return { exitCode: EXIT_OK };
2576
+ }
2577
+ const lines = [
2578
+ `Signed in${saved.email ? ` as ${saved.email}` : ""} to ${saved.name}. The API key is saved in ${configPath(env)}.`
2579
+ ];
2580
+ if (others.length) {
2581
+ lines.push(
2582
+ `Also signed in here: ${others.map((entry) => entry.name).join(", ")}. Switch with ${brand.bin} workspaces use <name>.`
2583
+ );
2584
+ }
2585
+ if (envNote) lines.push(envNote);
2586
+ lines.push(`Next: ${brand.bin} domains list`);
2587
+ io.out(lines.join("\n"));
2588
+ return { exitCode: EXIT_OK };
2589
+ }
2590
+ async function runLogoutCommand(argv, deps = {}) {
2591
+ const io = deps.io ?? processIo;
2592
+ const env = deps.env ?? process.env;
2593
+ const brand = cliBrand(env);
2594
+ const parsed = parseArgs(argv, { values: ["--workspace", "--base-url"], booleans: ["--json", "--all"] });
2595
+ if (!parsed.ok) return { exitCode: EXIT_USAGE, error: `${parsed.error}
2596
+ Usage: ${brand.bin} logout [--workspace <name>] [--all]` };
2597
+ const { args } = parsed;
2598
+ const json = wantsJson(args, io);
2599
+ const config = loadConfig(env);
2600
+ const all = savedWorkspaces(config);
2601
+ let targets;
2602
+ if (args.booleans["--all"]) {
2603
+ targets = all;
2604
+ } else if (args.values["--workspace"]) {
2605
+ const match = findSavedWorkspace(config, args.values["--workspace"]);
2606
+ if (!match.ok) {
2607
+ return { exitCode: EXIT_FAILED, error: `Not signed in to "${args.values["--workspace"]}" on this computer.` };
2608
+ }
2609
+ targets = [match.workspace];
2610
+ } else {
2611
+ const current = config.current ? config.workspaces?.[config.current] : all.length === 1 ? all[0] : void 0;
2612
+ if (!current && all.length > 1) {
2613
+ return {
2614
+ exitCode: EXIT_USAGE,
2615
+ error: `Signed in to ${all.length} workspaces and none is picked. Say which: ${brand.bin} logout --workspace <name>, or ${brand.bin} logout --all.`
2616
+ };
2617
+ }
2618
+ targets = current ? [current] : [];
2619
+ }
2620
+ const results = [];
2621
+ for (const workspace of targets) {
2622
+ const apiUrl = trimUrl(args.values["--base-url"]) || explicitApiUrl(env) || trimUrl(workspace.apiUrl) || defaultApiUrl(env);
2623
+ let revoked = false;
2624
+ let warning;
2625
+ try {
2626
+ const response = await apiRequest(apiUrl, "/cli/session", { method: "DELETE", apiKey: workspace.apiKey, env });
2627
+ revoked = response.ok && response.body.revoked === true;
2628
+ if (!response.ok && response.status !== 401) warning = errorMessage(response, "Could not revoke the key");
2629
+ } catch (error) {
2630
+ warning = error instanceof Error ? error.message : String(error);
2631
+ }
2632
+ results.push({ id: workspace.id, name: workspace.name, revoked, ...warning ? { warning } : {} });
2633
+ }
2634
+ const removing = new Set(targets.map((workspace) => workspace.id));
2635
+ const hadPending = Boolean(config.pendingLogin);
2636
+ if (removing.size || hadPending) {
2637
+ updateConfig((current) => {
2638
+ const workspaces = Object.fromEntries(
2639
+ Object.entries(current.workspaces ?? {}).filter(([id]) => !removing.has(id))
2640
+ );
2641
+ const { pendingLogin: _drop, current: picked, ...rest } = current;
2642
+ return { ...rest, workspaces, ...picked && !removing.has(picked) ? { current: picked } : {} };
2643
+ }, env);
2644
+ }
2645
+ const envNote = envApiKey(env) ? `${sourceLabel("env", env)} is still set in this environment, so commands keep using it.` : null;
2646
+ if (json) {
2647
+ printJson(io, { signed_out: results, config_path: configPath(env), ...envNote ? { note: envNote } : {} });
2648
+ return { exitCode: EXIT_OK };
2649
+ }
2650
+ if (!results.length) {
2651
+ io.out(`Not signed in on this computer.${envNote ? ` ${envNote}` : ""}`);
2652
+ return { exitCode: EXIT_OK };
2653
+ }
2654
+ const lines = results.map(
2655
+ (result) => `Signed out of ${result.name}: ${result.revoked ? "the key was revoked and" : "the key was"} removed from ${configPath(env)}.${result.warning ? ` (Could not revoke it: ${result.warning} Revoke it on the API keys page.)` : ""}`
2656
+ );
2657
+ if (envNote) lines.push(envNote);
2658
+ io.out(lines.join("\n"));
2659
+ return { exitCode: EXIT_OK };
2660
+ }
2661
+ async function runWhoamiCommand(argv, deps = {}) {
2662
+ const io = deps.io ?? processIo;
2663
+ const env = deps.env ?? process.env;
2664
+ const brand = cliBrand(env);
2665
+ const parsed = parseArgs(argv, { values: [...COMMON_VALUE_FLAGS], booleans: [...COMMON_BOOLEAN_FLAGS] });
2666
+ if (!parsed.ok) return { exitCode: EXIT_USAGE, error: `${parsed.error}
2667
+ Usage: ${brand.bin} whoami [--workspace <name>] [--json]` };
2668
+ const { args } = parsed;
2669
+ const resolved = resolveAuth(
2670
+ { apiKey: args.values["--api-key"], baseUrl: args.values["--base-url"], workspace: args.values["--workspace"] },
2671
+ env
2672
+ );
2673
+ if (!resolved.ok) return { exitCode: EXIT_FAILED, error: resolved.error };
2674
+ const { auth } = resolved;
2675
+ try {
2676
+ const response = await apiRequest(auth.baseUrl, "/cli/session", { apiKey: auth.apiKey, env });
2677
+ if (!response.ok) {
2678
+ const hint = response.status === 401 ? ` The key was rejected; run ${brand.bin} login to sign in again.` : "";
2679
+ return { exitCode: EXIT_FAILED, error: `${sentence(errorMessage(response, "Could not check the sign-in"))}${hint}` };
2680
+ }
2681
+ const session = response.body;
2682
+ const source = sourceLabel(auth.source, env);
2683
+ if (wantsJson(args, io)) {
2684
+ printJson(io, { ...response.body, source, api_url: auth.baseUrl, config_path: configPath(env) });
2685
+ return { exitCode: EXIT_OK };
2686
+ }
2687
+ io.out(
2688
+ [
2689
+ session.user?.email ?? "(an API key; no person is recorded for it)",
2690
+ `Workspace: ${session.workspace?.name ?? "?"} (${session.workspace?.id ?? "?"})`,
2691
+ `Key: ${session.key?.name ?? "?"} (${session.key?.prefix ?? "?"}\u2026${session.key?.scope === "sending" ? ", sending only" : ""}), from ${source}`,
2692
+ ...auth.baseUrl !== defaultApiUrl(env) ? [`API: ${auth.baseUrl}`] : []
2693
+ ].join("\n")
2694
+ );
2695
+ return { exitCode: EXIT_OK };
2696
+ } catch (error) {
2697
+ if (error instanceof CliRequestError) return { exitCode: EXIT_FAILED, error: error.message };
2698
+ throw error;
2699
+ }
2700
+ }
2701
+
2702
+ // src/commands/workspaces.ts
2703
+ async function runWorkspacesCommand(subcommand, argv, deps = {}) {
2704
+ const env = deps.env ?? process.env;
2705
+ const brand = cliBrand(env);
2706
+ const usage = `Usage:
2707
+ ${brand.bin} workspaces list
2708
+ ${brand.bin} workspaces use <name|id>`;
2709
+ if (subcommand === "list" || subcommand === "ls") return listWorkspaces(argv, deps);
2710
+ if (subcommand === "use" || subcommand === "switch") return switchWorkspace(argv, deps);
2711
+ return { exitCode: EXIT_USAGE, error: subcommand ? `Unknown: workspaces ${subcommand}.
2712
+ ${usage}` : usage };
2713
+ }
2714
+ async function listWorkspaces(argv, deps) {
2715
+ const io = deps.io ?? processIo;
2716
+ const env = deps.env ?? process.env;
2717
+ const brand = cliBrand(env);
2718
+ const parsed = parseArgs(argv, { booleans: ["--json"] });
2719
+ if (!parsed.ok) return { exitCode: EXIT_USAGE, error: parsed.error };
2720
+ if (parsed.args.positionals.length) return { exitCode: EXIT_USAGE, error: `${brand.bin} workspaces list takes no arguments.` };
2721
+ const config = loadConfig(env);
2722
+ const all = savedWorkspaces(config);
2723
+ const current = currentSavedWorkspace(config, env);
2724
+ const currentId = current.ok ? current.workspace.id : null;
2725
+ const envNote = envApiKey(env) ? "An API key is set in this environment; commands use it instead of these until you unset it." : null;
2726
+ const addHint = `To add a workspace: ${brand.bin} login --workspace "<name>", and pick it in the browser.`;
2727
+ if (wantsJson(parsed.args, io)) {
2728
+ printJson(io, {
2729
+ workspaces: all.map((workspace) => ({
2730
+ id: workspace.id,
2731
+ name: workspace.name,
2732
+ current: workspace.id === currentId,
2733
+ email: workspace.email ?? null,
2734
+ ...workspace.apiUrl && workspace.apiUrl !== defaultApiUrl(env) ? { api_url: workspace.apiUrl } : {}
2735
+ })),
2736
+ current: currentId,
2737
+ ...current.ok || current.reason === "none" ? {} : { next: current.error },
2738
+ config_path: configPath(env),
2739
+ ...envNote ? { note: envNote } : {}
2740
+ });
2741
+ return { exitCode: EXIT_OK };
2742
+ }
2743
+ if (!all.length) {
2744
+ io.out(`No workspaces signed in on this computer. Run: ${brand.bin} login${envNote ? `
2745
+ ${envNote}` : ""}`);
2746
+ return { exitCode: EXIT_OK };
2747
+ }
2748
+ const lines = all.map(
2749
+ (workspace) => `${workspace.id === currentId ? "*" : " "} ${workspace.name} (${workspace.id})${workspace.email ? ` ${workspace.email}` : ""}${workspace.apiUrl && workspace.apiUrl !== defaultApiUrl(env) ? ` ${workspace.apiUrl}` : ""}`
2750
+ );
2751
+ if (!current.ok) lines.push("", current.error);
2752
+ lines.push("", addHint);
2753
+ if (envNote) lines.push(envNote);
2754
+ io.out(lines.join("\n"));
2755
+ return { exitCode: EXIT_OK };
2756
+ }
2757
+ async function switchWorkspace(argv, deps) {
2758
+ const io = deps.io ?? processIo;
2759
+ const env = deps.env ?? process.env;
2760
+ const brand = cliBrand(env);
2761
+ const parsed = parseArgs(argv, { booleans: ["--json"] });
2762
+ if (!parsed.ok) return { exitCode: EXIT_USAGE, error: parsed.error };
2763
+ const wanted = parsed.args.positionals.join(" ").trim();
2764
+ if (!wanted) return { exitCode: EXIT_USAGE, error: `Name the workspace: ${brand.bin} workspaces use <name|id> (see ${brand.bin} workspaces list).` };
2765
+ const config = loadConfig(env);
2766
+ const match = findSavedWorkspace(config, wanted);
2767
+ if (!match.ok) {
2768
+ const saved = savedWorkspaces(config);
2769
+ return {
2770
+ exitCode: EXIT_FAILED,
2771
+ error: match.reason === "ambiguous" ? `More than one saved workspace is called "${wanted}". Use its id: ${match.matches.map((w) => w.id).join(", ")}.` : `Not signed in to "${wanted}" on this computer.${saved.length ? ` Signed in: ${saved.map((w) => `"${w.name}"`).join(", ")}.` : ""} To add it: ${brand.bin} login --workspace "${wanted}".`
2772
+ };
2773
+ }
2774
+ updateConfig((current) => ({ ...current, current: match.workspace.id }), env);
2775
+ if (wantsJson(parsed.args, io)) {
2776
+ printJson(io, { current: { id: match.workspace.id, name: match.workspace.name } });
2777
+ } else {
2778
+ io.out(`Now working in ${match.workspace.name}.`);
2779
+ }
2780
+ return { exitCode: EXIT_OK };
2781
+ }
2782
+
2783
+ // src/cli.ts
2784
+ function printUsage() {
2785
+ console.error("Usage:");
2786
+ console.error(" groundmail login [--workspace <name>] sign in through the browser (no key to copy)");
2787
+ console.error(" groundmail logout [--workspace <name>|--all]");
2788
+ console.error(" groundmail whoami");
2789
+ console.error(" groundmail workspaces list");
2790
+ console.error(" groundmail workspaces use <name|id>");
2791
+ console.error(" groundmail domains add example.com");
2792
+ console.error(" groundmail domains apply example.com --provider cloudflare");
2793
+ console.error(" groundmail domains apply example.com --provider vercel");
2794
+ console.error(" groundmail domains apply example.com --provider godaddy");
2795
+ console.error(" groundmail domains list");
2796
+ console.error(" groundmail domains get example.com");
2797
+ console.error(" groundmail domains update example.com --inbound true");
2798
+ console.error(" groundmail domains verify example.com");
2799
+ console.error(" groundmail domains delete example.com");
2800
+ console.error(" groundmail received-emails list [--domain inbound.example.com]");
2801
+ console.error(" groundmail received-emails get inb_...");
2802
+ console.error(' groundmail emails send --from you@domain.com --to user@example.com --subject "Hello" --html "<p>Hi</p>" [--category transactional|product|newsletter] [--unsubscribe]');
2803
+ console.error(" groundmail emails batch --file ./emails.json");
2804
+ console.error(" groundmail emails list [--limit 25] [--cursor \u2026]");
2805
+ console.error(" groundmail emails insights [--window 7d|30d]");
2806
+ console.error(" groundmail emails get --id msg_\u2026");
2807
+ console.error(" groundmail emails cancel --id msg_\u2026");
2808
+ console.error(" groundmail emails resend --id msg_\u2026");
2809
+ console.error(` groundmail events send --name user.created --email user@example.com --data '{"name":"Ada"}'`);
2810
+ console.error(" groundmail automations list");
2811
+ console.error(" groundmail automations create --file ./welcome.json");
2812
+ console.error(` groundmail automations create --name Welcome --trigger user.created --steps '[{"type":"send_email","email":{...}}]'`);
2813
+ console.error(" groundmail automations create --file ./otp-sms.json");
2814
+ console.error(" groundmail automations get --id <automation-id>");
2815
+ console.error(" groundmail automations update --id <automation-id> --file ./welcome.json");
2816
+ console.error(" groundmail automations activate --id <automation-id>");
2817
+ console.error(" groundmail automations pause --id <automation-id>");
2818
+ console.error(" groundmail automations delete --id <automation-id>");
2819
+ console.error(" groundmail webhooks list");
2820
+ console.error(" groundmail webhooks create --url https://yourapp.com/hooks");
2821
+ console.error(" groundmail webhooks get --id wh_\u2026");
2822
+ console.error(" groundmail webhooks update --id wh_\u2026 [--url \u2026] [--event email.sent] [--enabled true|false]");
2823
+ console.error(" groundmail webhooks delete --id <webhook-id>");
2824
+ console.error(" groundmail suppressions list");
2825
+ console.error(" groundmail suppressions add --email user@example.com [--reason \u2026]");
2826
+ console.error(" groundmail suppressions remove --id <id> | --email user@example.com");
2827
+ console.error(" groundmail templates list [--status draft|published]");
2828
+ console.error(" groundmail templates starters");
2829
+ console.error(" groundmail templates from-starter password-reset");
2830
+ console.error(' groundmail templates create --name Welcome --subject "Hi" --html "<p>Hi</p>" [--category transactional|product|newsletter] [--unsubscribe-enabled]');
2831
+ console.error(" groundmail templates get --id tpl_\u2026");
2832
+ console.error(" groundmail templates update --id tpl_\u2026 [--name \u2026] [--subject \u2026] [--html \u2026] [--text \u2026] [--set-alias \u2026] [--category transactional|product|newsletter] [--unsubscribe-enabled|--no-unsubscribe-enabled]");
2833
+ console.error(" groundmail templates publish --id tpl_\u2026");
2834
+ console.error(
2835
+ ` groundmail templates push ./emails/welcome.tsx --alias welcome [--subject "Welcome"] [--props '{"name":"Ada"}'] [--publish]`
2836
+ );
2837
+ console.error(" groundmail templates versions --id tpl_\u2026");
2838
+ console.error(" groundmail templates restore --id tpl_\u2026 --version 2");
2839
+ console.error(" groundmail templates test-send --id tpl_\u2026 --from you@domain.com --to you@domain.com");
2840
+ console.error(' groundmail templates duplicate --id tpl_\u2026 [--name "Copy"]');
2841
+ console.error(" groundmail templates delete --id tpl_\u2026");
2842
+ console.error(" groundmail keys list");
2843
+ console.error(" groundmail keys create [--name Default] [--scope full|sending]");
2844
+ console.error(" groundmail keys delete --id <api-key-id>");
2845
+ console.error(" groundmail integrations twilio status");
2846
+ console.error(" groundmail integrations twilio connect --account-sid AC\u2026 --auth-token \u2026 --from +15551234567");
2847
+ console.error(" groundmail integrations twilio disconnect");
2848
+ console.error("");
2849
+ console.error("Environment:");
2850
+ console.error(" GROUNDMAIL_API_KEY=gm_\u2026 optional: `groundmail login` saves a key instead");
2851
+ console.error(" TWILIO_ACCOUNT_SID=AC\u2026 TWILIO_AUTH_TOKEN=\u2026 TWILIO_DEFAULT_FROM=+1\u2026 (integrations twilio connect)");
2852
+ console.error(" CLOUDFLARE_API_TOKEN=\u2026 (optional local apply; else uses dashboard Integrations)");
2853
+ console.error(" VERCEL_API_TOKEN=\u2026 VERCEL_TEAM_ID=\u2026 (optional local apply; else uses dashboard Integrations)");
2854
+ console.error(" GODADDY_API_KEY=\u2026 GODADDY_API_SECRET=\u2026 (domains apply --provider godaddy)");
2855
+ }
2856
+ async function finish(result) {
2857
+ if (result.error) console.error(result.error);
2858
+ process.exit(result.exitCode);
2859
+ }
2860
+ async function main() {
2861
+ const [, , command, subcommand] = process.argv;
2862
+ const args = process.argv.slice(3);
2863
+ if (command === "help" || command === "--help" || command === "-h") {
2864
+ printUsage();
2865
+ process.exit(0);
2866
+ }
2867
+ if (command === "login") await finish(await runLoginCommand(args));
2868
+ if (command === "logout") await finish(await runLogoutCommand(args));
2869
+ if (command === "whoami") await finish(await runWhoamiCommand(args));
2870
+ if (command === "workspaces" || command === "workspace") await finish(await runWorkspacesCommand(subcommand, args.slice(1)));
2871
+ const session = applySavedSession(process.argv.slice(4));
2872
+ if (session.notice) console.error(session.notice);
2873
+ const rest = session.argv;
2874
+ if (command === "domains") {
2875
+ if (subcommand === "add" || subcommand === "create") {
2876
+ const result = await runAddCommand(rest);
2877
+ if (result.error) console.error(result.error);
2878
+ process.exit(result.exitCode);
2879
+ }
2880
+ if (subcommand === "apply") {
2881
+ const result = await runApplyCommand(rest);
2882
+ if (result.error) console.error(result.error);
2883
+ process.exit(result.exitCode);
2884
+ }
2885
+ if (subcommand === "get") {
2886
+ const result = await runGetCommand3(rest);
2887
+ if (result.error) console.error(result.error);
2888
+ process.exit(result.exitCode);
2889
+ }
2890
+ if (subcommand === "list") {
2891
+ const result = await runListCommand3(rest);
2892
+ if (result.error) console.error(result.error);
2893
+ process.exit(result.exitCode);
2894
+ }
2895
+ if (subcommand === "delete" || subcommand === "remove") {
2896
+ const result = await runDeleteCommand2(rest);
2897
+ if (result.error) console.error(result.error);
2898
+ process.exit(result.exitCode);
2899
+ }
2900
+ if (subcommand === "update") {
2901
+ const result = await runUpdateCommand2(rest);
2902
+ if (result.error) console.error(result.error);
2903
+ process.exit(result.exitCode);
2904
+ }
2905
+ if (subcommand === "verify") {
2906
+ const result = await runVerifyCommand(rest);
2907
+ if (result.error) console.error(result.error);
2908
+ process.exit(result.exitCode);
2909
+ }
2910
+ }
2911
+ if (command === "received-emails") {
2912
+ if (subcommand === "list") {
2913
+ const result = await runListCommand4(rest);
2914
+ if (result.error) console.error(result.error);
2915
+ process.exit(result.exitCode);
2916
+ }
2917
+ if (subcommand === "get") {
2918
+ const result = await runGetCommand4(rest);
2919
+ if (result.error) console.error(result.error);
2920
+ process.exit(result.exitCode);
2921
+ }
2922
+ }
2923
+ if (command === "emails") {
2924
+ if (subcommand === "send") {
2925
+ const result = await runSendCommandWithClient(rest);
2926
+ process.exit(result.exitCode);
2927
+ }
2928
+ if (subcommand === "batch") {
2929
+ const result = await runBatchCommandWithClient(rest);
2930
+ if (result.error) console.error(result.error);
2931
+ process.exit(result.exitCode);
2932
+ }
2933
+ if (subcommand === "cancel") {
2934
+ const result = await runCancelCommandWithClient(rest);
2935
+ if (result.error) console.error(result.error);
2936
+ process.exit(result.exitCode);
2937
+ }
2938
+ if (subcommand === "resend") {
2939
+ const result = await runResendCommandWithClient(rest);
2940
+ if (result.error) console.error(result.error);
2941
+ process.exit(result.exitCode);
2942
+ }
2943
+ if (subcommand === "list") {
2944
+ const result = await runListCommandWithClient(rest);
2945
+ if (result.error) console.error(result.error);
2946
+ process.exit(result.exitCode);
2947
+ }
2948
+ if (subcommand === "insights") {
2949
+ const result = await runInsightsCommandWithClient(rest);
2950
+ if (result.error) console.error(result.error);
2951
+ process.exit(result.exitCode);
2952
+ }
2953
+ if (subcommand === "get") {
2954
+ const result = await runGetCommandWithClient(rest);
2955
+ if (result.error) console.error(result.error);
2956
+ process.exit(result.exitCode);
2957
+ }
2958
+ }
2959
+ if (command === "events") {
2960
+ if (subcommand === "send" || subcommand === "trigger") {
2961
+ const result = await runSendEventCommand(rest);
2962
+ if (result.error) console.error(result.error);
2963
+ process.exit(result.exitCode);
2964
+ }
2965
+ }
2966
+ if (command === "automations") {
2967
+ if (subcommand === "list") {
2968
+ const result = await runListCommand2(rest);
2969
+ if (result.error) console.error(result.error);
2970
+ process.exit(result.exitCode);
2971
+ }
2972
+ if (subcommand === "get") {
2973
+ const result = await runGetCommand2(rest);
2974
+ if (result.error) console.error(result.error);
2975
+ process.exit(result.exitCode);
2976
+ }
2977
+ if (subcommand === "create" || subcommand === "add") {
2978
+ const result = await runCreateCommand(rest);
2979
+ if (result.error) console.error(result.error);
2980
+ process.exit(result.exitCode);
2981
+ }
2982
+ if (subcommand === "update") {
2983
+ const result = await runUpdateCommand(rest);
2984
+ if (result.error) console.error(result.error);
2985
+ process.exit(result.exitCode);
2986
+ }
2987
+ if (subcommand === "activate") {
2988
+ const result = await runActivateCommand(rest);
2989
+ if (result.error) console.error(result.error);
2990
+ process.exit(result.exitCode);
2991
+ }
2992
+ if (subcommand === "pause") {
2993
+ const result = await runPauseCommand(rest);
2994
+ if (result.error) console.error(result.error);
2995
+ process.exit(result.exitCode);
2996
+ }
2997
+ if (subcommand === "delete" || subcommand === "remove") {
2998
+ const result = await runDeleteCommand(rest);
2999
+ if (result.error) console.error(result.error);
3000
+ process.exit(result.exitCode);
3001
+ }
3002
+ }
3003
+ if (command === "webhooks") {
3004
+ if (subcommand === "list") {
3005
+ const result = await runListCommand5(rest);
3006
+ if (result.error) console.error(result.error);
3007
+ process.exit(result.exitCode);
3008
+ }
3009
+ if (subcommand === "get") {
3010
+ const result = await runGetCommand5(rest);
3011
+ if (result.error) console.error(result.error);
3012
+ process.exit(result.exitCode);
3013
+ }
3014
+ if (subcommand === "create") {
3015
+ const result = await runCreateCommand2(rest);
3016
+ if (result.error) console.error(result.error);
3017
+ process.exit(result.exitCode);
3018
+ }
3019
+ if (subcommand === "update") {
3020
+ const result = await runUpdateCommand3(rest);
3021
+ if (result.error) console.error(result.error);
3022
+ process.exit(result.exitCode);
3023
+ }
3024
+ if (subcommand === "delete") {
3025
+ const result = await runDeleteCommand3(rest);
3026
+ if (result.error) console.error(result.error);
3027
+ process.exit(result.exitCode);
3028
+ }
3029
+ }
3030
+ if (command === "suppressions") {
3031
+ if (subcommand === "list") {
3032
+ const result = await runListCommand6(rest);
3033
+ if (result.error) console.error(result.error);
3034
+ process.exit(result.exitCode);
3035
+ }
3036
+ if (subcommand === "add" || subcommand === "create") {
3037
+ const result = await runAddCommand2(rest);
3038
+ if (result.error) console.error(result.error);
3039
+ process.exit(result.exitCode);
3040
+ }
3041
+ if (subcommand === "remove" || subcommand === "delete") {
3042
+ const result = await runRemoveCommand(rest);
3043
+ if (result.error) console.error(result.error);
3044
+ process.exit(result.exitCode);
3045
+ }
3046
+ }
3047
+ if (command === "templates") {
3048
+ if (subcommand === "list") {
3049
+ const result = await runListCommand7(rest);
3050
+ if (result.error) console.error(result.error);
3051
+ process.exit(result.exitCode);
3052
+ }
3053
+ if (subcommand === "starters") {
3054
+ const result = await runListStartersCommand(rest);
3055
+ if (result.error) console.error(result.error);
3056
+ process.exit(result.exitCode);
3057
+ }
3058
+ if (subcommand === "from-starter") {
3059
+ const result = await runFromStarterCommand(rest);
3060
+ if (result.error) console.error(result.error);
3061
+ process.exit(result.exitCode);
3062
+ }
3063
+ if (subcommand === "create" || subcommand === "add") {
3064
+ const result = await runCreateCommand3(rest);
3065
+ if (result.error) console.error(result.error);
3066
+ process.exit(result.exitCode);
3067
+ }
3068
+ if (subcommand === "get") {
3069
+ const result = await runGetCommand6(rest);
3070
+ if (result.error) console.error(result.error);
3071
+ process.exit(result.exitCode);
3072
+ }
3073
+ if (subcommand === "update") {
3074
+ const result = await runUpdateCommand4(rest);
3075
+ if (result.error) console.error(result.error);
3076
+ process.exit(result.exitCode);
3077
+ }
3078
+ if (subcommand === "publish") {
3079
+ const result = await runPublishCommand(rest);
3080
+ if (result.error) console.error(result.error);
3081
+ process.exit(result.exitCode);
3082
+ }
3083
+ if (subcommand === "push") {
3084
+ const result = await runPushCommand(rest);
3085
+ if (result.error) console.error(result.error);
3086
+ process.exit(result.exitCode);
3087
+ }
3088
+ if (subcommand === "versions") {
3089
+ const result = await runVersionsCommand(rest);
3090
+ if (result.error) console.error(result.error);
3091
+ process.exit(result.exitCode);
3092
+ }
3093
+ if (subcommand === "restore") {
3094
+ const result = await runRestoreCommand(rest);
3095
+ if (result.error) console.error(result.error);
3096
+ process.exit(result.exitCode);
3097
+ }
3098
+ if (subcommand === "test-send") {
3099
+ const result = await runTestSendCommand(rest);
3100
+ if (result.error) console.error(result.error);
3101
+ process.exit(result.exitCode);
3102
+ }
3103
+ if (subcommand === "duplicate") {
3104
+ const result = await runDuplicateCommand(rest);
3105
+ if (result.error) console.error(result.error);
3106
+ process.exit(result.exitCode);
3107
+ }
3108
+ if (subcommand === "delete" || subcommand === "remove") {
3109
+ const result = await runDeleteCommand4(rest);
3110
+ if (result.error) console.error(result.error);
3111
+ process.exit(result.exitCode);
3112
+ }
3113
+ }
3114
+ if (command === "integrations") {
3115
+ if (subcommand === "twilio") {
3116
+ const action = rest[0];
3117
+ const actionArgs = rest.slice(1);
3118
+ if (action === "status" || action === "get") {
3119
+ const result = await runTwilioStatusCommand(actionArgs);
3120
+ if (result.error) console.error(result.error);
3121
+ process.exit(result.exitCode);
3122
+ }
3123
+ if (action === "connect" || action === "set") {
3124
+ const result = await runTwilioConnectCommand(actionArgs);
3125
+ if (result.error) console.error(result.error);
3126
+ process.exit(result.exitCode);
3127
+ }
3128
+ if (action === "disconnect" || action === "delete" || action === "remove") {
3129
+ const result = await runTwilioDisconnectCommand(actionArgs);
3130
+ if (result.error) console.error(result.error);
3131
+ process.exit(result.exitCode);
3132
+ }
3133
+ }
3134
+ }
3135
+ if (command === "keys") {
3136
+ if (subcommand === "list") {
3137
+ const result = await runListKeysCommandWithClient(rest);
3138
+ if (result.error) console.error(result.error);
3139
+ process.exit(result.exitCode);
3140
+ }
3141
+ if (subcommand === "create") {
3142
+ const result = await runCreateKeyCommandWithClient(rest);
3143
+ if (result.error) console.error(result.error);
3144
+ process.exit(result.exitCode);
3145
+ }
3146
+ if (subcommand === "delete") {
3147
+ const result = await runDeleteKeyCommandWithClient(rest);
3148
+ if (result.error) console.error(result.error);
3149
+ process.exit(result.exitCode);
3150
+ }
3151
+ }
3152
+ printUsage();
3153
+ process.exit(1);
3154
+ }
3155
+ main().catch((error) => {
3156
+ console.error(error instanceof Error ? error.message : String(error));
3157
+ process.exit(1);
3158
+ });