@aexhq/cli 0.42.3 → 0.44.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 (3) hide show
  1. package/README.md +6 -2
  2. package/package.json +26 -8
  3. package/src/index.mjs +18 -4
package/README.md CHANGED
@@ -4,7 +4,7 @@ Node.js 22 or newer. The CLI uses `@aexhq/sdk` and the same public Aex HTTP API
4
4
  the dashboard. No dashboard cookies, site credentials or operator credentials are needed.
5
5
 
6
6
  ```sh
7
- npm install -g @aexhq/cli@0.41.0
7
+ npm install -g @aexhq/cli@0.44.0
8
8
  aex login
9
9
  aex keys create "My application"
10
10
  aex keys list
@@ -25,7 +25,11 @@ credentials expire after seven days; run `login` again. `logout` revokes this se
25
25
 
26
26
  Results are JSON on stdout; errors and login progress go to stderr. A created key's
27
27
  token is returned once. Existing keys expose only their metadata and prefix.
28
- Billing currently reports free preview hosting with customer-paid model usage.
28
+ `billing` reports preview or prepaid status, available and reserved credits, prices and the monthly
29
+ spend limit. `billing ledger`, `billing topups` and `billing refunds` show account history.
30
+ `billing set PRICEBOOK MICRO_USD` accepts the offered prices and sets the monthly limit.
31
+ `billing topup CENTS KEY` returns a Stripe Checkout URL; `billing refund TOPUP CENTS KEY`
32
+ requests return of unused credits. Reuse the operation key for the same payment intent.
29
33
 
30
34
  The credential file is `~/.aex/account.json` on Unix or `%LOCALAPPDATA%/.aex/account.json`
31
35
  on Windows, restricted to the current user (and Windows SYSTEM). `AEX_CONFIG_DIR`
package/package.json CHANGED
@@ -1,14 +1,32 @@
1
1
  {
2
2
  "name": "@aexhq/cli",
3
- "version": "0.42.3",
3
+ "version": "0.44.0",
4
4
  "description": "Aex account and API key management from the terminal",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "engines": { "node": ">=22" },
8
- "bin": { "aex": "src/index.mjs" },
9
- "files": ["src", "README.md"],
10
- "repository": { "type": "git", "url": "git+https://github.com/aexhq/aex.git", "directory": "packages/cli" },
11
- "publishConfig": { "access": "public", "tag": "next" },
12
- "dependencies": { "@aexhq/sdk": "0.75.3" },
13
- "scripts": { "test": "node --test test/*.test.mjs" }
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "bin": {
11
+ "aex": "src/index.mjs"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "README.md"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/aexhq/aex.git",
20
+ "directory": "packages/cli"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public",
24
+ "tag": "next"
25
+ },
26
+ "dependencies": {
27
+ "@aexhq/sdk": "0.77.0"
28
+ },
29
+ "scripts": {
30
+ "test": "node --test test/*.test.mjs"
31
+ }
14
32
  }
package/src/index.mjs CHANGED
@@ -13,7 +13,13 @@ const help = `Usage: aex <command>
13
13
  keys rename <id> <name> Rename a key
14
14
  keys revoke <id> Revoke a key
15
15
  account Show account, limits and billing status
16
- billing Show billing status
16
+ billing Show credits, holds, prices and spend limit
17
+ billing ledger Show recent credit transactions
18
+ billing set <pricebook> <micro-usd> Accept prices and set a monthly spend limit
19
+ billing topup <cents> <key> Create an idempotent Stripe Checkout
20
+ billing refund <topup> <cents> <key> Request a refund of unused credits
21
+ billing topups Show payments and receipt links
22
+ billing refunds Show refund status
17
23
  usage Show current usage
18
24
  docs Open the documentation
19
25
 
@@ -26,8 +32,8 @@ async function main() {
26
32
  const { values, positionals } = parseArgs({ allowPositionals: true, options: { help: { type: "boolean", short: "h" }, "no-browser": { type: "boolean" }, "api-url": { type: "string" }, "site-url": { type: "string" } } });
27
33
  if (values.help || !positionals.length) { process.stdout.write(help); return; }
28
34
  const [command, operation, ...args] = positionals;
29
- const expected = { "keys list": 0, "keys create": 1, "keys rename": 2, "keys revoke": 1 };
30
- if (command === "keys" ? expected[`keys ${operation}`] !== args.length : !["login", "logout", "account", "billing", "usage", "docs"].includes(command) || positionals.length !== 1) throw new Error("Unknown command or incorrect arguments. Run aex --help.");
35
+ const expected = { "keys list": 0, "keys create": 1, "keys rename": 2, "keys revoke": 1, "billing ledger":0, "billing set":2, "billing topup":2, "billing refund":3, "billing topups":0, "billing refunds":0 };
36
+ if (command === "keys" || (command === "billing" && operation) ? expected[`${command} ${operation}`] !== args.length : !["login", "logout", "account", "billing", "usage", "docs"].includes(command) || positionals.length !== 1) throw new Error("Unknown command or incorrect arguments. Run aex --help.");
31
37
  const explicitApi = values["api-url"] ?? process.env.AEX_API_URL;
32
38
  const siteUrl = origin(values["site-url"] ?? "https://aex.dev");
33
39
  if (command === "docs") {
@@ -61,7 +67,15 @@ async function main() {
61
67
  if (!process.env.AEX_ACCOUNT_TOKEN) await removeSession();
62
68
  result = { signed_out: true };
63
69
  } else if (command === "account") result = await client.account.get();
64
- else if (command === "billing") result = { billing: (await client.account.get()).billing };
70
+ else if (command === "billing") {
71
+ const integer = value => { const n = Number(value); if (!/^\d+$/.test(value) || !Number.isSafeInteger(n)) throw new Error("Amounts must be nonnegative integers"); return n; };
72
+ if (!operation) result = await client.billing.get();
73
+ else if (operation === "ledger") result = await client.billing.ledger();
74
+ else if (operation === "set") result = await client.billing.update({ pricebook: args[0], spend_limit_micro_usd: integer(args[1]) });
75
+ else if (operation === "topup") result = await client.billing.topup({amount_cents:integer(args[0])},args[1]);
76
+ else if (operation === "refund") result = await client.billing.refund({topup:args[0],amount_cents:integer(args[1])},args[2]);
77
+ else result = await client.billing[operation]();
78
+ }
65
79
  else if (command === "usage") result = await client.account.usage();
66
80
  else if (operation === "list") result = await client.keys.list();
67
81
  else if (operation === "create") result = await client.keys.create({ name: args[0] });