@myapihq/cli 1.0.74 → 1.0.75

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.
@@ -6,11 +6,21 @@ export async function check(domainArg, flags) {
6
6
  const config = requireConfig();
7
7
  const orgId = flags.org || config.default_org;
8
8
  const domain = domainArg || config.default_domain;
9
- if (!orgId || !domain)
10
- error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Set defaults: myapi auth config set-org <id> / myapi auth config set-domain <domain>)");
9
+ if (!orgId || !domain) {
10
+ const hint = config.default_org
11
+ ? `(current default org: ${config.default_org})`
12
+ : '(Set defaults: myapi config set-org <id> / myapi config set-domain <domain>)';
13
+ error(`Missing required arguments.\nUsage: myapi domain check <domain>${config.default_org ? '' : ' --org <id>'}\n${hint}`);
14
+ }
11
15
  const res = await sdkDomain.checkDomain(config.api_key, orgId, domain);
12
16
  if (flags.json) {
13
- printJson(res);
17
+ const out = { domain, available: res.available };
18
+ if (res.available) {
19
+ out.price_cents = res.price_cents;
20
+ if (res.price_display)
21
+ out.price_display = res.price_display;
22
+ }
23
+ printJson(out);
14
24
  return;
15
25
  }
16
26
  if (res.available) {
@@ -2,6 +2,6 @@ export declare function list(flags: Record<string, string | boolean>): Promise<v
2
2
  export declare function create(flags: Record<string, string | boolean>): Promise<void>;
3
3
  export declare function get(id: string, flags: Record<string, string | boolean>): Promise<void>;
4
4
  export declare function del(id: string, flags: Record<string, string | boolean>): Promise<void>;
5
- export declare function push(id: string, slug: string, flags: Record<string, string | boolean>): Promise<void>;
5
+ export declare function push(slug: string, flags: Record<string, string | boolean>): Promise<void>;
6
6
  export declare function verify(id: string, flags: Record<string, string | boolean>): Promise<void>;
7
7
  export declare function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>): Promise<void>;
@@ -12,7 +12,12 @@ export async function list(flags) {
12
12
  printJson(funnels);
13
13
  return;
14
14
  }
