@formo/cli 1.0.0 → 1.1.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.
- package/LICENSE +21 -0
- package/README.md +111 -20
- package/dist/commands/alerts.d.ts +16 -3
- package/dist/commands/alerts.js +94 -24
- package/dist/commands/analytics.js +2 -2
- package/dist/commands/boards.d.ts +11 -2
- package/dist/commands/boards.js +49 -17
- package/dist/commands/charts.d.ts +30 -3
- package/dist/commands/charts.js +297 -33
- package/dist/commands/contracts.d.ts +17 -13
- package/dist/commands/contracts.js +165 -53
- package/dist/commands/events.d.ts +9 -0
- package/dist/commands/events.js +64 -0
- package/dist/commands/import.d.ts +8 -4
- package/dist/commands/import.js +33 -11
- package/dist/commands/profiles.d.ts +28 -2
- package/dist/commands/profiles.js +185 -17
- package/dist/commands/query.js +5 -1
- package/dist/commands/segments.d.ts +6 -2
- package/dist/commands/segments.js +19 -5
- package/dist/index.js +11 -4
- package/dist/lib/client.d.ts +10 -1
- package/dist/lib/client.js +27 -4
- package/dist/lib/config.js +10 -0
- package/dist/lib/json.d.ts +5 -0
- package/dist/lib/json.js +54 -0
- package/dist/lib/sql.d.ts +31 -0
- package/dist/lib/sql.js +151 -0
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Formo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -10,6 +10,23 @@ npm install -g @formo/cli
|
|
|
10
10
|
npx @formo/cli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## Install the Formo Analytics agent skill
|
|
14
|
+
|
|
15
|
+
This repository also ships the [`formo-analytics`](skills/formo-analytics/SKILL.md) skill for Claude Code, Codex, and other [Agent Skills](https://agentskills.io)-compatible tools. It teaches agents to use Formo's MCP server, CLI, and REST API for project-scoped product and onchain analytics.
|
|
16
|
+
|
|
17
|
+
Install it in the current project:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx skills add https://github.com/getformo/cli/tree/main/skills/formo-analytics
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install it globally for Claude Code and Codex:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx skills add getformo/cli --skill formo-analytics --global \
|
|
27
|
+
--agent claude-code --agent codex
|
|
28
|
+
```
|
|
29
|
+
|
|
13
30
|
## Authentication
|
|
14
31
|
|
|
15
32
|
Save your API key locally:
|
|
@@ -24,7 +41,14 @@ Or set the `FORMO_API_KEY` environment variable — it takes precedence over the
|
|
|
24
41
|
export FORMO_API_KEY=formo_abc123
|
|
25
42
|
```
|
|
26
43
|
|
|
27
|
-
Get your API key from `Settings → API
|
|
44
|
+
Get your API key from `Settings → API` in the [Formo dashboard](https://app.formo.so).
|
|
45
|
+
|
|
46
|
+
For local development or proxying, override API hosts with:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export FORMO_API_BASE_URL=http://localhost:3001
|
|
50
|
+
export FORMO_EVENTS_BASE_URL=http://localhost:3002
|
|
51
|
+
```
|
|
28
52
|
|
|
29
53
|
---
|
|
30
54
|
|
|
@@ -114,6 +138,15 @@ formo profiles update vitalik.eth --properties '{"email":"alice@example.com"}'
|
|
|
114
138
|
|
|
115
139
|
> Requires `profiles:write` scope.
|
|
116
140
|
|
|
141
|
+
### `profiles properties batch`
|
|
142
|
+
|
|
143
|
+
Batch update first-party properties for up to 100 wallets.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
formo profiles properties batch \
|
|
147
|
+
--rows '[{"address":"0xd8dA...","display_name":"alice.eth","email":"alice@example.com"}]'
|
|
148
|
+
```
|
|
149
|
+
|
|
117
150
|
### `profiles labels create <address>`
|
|
118
151
|
|
|
119
152
|
Upsert one or more labels on a wallet profile. Provide either a single label via `--tag-id` or a batch via `--labels`.
|
|
@@ -123,12 +156,16 @@ Upsert one or more labels on a wallet profile. Provide either a single label via
|
|
|
123
156
|
| `--tag-id` | Label identifier (e.g. `vip`, `airdrop_eligible`) |
|
|
124
157
|
| `--value` | Optional label value (e.g. tier name, country code) |
|
|
125
158
|
| `--chain-id` | Optional chain identifier the label applies to |
|
|
159
|
+
| `--timestamp` | Optional historical ISO-8601 timestamp |
|
|
160
|
+
| `--is-deleted` | Backfill a historical label removal tombstone |
|
|
126
161
|
| `--labels` | JSON array of `UserLabelInput` objects for batch upsert |
|
|
127
162
|
|
|
128
163
|
```bash
|
|
129
164
|
formo profiles labels create 0xd8dA... --tag-id vip
|
|
130
165
|
formo profiles labels create 0xd8dA... --tag-id tier --value gold --chain-id 1
|
|
131
166
|
formo profiles labels create 0xd8dA... --labels '[{"tag_id":"vip"},{"tag_id":"airdrop_eligible","chain_id":"1"}]'
|
|
167
|
+
formo profiles labels create 0xd8dA... --tag-id tier --timestamp 2024-03-15T00:00:00.000Z --is-deleted
|
|
168
|
+
formo profiles labels batch --labels '[{"address":"0xd8dA...","tag_id":"vip","value":"tier-1"}]'
|
|
132
169
|
```
|
|
133
170
|
|
|
134
171
|
### `profiles labels delete <address>`
|
|
@@ -164,14 +201,14 @@ Get a single alert by ID.
|
|
|
164
201
|
| Option | Description |
|
|
165
202
|
|---|---|
|
|
166
203
|
| `--name` | Alert name |
|
|
167
|
-
| `--trigger-type` | Trigger type
|
|
204
|
+
| `--trigger-type` | Trigger type: `event` or `user` |
|
|
168
205
|
| `--trigger-filters` | JSON array of trigger filter objects |
|
|
169
206
|
| `--recipient` | JSON array of recipient objects |
|
|
170
207
|
| `--secret` | Webhook secret |
|
|
171
208
|
|
|
172
209
|
```bash
|
|
173
210
|
formo alerts create --name "High value tx" --trigger-type event \
|
|
174
|
-
--trigger-filters '[{"name":"event","operator":"
|
|
211
|
+
--trigger-filters '[{"name":"event","operator":"eq","value":"transaction"}]' \
|
|
175
212
|
--recipient '[{"type":"email","value":["alerts@myapp.com"]}]'
|
|
176
213
|
```
|
|
177
214
|
|
|
@@ -181,11 +218,18 @@ Same options as `create`. Replaces the alert configuration.
|
|
|
181
218
|
### `alerts delete <alertId>`
|
|
182
219
|
Delete an alert.
|
|
183
220
|
|
|
184
|
-
### `alerts toggle <alertId> --status <active|
|
|
185
|
-
Toggle an alert between `active` and `
|
|
221
|
+
### `alerts toggle <alertId> --status <active|inactive>`
|
|
222
|
+
Toggle an alert between `active` and `inactive`.
|
|
186
223
|
|
|
187
224
|
```bash
|
|
188
|
-
formo alerts toggle alert_abc123 --status
|
|
225
|
+
formo alerts toggle alert_abc123 --status inactive
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### `alerts test <alertId>`
|
|
229
|
+
Send a test alert delivery with optional sample payloads.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
formo alerts test alert_abc123 --sample-event '{"event":"transaction","revenue":250}'
|
|
189
233
|
```
|
|
190
234
|
|
|
191
235
|
---
|
|
@@ -204,19 +248,21 @@ Get a single board by ID.
|
|
|
204
248
|
|
|
205
249
|
| Option | Description |
|
|
206
250
|
|---|---|
|
|
207
|
-
| `--
|
|
251
|
+
| `--title` | Board title |
|
|
208
252
|
| `--description` | Optional board description |
|
|
253
|
+
| `--is-public` | Make the board publicly viewable |
|
|
209
254
|
|
|
210
255
|
```bash
|
|
211
|
-
formo boards create --
|
|
256
|
+
formo boards create --title "Revenue Metrics" --description "Weekly revenue tracking"
|
|
212
257
|
```
|
|
213
258
|
|
|
214
259
|
### `boards update <boardId>`
|
|
215
260
|
|
|
216
261
|
| Option | Description |
|
|
217
262
|
|---|---|
|
|
218
|
-
| `--
|
|
263
|
+
| `--title` | New board title |
|
|
219
264
|
| `--description` | New board description |
|
|
265
|
+
| `--is-public` | Update public visibility |
|
|
220
266
|
|
|
221
267
|
### `boards delete <boardId>`
|
|
222
268
|
Delete a board.
|
|
@@ -233,12 +279,30 @@ List all charts in a board.
|
|
|
233
279
|
### `charts get <chartId> --board-id <boardId>`
|
|
234
280
|
Get a single chart by ID.
|
|
235
281
|
|
|
236
|
-
### `charts
|
|
237
|
-
|
|
282
|
+
### `charts meta --board-id <boardId>`
|
|
283
|
+
List lightweight chart metadata without executing chart queries.
|
|
284
|
+
|
|
285
|
+
### `charts create --board-id <boardId> [options]`
|
|
286
|
+
Create a chart from typed flags or a raw JSON body.
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
formo charts create --board-id brd_123 --title "Daily Active Users" \
|
|
290
|
+
--chart-type line \
|
|
291
|
+
--query "SELECT toDate(timestamp) AS date, countDistinct(address) AS users FROM events GROUP BY date ORDER BY date" \
|
|
292
|
+
--x-axis date --y-axis users
|
|
293
|
+
|
|
294
|
+
formo charts create --board-id brd_123 --body '{"title":"Recent Events","chart_type":"table","query":"SELECT * FROM events LIMIT 10"}'
|
|
295
|
+
```
|
|
238
296
|
|
|
239
297
|
### `charts update <chartId> --board-id <boardId> --body '<json>'`
|
|
240
298
|
Update a chart.
|
|
241
299
|
|
|
300
|
+
### `charts query <chartId> --board-id <boardId> --date-from <YYYY-MM-DD> --date-to <YYYY-MM-DD>`
|
|
301
|
+
Execute a saved chart that uses `{{date_from}}` / `{{date_to}}` variables.
|
|
302
|
+
|
|
303
|
+
### `charts move|duplicate|reorder`
|
|
304
|
+
Move a chart to another board, duplicate a chart, or reorder charts in a board.
|
|
305
|
+
|
|
242
306
|
### `charts delete <chartId> --board-id <boardId>`
|
|
243
307
|
Delete a chart.
|
|
244
308
|
|
|
@@ -251,6 +315,12 @@ Smart contract commands. Requires `contracts:read` / `contracts:write`.
|
|
|
251
315
|
### `contracts list`
|
|
252
316
|
List all tracked contracts. Returns `{ data: Contract[], deploy: { last_deployed_at, diff }, total, page, size, has_more }`.
|
|
253
317
|
|
|
318
|
+
### `contracts get <chain> <address>`
|
|
319
|
+
Get a single tracked contract.
|
|
320
|
+
|
|
321
|
+
### `contracts recommendations`
|
|
322
|
+
List contracts the project already interacts with but has not added yet.
|
|
323
|
+
|
|
254
324
|
### `contracts create`
|
|
255
325
|
|
|
256
326
|
| Option | Description |
|
|
@@ -258,13 +328,15 @@ List all tracked contracts. Returns `{ data: Contract[], deploy: { last_deployed
|
|
|
258
328
|
| `--address` | Contract address (`0x…`) |
|
|
259
329
|
| `--chain` | Chain ID (e.g. `1`, `137`) |
|
|
260
330
|
| `--name` | Human-readable contract name |
|
|
261
|
-
| `--abi` | Contract ABI as a JSON string |
|
|
262
|
-
| `--events` |
|
|
331
|
+
| `--abi` | Contract ABI as a JSON string; sent stringified to the API |
|
|
332
|
+
| `--events` | JSON array of ABI event objects to monitor |
|
|
333
|
+
| `--start-block` | Optional start block |
|
|
334
|
+
| `--include-in-pipeline` | Include this contract in the Goldsky events pipeline (`true` by default in the API) |
|
|
263
335
|
|
|
264
336
|
```bash
|
|
265
337
|
formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --chain 1 \
|
|
266
338
|
--name "UNI Token" --abi '[{"type":"event","name":"Transfer","inputs":[]}]' \
|
|
267
|
-
--events '{"Transfer":
|
|
339
|
+
--events '[{"type":"event","name":"Transfer","inputs":[]}]'
|
|
268
340
|
```
|
|
269
341
|
|
|
270
342
|
### `contracts update <chain> <address>`
|
|
@@ -273,7 +345,12 @@ formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --ch
|
|
|
273
345
|
|---|---|
|
|
274
346
|
| `--name` | Updated contract name |
|
|
275
347
|
| `--abi` | Updated ABI |
|
|
276
|
-
| `--events` | Updated
|
|
348
|
+
| `--events` | Updated JSON array of ABI event objects |
|
|
349
|
+
| `--start-block` | Optional start block |
|
|
350
|
+
| `--include-in-pipeline` | Include or exclude this contract from the Goldsky events pipeline |
|
|
351
|
+
|
|
352
|
+
### `contracts pipeline <chain> <address> --include-in-pipeline <true|false>`
|
|
353
|
+
Toggle pipeline inclusion without re-sending the full ABI/events payload.
|
|
277
354
|
|
|
278
355
|
### `contracts delete <chain> <address>`
|
|
279
356
|
Remove a tracked contract.
|
|
@@ -324,7 +401,7 @@ Pre-built analytics pipes — the same data that powers the Formo dashboard —
|
|
|
324
401
|
|---|---|
|
|
325
402
|
| `--date-from` | Inclusive start date `YYYY-MM-DD` (default: 7 days before `--date-to`) |
|
|
326
403
|
| `--date-to` | Inclusive end date `YYYY-MM-DD` (default: today) |
|
|
327
|
-
| `--filters` | JSON array of `[{field,op,value}]`. Use `in`/`
|
|
404
|
+
| `--filters` | JSON array of `[{field,op,value}]`. Use `in`/`nin` with a pipe-delimited value (e.g. `"chrome\|firefox"`) |
|
|
328
405
|
| `--params` | JSON object of pipe-specific params merged into the query (e.g. `{"limit":10,"group_by":"device"}`) |
|
|
329
406
|
|
|
330
407
|
```bash
|
|
@@ -332,7 +409,7 @@ formo analytics kpis
|
|
|
332
409
|
formo analytics kpis --date-from 2026-04-01 --date-to 2026-04-30 --params '{"group_by":"device"}'
|
|
333
410
|
formo analytics funnel --date-from 2026-04-01 --date-to 2026-04-30 --params '{"steps":[{"type":"event","event":"page","name":"page::0","filters":[]},{"type":"track","event":"connect","name":"connect::1","filters":[]}],"window_seconds":86400}'
|
|
334
411
|
formo analytics top_wallets --date-from 2026-04-01 --date-to 2026-04-30 --params '{"limit":10}'
|
|
335
|
-
formo analytics retention --filters '[{"field":"location","op":"
|
|
412
|
+
formo analytics retention --filters '[{"field":"location","op":"eq","value":"US"}]'
|
|
336
413
|
```
|
|
337
414
|
|
|
338
415
|
> Requires `query:read` scope. Run `formo analytics <pipe> --help` for the pipe-specific params accepted via `--params`.
|
|
@@ -348,10 +425,24 @@ Bulk-import wallet addresses into the project via the events API.
|
|
|
348
425
|
| Option | Description |
|
|
349
426
|
|---|---|
|
|
350
427
|
| `--addresses` | JSON array of wallet address strings |
|
|
351
|
-
| `--
|
|
428
|
+
| `--rows` | JSON array of `{address,properties?}` objects |
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
formo import wallets --addresses '["0xabc...","0xdef..."]'
|
|
432
|
+
formo import wallets --rows '[{"address":"0xabc...","properties":{"display_name":"Alice"}}]'
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## `formo events`
|
|
438
|
+
|
|
439
|
+
### `events ingest`
|
|
440
|
+
|
|
441
|
+
Send raw analytics events to `events.formo.so`. This command uses a project SDK write key, not the workspace API key.
|
|
352
442
|
|
|
353
443
|
```bash
|
|
354
|
-
|
|
444
|
+
export FORMO_WRITE_KEY=formo_write_key_xxx
|
|
445
|
+
formo events ingest --event '{"type":"track","channel":"cli","version":"1","anonymous_id":"anon_123","event":"CLI Test","context":{},"properties":{},"original_timestamp":"2026-04-27T23:05:38.000Z","sent_at":"2026-04-27T23:05:42.000Z","message_id":"cli-test-1"}'
|
|
355
446
|
```
|
|
356
447
|
|
|
357
448
|
---
|
|
@@ -374,7 +465,7 @@ formo import wallets --addresses '["0xabc...","0xdef..."]' --write-key write_key
|
|
|
374
465
|
| Field | Type | Description |
|
|
375
466
|
|---|---|---|
|
|
376
467
|
| `field` | `string` | Typed path (see prefixes below) |
|
|
377
|
-
| `op` | `string` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin` |
|
|
468
|
+
| `op` | `string` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains` (social fields only), `notEmpty` / `isEmpty` (value-less existence checks). Long-form spellings (`equals`, `greater`, `includes`, …) are retired — the API rejects them with a `400` naming the token |
|
|
378
469
|
| `value` | `any` | Value to compare against |
|
|
379
470
|
| `scope` | `string` | _(token filters only)_ `any` or `protocol` |
|
|
380
471
|
| `appId` | `string` | _(token filters with `scope: protocol`)_ e.g. `aave-v3` |
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
2
|
export declare const alerts: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export
|
|
3
|
+
export interface PaginationOptions {
|
|
4
|
+
page?: number;
|
|
5
|
+
size?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function listAlertsRun(options?: PaginationOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
4
8
|
export declare function getAlertRun(alertId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
5
9
|
export interface CreateAlertOptions {
|
|
6
10
|
name: string;
|
|
7
|
-
triggerType: string;
|
|
11
|
+
triggerType: 'event' | 'user' | string;
|
|
8
12
|
triggerFilters?: string;
|
|
9
13
|
recipient?: string;
|
|
10
14
|
secret?: string;
|
|
15
|
+
slackPropertyKeys?: string;
|
|
11
16
|
}
|
|
12
17
|
export declare function buildAlertBody(options: CreateAlertOptions | UpdateAlertOptions): Record<string, unknown>;
|
|
13
18
|
export declare function createAlertRun(options: CreateAlertOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
14
19
|
export interface UpdateAlertOptions {
|
|
15
20
|
name: string;
|
|
16
|
-
triggerType: string;
|
|
21
|
+
triggerType: 'event' | 'user' | string;
|
|
17
22
|
triggerFilters?: string;
|
|
18
23
|
recipient?: string;
|
|
19
24
|
secret?: string;
|
|
25
|
+
slackPropertyKeys?: string;
|
|
20
26
|
}
|
|
21
27
|
export declare function updateAlertRun(alertId: string, options: UpdateAlertOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
22
28
|
export declare function deleteAlertRun(alertId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
23
29
|
export declare function toggleAlertRun(alertId: string, status: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
30
|
+
export interface TestAlertOptions {
|
|
31
|
+
sampleEvent?: string;
|
|
32
|
+
sampleUser?: string;
|
|
33
|
+
recipientOverrides?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function buildTestAlertBody(options: TestAlertOptions): Record<string, unknown> | undefined;
|
|
36
|
+
export declare function testAlertRun(alertId: string, options?: TestAlertOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
package/dist/commands/alerts.js
CHANGED
|
@@ -8,23 +8,37 @@ exports.createAlertRun = createAlertRun;
|
|
|
8
8
|
exports.updateAlertRun = updateAlertRun;
|
|
9
9
|
exports.deleteAlertRun = deleteAlertRun;
|
|
10
10
|
exports.toggleAlertRun = toggleAlertRun;
|
|
11
|
+
exports.buildTestAlertBody = buildTestAlertBody;
|
|
12
|
+
exports.testAlertRun = testAlertRun;
|
|
11
13
|
const incur_1 = require("incur");
|
|
12
14
|
const client_1 = require("../lib/client");
|
|
15
|
+
const json_1 = require("../lib/json");
|
|
13
16
|
exports.alerts = incur_1.Cli.create('alerts', {
|
|
14
17
|
description: 'Project alert commands — create, list, update, and delete alerts',
|
|
15
18
|
});
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
function buildPaginationParams(options = {}) {
|
|
20
|
+
const params = {};
|
|
21
|
+
if (options.page !== undefined)
|
|
22
|
+
params.page = options.page;
|
|
23
|
+
if (options.size !== undefined)
|
|
24
|
+
params.size = options.size;
|
|
25
|
+
return params;
|
|
26
|
+
}
|
|
27
|
+
function listAlertsRun(options = {}) {
|
|
18
28
|
(0, client_1.requireApiKey)();
|
|
19
29
|
const client = (0, client_1.createClient)();
|
|
20
|
-
return client.get('/v0/alerts/');
|
|
30
|
+
return client.get('/v0/alerts/', { params: buildPaginationParams(options) });
|
|
21
31
|
}
|
|
22
32
|
exports.alerts.command('list', {
|
|
23
33
|
description: 'List all alerts for the project',
|
|
34
|
+
options: incur_1.z.object({
|
|
35
|
+
page: incur_1.z.coerce.number().optional().describe('Page number (1-indexed, default 1)'),
|
|
36
|
+
size: incur_1.z.coerce.number().optional().describe('Page size (default 100, max 200)'),
|
|
37
|
+
}),
|
|
24
38
|
examples: [{ description: 'List all project alerts' }],
|
|
25
39
|
hint: 'Requires alerts:read scope on your API key.',
|
|
26
|
-
run() {
|
|
27
|
-
return listAlertsRun();
|
|
40
|
+
run({ options }) {
|
|
41
|
+
return listAlertsRun(options);
|
|
28
42
|
},
|
|
29
43
|
});
|
|
30
44
|
// ── Get a single alert ──
|
|
@@ -50,26 +64,20 @@ function buildAlertBody(options) {
|
|
|
50
64
|
const body = {
|
|
51
65
|
name: options.name,
|
|
52
66
|
trigger_type: options.triggerType,
|
|
67
|
+
trigger_filters: [],
|
|
53
68
|
};
|
|
54
69
|
if (options.triggerFilters) {
|
|
55
|
-
|
|
56
|
-
body.trigger_filters = JSON.parse(options.triggerFilters);
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
throw new Error('--trigger-filters must be a valid JSON array');
|
|
60
|
-
}
|
|
70
|
+
body.trigger_filters = (0, json_1.parseJsonArray)(options.triggerFilters, '--trigger-filters');
|
|
61
71
|
}
|
|
62
72
|
if (options.recipient) {
|
|
63
|
-
|
|
64
|
-
body.recipient = JSON.parse(options.recipient);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
throw new Error('--recipient must be a valid JSON array');
|
|
68
|
-
}
|
|
73
|
+
body.recipient = (0, json_1.parseJsonArray)(options.recipient, '--recipient');
|
|
69
74
|
}
|
|
70
75
|
if (options.secret !== undefined) {
|
|
71
76
|
body.secret = options.secret;
|
|
72
77
|
}
|
|
78
|
+
if (options.slackPropertyKeys !== undefined) {
|
|
79
|
+
body.slack_property_keys = (0, json_1.parseJsonArray)(options.slackPropertyKeys, '--slack-property-keys');
|
|
80
|
+
}
|
|
73
81
|
return body;
|
|
74
82
|
}
|
|
75
83
|
function createAlertRun(options) {
|
|
@@ -81,7 +89,7 @@ exports.alerts.command('create', {
|
|
|
81
89
|
description: 'Create a new project alert',
|
|
82
90
|
options: incur_1.z.object({
|
|
83
91
|
name: incur_1.z.string().describe('Alert name'),
|
|
84
|
-
triggerType: incur_1.z.
|
|
92
|
+
triggerType: incur_1.z.enum(['event', 'user']).describe('Trigger type'),
|
|
85
93
|
triggerFilters: incur_1.z
|
|
86
94
|
.string()
|
|
87
95
|
.optional()
|
|
@@ -91,6 +99,10 @@ exports.alerts.command('create', {
|
|
|
91
99
|
.optional()
|
|
92
100
|
.describe('JSON array of recipient objects'),
|
|
93
101
|
secret: incur_1.z.string().optional().describe('Webhook secret for the alert'),
|
|
102
|
+
slackPropertyKeys: incur_1.z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('JSON array of event/user property keys to include in Slack alerts'),
|
|
94
106
|
}),
|
|
95
107
|
examples: [
|
|
96
108
|
{
|
|
@@ -115,7 +127,7 @@ exports.alerts.command('update', {
|
|
|
115
127
|
}),
|
|
116
128
|
options: incur_1.z.object({
|
|
117
129
|
name: incur_1.z.string().describe('Alert name'),
|
|
118
|
-
triggerType: incur_1.z.
|
|
130
|
+
triggerType: incur_1.z.enum(['event', 'user']).describe('Trigger type'),
|
|
119
131
|
triggerFilters: incur_1.z
|
|
120
132
|
.string()
|
|
121
133
|
.optional()
|
|
@@ -125,6 +137,10 @@ exports.alerts.command('update', {
|
|
|
125
137
|
.optional()
|
|
126
138
|
.describe('JSON array of recipient objects'),
|
|
127
139
|
secret: incur_1.z.string().optional().describe('Webhook secret for the alert'),
|
|
140
|
+
slackPropertyKeys: incur_1.z
|
|
141
|
+
.string()
|
|
142
|
+
.optional()
|
|
143
|
+
.describe('JSON array of event/user property keys to include in Slack alerts'),
|
|
128
144
|
}),
|
|
129
145
|
examples: [
|
|
130
146
|
{
|
|
@@ -161,21 +177,24 @@ exports.alerts.command('delete', {
|
|
|
161
177
|
function toggleAlertRun(alertId, status) {
|
|
162
178
|
(0, client_1.requireApiKey)();
|
|
163
179
|
const client = (0, client_1.createClient)();
|
|
164
|
-
|
|
180
|
+
const normalizedStatus = status === 'paused' ? 'inactive' : status;
|
|
181
|
+
return client.patch(`/v0/alerts/${encodeURIComponent(alertId)}`, {
|
|
182
|
+
status: normalizedStatus,
|
|
183
|
+
});
|
|
165
184
|
}
|
|
166
185
|
exports.alerts.command('toggle', {
|
|
167
|
-
description: 'Toggle an alert status (active/
|
|
186
|
+
description: 'Toggle an alert status (active/inactive)',
|
|
168
187
|
args: incur_1.z.object({
|
|
169
188
|
alertId: incur_1.z.string().describe('Alert ID to toggle'),
|
|
170
189
|
}),
|
|
171
190
|
options: incur_1.z.object({
|
|
172
|
-
status: incur_1.z.enum(['active', 'paused']).describe('New status'),
|
|
191
|
+
status: incur_1.z.enum(['active', 'inactive', 'paused']).describe('New status. "paused" is accepted as a deprecated alias for "inactive".'),
|
|
173
192
|
}),
|
|
174
193
|
examples: [
|
|
175
194
|
{
|
|
176
195
|
args: { alertId: 'alert_abc123' },
|
|
177
|
-
options: { status: '
|
|
178
|
-
description: '
|
|
196
|
+
options: { status: 'inactive' },
|
|
197
|
+
description: 'Deactivate an alert',
|
|
179
198
|
},
|
|
180
199
|
],
|
|
181
200
|
hint: 'Requires alerts:write scope on your API key.',
|
|
@@ -183,3 +202,54 @@ exports.alerts.command('toggle', {
|
|
|
183
202
|
return toggleAlertRun(args.alertId, options.status);
|
|
184
203
|
},
|
|
185
204
|
});
|
|
205
|
+
function buildTestAlertBody(options) {
|
|
206
|
+
const body = {};
|
|
207
|
+
if (options.sampleEvent !== undefined) {
|
|
208
|
+
body.sampleEvent = (0, json_1.parseJsonObject)(options.sampleEvent, '--sample-event');
|
|
209
|
+
}
|
|
210
|
+
if (options.sampleUser !== undefined) {
|
|
211
|
+
body.sampleUser = (0, json_1.parseJsonObject)(options.sampleUser, '--sample-user');
|
|
212
|
+
}
|
|
213
|
+
if (options.recipientOverrides !== undefined) {
|
|
214
|
+
body.recipientOverrides = (0, json_1.parseJsonArray)(options.recipientOverrides, '--recipient-overrides');
|
|
215
|
+
}
|
|
216
|
+
return Object.keys(body).length > 0 ? body : undefined;
|
|
217
|
+
}
|
|
218
|
+
function testAlertRun(alertId, options = {}) {
|
|
219
|
+
(0, client_1.requireApiKey)();
|
|
220
|
+
const client = (0, client_1.createClient)();
|
|
221
|
+
return client.post(`/v0/alerts/${encodeURIComponent(alertId)}/test`, buildTestAlertBody(options));
|
|
222
|
+
}
|
|
223
|
+
exports.alerts.command('test', {
|
|
224
|
+
description: 'Send a test delivery for an alert',
|
|
225
|
+
args: incur_1.z.object({
|
|
226
|
+
alertId: incur_1.z.string().describe('Alert ID to test'),
|
|
227
|
+
}),
|
|
228
|
+
options: incur_1.z.object({
|
|
229
|
+
sampleEvent: incur_1.z
|
|
230
|
+
.string()
|
|
231
|
+
.optional()
|
|
232
|
+
.describe('Optional JSON object to use as the sample event'),
|
|
233
|
+
sampleUser: incur_1.z
|
|
234
|
+
.string()
|
|
235
|
+
.optional()
|
|
236
|
+
.describe('Optional JSON object to use as the sample user/profile'),
|
|
237
|
+
recipientOverrides: incur_1.z
|
|
238
|
+
.string()
|
|
239
|
+
.optional()
|
|
240
|
+
.describe('Optional JSON array of recipient objects to test instead of saved recipients'),
|
|
241
|
+
}),
|
|
242
|
+
examples: [
|
|
243
|
+
{
|
|
244
|
+
args: { alertId: 'alert_abc123' },
|
|
245
|
+
options: {
|
|
246
|
+
sampleEvent: '{"event":"transaction","revenue":250}',
|
|
247
|
+
},
|
|
248
|
+
description: 'Send a test alert with a sample event',
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
hint: 'Requires alerts:write scope on your API key.',
|
|
252
|
+
run({ args, options }) {
|
|
253
|
+
return testAlertRun(args.alertId, options);
|
|
254
|
+
},
|
|
255
|
+
});
|
|
@@ -15,7 +15,7 @@ exports.analytics = incur_1.Cli.create('analytics', {
|
|
|
15
15
|
const PIPES = [
|
|
16
16
|
{ name: 'kpis', description: 'Traffic KPIs: visitors, pageviews, bounce rate, session duration' },
|
|
17
17
|
{ name: 'event_timeseries', description: 'Event counts over time' },
|
|
18
|
-
{ name: 'funnel', description: 'Conversion funnel across ordered steps. --params: steps (JSON array of {type,event,name,filters?}), window_seconds, funnel_type,
|
|
18
|
+
{ name: 'funnel', description: 'Conversion funnel across ordered steps. --params: steps (JSON array of {type,event,name,filters?}), window_seconds, funnel_type, group_by, limit, attribution' },
|
|
19
19
|
{ name: 'flow', description: 'User path/flow analysis. --params: start_step / end_step (JSON {type,event,...}), global_filters, window_seconds, max_steps' },
|
|
20
20
|
{ name: 'frequency', description: 'Engagement frequency distribution' },
|
|
21
21
|
{ name: 'lifecycle', description: 'User lifecycle stages (new, returning, power, resurrected, churned)' },
|
|
@@ -123,7 +123,7 @@ const sharedOptions = incur_1.z.object({
|
|
|
123
123
|
.string()
|
|
124
124
|
.optional()
|
|
125
125
|
.describe('JSON array of filter conditions: [{"field","op","value"}]. ' +
|
|
126
|
-
'Use op "in"/"
|
|
126
|
+
'Use op "in"/"nin" with a pipe-delimited value (e.g. "chrome|firefox").'),
|
|
127
127
|
params: incur_1.z
|
|
128
128
|
.string()
|
|
129
129
|
.optional()
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
2
|
export declare const boards: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export
|
|
3
|
+
export interface PaginationOptions {
|
|
4
|
+
page?: number;
|
|
5
|
+
size?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function listBoardsRun(options?: PaginationOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
4
8
|
export declare function getBoardRun(boardId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
5
9
|
export interface CreateBoardOptions {
|
|
6
|
-
|
|
10
|
+
title?: string;
|
|
11
|
+
name?: string;
|
|
7
12
|
description?: string;
|
|
13
|
+
isPublic?: boolean;
|
|
8
14
|
}
|
|
15
|
+
export declare function buildBoardBody(options: CreateBoardOptions | UpdateBoardOptions): Record<string, unknown>;
|
|
9
16
|
export declare function createBoardRun(options: CreateBoardOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
10
17
|
export interface UpdateBoardOptions {
|
|
18
|
+
title?: string;
|
|
11
19
|
name?: string;
|
|
12
20
|
description?: string;
|
|
21
|
+
isPublic?: boolean;
|
|
13
22
|
}
|
|
14
23
|
export declare function updateBoardRun(boardId: string, options: UpdateBoardOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
15
24
|
export declare function deleteBoardRun(boardId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|