@myapihq/cli 2.23.2 → 2.23.3

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.
@@ -50,3 +50,13 @@ describe('campaign source flags', () => {
50
50
  expect(unread, 'watched by update() but never read when building a source').toEqual([]);
51
51
  });
52
52
  });
53
+ describe('campaign delete', () => {
54
+ // The backend shipped DELETE and the CLI did not, so the only way to remove a
55
+ // campaign was a raw HTTP call. A verb that exists on one side of the wire
56
+ // and not the other is invisible until someone needs it.
57
+ it('is dispatched and declared', async () => {
58
+ const mod = await import('./campaign.js');
59
+ expect(mod.HELP).toContain('delete <id>');
60
+ expect(mod.EXPOSES).toContain('DELETE /email/orgs/{org_id}/campaigns/{campaign_id}');
61
+ });
62
+ });
@@ -1,6 +1,6 @@
1
1
  import { type Flags } from '../../helpers.js';
2
2
  import type { Exposes } from '../../exposes.js';
3
3
  export declare const EXPOSES: Exposes;
4
- export declare const HELP = "Usage: myapi email campaign <subcommand>\n\n create Create a draft (--template, --from, and a source)\n list Campaigns in this org\n get <id> One campaign\n update <id> Edit a DRAFT's name or source\n resolve <id> Freeze who it reaches; reports the count and cost, sends nothing\n start <id> Begin sending a resolved campaign\n pause <id> Stop after the message in flight\n resume <id> Continue a paused campaign\n cancel <id> End it for good; queued recipients are dropped\n recipients <id> Who it resolved to, and what happened to each\n stats <id> Counts by state, sent today, and the daily limit\n\nA campaign drains at its per-day limit rather than sending at once, so it is\ncommonly still active tomorrow \u2014 that is the design, not a stall.\n\nRecipients come from a SOURCE, not a list you upload:\n --crm-stage / --crm-origin / --crm-max-days filter CRM contacts\n --crm-audience <id> only people promoted from it\n --addresses a@x.com,b@y.com an explicit short list";
4
+ export declare const HELP = "Usage: myapi email campaign <subcommand>\n\n create Create a draft (--template, --from, and a source)\n list Campaigns in this org\n get <id> One campaign\n update <id> Edit a DRAFT's name or source\n resolve <id> Freeze who it reaches; reports the count and cost, sends nothing\n start <id> Begin sending a resolved campaign\n pause <id> Stop after the message in flight\n resume <id> Continue a paused campaign\n cancel <id> End it for good; queued recipients are dropped\n recipients <id> Who it resolved to, and what happened to each\n stats <id> Counts by state, sent today, and the daily limit\n delete <id> Remove it and its recipient rows; what was sent stays in the log\n\nA campaign drains at its per-day limit rather than sending at once, so it is\ncommonly still active tomorrow \u2014 that is the design, not a stall.\n\nRecipients come from a SOURCE, not a list you upload:\n --crm-stage / --crm-origin / --crm-max-days filter CRM contacts\n --crm-audience <id> only people promoted from it\n --addresses a@x.com,b@y.com an explicit short list";
5
5
  export declare const SOURCE_FLAGS: readonly ["addresses", "crm-stage", "crm-origin", "crm-company", "crm-audience", "crm-max-days", "crm-min-days", "all-contacts"];
