@itznexus/itznexus-cli 1.25.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/commands/agents/upwork.js +43 -2
  2. package/dist/commands/agents/upwork.js.map +1 -1
  3. package/dist/commands/api/agent-jobs.d.ts +2 -0
  4. package/dist/commands/api/agent-jobs.js +178 -0
  5. package/dist/commands/api/agent-jobs.js.map +1 -0
  6. package/dist/commands/api/aws-accounts.d.ts +2 -0
  7. package/dist/commands/api/aws-accounts.js +649 -0
  8. package/dist/commands/api/aws-accounts.js.map +1 -0
  9. package/dist/commands/api/capabilities.d.ts +2 -0
  10. package/dist/commands/api/capabilities.js +31 -0
  11. package/dist/commands/api/capabilities.js.map +1 -0
  12. package/dist/commands/api/deployments.d.ts +2 -0
  13. package/dist/commands/api/deployments.js +177 -0
  14. package/dist/commands/api/deployments.js.map +1 -0
  15. package/dist/commands/api/email-captures.d.ts +3 -0
  16. package/dist/commands/api/email-captures.js +234 -0
  17. package/dist/commands/api/email-captures.js.map +1 -0
  18. package/dist/commands/api/folders.js +45 -0
  19. package/dist/commands/api/folders.js.map +1 -1
  20. package/dist/commands/api/gmail-messages.d.ts +2 -0
  21. package/dist/commands/api/gmail-messages.js +210 -0
  22. package/dist/commands/api/gmail-messages.js.map +1 -0
  23. package/dist/commands/api/notifications.d.ts +2 -0
  24. package/dist/commands/api/notifications.js +146 -0
  25. package/dist/commands/api/notifications.js.map +1 -0
  26. package/dist/commands/api/organizations.js +66 -1
  27. package/dist/commands/api/organizations.js.map +1 -1
  28. package/dist/commands/api/persons.js +36 -1
  29. package/dist/commands/api/persons.js.map +1 -1
  30. package/dist/commands/api/projects.js +323 -0
  31. package/dist/commands/api/projects.js.map +1 -1
  32. package/dist/commands/api/repositories.js +22 -0
  33. package/dist/commands/api/repositories.js.map +1 -1
  34. package/dist/commands/api/telemetry.d.ts +2 -0
  35. package/dist/commands/api/telemetry.js +282 -0
  36. package/dist/commands/api/telemetry.js.map +1 -0
  37. package/dist/commands/api/uptime.js +19 -0
  38. package/dist/commands/api/uptime.js.map +1 -1
  39. package/dist/commands/api/website-scrapes.js +19 -0
  40. package/dist/commands/api/website-scrapes.js.map +1 -1
  41. package/dist/commands/api/youtube-productions.js +76 -1
  42. package/dist/commands/api/youtube-productions.js.map +1 -1
  43. package/dist/index.js +26 -0
  44. package/dist/index.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,649 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import { api } from "../../lib/api.js";
