@myapihq/cli 2.31.4 → 2.31.5

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.
@@ -51,6 +51,9 @@ export const SCHEMA = {
51
51
  'registrant-state': 'string',
52
52
  'registrant-postal-code': 'string',
53
53
  'registrant-country': 'string',
54
+ // Alias for --registrant-country, kept because account declared this
55
+ // spelling for the same field. See fromFlags in registrant.ts.
56
+ 'registrant-country-code': 'string',
54
57
  'registrant-organization': 'string',
55
58
  // DNS records sub-surface
56
59
  type: 'string',
@@ -26,7 +26,7 @@ export async function interactions(flags) {
26
26
  const config = requireConfig();
27
27
  const orgId = flags.org || config.default_org;
28
28
  if (!orgId) {
29
- error("Missing required arguments.\nUsage: myapi pixel interactions --org <id> [--website <domain>] [--campaign-id <id>] [--domain <domain>]\n(Or set defaults via: myapi config set-org <id>)");
29
+ error("Missing required arguments.\nUsage: myapi pixel interactions (--website <host> | --campaign-id <id> | --domain <domain>) [--org <id>]\n --website: a site YOU own, where your pixel runs · --domain: a domain your visitors went to\n(Or set defaults via: myapi config set-org <id>)");
30
30
  }
31
31
  const params = {};
32
32
  if (flags.website)
@@ -44,7 +44,7 @@ export async function interactions(flags) {
44
44
  if (flags.offset)
45
45
  params.offset = parseInt(flags.offset, 10);
46
46
  if (!params.website && !params.campaign_id && !params.domain) {
47
- error("You must provide at least one filter: --website, --campaign-id, or --domain");
47
+ error("You must provide at least one filter.\n --website <host> a site you own (where your pixel runs)\n --campaign-id <id> one email campaign\n --domain <domain> a domain your visitors went to");
48
48
  }
49
49
  const res = await sdkPixel.getInteractions(config.api_key, orgId, params);
50
50
  if (flags.json) {
@@ -195,7 +195,7 @@ Subcommands:
195
195
  identify Link a known email/user id to an anonymous pixel visitor
196
196
  identity Resolve the identity graph (emails, IPs, profiles) for a pixel ID
197
197
  interactions Get a unified timeline of visits and events
198
- (requires at least one filter: --website, --campaign-id, or --domain)
198
+ (requires one of: --website = a site you own · --campaign-id · --domain = a visited domain)
199
199
  visits Page-visit timeline scoped to a website host
200
200
 
201
201
  All commands accept --org <id> (or set default: myapi config set-org <id>).`);
@@ -113,8 +113,13 @@ export async function run(_subcommand, _args, flags = {}) {
113
113
  info(`Recharge: ${summary}`);
114
114
  }
115
115
  if (Array.isArray(freeTier) && freeTier.length > 0) {
116
+ // A zero allowance rendered as "domain 0/0" reads like an error and says
117
+ // nothing a user can act on — there is no free tier for that slot, which
118
+ // is the platform's default, not this account's state. Show a slot only
119
+ // when there is an allowance to consume or usage to explain.
116
120
  const parts = freeTier
117
121
  .filter((e) => e && typeof e.service === 'string')
122
+ .filter((e) => (e.allowance ?? 0) > 0 || (e.used ?? 0) > 0)
118
123
  .map((e) => `${e.service} ${e.used ?? 0}/${e.allowance ?? '?'}`);
119
124
  if (parts.length > 0)
120
125
  info(`FreeTier: ${parts.join(' · ')}`);
@@ -21,6 +21,21 @@ import { saveConfig } from './config.js';
21
21
  // whether the partial is "complete enough" (we require all six base
22
22
  // fields plus country_code; state is optional).
23
23
  function fromFlags(flags) {
24
+ // Two spellings exist in the wild: account's schema declared
25
+ // `registrant-country-code` while this reader only ever read
26
+ // `registrant-country` — so the -code spelling was typed, swallowed a value,
27
+ // and did nothing. A scripted `account registrant set` then failed with
28
+ // "country_code missing" while the country sat in argv. Accept both;
29
+ // `registrant-country` is canonical (matching the rest of the family, which
30
+ // carries no type suffixes). Both-with-different-values is refused rather
31
+ // than resolved by precedence.
32
+ const country = flags['registrant-country'];
33
+ const countryAlias = flags['registrant-country-code'];
34
+ if (typeof country === 'string' && typeof countryAlias === 'string' && country !== countryAlias) {
35
+ error(`--registrant-country ("${country}") and --registrant-country-code ("${countryAlias}") disagree — they are the same field. Pass one.`);
36
+ }
37
+ const countryCode = typeof country === 'string' ? country
38
+ : typeof countryAlias === 'string' ? countryAlias : undefined;
24
39
  return {
25
40
  name: typeof flags['registrant-name'] === 'string' ? flags['registrant-name'] : undefined,
26
41
  email: typeof flags['registrant-email'] === 'string' ? flags['registrant-email'] : undefined,
@@ -29,7 +44,7 @@ function fromFlags(flags) {
29
44
  city: typeof flags['registrant-city'] === 'string' ? flags['registrant-city'] : undefined,
30
45
  state: typeof flags['registrant-state'] === 'string' ? flags['registrant-state'] : undefined,
31
46
  postal_code: typeof flags['registrant-postal-code'] === 'string' ? flags['registrant-postal-code'] : undefined,
32
- country_code: typeof flags['registrant-country'] === 'string' ? flags['registrant-country'] : undefined,
47
+ country_code: countryCode,
33
48
  organization: typeof flags['registrant-organization'] === 'string' ? flags['registrant-organization'] : undefined,
34
49
  };
35
50
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { resolveRegistrantForRegister } from './registrant.js';
3
+ import { withSink, CommandFailed } from './output.js';
4
+ // error() exits the process unless a sink captures it — same pattern as
5
+ // dispatch-in-process.test.ts.
6
+ const SINK = { out: () => { }, err: () => { }, fail: (m) => { throw new CommandFailed(m); } };
7
+ // `--registrant-country-code` was declared in account's SCHEMA but read by
8
+ // nothing: fromFlags only ever looked at `registrant-country`. The -code
9
+ // spelling consumed a value and discarded it, so a scripted registrant set
10
+ // failed with "country_code missing" while the country sat in argv. Found
11
+ // 2026-08-24 by dumping every SCHEMA key and asking which have no consumer.
12
+ // Both spellings are read now; these tests pin that to behaviour, not to a
13
+ // schema entry a lint could satisfy without a consumer.
14
+ const BASE = {
15
+ 'registrant-name': 'Ada Lovelace',
16
+ 'registrant-email': 'ada@example.com',
17
+ 'registrant-phone': '+44.2071234567',
18
+ 'registrant-street': '12 Analytical Way',
19
+ 'registrant-city': 'London',
20
+ 'registrant-postal-code': 'EC1A 1AA',
21
+ };
22
+ const CONFIG = {};
23
+ describe('registrant country spellings', () => {
24
+ it('canonical --registrant-country reaches country_code', async () => {
25
+ const r = await resolveRegistrantForRegister({ ...BASE, 'registrant-country': 'GB' }, CONFIG);
26
+ expect(r.country_code).toBe('GB');
27
+ });
28
+ it('the alias --registrant-country-code reaches country_code too', async () => {
29
+ const r = await resolveRegistrantForRegister({ ...BASE, 'registrant-country-code': 'GB' }, CONFIG);
30
+ expect(r.country_code).toBe('GB');
31
+ });
32
+ it('both spellings with different values are refused, not resolved by precedence', async () => {
33
+ await expect(withSink(SINK, () => resolveRegistrantForRegister({ ...BASE, 'registrant-country': 'GB', 'registrant-country-code': 'DE' }, CONFIG))).rejects.toThrow(/disagree/);
34
+ });
35
+ it('both spellings agreeing is fine', async () => {
36
+ const r = await resolveRegistrantForRegister({ ...BASE, 'registrant-country': 'GB', 'registrant-country-code': 'GB' }, CONFIG);
37
+ expect(r.country_code).toBe('GB');
38
+ });
39
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@myapihq/cli",
3
3
  "license": "Apache-2.0",
4
- "version": "2.31.4",
4
+ "version": "2.31.5",
5
5
  "description": "MyAPI command-line interface",
6
6
  "repository": {
7
7
  "type": "git",
@@ -35,6 +35,8 @@
35
35
  "lint:help-order": "node scripts/lint-help-order.js",
36
36
  "lint:exposes": "node scripts/lint-exposes.js",
37
37
  "lint:query-params": "node scripts/lint-query-params.js",
38
+ "lint:flag-lexicon": "node scripts/lint-flag-lexicon.js",
39
+ "lint:verb-symmetry": "node scripts/lint-verb-symmetry.js",
38
40
  "lint:request-fields": "node scripts/lint-request-fields.js",
39
41
  "audit:doctor": "npm run build && node scripts/audit-doctor.js",
40
42
  "lint:docs": "node scripts/lint-docs.js",
@@ -47,7 +49,7 @@
47
49
  "lint:skills:strict": "node scripts/copy-skills.js && node scripts/lint-skills.js --strict"
48
50
  },
49
51
  "dependencies": {
50
- "@myapihq/sdk": "^2.31.4"
52
+ "@myapihq/sdk": "^2.31.5"
51
53
  },
52
54
  "devDependencies": {
53
55
  "@types/node": "^25.6.0",