@staqon/cli 0.0.0-stage → 0.1.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/LICENSE +6 -0
- package/README.md +278 -2
- package/bin/staqon.js +2 -0
- package/dist/cli.js +1155 -0
- package/package.json +52 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Copyright (c) 2026 VistarKriya Marketings Private Limited. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software is proprietary. No licence is granted to copy, modify, merge,
|
|
4
|
+
publish, distribute, sublicense or sell it, except as expressly agreed in
|
|
5
|
+
writing with the copyright holder. It is provided "as is", without warranty of
|
|
6
|
+
any kind.
|
package/README.md
CHANGED
|
@@ -1,3 +1,279 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @staqon/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Command-line client for the StaqOn partner API. Send messages, post comments, run push-approval
|
|
4
|
+
verifications and broadcast ads as your workspace, from a terminal or a script.
|
|
5
|
+
|
|
6
|
+
- Requires **Node.js 20 or newer**.
|
|
7
|
+
- Talks to `https://staqon.one` by default (override with `--base-url` or `STAQON_BASE_URL`).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install -g @staqon/cli
|
|
13
|
+
staqon --version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Getting started
|
|
17
|
+
|
|
18
|
+
1. **The workspace owner creates an API key first.** Open your workspace at
|
|
19
|
+
`<your-workspace-url>/workspace/settings.php?w=<your-workspace-slug>&tab=api` and, under the
|
|
20
|
+
relevant card (Messaging API, Ad API, etc.), generate a key for the team you want the CLI to
|
|
21
|
+
act as. Messaging and Ad keys both require a **Link** key to already exist on that same tab �
|
|
22
|
+
set that up first if you see a "set up Link API first" notice.
|
|
23
|
+
2. On that same `api` tab, turn on **"Allow CLI access"** for the workspace. This is a separate
|
|
24
|
+
switch from the API key above � it must be ON before `staqon login` can be approved. Turning it
|
|
25
|
+
OFF immediately signs out every CLI session for that workspace.
|
|
26
|
+
3. Run `staqon login` from the machine or server you want to use. It prints a URL and a short code.
|
|
27
|
+
4. The **workspace owner** opens that URL (it's also reachable directly at `/cli`) and approves the
|
|
28
|
+
code � they may be asked for their MPIN if their web session is old.
|
|
29
|
+
5. Run `staqon whoami`. It lists every key the CLI can use and which teams hold it. If a command you
|
|
30
|
+
need isn't listed, go back to step 1 for that key type � the CLI itself can never create or see
|
|
31
|
+
API keys, only the owner can.
|
|
32
|
+
6. Send your first message:
|
|
33
|
+
```sh
|
|
34
|
+
staqon message send --email member@example.com -m "Hello from the CLI"
|
|
35
|
+
```
|
|
36
|
+
7. **Member approval (exit code 6).** Most calls that reach a specific member � direct messages,
|
|
37
|
+
comments, internal messages, verification requests � require that member to have approved
|
|
38
|
+
linking with your workspace in their own StaqOn app first. If they haven't, the CLI exits with
|
|
39
|
+
code 6 and a message like "This member hasn't approved linking with this workspace." This isn't
|
|
40
|
+
something the CLI or the owner can bypass � the member has to approve it on their end.
|
|
41
|
+
|
|
42
|
+
## Sign in
|
|
43
|
+
|
|
44
|
+
There is no separate `init` step: `staqon login` is the whole setup.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
staqon login # prints a URL and a one-time code
|
|
48
|
+
staqon login --open # also opens the URL in your browser
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
1. The CLI shows a verification URL and a code.
|
|
52
|
+
2. **The workspace owner** opens the URL and approves the code (they may be asked for their MPIN).
|
|
53
|
+
3. The CLI polls, receives a session token, and stores it.
|
|
54
|
+
|
|
55
|
+
Where the token lives: the OS keychain when available, otherwise a user-only file
|
|
56
|
+
(`credentials.json` in the `staqon` config directory: `%APPDATA%\staqon` on Windows,
|
|
57
|
+
`$XDG_CONFIG_HOME/staqon` or `~/.config/staqon` elsewhere). The CLI says so when it has to use the file.
|
|
58
|
+
|
|
59
|
+
| Command | What it does |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `staqon whoami` | Workspace, session expiry, rate limits, and which teams can do what |
|
|
62
|
+
| `staqon refresh` | Rotate the session token (the old one works for 5 more minutes) |
|
|
63
|
+
| `staqon logout` | Forget the local token. Revoking it is done by the owner in the web UI |
|
|
64
|
+
|
|
65
|
+
### Running unattended (a server sending automatic alerts)
|
|
66
|
+
|
|
67
|
+
Session tokens are sliding-expiry: **90 days of inactivity invalidates them, and every call extends
|
|
68
|
+
that window**, up to a hard cap of **1 year from the original login**. For a server that calls the
|
|
69
|
+
CLI regularly (e.g. daily alerts), the token effectively never goes stale on its own � but you should
|
|
70
|
+
still rotate it well before the 90-day mark, in case the server is ever idle for a stretch:
|
|
71
|
+
|
|
72
|
+
- Run `staqon refresh` on a schedule (cron / Task Scheduler) every 30-60 days. It rotates the token;
|
|
73
|
+
the old one keeps working for 5 more minutes, so overlap is safe. Save the new token exactly as
|
|
74
|
+
`staqon` does (OS keychain, or the user-only `credentials.json` file) � don't hardcode it elsewhere.
|
|
75
|
+
- Once a year, at the hard cap, `refresh` will stop working and the command exits with an auth error.
|
|
76
|
+
At that point a human (the workspace owner, or whoever can reach the approval URL) has to run
|
|
77
|
+
`staqon login` again � there is no way around this step by design, since it's what lets the owner
|
|
78
|
+
revoke access.
|
|
79
|
+
- Do **not** try to use the partner's raw API key directly as a substitute for a long-lived token:
|
|
80
|
+
the CLI protocol deliberately never hands the API key to the CLI session at all (see the server
|
|
81
|
+
contract) � the CLI only ever gets a revocable, rate-limited session token, scoped to the CLI's own
|
|
82
|
+
separate limits, so the partner's production API key headroom is never affected by CLI traffic.
|
|
83
|
+
`STAQON_TOKEN` (below) is the only supported "skip login" path, and it still expires the same way.
|
|
84
|
+
|
|
85
|
+
For CI, set `STAQON_TOKEN` instead of logging in (and `STAQON_BASE_URL` if not production). Tokens are
|
|
86
|
+
only ever sent to the host that issued them, and the CLI refuses to send one to a different `--base-url`.
|
|
87
|
+
`refresh` is not available for `STAQON_TOKEN` sessions -- if you use this path, you are responsible for
|
|
88
|
+
replacing the value yourself before it expires (same 90-day sliding / 1-year hard cap rules apply).
|
|
89
|
+
|
|
90
|
+
## Teams
|
|
91
|
+
|
|
92
|
+
Most calls are made on behalf of a **team** that holds the right API key. Selection order:
|
|
93
|
+
|
|
94
|
+
1. `--team <id|slug>` on the command line
|
|
95
|
+
2. the saved default (`staqon use <team>`; `staqon use` shows it; `staqon use --clear` removes it)
|
|
96
|
+
3. if the server answers `team_required`:
|
|
97
|
+
- in a terminal, you are asked to pick one (and can save it as the default);
|
|
98
|
+
- otherwise the CLI exits with code 5 and lists the eligible teams. It never picks one for you.
|
|
99
|
+
|
|
100
|
+
`team_not_eligible` (exit 5) means the chosen team has no key for that call; the error lists the teams that do.
|
|
101
|
+
`staqon whoami` shows which teams can send messages and ads.
|
|
102
|
+
|
|
103
|
+
## Commands
|
|
104
|
+
|
|
105
|
+
Every command accepts the global options below. `--to` takes an email **or** a username and converts it if the
|
|
106
|
+
endpoint wants the other kind (see [Identity](#identity-email-vs-username)).
|
|
107
|
+
|
|
108
|
+
| Global option | |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `--json` | Machine-readable: raw response body on stdout, errors as JSON on stderr |
|
|
111
|
+
| `--team <team>` | Team to act as |
|
|
112
|
+
| `--base-url <url>` | API host |
|
|
113
|
+
| `--verbose` | Print request lines and trace ids to stderr |
|
|
114
|
+
| `--no-color` | Disable colors |
|
|
115
|
+
|
|
116
|
+
### Messaging
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
staqon message send --email ada@example.com -m "Hello"
|
|
120
|
+
staqon message send --to ada_username -m "Hello" # username resolved to an email
|
|
121
|
+
staqon message send --email ada@example.com --message-file note.txt # or -m - to read stdin
|
|
122
|
+
|
|
123
|
+
staqon messages --username ada_username --limit 20 # read a thread (needs the member's approved link)
|
|
124
|
+
staqon messages --username ada_username --before 152698 # page backwards (--after pages forwards)
|
|
125
|
+
|
|
126
|
+
staqon comment --username ada_username -c "Looks good" --external-ref order-1042
|
|
127
|
+
staqon comment --username ada_username -c "Status" --card @card.json
|
|
128
|
+
|
|
129
|
+
staqon internal message --email ada@example.com -m "FYI" --title "Heads up" --link-url https://example.com
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- Message and comment text: up to 60,000 characters. `--external-ref` (max 190) is an idempotency key: a repeat is
|
|
133
|
+
rejected and nothing is posted.
|
|
134
|
+
- `messages --limit` is 1-200 (default 50). Attachment URLs in results are signed and **expire after 1 day**;
|
|
135
|
+
re-fetch the thread for fresh ones.
|
|
136
|
+
- `internal message` sends to a member's one-way API Messages feed and needs their approval.
|
|
137
|
+
|
|
138
|
+
### Members
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
staqon members list --search "Ada" --limit 50 --page 2
|
|
142
|
+
staqon member ada@example.com # or: staqon member --member-id 311
|
|
143
|
+
staqon internal members --search ada # internal directory (search also matches username)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`members list` shows email and username side by side. `--limit` is **1-100**: the directory is slow server-side
|
|
147
|
+
(about 0.35 s per row) and larger pages hit the gateway timeout. Member searches match **name or email**, not username.
|
|
148
|
+
|
|
149
|
+
### Verification (push approval)
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
staqon verify start --username ada_username --action "Approve payout #1042" \
|
|
153
|
+
--context "Payout of 5,000 to account ending 1234" --ttl 60
|
|
154
|
+
staqon verify check <verification_id> # prints Verified. / Not verified: <reason>
|
|
155
|
+
staqon verify check <verification_id> --strict # exit 1 unless verified
|
|
156
|
+
staqon verify cancel <verification_id>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
- `--ttl` is clamped to 30-180 seconds (default 30). `--action` max 100 chars, `--context` max 500.
|
|
160
|
+
- `check` reasons include `pending`, `declined`, `timeout` and `cancelled`. Without `--strict`, `check` exits 0 for any
|
|
161
|
+
answer; with it, only a verified result exits 0.
|
|
162
|
+
- `cancel` after the member answered returns exit 1 with "Too late to cancel"; after expiry, "already expired".
|
|
163
|
+
- Needs the member's approved link.
|
|
164
|
+
|
|
165
|
+
### Ads
|
|
166
|
+
|
|
167
|
+
Ads are delivered asynchronously by a background worker.
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
staqon ad image banner.png # upload only; nothing is delivered
|
|
171
|
+
staqon ad create --body-file ad.txt --button-label "Open" --button-url https://example.com --image banner.png --wait
|
|
172
|
+
staqon ad status <ad_request_id> # or --external-ref <ref>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- Images: JPEG, PNG or WebP (checked on file contents), **max 300 KB**; the server crops to 16:9 and downsizes to
|
|
176
|
+
at most 1280x720, so the stored size differs from your file.
|
|
177
|
+
- `ad create`: body 50-900 characters; success is HTTP 202 plus an `ad_request_id`. `--wait` polls every 5 s for up
|
|
178
|
+
to 10 minutes. `--external-ref` (max 150) is an idempotency key.
|
|
179
|
+
|
|
180
|
+
### Raw access
|
|
181
|
+
|
|
182
|
+
```sh
|
|
183
|
+
staqon api external/members -q search=ada -q limit=10
|
|
184
|
+
staqon api external/message -d '{"email":"ada@example.com","message":"Hi"}'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Calls any CLI-proxy endpoint directly: `external/{message,messages,comment,members,member,ad,ad-image,ad-status,
|
|
188
|
+
staqon-verify-start,staqon-verify-check,staqon-verify-cancel}` and `internal/{message,members}`.
|
|
189
|
+
`-d` takes inline JSON, `@file.json` or `-` for stdin; `-F k=v` / `-F k=@path` sends multipart.
|
|
190
|
+
|
|
191
|
+
### Cards
|
|
192
|
+
|
|
193
|
+
`--card` (comment, internal message, verify start) takes a JSON object, inline, `@file.json` or `-`. The CLI
|
|
194
|
+
validates it before sending: required `header_color` (one of the palette colors), `title` (200) and `body` (2000);
|
|
195
|
+
optional `meta_title`, `sub_body`, `icon`, `button` (`label`, `url`; not allowed on verification cards) and `table`
|
|
196
|
+
(2-6 columns, 1-500 rows). Unknown keys are rejected.
|
|
197
|
+
|
|
198
|
+
## Identity: email vs. username
|
|
199
|
+
|
|
200
|
+
The endpoints disagree: `message send` wants an email, while `messages`, `comment`, `verify` want a username. Give
|
|
201
|
+
`--email`, `--username` or `--to <either>`; the CLI converts when needed.
|
|
202
|
+
|
|
203
|
+
- email -> username is one fast lookup.
|
|
204
|
+
- username -> email tries the directory search, then looks up the member's name via their thread and searches by
|
|
205
|
+
name (fast, but only for members linked to your workspace), then **pages through the whole directory**. That last
|
|
206
|
+
step can take minutes on a large workspace. **If you know the email, pass `--email`.**
|
|
207
|
+
|
|
208
|
+
## The consent model (why some calls return 403)
|
|
209
|
+
|
|
210
|
+
Members control what a workspace may do. For `messages`, `comment`, `verify *` and `internal message`, the member must
|
|
211
|
+
have approved the link with your workspace in their app. If they have not, the server answers 403 and the CLI prints
|
|
212
|
+
a friendly message and exits with **code 6**:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
Error: This member hasn't approved linking with this workspace.
|
|
216
|
+
trace id: ...
|
|
217
|
+
Server said: No approved link for this member
|
|
218
|
+
The member has to approve the link in their app; the CLI can't do it for them.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The CLI can't work around it. Ask the member to approve, then retry. A 403 that is *not* about consent (CLI access
|
|
222
|
+
switched off, workspace inactive) exits with code 3 instead.
|
|
223
|
+
|
|
224
|
+
## Exit codes
|
|
225
|
+
|
|
226
|
+
| Code | Meaning |
|
|
227
|
+
|---|---|
|
|
228
|
+
| 0 | Success |
|
|
229
|
+
| 1 | General failure: server rejected the request (4xx/5xx), network error or timeout, `verify check --strict` not verified, cancel too late or expired |
|
|
230
|
+
| 2 | Usage error: bad flags or input, caught before anything is sent; also a token used against a different host |
|
|
231
|
+
| 3 | Authentication: not logged in, session expired/revoked (401), or access denied (non-consent 403) |
|
|
232
|
+
| 4 | Rate limited (429): session 30/min, 3,000/day, or the API key's own ceiling. `Retry after` is shown when sent |
|
|
233
|
+
| 5 | Team or key problem: `team_required` (non-interactive), `team_not_eligible`, `no_key` |
|
|
234
|
+
| 6 | Member has not approved the link (consent 403) |
|
|
235
|
+
| 130 | Interrupted (Ctrl-C) |
|
|
236
|
+
|
|
237
|
+
The CLI never retries on its own, except re-asking once after you pick a team interactively.
|
|
238
|
+
Requests time out after 30 s (120 s for member directory listings); override with `STAQON_TIMEOUT_MS`.
|
|
239
|
+
|
|
240
|
+
## `--json`
|
|
241
|
+
|
|
242
|
+
With `--json`, success prints the server's response body, unchanged, on stdout. Errors print **one JSON object on
|
|
243
|
+
stderr** and nothing on stdout:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"error": "This member hasn't approved linking with this workspace.",
|
|
248
|
+
"exit_code": 6,
|
|
249
|
+
"status": 403,
|
|
250
|
+
"trace_id": "30becdb4-daac-46b0-9fb6-395249329632",
|
|
251
|
+
"body": { "ok": false, "error": "No approved link for this member" },
|
|
252
|
+
"hint": "Server said: No approved link for this member\n..."
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`status`, `trace_id` and `body` appear for errors that came from the server; client-side errors have only
|
|
257
|
+
`error`, `exit_code` and optionally `hint`. In `--json` mode the CLI never prompts, so team selection must be
|
|
258
|
+
explicit (`--team` or a saved default). Tokens are redacted (`stq_cli_***`) from all output. Quote the `trace_id`
|
|
259
|
+
when contacting support.
|
|
260
|
+
|
|
261
|
+
## Environment variables
|
|
262
|
+
|
|
263
|
+
| Variable | Purpose |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `STAQON_TOKEN` | Use this session token instead of the stored login |
|
|
266
|
+
| `STAQON_BASE_URL` | API host (default `https://staqon.one`) |
|
|
267
|
+
| `STAQON_TIMEOUT_MS` | Request timeout in milliseconds |
|
|
268
|
+
|
|
269
|
+
## Development
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
npm install
|
|
273
|
+
npm run build # bundle to dist/
|
|
274
|
+
npm test # 52 mocked tests; no network, no login needed
|
|
275
|
+
npm run test:live # optional; needs a login: STAQON_LIVE_USERNAME=... STAQON_LIVE_EMAIL=... (slow case: SLOW=1)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The mocked tests run the real CLI against a local fake server with an isolated config directory, so they never touch
|
|
279
|
+
your real login or keychain.
|
package/bin/staqon.js
ADDED