6
6
  export declare function run(sub: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -7,6 +7,7 @@ export const EXPOSES = [
7
7
  'POST /email/orgs/{org_id}/campaigns',
8
8
  'GET /email/orgs/{org_id}/campaigns',
9
9
  'GET /email/orgs/{org_id}/campaigns/{campaign_id}',
10
+ 'DELETE /email/orgs/{org_id}/campaigns/{campaign_id}',
10
11
  'PATCH /email/orgs/{org_id}/campaigns/{campaign_id}',
11
12
  'POST /email/orgs/{org_id}/campaigns/{campaign_id}/resolve',
12
13
  'POST /email/orgs/{org_id}/campaigns/{campaign_id}/start',
@@ -29,6 +30,7 @@ export const HELP = `Usage: myapi email campaign <subcommand>
29
30
  cancel <id> End it for good; queued recipients are dropped
30
31
  recipients <id> Who it resolved to, and what happened to each
31
32
  stats <id> Counts by state, sent today, and the daily limit
33
+ delete <id> Remove it and its recipient rows; what was sent stays in the log
32
34
 
33
35
  A campaign drains at its per-day limit rather than sending at once, so it is
34
36
  commonly still active tomorrow — that is the design, not a stall.
@@ -203,6 +205,19 @@ async function transition(verb, id, flags) {
203
205
  info(`It sends up to its daily limit and continues tomorrow — check with: myapi email campaign stats ${id}`);
204
206
  }
205
207
  }
208
+ async function remove(id, flags) {
209
+ const config = requireConfig();
210
+ const orgId = requireOrg(flags, config, 'myapi email campaign delete <id>');
211
+ const r = await sdkEmail.deleteCampaign(config.api_key, orgId, id);
212
+ if (flags.json) {
213
+ printJson(r);
214
+ return;
215
+ }
216
+ success(`Deleted campaign ${r.id}`);
217
+ // People reach for delete to undo a send. It does not undo one, and saying
218
+ // so here is cheaper than letting them find out from a reply.
219
+ info('Messages already sent stay in the send log — this removed the campaign, not the mail.');
220
+ }
206
221
  async function recipients(id, flags) {
207
222
  const config = requireConfig();
208
223
  const orgId = requireOrg(flags, config, 'myapi email campaign recipients <id> [--state queued|sent|failed|excluded]');
@@ -252,6 +267,7 @@ export async function run(sub, args, flags) {
252
267
  case 'cancel': return transition('cancel', need('myapi email campaign cancel <id>'), flags);
253
268
  case 'recipients': return recipients(need('myapi email campaign recipients <id>'), flags);
254
269
  case 'stats': return stats(need('myapi email campaign stats <id>'), flags);
270
+ case 'delete': return remove(need('myapi email campaign delete <id>'), flags);
255
271
  default: error(`Unknown subcommand: email campaign ${sub}. Run "myapi email campaign --help".`);
256
272
  }
257
273
  }
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: my-email-api
3
- version: 1.2.0
3
+ version: 1.2.1
4
4
  description: >
5
5
  Send transactional and bulk email from your own domain. Create mailboxes, send/receive messages, generate AI templates, and manage warmup.
6
6
  triggers: [email, mailbox, send email, transactional email, template, warmup, inbox, outbox, ses, sender reputation]
7
- checksum: sha256-897cf3dbc843ca06d02aecf298151e8635890852a5db8ab4035ee59df8db0aa9
7
+ checksum: sha256-b458699a69c15d02d33dab6bc00445f05fb6e55ee844d35d8b745a13a6533b9e
8
8
  ---
9
9
 
10
10
  # MyEmailAPI
@@ -28,7 +28,7 @@ A registered domain via **mydomainapi** is the prerequisite — mailboxes need a
28
28
  | `email message` | `send`, `status`, `sent`, `inbox`, `outbox`, `get` | Transactional send + read |
29
29
  | `email warmup` | `start`, `stats`, `pause`, `resume`, `stop` | IP/domain warmup for sending reputation |
30
30
  | `email template` | `generate`, `list`, `get`, `preview`, `edit`, `send-test`, `delete` | AI-generated HTML templates |
31
- | `email campaign` | `create`, `list`, `get`, `update`, `resolve`, `start`, `pause`, `resume`, `cancel`, `recipients`, `stats` | Scheduled bulk send that drains at a daily limit |
31
+ | `email campaign` | `create`, `list`, `get`, `update`, `resolve`, `start`, `pause`, `resume`, `cancel`, `recipients`, `stats`, `delete` | Scheduled bulk send that drains at a daily limit |
32
32
  <!-- generated:end -->
33
33
 
34
34
  ## Examples
@@ -120,7 +120,9 @@ Four things that decide how you use it:
120
120
 
121
121
  `pause` stops after the message in flight; `resume` continues; `cancel` ends it
122
122
  and drops what was queued. Status `paused_insufficient_funds` means the account
123
- could not pay — top up or enable auto-recharge, then `resume`.
123
+ could not pay — top up or enable auto-recharge, then `resume`. `delete` removes
124
+ the campaign and its recipients, never the send log — it tidies up, it does not
125
+ unsend, and it refuses while a campaign is active.
124
126
 
125
127
  ## Notes
126
128
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@myapihq/cli",
3
3
  "license": "Apache-2.0",
4
- "version": "2.23.2",
4
+ "version": "2.23.3",
5
5
  "description": "MyAPI command-line interface",
6
6
  "repository": {
7
7
  "type": "git",
@@ -46,7 +46,7 @@
46
46
  "lint:skills:strict": "node scripts/copy-skills.js && node scripts/lint-skills.js --strict"
47
47
  },
48
48
  "dependencies": {
49
- "@myapihq/sdk": "^2.23.2"
49
+ "@myapihq/sdk": "^2.23.3"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^25.6.0",