mayar 0.1.9 → 1.0.1

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.
package/README.md CHANGED
@@ -4,13 +4,28 @@ Command-line interface for the [Mayar](https://docs.mayar.id) API. Zero runtime
4
4
 
5
5
  ## Install
6
6
 
7
+ **One-liner (no npm required):**
8
+
9
+ ```bash
10
+ curl -fsSL https://raw.githubusercontent.com/mayarid/mayar-cli/main/install.sh | sh
11
+ ```
12
+
13
+ Downloads the latest tarball from the npm registry, extracts to `~/.local/share/mayar`, and symlinks the binary to `~/.local/bin/mayar`. Requires only `node>=18`, `curl`, and `tar`. Override paths or pin a version:
14
+
15
+ ```bash
16
+ MAYAR_VERSION=0.1.9 MAYAR_BIN_DIR=/usr/local/bin \
17
+ curl -fsSL https://raw.githubusercontent.com/mayarid/mayar-cli/main/install.sh | sh
18
+ ```
19
+
20
+ **Via npm:**
21
+
7
22
  ```bash
8
23
  npm install -g mayar
9
24
  # or run without installing:
10
25
  npx mayar --help
11
26
  ```
12
27
 
13
- Or from source:
28
+ **From source:**
14
29
 
15
30
  ```bash
16
31
  git clone https://github.com/mayarid/mayar-cli.git
@@ -55,75 +70,138 @@ mayar --api-key YOUR_KEY_HERE balance
55
70
 
56
71
  Get your API key from [web.mayar.id](https://web.mayar.id) → Integration → API Key.
57
72
 
73
+ > **v1.0.0 — Mayar API v2.** All commands now target `/hl/v2/...`. Pagination switched from `--page`/`--pageSize` to cursor-based `--limit`/`--after` (returned in the previous response's `nextStartingAfter`). The `--pageSize` flag is still accepted as an alias for `--limit`.
74
+
58
75
  ## Commands
59
76
 
60
77
  ```
61
78
  Setup
62
- init Run first-time setup (interactive, masked input)
63
- api-key <key> Save API key non-interactively (e.g. for scripts)
64
- config show Show masked saved key and config path
65
- config reset Remove the saved key
79
+ init First-time setup (interactive, masked input)
80
+ login [--no-browser] Sign in via Google OAuth
81
+ api-key <key> Save API key non-interactively
82
+ config show|reset Inspect or remove the saved config
66
83
 
67
84
  Account
68
- whoami Show merchant identity (decoded from JWT) + verify key
69
- balance GET /hl/v1/balance
85
+ whoami Merchant identity (JWT decode + live verify)
86
+ balance GET /hl/v2/balances
70
87
 
71
88
  Invoices
72
- invoice list [--page N --pageSize N] GET /hl/v1/invoice
73
- invoice get <id> GET /hl/v1/invoice/{id}
74
- invoice close <id> GET /hl/v1/invoice/close/{id}
75
- invoice reopen <id> GET /hl/v1/invoice/open/{id}
76
- invoice create --data <json|@file> POST /hl/v1/invoice/create
89
+ invoice list [--limit --after --status --search]
90
+ invoice get <id>
91
+ invoice close <id> | reopen <id> POST /hl/v2/invoices/{id}/{open|close}
92
+ invoice status <id> <action> action ∈ open|close|active|closed|unlisted
93
+ invoice edit <id> --data <json|@file>
94
+ invoice filter --email <email> [--limit --after --status --search]
95
+ invoice create --data <json|@file>
77
96
 
78
97
  Products
79
- product list [--page N --pageSize N] GET /hl/v1/product
80
- product search <keyword> GET /hl/v1/product?search=...
81
- product type <type> [--page ...] GET /hl/v1/product/type/{type}
82
- product get <id> GET /hl/v1/product/{id}
83
- product close <id> GET /hl/v1/product/close/{id}
84
- product reopen <id> GET /hl/v1/product/open/{id}
98
+ product list [--limit --after --search --type --stock]
99
+ product search <keyword>
100
+ product type <ebook|course|membership|saas|event|webinar|…>
101
+ product get <id>
102
+ product close | reopen | status <id> <action>
103
+ product transactions <id> [--limit --after --status --customerId]
104
+ product create --type <T> --data <json|@file>
105
+ T ∈ ebook|digital|event|webinar|generic|payment-link
106
+ product edit <id> --type <T> --data <json|@file>
85
107
 
86
108
  Single payment requests
87
- payment list GET /hl/v1/payment
88
- payment get <id> GET /hl/v1/payment/{id}
89
- payment close <id> GET /hl/v1/payment/close/{id}
90
- payment reopen <id> GET /hl/v1/payment/open/{id}
91
- payment create --data <json|@file> POST /hl/v1/payment/create
109
+ payment list [--limit --after --status]
110
+ payment get <id>
111
+ payment close | reopen | status <id> <action>
112
+ payment edit <id> --data <json|@file>
113
+ payment create --data <json|@file>
92
114
 
93
115
  Customers
94
- customer list [--page ...] GET /hl/v1/customer
95
- customer create --data <json|@file> POST /hl/v1/customer/create
96
- customer search <email> GET /hl/v1/customer/detail?email=
97
- customer update <from> <to> POST /hl/v1/customer/update
98
- customer magic-link <email> POST /hl/v1/customer/login/portal
116
+ customer list GET /hl/v2/customers
117
+ customer create --data <json|@file>
118
+ customer search <email> GET /hl/v2/customers/detail?email=
119
+ customer update <fromEmail> <toEmail>
120
+ customer magic-link <email> POST /hl/v2/customers/portal-login
99
121
 
100
122
  Transactions
101
- tx list [--page ...] GET /hl/v1/transactions (paid)
102
- tx unpaid [--page ...] GET /hl/v1/transactions/unpaid
103
- tx daily GET /hl/v1/transactions/daily
123
+ tx list [--limit --after --status --customerId --type --startAt --endAt]
124
+ tx unpaid [--limit --after --status --customerId --startAt --endAt]
125
+ tx daily
126
+ tx product <productId> [--limit --after --status]
104
127
 
105
128
  Reviews
106
- review list [--page ...] GET /hl/v1/reviews
107
-
108
- Dynamic QR
109
- qrcode <amount> POST /hl/v1/qrcode/create
129
+ review list [--limit --after --status --paymentLinkId --rating]
130
+ review stats [productId] merchant-wide or per-product
131
+ review create --data <json|@file>
132
+ review update <id> --data <json|@file>
133
+ review bulk-status --data <json> [{id,status: ACTIVE|ARCHIVED|INACTIVE}, …]
134
+ review product <paymentLinkId> [--limit --after --rating]
135
+ review product-customer <paymentLinkId> --customerId <id>
136
+
137
+ Discounts (coupons)
138
+ discount create --data <json|@file>
139
+ discount get <id>
140
+ discount validate <code> <paymentLinkId>
141
+ discount check <code>
142
+
143
+ Bundling
144
+ bundling list [--limit --after]
145
+ bundling get <id>
146
+
147
+ Installments
148
+ installment list [--limit --after --status --customerId]
149
+ installment get <id>
150
+ installment create --data <json|@file>
151
+
152
+ Memberships
153
+ membership members --productId <id> [--limit --after]
154
+ membership tiers --productId <id> [--limit --after]
155
+ membership register --data <json|@file>
156
+ membership get <memberId> --productId <id>
157
+ membership update <memberId> --productId <id> [--data <json|@file>]
158
+ membership cancel <memberId> --productId <id>
159
+ membership create-invoice <memberId> --productId <id>
160
+
161
+ Credit wallets
162
+ credit balance --customerId <id> --productId <id> [--tierId <id>]
163
+ credit add --data <json|@file> {customerId, productId, amount}
164
+ credit spend --data <json|@file> {customerId, productId, amount}
165
+ credit history <customerId> --productId <id> [--page N --limit N]
166
+ credit register-usage --data <json|@file>
167
+ credit register-membership --data <json|@file>
168
+ credit checkout --data <json|@file>
169
+
170
+ SaaS licensing
171
+ saas activate <licenseCode> <productId> POST /saas/v2/license/activate
172
+ saas deactivate <licenseCode> <productId> POST /saas/v2/license/deactivate
173
+ saas verify <licenseCode> <productId> POST /saas/v2/license/verify
174
+
175
+ Software licensing
176
+ software verify <licenseCode> <productId> POST /software/v2/license/verify
177
+
178
+ QR & payment channels
179
+ qrcode <amount> POST /hl/v2/qr-codes/create
180
+ qrcode static GET /hl/v2/qr-codes/static
181
+ qrcode channels GET /hl/v2/payment-channels
110
182
 
111
183
  Webhooks
112
- webhook register <url> GET /hl/v1/webhook/register
113
- webhook test <url> POST /hl/v1/webhook/test
114
- webhook history [--page ...] GET /hl/v1/webhook/history
184
+ webhook register <url> POST /hl/v2/webhooks/update
185
+ webhook test <url>
186
+ webhook history [--limit --after --status --type --startAt --endAt]
187
+ webhook new-history [--limit --after]
188
+ webhook retry <historyId>
115
189
 
116
190
  Global flags
117
191
  --json Output raw JSON instead of pretty tables
118
192
  --api-key <key> Use this API key for the run (also accepts --api-key=KEY)
119
- --page N Pagination page (default 1)
120
- --pageSize N Pagination page size (default 10)
193
+ --limit N Page size (default 10, max 50)
194
+ --after CURSOR Pagination cursor (from previous nextStartingAfter)
195
+ --pageSize N Alias for --limit
196
+ --data <json|@file> Inline JSON, or @path to a JSON file
121
197
  -h, --help Show help
122
198
  -v, --version Show version
123
199
 
124
200
  Environment
125
- MAYAR_API_KEY API key — used when --api-key flag is absent and no config is saved
126
- MAYAR_API_URL Override API base URL (default: https://api.mayar.id)
201
+ MAYAR_API_KEY Used when --api-key is absent and no config is saved
202
+ MAYAR_API_URL Override API base URL
203
+ MAYAR_AUTH_URL Override auth server base URL (used by 'login')
204
+ NODE_ENV=development Target the sandbox (*.mayar.club) instead of production
127
205
  ```
128
206
 
129
207
  ## Examples
@@ -135,9 +213,10 @@ mayar whoami
135
213
  # Account balance
136
214
  mayar balance
137
215
 
138
- # Paginated lists
139
- mayar invoice list --page 1 --pageSize 20
140
- mayar product type ebook --pageSize 50
216
+ # Paginated lists (v2 cursor pagination)
217
+ mayar invoice list --limit 20
218
+ mayar invoice list --limit 20 --after 1730000000000 # next page
219
+ mayar product type ebook --limit 50
141
220
 
142
221
  # Search
143
222
  mayar product search "kelas python"
@@ -168,7 +247,13 @@ mayar qrcode 10000
168
247
  # Webhooks
169
248
  mayar webhook register https://example.com/hooks/mayar
170
249
  mayar webhook test https://example.com/hooks/mayar
171
- mayar webhook history --page 1 --pageSize 20
250
+ mayar webhook history --limit 20
251
+
252
+ # Membership members
253
+ mayar membership members --productId prd-42 --limit 20
254
+
255
+ # SaaS license verify
256
+ mayar saas verify LIC-123 prd-42
172
257
 
173
258
  # Pipe raw JSON to jq
174
259
  mayar invoice list --json | jq '.data[] | {id, status}'
@@ -190,4 +275,5 @@ To rotate keys: `mayar config reset && mayar init`.
190
275
  - All requests use `Authorization: Bearer <key>`. Errors print `API <status> — <message>` and exit non-zero.
191
276
  - `--data @file.json` reads from disk; `--data '{...}'` reads inline JSON.
192
277
  - `MAYAR_API_URL` overrides the base URL — useful for staging or custom proxy environments.
193
- - `mayar whoami` decodes the JWT locally and verifies the key live against `/hl/v1/balance`.
278
+ - `mayar whoami` decodes the JWT locally and verifies the key live against `/hl/v2/balances`.
279
+ - **v1.0.0 migration**: all API paths moved from `/hl/v1/*` to `/hl/v2/*`. `--page` is no longer used (v2 has no page numbers); the cursor is returned as `nextStartingAfter` in each response and passed as `--after` for the next page.
package/package.json CHANGED
@@ -1,17 +1,25 @@
1
1
  {
2
2
  "name": "mayar",
3
- "version": "0.1.9",
3
+ "version": "1.0.1",
4
4
  "description": "Zero-dependency Node.js CLI for the Mayar API (production endpoint).",
5
5
  "bin": {
6
6
  "mayar": "bin/mayar.js"
7
7
  },
8
8
  "main": "src/cli.js",
9
9
  "scripts": {
10
- "start": "node bin/mayar.js"
10
+ "start": "node bin/mayar.js",
11
+ "test": "node --test",
12
+ "test:coverage": "node --test --experimental-test-coverage"
11
13
  },
12
14
  "engines": {
13
15
  "node": ">=18"
14
16
  },
17
+ "dependencies": {
18
+ "@mayaross/auth": "^1.0.0"
19
+ },
20
+ "bundleDependencies": [
21
+ "@mayaross/auth"
22
+ ],
15
23
  "keywords": [
16
24
  "mayar",
17
25
  "mayar-api",
package/src/api.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const https = require('https');
2
2
  const { URL } = require('url');
3
+ const config = require('./config');
3
4
 
4
- const BASE_URL = process.env.MAYAR_API_URL || 'https://api.mayar.id';
5
+ const BASE_URL = config.apiBaseUrl();
5
6
  const VERSION = require('../package.json').version;
6
7
 
7
8
  function request(method, pathname, { apiKey, body, query } = {}) {
package/src/cli.js CHANGED
@@ -3,13 +3,14 @@ const config = require('./config');
3
3
 
4
4
  const VERSION = require('../package.json').version;
5
5
 
6
- const HELP = () => `${ui.bold('mayar')} ${ui.dim('— Mayar API CLI (production)')}
6
+ const HELP = () => `${ui.bold('mayar')} ${ui.dim('— Mayar API CLI (v2)')}
7
7
 
8
8
  ${ui.bold('Usage:')}
9
9
  mayar <command> [args] [flags]
10
10
 
11
11
  ${ui.bold('Setup:')}
12
12
  init Run first-time setup (or re-configure API key)
13
+ login [--no-browser] Sign in via browser (Google OAuth) and save auth token
13
14
  api-key <key> Save API key non-interactively
14
15
  config show Show config path and masked API key
15
16
  config reset Remove the saved API key
@@ -19,64 +20,132 @@ ${ui.bold('Account:')}
19
20
  balance Get account balance
20
21
 
21
22
  ${ui.bold('Invoices:')}
22
- invoice list [--page N --pageSize N]
23
+ invoice list [--limit N --after CURSOR]
23
24
  invoice get <id>
24
25
  invoice close <id>
25
26
  invoice reopen <id>
26
- invoice create --data <json|@file.json>
27
+ invoice status <id> <open|close|active|closed|unlisted>
28
+ invoice edit <id> --data <json|@file>
29
+ invoice filter --email <email> [--limit N --after CURSOR]
30
+ invoice create --data <json|@file>
27
31
 
28
32
  ${ui.bold('Products:')}
29
- product list [--page N --pageSize N]
33
+ product list [--limit N --after CURSOR --search Q --type T]
30
34
  product search <keyword>
31
35
  product type <ebook|course|membership|saas|event|webinar|...>
32
36
  product get <id>
33
37
  product close <id>
34
38
  product reopen <id>
39
+ product status <id> <open|close|active|closed|unlisted>
40
+ product transactions <id> [--limit N --after CURSOR]
41
+ product create --type <T> --data <json|@file>
42
+ product edit <id> --data <json|@file>
43
+ product sort <generic_link|event|webinar|digital_product> [--limit --after]
44
+
45
+ ${ui.bold('Payment links (alt route):')}
46
+ payment-link edit <id> --data <json|@file> Alias for /hl/v2/payment-links/{id}/update
35
47
 
36
48
  ${ui.bold('Single payment requests:')}
37
- payment list
49
+ payment list [--limit N --after CURSOR --status paid|unpaid|closed]
38
50
  payment get <id>
39
- payment close <id>
40
- payment reopen <id>
41
- payment create --data <json|@file.json>
51
+ payment status <id> <open|close|active|closed|unlisted>
52
+ payment edit <id> --data <json|@file>
53
+ payment create --data <json|@file>
42
54
 
43
55
  ${ui.bold('Customers:')}
44
- customer list [--page N --pageSize N]
45
- customer create --data <json|@file.json>
46
- customer search <email> Look up a customer by email
56
+ customer list
57
+ customer create --data <json|@file>
58
+ customer search <email>
47
59
  customer update <fromEmail> <toEmail>
48
- customer magic-link <email> Email a portal login link to the customer
60
+ customer magic-link <email>
49
61
 
50
62
  ${ui.bold('Transactions:')}
51
- tx list [--page N --pageSize N] Paid transactions
52
- tx unpaid [--page N --pageSize N] Unpaid transactions
53
- tx daily Today's totals (volume + count)
63
+ tx list [--limit N --after CURSOR --status --customerId --startAt --endAt]
64
+ tx unpaid [--limit N --after CURSOR]
65
+ tx daily
66
+ tx product <productId> [--limit N --after CURSOR]
54
67
 
55
68
  ${ui.bold('Reviews:')}
56
- review list [--page N --pageSize N]
69
+ review list [--limit N --after CURSOR --status --paymentLinkId --rating]
70
+ review stats [productId]
71
+ review create --data <json|@file>
72
+ review update <id> --data <json|@file>
73
+ review bulk-status --data <json|@file> (array of {id,status})
74
+ review product <paymentLinkId> [--limit N --after CURSOR]
75
+ review product-customer <paymentLinkId> --customerId <id>
76
+
77
+ ${ui.bold('Discounts (coupons):')}
78
+ discount create --data <json|@file>
79
+ discount get <id>
80
+ discount validate <code> <paymentLinkId>
81
+ discount check <code>
82
+
83
+ ${ui.bold('Bundling:')}
84
+ bundling list [--limit N --after CURSOR]
85
+ bundling get <id>
86
+
87
+ ${ui.bold('Installments:')}
88
+ installment list [--limit N --after CURSOR]
89
+ installment get <id>
90
+ installment create --data <json|@file>
91
+
92
+ ${ui.bold('Memberships:')}
93
+ membership members --productId <id> [--limit N --after CURSOR]
94
+ membership tiers --productId <id> [--limit N --after CURSOR]
95
+ membership register --data <json|@file>
96
+ membership get <memberId> --productId <id>
97
+ membership update <memberId> --productId <id> [--data <json|@file>]
98
+ membership cancel <memberId> --productId <id>
99
+ membership create-invoice <memberId> --productId <id>
57
100
 
58
- ${ui.bold('Dynamic QR:')}
59
- qrcode <amount>
101
+ ${ui.bold('Credit wallets:')}
102
+ credit balance --customerId <id> --productId <id> [--tierId <id>]
103
+ credit add --data <json|@file> ({customerId, productId, amount})
104
+ credit spend --data <json|@file> ({customerId, productId, amount})
105
+ credit history <customerId> --productId <id> [--page N --limit N]
106
+ credit register-usage --data <json|@file>
107
+ credit register-membership --data <json|@file>
108
+ credit checkout --data <json|@file>
109
+
110
+ ${ui.bold('SaaS licensing:')}
111
+ saas activate <licenseCode> <productId>
112
+ saas deactivate <licenseCode> <productId>
113
+ saas verify <licenseCode> <productId>
114
+
115
+ ${ui.bold('Software licensing:')}
116
+ software verify <licenseCode> <productId>
117
+
118
+ ${ui.bold('QR & payment channels:')}
119
+ qrcode <amount> Dynamic QR for the given amount
120
+ qrcode static Merchant's static QRIS image
121
+ qrcode channels List enabled payment channels
60
122
 
61
123
  ${ui.bold('Webhooks:')}
62
124
  webhook register <url>
63
125
  webhook test <url>
64
- webhook history [--page N --pageSize N]
126
+ webhook history [--limit N --after CURSOR]
127
+ webhook new-history [--limit N --after CURSOR]
128
+ webhook retry <historyId>
65
129
 
66
130
  ${ui.bold('Global flags:')}
67
131
  --json Output raw JSON instead of formatted tables
68
132
  --api-key <key> Use this API key for the run (overrides env + saved config)
69
- --page N Pagination page (default 1)
70
- --pageSize N Pagination page size (default 10)
133
+ --limit N Page size (v2, default 10, max 50)
134
+ --after CURSOR Cursor for next page (from previous response's nextStartingAfter)
135
+ --pageSize N Alias for --limit
136
+ --data <json|@file> Inline JSON or @path to a JSON file
71
137
  -h, --help Show help
72
138
  -v, --version Show version
73
139
 
74
140
  ${ui.bold('Environment:')}
75
141
  MAYAR_API_KEY Used when --api-key is not given and no config is saved
76
- MAYAR_API_URL Override API base URL (default: https://api.mayar.id)
142
+ MAYAR_API_URL Override API base URL
143
+ MAYAR_AUTH_URL Override auth server base URL (used by 'login')
144
+ NODE_ENV=development Target the sandbox (api/auth .mayar.club) instead of production
77
145
 
78
146
  ${ui.dim('Resolution order: --api-key flag > MAYAR_API_KEY env > saved config.')}
79
- ${ui.dim('Endpoint: MAYAR_API_URL env or https://api.mayar.id (default)')}
147
+ ${ui.dim('API endpoint: MAYAR_API_URL, else NODE_ENV=development api.mayar.club, else api.mayar.id')}
148
+ ${ui.dim('Auth endpoint: MAYAR_AUTH_URL, else NODE_ENV=development → auth.mayar.club, else auth.mayar.id')}
80
149
  ${ui.dim('Config: ~/.config/mayar/config.json (chmod 600)')}
81
150
  `;
82
151
 
@@ -88,10 +157,13 @@ function parseFlags(argv) {
88
157
  if (a === '--') { positional.push(...argv.slice(i + 1)); break; }
89
158
  if (a === '--json') flags.json = true;
90
159
  else if (a === '--force') flags.force = true;
160
+ else if (a === '--no-browser') flags['no-browser'] = true;
91
161
  else if (a === '--api-key') flags.apiKey = argv[++i];
92
162
  else if (a.startsWith('--api-key=')) flags.apiKey = a.slice('--api-key='.length);
93
163
  else if (a === '--page') flags.page = argv[++i];
94
164
  else if (a === '--pageSize' || a === '--page-size') flags.pageSize = argv[++i];
165
+ else if (a === '--limit') flags.limit = argv[++i];
166
+ else if (a === '--after' || a === '--starting-after' || a === '--startingAfter') flags.after = argv[++i];
95
167
  else if (a === '--data') flags.data = argv[++i];
96
168
  else if (a === '-h' || a === '--help') flags.help = true;
97
169
  else if (a === '-v' || a === '--version') flags.version = true;
@@ -111,7 +183,6 @@ async function ensureKey(flags) {
111
183
  if (process.env.MAYAR_API_KEY) return process.env.MAYAR_API_KEY;
112
184
  const cfg = config.load();
113
185
  if (cfg && cfg.apiKey) return cfg.apiKey;
114
- // First-run flow
115
186
  ui.printBanner();
116
187
  process.stdout.write(`${ui.bold('Welcome to Mayar CLI.')}\n`);
117
188
  process.stdout.write(`No API key found. Get yours from ${ui.cyan('https://web.mayar.id')} → Integration → API Key.\n\n`);
@@ -136,13 +207,10 @@ async function run(argv) {
136
207
 
137
208
  try {
138
209
  if (cmd === 'help') { process.stdout.write(HELP()); return; }
139
- if (cmd === 'init') {
140
- const init = require('./commands/init');
141
- return await init.run({ flags });
142
- }
210
+ if (cmd === 'init') { return await require('./commands/init').run({ flags }); }
211
+ if (cmd === 'login') { return await require('./commands/login').run({ flags }); }
143
212
  if (cmd === 'api-key' || cmd === 'apikey') {
144
- const apikey = require('./commands/apikey');
145
- return await apikey.run({ positional: [sub, ...rest].filter((x) => x !== undefined) });
213
+ return await require('./commands/apikey').run({ positional: [sub, ...rest].filter((x) => x !== undefined) });
146
214
  }
147
215
  if (cmd === 'config') {
148
216
  if (sub === 'show') {
@@ -168,17 +236,40 @@ async function run(argv) {
168
236
  whoami: './commands/whoami',
169
237
  balance: './commands/balance',
170
238
  invoice: './commands/invoice',
239
+ invoices: './commands/invoice',
171
240
  product: './commands/product',
241
+ products: './commands/product',
172
242
  payment: './commands/payment',
243
+ payments: './commands/payment',
173
244
  customer: './commands/customer',
245
+ customers: './commands/customer',
174
246
  tx: './commands/transaction',
175
247
  transaction: './commands/transaction',
176
248
  transactions: './commands/transaction',
177
249
  qr: './commands/qrcode',
178
250
  qrcode: './commands/qrcode',
179
251
  webhook: './commands/webhook',
252
+ webhooks: './commands/webhook',
180
253
  review: './commands/review',
181
254
  reviews: './commands/review',
255
+ discount: './commands/discount',
256
+ discounts: './commands/discount',
257
+ coupon: './commands/discount',
258
+ coupons: './commands/discount',
259
+ bundling: './commands/bundling',
260
+ bundlings: './commands/bundling',
261
+ installment: './commands/installment',
262
+ installments: './commands/installment',
263
+ membership: './commands/membership',
264
+ memberships: './commands/membership',
265
+ credit: './commands/credit',
266
+ credits: './commands/credit',
267
+ saas: './commands/saas',
268
+ software: './commands/software',
269
+ 'payment-link': './commands/payment-link',
270
+ paymentlink: './commands/payment-link',
271
+ 'payment-links': './commands/payment-link',
272
+ plink: './commands/payment-link',
182
273
  };
183
274
  const handler = handlers[cmd];
184
275
  if (!handler) {
@@ -196,4 +287,4 @@ async function run(argv) {
196
287
  }
197
288
  }
198
289
 
199
- module.exports = { run };
290
+ module.exports = { run, parseFlags };
@@ -3,7 +3,7 @@ const ui = require('../ui');
3
3
  const { checkResp } = require('../util');
4
4
 
5
5
  async function run({ apiKey, flags }) {
6
- const res = await api.request('GET', '/hl/v1/balance', { apiKey });
6
+ const res = await api.request('GET', '/hl/v2/balances', { apiKey });
7
7
  checkResp(res);
8
8
  if (flags.json) return ui.jsonOut(res.body);
9
9
  const d = (res.body && res.body.data) || {};
@@ -0,0 +1,36 @@
1
+ const api = require('../api');
2
+ const ui = require('../ui');
3
+ const { checkResp, pagination, cursorFooter } = require('../util');
4
+
5
+ const USAGE = 'Usage: mayar bundling <list|get>';
6
+
7
+ async function run({ apiKey, flags, positional }) {
8
+ const [sub, ...rest] = positional;
9
+ switch (sub) {
10
+ case undefined:
11
+ case 'list': {
12
+ const res = await api.request('GET', '/hl/v2/bundling', {
13
+ apiKey, query: pagination(flags),
14
+ });
15
+ checkResp(res);
16
+ if (flags.json) return ui.jsonOut(res.body);
17
+ const data = (res.body && res.body.data) || [];
18
+ const rows = data.map((b) => ({
19
+ id: b.id, name: b.name, amount: b.amount, status: b.status,
20
+ }));
21
+ ui.table(rows, ['id', 'name', 'amount', 'status']);
22
+ cursorFooter(res.body, data.length);
23
+ return;
24
+ }
25
+ case 'get':
26
+ case 'detail': {
27
+ if (!rest[0]) throw new Error('Usage: mayar bundling get <id>');
28
+ const res = await api.request('GET', `/hl/v2/bundling/${encodeURIComponent(rest[0])}`, { apiKey });
29
+ checkResp(res); ui.jsonOut(res.body); return;
30
+ }
31
+ default:
32
+ throw new Error(USAGE);
33
+ }
34
+ }
35
+
36
+ module.exports = { run };
@@ -0,0 +1,72 @@
1
+ const api = require('../api');
2
+ const ui = require('../ui');
3
+ const { checkResp, readData } = require('../util');
4
+
5
+ const USAGE = 'Usage: mayar credit <balance|add|spend|history|register-usage|register-membership|checkout>';
6
+
7
+ async function run({ apiKey, flags, positional }) {
8
+ const [sub, ...rest] = positional;
9
+ switch (sub) {
10
+ case 'balance': {
11
+ if (!flags.customerId) throw new Error('mayar credit balance requires --customerId <id>');
12
+ if (!flags.productId) throw new Error('mayar credit balance requires --productId <id>');
13
+ const res = await api.request('GET', '/hl/v2/credit/customer/balance', {
14
+ apiKey,
15
+ query: {
16
+ customerId: flags.customerId,
17
+ productId: flags.productId,
18
+ membershipTierId: flags.tierId || flags.membershipTierId,
19
+ },
20
+ });
21
+ checkResp(res); ui.jsonOut(res.body); return;
22
+ }
23
+ case 'add': {
24
+ const body = readData(flags.data);
25
+ if (!body) throw new Error('mayar credit add requires --data <json|@file> ({customerId,productId,amount})');
26
+ const res = await api.request('POST', '/hl/v2/credit/customer/add-credit', { apiKey, body });
27
+ checkResp(res); ui.jsonOut(res.body); return;
28
+ }
29
+ case 'spend': {
30
+ const body = readData(flags.data);
31
+ if (!body) throw new Error('mayar credit spend requires --data <json|@file> ({customerId,productId,amount})');
32
+ const res = await api.request('POST', '/hl/v2/credit/customer/spend', { apiKey, body });
33
+ checkResp(res); ui.jsonOut(res.body); return;
34
+ }
35
+ case 'history': {
36
+ if (!rest[0]) throw new Error('Usage: mayar credit history <customerId> --productId <id>');
37
+ if (!flags.productId) throw new Error('mayar credit history requires --productId <id>');
38
+ const res = await api.request('GET', `/hl/v2/credit/customer/paginate-credit-history/${encodeURIComponent(rest[0])}`, {
39
+ apiKey,
40
+ query: {
41
+ productId: flags.productId,
42
+ page: flags.page,
43
+ limit: flags.limit,
44
+ },
45
+ });
46
+ checkResp(res); ui.jsonOut(res.body); return;
47
+ }
48
+ case 'register-usage': {
49
+ const body = readData(flags.data);
50
+ if (!body) throw new Error('mayar credit register-usage requires --data <json|@file>');
51
+ const res = await api.request('POST', '/hl/v2/credit/credit-usage/customer/regist', { apiKey, body });
52
+ checkResp(res); ui.jsonOut(res.body); return;
53
+ }
54
+ case 'register-membership': {
55
+ const body = readData(flags.data);
56
+ if (!body) throw new Error('mayar credit register-membership requires --data <json|@file>');
57
+ const res = await api.request('POST', '/hl/v2/credit/membership/customer/regist', { apiKey, body });
58
+ checkResp(res); ui.jsonOut(res.body); return;
59
+ }
60
+ case 'checkout':
61
+ case 'generate-checkout': {
62
+ const body = readData(flags.data);
63
+ if (!body) throw new Error('mayar credit checkout requires --data <json|@file>');
64
+ const res = await api.request('POST', '/hl/v2/credit/generate/immutable/checkout', { apiKey, body });
65
+ checkResp(res); ui.jsonOut(res.body); return;
66
+ }
67
+ default:
68
+ throw new Error(USAGE);
69
+ }
70
+ }
71
+
72
+ module.exports = { run };