15
- const rows = funnels.map(f => ({ id: f.id, created_at: formatDate(f.created_at), updated_at: formatDate(f.updated_at) }));
15
+ const rows = funnels.map(f => ({
16
+ id: f.id,
17
+ preview_url: f.subdomain_url || f.domain_url || '',
18
+ created_at: formatDate(f.created_at),
19
+ updated_at: formatDate(f.updated_at),
20
+ }));
16
21
  if (rows.length === 0) {
17
22
  info('No funnels found. Create one with: myapi funnel create');
18
23
  return;
@@ -38,7 +43,21 @@ export async function get(id, flags) {
38
43
  if (!orgId || !id)
39
44
  error("Missing required arguments.\nUsage: myapi funnel get <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
40
45
  const funnel = await sdkFunnel.getFunnel(config.api_key, orgId, id);
41
- printJson(funnel);
46
+ if (flags.json) {
47
+ printJson(funnel);
48
+ return;
49
+ }
50
+ info(`ID: ${funnel.id}`);
51
+ if (funnel.domain_url)
52
+ info(`Domain: ${funnel.domain_url}`);
53
+ else if (funnel.subdomain_url)
54
+ info(`Preview: ${funnel.subdomain_url}`);
55
+ if (funnel.created_at)
56
+ info(`Created: ${formatDate(funnel.created_at)}`);
57
+ if (funnel.updated_at)
58
+ info(`Updated: ${formatDate(funnel.updated_at)}`);
59
+ if (Array.isArray(funnel.pages))
60
+ info(`Pages: ${funnel.pages.length}`);
42
61
  }
43
62
  export async function del(id, flags) {
44
63
  const config = requireConfig();
@@ -48,17 +67,14 @@ export async function del(id, flags) {
48
67
  await sdkFunnel.deleteFunnel(config.api_key, orgId, id);
49
68
  success(`Funnel ${id} deleted`);
50
69
  }
51
- export async function push(id, slug, flags) {
70
+ export async function push(slug, flags) {
52
71
  const config = requireConfig();
53
72
  const orgId = flags.org || config.default_org;
54
73
  if (!orgId)
55
- error("Missing org. Set a default with: myapi auth config set-org <id>");
56
- if (slug && flags.slug && slug !== flags.slug) {
57
- info(`› Note: positional slug "${slug}" takes precedence over --slug "${flags.slug}".`);
58
- }
74
+ error("Missing org. Set a default with: myapi config set-org <id>");
59
75
  const rawSlug = slug || flags.slug || '/';
60
76
  const finalSlug = rawSlug.startsWith('/') ? rawSlug : `/${rawSlug}`;
61
- let funnelId = id || config.default_funnel;
77
+ let funnelId = flags.funnel || config.default_funnel;
62
78
  if (!funnelId) {
63
79
  const existing = await sdkFunnel.listFunnels(config.api_key, orgId);
64
80
  if (existing.length === 0)
@@ -75,7 +91,7 @@ export async function push(id, slug, flags) {
75
91
  process.stdin.on('error', reject);
76
92
  });
77
93
  if (!html.trim())
78
- error("No content provided via stdin. Usage: echo '<h1>Hello</h1>' | myapi funnel push [id] [slug]");
94
+ error("No content provided via stdin. Usage: echo '<h1>Hello</h1>' | myapi funnel push [slug]");
79
95
  const result = await sdkFunnel.pushFunnelPage(config.api_key, orgId, funnelId, { slug: finalSlug, html });
80
96
  success(`Pushed page to ${finalSlug}`);
81
97
  if (result?.url) {
@@ -114,7 +130,7 @@ export async function run(subcommand, args, flags) {
114
130
  else if (subcommand === 'delete')
115
131
  info('Usage: myapi funnel delete <id> --org <id>\n\nDeletes a funnel permanently.\n\nFlags:\n --org <id> Organization ID (or set default via myapi auth config set-org)');
116
132
  else if (subcommand === 'push')
117
- info('Usage: myapi funnel push [funnel_id] [slug] < page.html\n\nPublishes an HTML page from stdin to a path within your funnel (website).\n\nArgument resolution:\n - If the first positional argument starts with "/", it is treated as the slug\n (funnel_id is omitted and your default funnel is used).\n - If the first positional argument looks like a UUID, it is treated as funnel_id;\n the second argument (if any) is the slug.\n - Omit both to use your configured default funnel and slug "/".\n\nFlags:\n --org <id> Organization ID (or set default via myapi auth config set-org)\n --slug <path> Alternative way to specify the slug\n\nExamples:\n echo \'<h1>Hello</h1>\' | myapi funnel push / # push to / on default funnel\n cat about.html | myapi funnel push /about # push to /about\n myapi funnel push < index.html # push to / on default funnel\n cat p.html | myapi funnel push <uuid> /pricing # explicit funnel + slug');
133
+ info('Usage: myapi funnel push [slug] < page.html\n\nPublishes an HTML page from stdin to a path within your funnel (website).\nThe funnel is always resolved from your default or --funnel flag.\n\nFlags:\n --org <id> Organization ID (or set default via myapi config set-org)\n --funnel <id> Funnel ID (or set default via myapi config set-funnel)\n --slug <path> Alternative way to specify the slug\n\nExamples:\n echo \'<h1>Hello</h1>\' | myapi funnel push / # push to /\n cat about.html | myapi funnel push /about # push to /about\n myapi funnel push < index.html # push to / on default funnel\n cat p.html | myapi funnel push /pricing --funnel <uuid>');
118
134
  else if (subcommand === 'pull')
119
135
  info('Usage: myapi funnel pull [funnel_id] [slug]\n\nFetches the HTML content of a funnel page.');
120
136
  return;
@@ -128,7 +144,7 @@ export async function run(subcommand, args, flags) {
128
144
  else if (subcommand === 'delete')
129
145
  await del(args[0], flags);
130
146
  else if (subcommand === 'push')
131
- await push(args[0], args[1], flags);
147
+ await push(args[0], flags);
132
148
  else if (subcommand === 'verify')
133
149
  await verify(args[0], flags);
134
150
  else
@@ -51,7 +51,16 @@ export async function list(flags) {
51
51
  const config = requireConfig();
52
52
  const orgs = await hq.listOrgs(config.api_key);
53
53
  if (flags.json) {
54
- printJson(orgs);
54
+ if (flags.verbose) {
55
+ printJson(orgs);
56
+ return;
57
+ }
58
+ printJson(orgs.map((o) => ({
59
+ id: o.id,
60
+ name: o.name,
61
+ preview_subdomain: o.preview_subdomain || undefined,
62
+ created_at: o.created_at || undefined,
63
+ })));
55
64
  return;
56
65
  }
57
66
  const rows = orgs.map((o) => ({
@@ -66,12 +75,13 @@ export async function get(id, flags) {
66
75
  info('Usage: myapi org get <id> [--json]\n\nFetches details of a specific organization.\n\nFlags:\n --json Output raw JSON');
67
76
  return;
68
77
  }
69
- if (!id) {
70
- error("Missing org id. Usage: myapi org get <id>");
78
+ const config = requireConfig();
79
+ const resolvedId = id || config.default_org;
80
+ if (!resolvedId) {
81
+ error("Missing org id. Usage: myapi org get <id>\n(Or set a default: myapi config set-org <id>)");
71
82
  return;
72
83
  }
73
- const config = requireConfig();
74
- const org = await hq.getOrg(config.api_key, id);
84
+ const org = await hq.getOrg(config.api_key, resolvedId);
75
85
  if (flags.json) {
76
86
  printJson(org);
77
87
  return;
@@ -1,7 +1,7 @@
1
1
  import { execSync } from 'child_process';
2
2
  import { existsSync } from 'fs';
3
3
  import { loadConfig } from '../config.js';
4
- import { info, success } from '../output.js';
4
+ import { info, success, banner } from '../output.js';
5
5
  import { installSkills } from './setup.js';
6
6
  const REGISTRY_URL = 'https://registry.npmjs.org/@myapihq/cli/latest';
7
7
  const PACKUMENT_URL = 'https://registry.npmjs.org/@myapihq/cli';
@@ -46,7 +46,10 @@ function npmInstallArgs(version) {
46
46
  }
47
47
  // checkForUpdate runs silently in the background on every command.
48
48
  // Auto-installs if a newer version is available.
49
+ // Suppress entirely with MYAPI_NO_UPDATE=1 or when stdout is not a TTY.
49
50
  export async function checkForUpdate(currentVersion) {
51
+ if (process.env.MYAPI_NO_UPDATE === '1' || !process.stdout.isTTY)
52
+ return;
50
53
  try {
51
54
  const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(3000) });
52
55
  if (!res.ok)
@@ -59,7 +62,7 @@ export async function checkForUpdate(currentVersion) {
59
62
  // (which `npm install` consults) has propagated through the CDN.
60
63
  if (!(await isVersionInstallable(latest)))
61
64
  return;
62
- info(`\n› New version available (${currentVersion} → ${latest}) — installing…`);
65
+ banner(`\n› New version available (${currentVersion} → ${latest}) — installing…`);
63
66
  try {
64
67
  const { bin, args } = npmInstallArgs(latest);
65
68
  execSync(`"${bin}" ${args.map(a => `"${a}"`).join(' ')}`, { stdio: 'pipe' });
@@ -67,12 +70,12 @@ export async function checkForUpdate(currentVersion) {
67
70
  if (config?.skills_installed) {
68
71
  await installSkills();
69
72
  }
70
- info(`› Updated to ${latest} — active after this command completes.\n`);
73
+ banner(`› Updated to ${latest} — active after this command completes.\n`);
71
74
  }
72
75
  catch (installErr) {
73
76
  const msg = installErr?.stderr?.toString?.() || installErr?.message || String(installErr);
74
- info(`› Auto-update failed: ${msg.trim()}`);
75
- info(`› Run manually: npm install -g @myapihq/cli@latest`);
77
+ banner(`› Auto-update failed: ${msg.trim()}`);
78
+ banner(`› Run manually: npm install -g @myapihq/cli@latest`);
76
79
  }
77
80
  }
78
81
  }
@@ -83,7 +86,7 @@ export async function checkForUpdate(currentVersion) {
83
86
  // myapi update — explicit update, same logic as auto-update.
84
87
  export async function update(flags = {}) {
85
88
  if (flags.help) {
86
- info('Usage: myapi update\n\nUpdates the MyAPI CLI and installed skills to the latest published version.\nEquivalent to: npm install -g @myapihq/cli@latest\n\nNotes:\n - Version pinning and rollback are not supported — always installs the latest.\n - The CLI also auto-updates silently on each command when a newer version is\n detected. If you need a stable version in CI, pin with:\n npm install -g @myapihq/cli@<version>\n and set NO_COLOR=1 to suppress ANSI output in non-TTY environments.');
89
+ info('Usage: myapi update\n\nUpdates the MyAPI CLI and installed skills to the latest published version.\nEquivalent to: npm install -g @myapihq/cli@latest\n\nNotes:\n - Version pinning and rollback are not supported — always installs the latest.\n - The CLI also auto-updates silently on each command when a newer version is\n detected (banner goes to stderr, suppressed on non-TTY stdout).\n - To disable auto-update: set MYAPI_NO_UPDATE=1 in your environment.\n - For a pinned version in CI: npm install -g @myapihq/cli@<version>');
87
90
  return;
88
91
  }
89
92
  info('› Checking for updates…');
@@ -108,7 +111,7 @@ export async function update(flags = {}) {
108
111
  }
109
112
  info('› Refreshing skills…');
110
113
  await installSkills();
111
- success('Up to date.');
114
+ success('Up to date.');
112
115
  }
113
116
  // latestVersion fetches the current published version for --version display.
114
117
  export async function latestVersion() {
package/dist/index.js CHANGED
@@ -23,25 +23,32 @@ const ERROR_MESSAGES = {
23
23
  org_not_found: 'Organization not found.',
24
24
  FUNNEL_NOT_FOUND: 'Funnel not found.',
25
25
  funnel_not_found: 'Funnel not found.',
26
+ funnel_already_exists: 'Your org already has a funnel. Use: myapi funnel list',
27
+ FUNNEL_ALREADY_EXISTS: 'Your org already has a funnel. Use: myapi funnel list',
28
+ domain_already_registered: 'This domain is already registered under your account.',
29
+ DOMAIN_ALREADY_REGISTERED: 'This domain is already registered under your account.',
30
+ domain_not_available: 'This domain is not available for registration.',
31
+ DOMAIN_NOT_AVAILABLE: 'This domain is not available for registration.',
26
32
  db_error: 'Resource not found or invalid ID.',
27
33
  NOT_FOUND: 'Resource not found.',
28
34
  FORBIDDEN: 'You do not have permission to perform this action.',
29
35
  RATE_LIMITED: 'Too many requests. Please wait a moment and try again.',
36
+ INSUFFICIENT_BALANCE: 'Insufficient balance. Run: myapi billing topup <amount>',
30
37
  };
31
38
  function friendlyError(code) {
32
39
  return ERROR_MESSAGES[code] || code;
33
40
  }
34
41
  async function main() {
35
- const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => { });
36
42
  const { args, flags } = parseArgs(process.argv.slice(2));
37
43
  if (flags.version || flags.v || flags.V) {
38
- const [latest] = await Promise.all([updateCmd.latestVersion(), updatePromise]);
44
+ const latest = await updateCmd.latestVersion();
39
45
  const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
40
46
  ? ` (update available: ${latest})`
41
47
  : '';
42
48
  info(`myapi ${pkg.version}${updateNote}`);
43
49
  return;
44
50
  }
51
+ const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => { });
45
52
  if (flags.help && args.length === 0) {
46
53
  printHelp();
47
54
  return;
@@ -54,7 +61,7 @@ async function main() {
54
61
  }
55
62
  printHelp();
56
63
  await updatePromise;
57
- return;
64
+ process.exit(1);
58
65
  }
59
66
  const [command, subcommand, ...restArgs] = args;
60
67
  try {
@@ -177,7 +184,12 @@ async function main() {
177
184
  success('› Skills installed.');
178
185
  break;
179
186
  case 'help':
180
- printHelp();
187
+ if (subcommand) {
188
+ info(`Run: myapi ${subcommand} --help`);
189
+ }
190
+ else {
191
+ printHelp();
192
+ }
181
193
  break;
182
194
  default:
183
195
  error(`Unknown command: ${command}. Run "myapi" for available commands.`);
package/dist/output.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare function success(message: string): void;
2
2
  export declare function error(message: string): never;
3
3
  export declare function info(message: string): void;
4
+ export declare function banner(message: string): void;
4
5
  export declare function printJson(data: unknown): void;
5
6
  export declare function printTable(rows: Record<string, unknown>[]): void;
package/dist/output.js CHANGED
@@ -9,6 +9,9 @@ export function error(message) {
9
9
  export function info(message) {
10
10
  console.log(message);
11
11
  }
12
+ export function banner(message) {
13
+ process.stderr.write(message + '\n');
14
+ }
12
15
  export function printJson(data) {
13
16
  console.log(JSON.stringify(data, null, 2));
14
17
  }
package/dist/utils.js CHANGED
@@ -43,5 +43,5 @@ export function formatDate(str) {
43
43
  const date = new Date(clean);
44
44
  if (isNaN(date.getTime()))
45
45
  return str;
46
- return date.toISOString().replace('T', ' ').slice(0, 16);
46
+ return date.toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
47
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myapihq/cli",
3
- "version": "1.0.74",
3
+ "version": "1.0.75",
4
4
  "description": "MyAPI command-line interface",
5
5
  "type": "module",
6
6
  "files": [