4
+ import { printList, printDetail, handleError } from "../../lib/format.js";
5
+ function fmtCounts(counts) {
6
+ const parts = Object.entries(counts).map(([k, v]) => `${k}:${v}`);
7
+ return parts.length ? parts.join(" ") : "-";
8
+ }
9
+ // --- account CRUD ---
10
+ const createCommand = new Command("create")
11
+ .description("Provision a new AWS account (admin)")
12
+ .option("--name <name>", "Editable label for the account")
13
+ .option("--json", "Output as JSON")
14
+ .action(async (opts) => {
15
+ try {
16
+ const payload = {};
17
+ if (opts.name !== undefined)
18
+ payload.name = opts.name;
19
+ const data = await api.post("/aws-accounts", payload);
20
+ if (opts.json) {
21
+ console.log(JSON.stringify(data, null, 2));
22
+ return;
23
+ }
24
+ console.log(chalk.green("✓"), `AWS account queued: ${chalk.bold(data.account.slug)} (${data.account.id})`);
25
+ console.log(chalk.dim(` Provisioning job: ${data.job.id} (${data.job.status})`));
26
+ }
27
+ catch (err) {
28
+ handleError(err);
29
+ }
30
+ });
31
+ const listCommand = new Command("list")
32
+ .description("List AWS accounts")
33
+ .option("--status <status>", "Filter by status")
34
+ .option("--type <type>", "management | member")
35
+ .option("--json", "Output as JSON")
36
+ .action(async (opts) => {
37
+ try {
38
+ const params = new URLSearchParams();
39
+ if (opts.status)
40
+ params.set("status", opts.status);
41
+ if (opts.type)
42
+ params.set("type", opts.type);
43
+ const qs = params.toString();
44
+ const data = await api.get(`/aws-accounts${qs ? `?${qs}` : ""}`);
45
+ printList(data, [
46
+ { key: "slug", label: "Slug", width: 22 },
47
+ { key: "name", label: "Name", width: 20 },
48
+ { key: "awsAccountId", label: "AWS ID", width: 14 },
49
+ { key: "status", label: "Status", width: 12 },
50
+ { key: "region", label: "Region", width: 12 },
51
+ { key: "id", label: "ID", width: 38 },
52
+ ], opts);
53
+ }
54
+ catch (err) {
55
+ handleError(err);
56
+ }
57
+ });
58
+ const getCommand = new Command("get")
59
+ .description("Get an AWS account")
60
+ .argument("<id>", "Account ID or slug")
61
+ .option("--json", "Output as JSON")
62
+ .action(async (id, opts) => {
63
+ try {
64
+ const data = await api.get(`/aws-accounts/${id}`);
65
+ if (opts.json) {
66
+ console.log(JSON.stringify(data, null, 2));
67
+ return;
68
+ }
69
+ console.log(chalk.bold(data.name ?? data.slug), chalk.dim(`(${data.status})`));
70
+ printDetail({
71
+ ...data,
72
+ monthlyCostUsd: data.metrics?.monthlyCostUsd ?? null,
73
+ sending: data.sesAccount
74
+ ? `${data.sesAccount.sendingEnabled ? "enabled" : "disabled"}, ${data.sesAccount.productionEnabled ? "production" : "sandbox"}`
75
+ : null,
76
+ }, [
77
+ { key: "id", label: "ID" },
78
+ { key: "slug", label: "Slug" },
79
+ { key: "type", label: "Type" },
80
+ { key: "awsAccountId", label: "AWS account ID" },
81
+ { key: "email", label: "Email" },
82
+ { key: "status", label: "Status" },
83
+ { key: "region", label: "Region" },
84
+ { key: "monthlyCostUsd", label: "Monthly cost (USD)" },
85
+ { key: "sending", label: "SES sending" },
86
+ { key: "error", label: "Error" },
87
+ { key: "createdAt", label: "Created" },
88
+ ], opts);
89
+ }
90
+ catch (err) {
91
+ handleError(err);
92
+ }
93
+ });
94
+ const updateCommand = new Command("update")
95
+ .description("Update an AWS account label (admin)")
96
+ .argument("<id>", "Account ID or slug")
97
+ .option("--name <name>", "New label")
98
+ .option("--clear", "Clear the label")
99
+ .option("--json", "Output as JSON")
100
+ .action(async (id, opts) => {
101
+ try {
102
+ if (!opts.clear && opts.name === undefined) {
103
+ console.error(chalk.red("✗"), "Provide --name <name> or --clear");
104
+ process.exit(1);
105
+ }
106
+ const data = await api.post(`/aws-accounts/${id}`, {
107
+ name: opts.clear ? null : opts.name,
108
+ });
109
+ if (opts.json)
110
+ console.log(JSON.stringify(data, null, 2));
111
+ else
112
+ console.log(chalk.green("✓"), "AWS account updated");
113
+ }
114
+ catch (err) {
115
+ handleError(err);
116
+ }
117
+ });
118
+ const testEmailCommand = new Command("test-email")
119
+ .description("Send a test email through the account (admin)")
120
+ .argument("<id>", "Account ID or slug")
121
+ .option("--json", "Output as JSON")
122
+ .action(async (id, opts) => {
123
+ try {
124
+ const data = await api.post(`/aws-accounts/${id}/test-email`, {});
125
+ if (opts.json) {
126
+ console.log(JSON.stringify(data, null, 2));
127
+ return;
128
+ }
129
+ console.log(chalk.green("✓"), `Test email queued: ${data.from} to ${data.to} (${data.emailId})`);
130
+ }
131
+ catch (err) {
132
+ handleError(err);
133
+ }
134
+ });
135
+ // --- credentials subcommand ---
136
+ const credentialListCommand = new Command("list")
137
+ .description("List app credentials for an account")
138
+ .argument("<id>", "Account ID or slug")
139
+ .option("--json", "Output as JSON")
140
+ .action(async (id, opts) => {
141
+ try {
142
+ const data = await api.get(`/aws-accounts/${id}/app-credentials`);
143
+ printList(data, [
144
+ { key: "name", label: "Name", width: 20 },
145
+ { key: "iamUserName", label: "IAM user", width: 28 },
146
+ { key: "accessKeyId", label: "Access key", width: 24 },
147
+ { key: "status", label: "Status", width: 10 },
148
+ { key: "id", label: "ID", width: 38 },
149
+ ], opts);
150
+ }
151
+ catch (err) {
152
+ handleError(err);
153
+ }
154
+ });
155
+ const credentialCreateCommand = new Command("create")
156
+ .description("Create app credentials for an account (admin)")
157
+ .argument("<id>", "Account ID or slug")
158
+ .requiredOption("--name <name>", "App name (lowercase, digits, hyphens)")
159
+ .option("--json", "Output as JSON")
160
+ .action(async (id, opts) => {
161
+ try {
162
+ const data = await api.post(`/aws-accounts/${id}/app-credentials`, { name: opts.name });
163
+ if (opts.json) {
164
+ console.log(JSON.stringify(data, null, 2));
165
+ return;
166
+ }
167
+ console.log(chalk.green("✓"), `Credentials created for ${chalk.bold(data.credential.name)}`);
168
+ console.log(chalk.dim(` Access key ID: ${data.credential.accessKeyId}`));
169
+ console.log();
170
+ console.log(chalk.yellow("⚠"), "Copy this now — it won't be shown again:");
171
+ console.log(` Secret access key: ${chalk.bold(data.secretAccessKey)}`);
172
+ }
173
+ catch (err) {
174
+ handleError(err);
175
+ }
176
+ });
177
+ const credentialDeleteCommand = new Command("delete")
178
+ .description("Delete app credentials (admin)")
179
+ .argument("<id>", "Account ID or slug")
180
+ .argument("<credentialId>", "Credential ID")
181
+ .option("--json", "Output as JSON")
182
+ .action(async (id, credentialId, opts) => {
183
+ try {
184
+ await api.delete(`/aws-accounts/${id}/app-credentials/${credentialId}`);
185
+ if (opts.json)
186
+ console.log(JSON.stringify({ deleted: true, id: credentialId }));
187
+ else
188
+ console.log(chalk.green("✓"), "Credentials deleted");
189
+ }
190
+ catch (err) {
191
+ handleError(err);
192
+ }
193
+ });
194
+ const credentialCommand = new Command("credential")
195
+ .description("Manage IAM app credentials")
196
+ .addCommand(credentialListCommand)
197
+ .addCommand(credentialCreateCommand)
198
+ .addCommand(credentialDeleteCommand);
199
+ // --- profiles subcommand ---
200
+ const profileListCommand = new Command("list")
201
+ .description("List mailer profiles for an account")
202
+ .argument("<id>", "Account ID or slug")
203
+ .option("--json", "Output as JSON")
204
+ .action(async (id, opts) => {
205
+ try {
206
+ const data = await api.get(`/aws-accounts/${id}/profiles`);
207
+ if (opts.json) {
208
+ console.log(JSON.stringify(data, null, 2));
209
+ return;
210
+ }
211
+ if (data.apiUrl)
212
+ console.log(chalk.dim(`API URL: ${data.apiUrl}`));
213
+ printList(data.profiles, [
214
+ { key: "slug", label: "Slug", width: 28 },
215
+ { key: "apiKeyUpdatedAt", label: "Key updated", width: 26 },
216
+ ], opts);
217
+ }
218
+ catch (err) {
219
+ handleError(err);
220
+ }
221
+ });
222
+ const profileCreateCommand = new Command("create")
223
+ .description("Create a mailer profile (admin)")
224
+ .argument("<id>", "Account ID or slug")
225
+ .requiredOption("--slug <slug>", "Profile slug (lowercase, digits, hyphens)")
226
+ .option("--json", "Output as JSON")
227
+ .action(async (id, opts) => {
228
+ try {
229
+ const data = await api.post(`/aws-accounts/${id}/profiles`, { slug: opts.slug });
230
+ if (opts.json) {
231
+ console.log(JSON.stringify(data, null, 2));
232
+ return;
233
+ }
234
+ console.log(chalk.green("✓"), `Profile created: ${chalk.bold(data.profile.slug)}`);
235
+ console.log();
236
+ console.log(chalk.yellow("⚠"), "Copy this now — it won't be shown again:");
237
+ console.log(` API key: ${chalk.bold(data.apiKey)}`);
238
+ }
239
+ catch (err) {
240
+ handleError(err);
241
+ }
242
+ });
243
+ const profileRotateKeyCommand = new Command("rotate-key")
244
+ .description("Rotate a profile's API key (admin)")
245
+ .argument("<id>", "Account ID or slug")
246
+ .argument("<slug>", "Profile slug")
247
+ .option("--json", "Output as JSON")
248
+ .action(async (id, slug, opts) => {
249
+ try {
250
+ const data = await api.post(`/aws-accounts/${id}/profiles/${slug}/key`, {});
251
+ if (opts.json) {
252
+ console.log(JSON.stringify(data, null, 2));
253
+ return;
254
+ }
255
+ console.log(chalk.green("✓"), `Rotated key for ${chalk.bold(slug)}`);
256
+ console.log();
257
+ console.log(chalk.yellow("⚠"), "Copy this now — it won't be shown again:");
258
+ console.log(` API key: ${chalk.bold(data.apiKey)}`);
259
+ }
260
+ catch (err) {
261
+ handleError(err);
262
+ }
263
+ });
264
+ const profileDeleteCommand = new Command("delete")
265
+ .description("Delete a mailer profile (admin)")
266
+ .argument("<id>", "Account ID or slug")
267
+ .argument("<slug>", "Profile slug")
268
+ .option("--json", "Output as JSON")
269
+ .action(async (id, slug, opts) => {
270
+ try {
271
+ await api.delete(`/aws-accounts/${id}/profiles/${slug}`);
272
+ if (opts.json)
273
+ console.log(JSON.stringify({ deleted: true, slug }));
274
+ else
275
+ console.log(chalk.green("✓"), "Profile deleted");
276
+ }
277
+ catch (err) {
278
+ handleError(err);
279
+ }
280
+ });
281
+ const profileCommand = new Command("profile")
282
+ .description("Manage mailer profiles")
283
+ .addCommand(profileListCommand)
284
+ .addCommand(profileCreateCommand)
285
+ .addCommand(profileRotateKeyCommand)
286
+ .addCommand(profileDeleteCommand);
287
+ // --- SES subcommand ---
288
+ const sesIdentityListCommand = new Command("list")
289
+ .description("List SES identities for an account")
290
+ .argument("<id>", "Account ID or slug")
291
+ .option("--json", "Output as JSON")
292
+ .action(async (id, opts) => {
293
+ try {
294
+ const data = await api.get(`/aws-accounts/${id}/ses/identities`);
295
+ printList(data, [
296
+ { key: "domain", label: "Domain", width: 28 },
297
+ { key: "status", label: "Status", width: 12 },
298
+ { key: "dkimStatus", label: "DKIM", width: 12 },
299
+ { key: "lastCheckedAt", label: "Checked", width: 24 },
300
+ { key: "id", label: "ID", width: 38 },
301
+ ], opts);
302
+ }
303
+ catch (err) {
304
+ handleError(err);
305
+ }
306
+ });
307
+ const sesIdentityCreateCommand = new Command("create")
308
+ .description("Add an SES identity (admin)")
309
+ .argument("<id>", "Account ID or slug")
310
+ .option("--domain <domain>", "Domain (defaults to the sending domain)")
311
+ .option("--json", "Output as JSON")
312
+ .action(async (id, opts) => {
313
+ try {
314
+ const payload = {};
315
+ if (opts.domain !== undefined)
316
+ payload.domain = opts.domain;
317
+ const data = await api.post(`/aws-accounts/${id}/ses/identities`, payload);
318
+ if (opts.json)
319
+ console.log(JSON.stringify(data, null, 2));
320
+ else
321
+ console.log(chalk.green("✓"), `SES identity added: ${chalk.bold(data.domain)} (${data.status})`);
322
+ }
323
+ catch (err) {
324
+ handleError(err);
325
+ }
326
+ });
327
+ const sesIdentityRefreshCommand = new Command("refresh")
328
+ .description("Refresh an SES identity's verification status")
329
+ .argument("<id>", "Account ID or slug")
330
+ .argument("<identityId>", "Identity ID")
331
+ .option("--json", "Output as JSON")
332
+ .action(async (id, identityId, opts) => {
333
+ try {
334
+ const data = await api.post(`/aws-accounts/${id}/ses/identities/${identityId}/refresh`, {});
335
+ if (opts.json)
336
+ console.log(JSON.stringify(data, null, 2));
337
+ else
338
+ console.log(chalk.green("✓"), `${data.domain} is ${data.status}`);
339
+ }
340
+ catch (err) {
341
+ handleError(err);
342
+ }
343
+ });
344
+ const sesIdentityDeleteCommand = new Command("delete")
345
+ .description("Delete an SES identity (admin)")
346
+ .argument("<id>", "Account ID or slug")
347
+ .argument("<identityId>", "Identity ID")
348
+ .option("--json", "Output as JSON")
349
+ .action(async (id, identityId, opts) => {
350
+ try {
351
+ await api.delete(`/aws-accounts/${id}/ses/identities/${identityId}`);
352
+ if (opts.json)
353
+ console.log(JSON.stringify({ deleted: true, id: identityId }));
354
+ else
355
+ console.log(chalk.green("✓"), "SES identity deleted");
356
+ }
357
+ catch (err) {
358
+ handleError(err);
359
+ }
360
+ });
361
+ const sesIdentityCommand = new Command("identity")
362
+ .description("Manage SES domain identities")
363
+ .addCommand(sesIdentityListCommand)
364
+ .addCommand(sesIdentityCreateCommand)
365
+ .addCommand(sesIdentityRefreshCommand)
366
+ .addCommand(sesIdentityDeleteCommand);
367
+ const sesAccountCommand = new Command("account")
368
+ .description("Show SES account sending status")
369
+ .argument("<id>", "Account ID or slug")
370
+ .option("--json", "Output as JSON")
371
+ .action(async (id, opts) => {
372
+ try {
373
+ const data = await api.get(`/aws-accounts/${id}/ses/account`);
374
+ if (opts.json) {
375
+ console.log(JSON.stringify(data, null, 2));
376
+ return;
377
+ }
378
+ printDetail(data, [
379
+ { key: "productionEnabled", label: "Production enabled" },
380
+ { key: "sendingEnabled", label: "Sending enabled" },
381
+ { key: "max24hSend", label: "Max 24h send" },
382
+ { key: "maxSendRate", label: "Max send rate" },
383
+ { key: "sentLast24h", label: "Sent last 24h" },
384
+ { key: "enforcementStatus", label: "Enforcement" },
385
+ ], opts);
386
+ }
387
+ catch (err) {
388
+ handleError(err);
389
+ }
390
+ });
391
+ const sesDefaultsCommand = new Command("defaults")
392
+ .description("Show SES default sender / reply-to")
393
+ .argument("<id>", "Account ID or slug")
394
+ .option("--json", "Output as JSON")
395
+ .action(async (id, opts) => {
396
+ try {
397
+ const data = await api.get(`/aws-accounts/${id}/ses/defaults`);
398
+ if (opts.json) {
399
+ console.log(JSON.stringify(data, null, 2));
400
+ return;
401
+ }
402
+ printDetail(data, [
403
+ { key: "defaultSender", label: "Default sender" },
404
+ { key: "defaultReplyTo", label: "Default reply-to" },
405
+ ], opts);
406
+ }
407
+ catch (err) {
408
+ handleError(err);
409
+ }
410
+ });
411
+ const sesSetDefaultsCommand = new Command("set-defaults")
412
+ .description("Set SES default sender / reply-to (admin; empty string clears)")
413
+ .argument("<id>", "Account ID or slug")
414
+ .option("--sender <sender>", 'Default sender (e.g. "Acme <noreply@acme.com>")')
415
+ .option("--reply-to <replyTo>", "Default reply-to address")
416
+ .option("--json", "Output as JSON")
417
+ .action(async (id, opts) => {
418
+ try {
419
+ const payload = {};
420
+ if (opts.sender !== undefined)
421
+ payload.defaultSender = opts.sender;
422
+ if (opts.replyTo !== undefined)
423
+ payload.defaultReplyTo = opts.replyTo;
424
+ const data = await api.post(`/aws-accounts/${id}/ses/defaults`, payload);
425
+ if (opts.json)
426
+ console.log(JSON.stringify(data, null, 2));
427
+ else
428
+ console.log(chalk.green("✓"), "SES defaults updated");
429
+ }
430
+ catch (err) {
431
+ handleError(err);
432
+ }
433
+ });
434
+ const sesCommand = new Command("ses")
435
+ .description("Manage SES identities, defaults and status")
436
+ .addCommand(sesIdentityCommand)
437
+ .addCommand(sesAccountCommand)
438
+ .addCommand(sesDefaultsCommand)
439
+ .addCommand(sesSetDefaultsCommand);
440
+ // --- email stats subcommand ---
441
+ const emailStatsCommand = new Command("stats")
442
+ .description("Daily email event counts")
443
+ .argument("<id>", "Account ID or slug")
444
+ .option("--days <n>", "Window in days (1-90, default 30)", (v) => parseInt(v, 10))
445
+ .option("--json", "Output as JSON")
446
+ .action(async (id, opts) => {
447
+ try {
448
+ const params = new URLSearchParams();
449
+ if (opts.days != null)
450
+ params.set("days", String(opts.days));
451
+ const qs = params.toString();
452
+ const data = await api.get(`/aws-accounts/${id}/email/stats${qs ? `?${qs}` : ""}`);
453
+ printList(data.map((d) => ({
454
+ day: d.day,
455
+ counts: fmtCounts(d.counts),
456
+ })), [
457
+ { key: "day", label: "Day", width: 14 },
458
+ { key: "counts", label: "Events", width: 60 },
459
+ ], opts);
460
+ }
461
+ catch (err) {
462
+ handleError(err);
463
+ }
464
+ });
465
+ const emailMonthlyCommand = new Command("monthly")
466
+ .description("This month vs last month email totals")
467
+ .argument("<id>", "Account ID or slug")
468
+ .option("--json", "Output as JSON")
469
+ .action(async (id, opts) => {
470
+ try {
471
+ const data = await api.get(`/aws-accounts/${id}/email/monthly`);
472
+ if (opts.json) {
473
+ console.log(JSON.stringify(data, null, 2));
474
+ return;
475
+ }
476
+ if (!data) {
477
+ console.log(chalk.dim("No email events table deployed for this account."));
478
+ return;
479
+ }
480
+ for (const bucket of [data.thisMonth, data.prevMonth]) {
481
+ console.log(` ${chalk.bold(bucket.month)} ${bucket.sends} sends ${chalk.dim(`(${bucket.daysWithData} days with data)`)}`);
482
+ console.log(chalk.dim(` ${fmtCounts(bucket.counts)}`));
483
+ }
484
+ }
485
+ catch (err) {
486
+ handleError(err);
487
+ }
488
+ });
489
+ const emailEventsCommand = new Command("events")
490
+ .description("Recent email events")
491
+ .argument("<id>", "Account ID or slug")
492
+ .option("--days <n>", "Window in days (1-14, default 3)", (v) => parseInt(v, 10))
493
+ .option("--limit <n>", "Max rows (1-200, default 50)", (v) => parseInt(v, 10))
494
+ .option("--json", "Output as JSON")
495
+ .action(async (id, opts) => {
496
+ try {
497
+ const params = new URLSearchParams();
498
+ if (opts.days != null)
499
+ params.set("days", String(opts.days));
500
+ if (opts.limit != null)
501
+ params.set("limit", String(opts.limit));
502
+ const qs = params.toString();
503
+ const data = await api.get(`/aws-accounts/${id}/email/events${qs ? `?${qs}` : ""}`);
504
+ printList(data, [
505
+ { key: "eventType", label: "Event", width: 16 },
506
+ { key: "messageId", label: "Message ID", width: 40 },
507
+ { key: "timestamp", label: "When", width: 26 },
508
+ ], opts);
509
+ }
510
+ catch (err) {
511
+ handleError(err);
512
+ }
513
+ });
514
+ const emailMessageCommand = new Command("message")
515
+ .description("Event timeline for one message")
516
+ .argument("<id>", "Account ID or slug")
517
+ .argument("<messageId>", "Message ID")
518
+ .option("--json", "Output as JSON")
519
+ .action(async (id, messageId, opts) => {
520
+ try {
521
+ const data = await api.get(`/aws-accounts/${id}/email/events/${encodeURIComponent(messageId)}`);
522
+ printList(data, [
523
+ { key: "eventType", label: "Event", width: 16 },
524
+ { key: "timestamp", label: "When", width: 26 },
525
+ ], opts);
526
+ }
527
+ catch (err) {
528
+ handleError(err);
529
+ }
530
+ });
531
+ const emailCommand = new Command("email")
532
+ .description("Inspect SES email delivery events")
533
+ .addCommand(emailStatsCommand)
534
+ .addCommand(emailMonthlyCommand)
535
+ .addCommand(emailEventsCommand)
536
+ .addCommand(emailMessageCommand);
537
+ // --- warmup subcommand ---
538
+ const warmupListCommand = new Command("list")
539
+ .description("List SES warm-up runs")
540
+ .argument("<id>", "Account ID or slug")
541
+ .option("--json", "Output as JSON")
542
+ .action(async (id, opts) => {
543
+ try {
544
+ const data = await api.get(`/aws-accounts/${id}/warmup/runs`);
545
+ printList(data.map((r) => ({
546
+ ...r,
547
+ progress: r.progress ? `${r.progress.done}/${r.progress.total}` : "-",
548
+ })), [
549
+ { key: "status", label: "Status", width: 12 },
550
+ { key: "brand", label: "Brand", width: 18 },
551
+ { key: "progress", label: "Progress", width: 10 },
552
+ { key: "startedAt", label: "Started", width: 24 },
553
+ { key: "id", label: "ID", width: 38 },
554
+ ], opts);
555
+ }
556
+ catch (err) {
557
+ handleError(err);
558
+ }
559
+ });
560
+ const warmupCreateCommand = new Command("create")
561
+ .description("Start an SES warm-up run (admin)")
562
+ .argument("<id>", "Account ID or slug")
563
+ .option("--signups <n>", "Signup flows (2-6, random if omitted)", (v) => parseInt(v, 10))
564
+ .option("--magic-links <n>", "Magic-link flows (2-4)", (v) => parseInt(v, 10))
565
+ .option("--forgot-password <n>", "Forgot-password flows (1-2)", (v) => parseInt(v, 10))
566
+ .option("--json", "Output as JSON")
567
+ .action(async (id, opts) => {
568
+ try {
569
+ const payload = {};
570
+ if (opts.signups != null)
571
+ payload.signups = opts.signups;
572
+ if (opts.magicLinks != null)
573
+ payload.magicLinks = opts.magicLinks;
574
+ if (opts.forgotPassword != null)
575
+ payload.forgotPassword = opts.forgotPassword;
576
+ const data = await api.post(`/aws-accounts/${id}/warmup/runs`, payload);
577
+ if (opts.json) {
578
+ console.log(JSON.stringify(data, null, 2));
579
+ return;
580
+ }
581
+ console.log(chalk.green("✓"), `Warm-up started: ${chalk.bold(data.run.id)} (${data.stepCount} steps)`);
582
+ }
583
+ catch (err) {
584
+ handleError(err);
585
+ }
586
+ });
587
+ const warmupGetCommand = new Command("get")
588
+ .description("Show a warm-up run and its steps")
589
+ .argument("<id>", "Account ID or slug")
590
+ .argument("<runId>", "Warm-up run ID")
591
+ .option("--json", "Output as JSON")
592
+ .action(async (id, runId, opts) => {
593
+ try {
594
+ const data = await api.get(`/aws-accounts/${id}/warmup/runs/${runId}`);
595
+ if (opts.json) {
596
+ console.log(JSON.stringify(data, null, 2));
597
+ return;
598
+ }
599
+ console.log(chalk.bold(data.brand), chalk.dim(`(${data.status})`), data.progress
600
+ ? chalk.dim(`${data.progress.done}/${data.progress.total}`)
601
+ : "");
602
+ printList(data.steps, [
603
+ { key: "flow", label: "Flow", width: 16 },
604
+ { key: "kind", label: "Kind", width: 8 },
605
+ { key: "status", label: "Status", width: 10 },
606
+ { key: "recipient", label: "Recipient", width: 30 },
607
+ { key: "runAt", label: "Run at", width: 24 },
608
+ ], opts);
609
+ }
610
+ catch (err) {
611
+ handleError(err);
612
+ }
613
+ });
614
+ const warmupCancelCommand = new Command("cancel")
615
+ .description("Cancel a running warm-up (admin)")
616
+ .argument("<id>", "Account ID or slug")
617
+ .argument("<runId>", "Warm-up run ID")
618
+ .option("--json", "Output as JSON")
619
+ .action(async (id, runId, opts) => {
620
+ try {
621
+ const data = await api.post(`/aws-accounts/${id}/warmup/runs/${runId}/cancel`, {});
622
+ if (opts.json)
623
+ console.log(JSON.stringify(data, null, 2));
624
+ else
625
+ console.log(chalk.green("✓"), `Warm-up ${data.status}`);
626
+ }
627
+ catch (err) {
628
+ handleError(err);
629
+ }
630
+ });
631
+ const warmupCommand = new Command("warmup")
632
+ .description("Manage SES warm-up runs")
633
+ .addCommand(warmupListCommand)
634
+ .addCommand(warmupCreateCommand)
635
+ .addCommand(warmupGetCommand)
636
+ .addCommand(warmupCancelCommand);
637
+ export const awsAccountCommand = new Command("aws-account")
638
+ .description("Manage AWS accounts, SES, credentials and warm-up")
639
+ .addCommand(createCommand)
640
+ .addCommand(listCommand)
641
+ .addCommand(getCommand)
642
+ .addCommand(updateCommand)
643
+ .addCommand(testEmailCommand)
644
+ .addCommand(credentialCommand)
645
+ .addCommand(profileCommand)
646
+ .addCommand(sesCommand)
647
+ .addCommand(emailCommand)
648
+ .addCommand(warmupCommand);
649
+ //# sourceMappingURL=aws-accounts.js.map