@formo/cli 0.2.0 → 1.0.2
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 +154 -40
- package/dist/commands/alerts.d.ts +16 -3
- package/dist/commands/alerts.js +94 -24
- package/dist/commands/analytics.d.ts +25 -0
- package/dist/commands/analytics.js +153 -0
- 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 +35 -2
- package/dist/commands/profiles.js +260 -32
- package/dist/commands/query.js +5 -1
- package/dist/commands/segments.d.ts +6 -2
- package/dist/commands/segments.js +20 -6
- package/dist/index.js +15 -3
- 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 -3
package/README.md
CHANGED
|
@@ -26,6 +26,13 @@ export FORMO_API_KEY=formo_abc123
|
|
|
26
26
|
|
|
27
27
|
Get your API key from `Settings → API Keys` in the [Formo dashboard](https://app.formo.so).
|
|
28
28
|
|
|
29
|
+
For local development or proxying, override API hosts with:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export FORMO_API_BASE_URL=http://localhost:3001
|
|
33
|
+
export FORMO_EVENTS_BASE_URL=http://localhost:3002
|
|
34
|
+
```
|
|
35
|
+
|
|
29
36
|
---
|
|
30
37
|
|
|
31
38
|
## Auth commands
|
|
@@ -82,18 +89,19 @@ Search wallet profiles with filters, sorting, and pagination. Returns a `Paginat
|
|
|
82
89
|
| `--address` | Filter by wallet address |
|
|
83
90
|
| `--page` | Page number (1-indexed, default `1`) |
|
|
84
91
|
| `--size` | Page size (default `100`, max `1000`) |
|
|
85
|
-
| `--
|
|
86
|
-
| `--
|
|
92
|
+
| `--order-by` | `last_onchain`, `first_onchain`, `net_worth_usd`, `updated_at`, `tx_count`, `first_seen`, `last_seen`, `num_sessions`, `revenue`, `volume`, `points` |
|
|
93
|
+
| `--order-dir` | `asc` or `desc` |
|
|
87
94
|
| `--expand` | Comma-separated fields to expand |
|
|
88
95
|
| `--conditions` | JSON array of `FilterCondition` objects (see below) |
|
|
89
96
|
| `--logic` | Combine conditions with `and` (default) or `or` |
|
|
90
97
|
|
|
91
98
|
```bash
|
|
92
99
|
formo profiles search --size 10
|
|
93
|
-
formo profiles search --
|
|
100
|
+
formo profiles search --order-by net_worth_usd --order-dir desc --size 5
|
|
94
101
|
formo profiles search --page 2 --size 20
|
|
95
|
-
formo profiles search --conditions '[{"field":"net_worth_usd","op":"gt","value":10000}]' --size 20
|
|
96
|
-
formo profiles search --conditions '[{"field":"net_worth_usd","op":"gt","value":10000},{"field":"
|
|
102
|
+
formo profiles search --conditions '[{"field":"users.net_worth_usd","op":"gt","value":10000}]' --size 20
|
|
103
|
+
formo profiles search --conditions '[{"field":"users.net_worth_usd","op":"gt","value":10000},{"field":"users.volume","op":"gt","value":1000}]' --logic or --size 20
|
|
104
|
+
formo profiles search --conditions '[{"field":"chains.1.balance","op":"gt","value":1000}]' --size 20
|
|
97
105
|
```
|
|
98
106
|
|
|
99
107
|
### `profiles update <address>`
|
|
@@ -113,21 +121,34 @@ formo profiles update vitalik.eth --properties '{"email":"alice@example.com"}'
|
|
|
113
121
|
|
|
114
122
|
> Requires `profiles:write` scope.
|
|
115
123
|
|
|
124
|
+
### `profiles properties batch`
|
|
125
|
+
|
|
126
|
+
Batch update first-party properties for up to 100 wallets.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
formo profiles properties batch \
|
|
130
|
+
--rows '[{"address":"0xd8dA...","display_name":"alice.eth","email":"alice@example.com"}]'
|
|
131
|
+
```
|
|
132
|
+
|
|
116
133
|
### `profiles labels create <address>`
|
|
117
134
|
|
|
118
|
-
Upsert one or more labels on a wallet profile. Provide either a single label via `--
|
|
135
|
+
Upsert one or more labels on a wallet profile. Provide either a single label via `--tag-id` or a batch via `--labels`.
|
|
119
136
|
|
|
120
137
|
| Option | Description |
|
|
121
138
|
|---|---|
|
|
122
|
-
| `--
|
|
139
|
+
| `--tag-id` | Label identifier (e.g. `vip`, `airdrop_eligible`) |
|
|
123
140
|
| `--value` | Optional label value (e.g. tier name, country code) |
|
|
124
|
-
| `--
|
|
141
|
+
| `--chain-id` | Optional chain identifier the label applies to |
|
|
142
|
+
| `--timestamp` | Optional historical ISO-8601 timestamp |
|
|
143
|
+
| `--is-deleted` | Backfill a historical label removal tombstone |
|
|
125
144
|
| `--labels` | JSON array of `UserLabelInput` objects for batch upsert |
|
|
126
145
|
|
|
127
146
|
```bash
|
|
128
|
-
formo profiles labels create 0xd8dA... --
|
|
129
|
-
formo profiles labels create 0xd8dA... --
|
|
147
|
+
formo profiles labels create 0xd8dA... --tag-id vip
|
|
148
|
+
formo profiles labels create 0xd8dA... --tag-id tier --value gold --chain-id 1
|
|
130
149
|
formo profiles labels create 0xd8dA... --labels '[{"tag_id":"vip"},{"tag_id":"airdrop_eligible","chain_id":"1"}]'
|
|
150
|
+
formo profiles labels create 0xd8dA... --tag-id tier --timestamp 2024-03-15T00:00:00.000Z --is-deleted
|
|
151
|
+
formo profiles labels batch --labels '[{"address":"0xd8dA...","tag_id":"vip","value":"tier-1"}]'
|
|
131
152
|
```
|
|
132
153
|
|
|
133
154
|
### `profiles labels delete <address>`
|
|
@@ -136,12 +157,12 @@ Delete a label from a wallet profile.
|
|
|
136
157
|
|
|
137
158
|
| Option | Description |
|
|
138
159
|
|---|---|
|
|
139
|
-
| `--
|
|
140
|
-
| `--
|
|
160
|
+
| `--tag-id` | Label identifier to delete (required) |
|
|
161
|
+
| `--chain-id` | Optional chain identifier to scope the deletion |
|
|
141
162
|
|
|
142
163
|
```bash
|
|
143
|
-
formo profiles labels delete 0xd8dA... --
|
|
144
|
-
formo profiles labels delete 0xd8dA... --
|
|
164
|
+
formo profiles labels delete 0xd8dA... --tag-id vip
|
|
165
|
+
formo profiles labels delete 0xd8dA... --tag-id tier --chain-id 1
|
|
145
166
|
```
|
|
146
167
|
|
|
147
168
|
> Requires `profiles:write` scope.
|
|
@@ -163,14 +184,14 @@ Get a single alert by ID.
|
|
|
163
184
|
| Option | Description |
|
|
164
185
|
|---|---|
|
|
165
186
|
| `--name` | Alert name |
|
|
166
|
-
| `--
|
|
167
|
-
| `--
|
|
187
|
+
| `--trigger-type` | Trigger type: `event` or `user` |
|
|
188
|
+
| `--trigger-filters` | JSON array of trigger filter objects |
|
|
168
189
|
| `--recipient` | JSON array of recipient objects |
|
|
169
190
|
| `--secret` | Webhook secret |
|
|
170
191
|
|
|
171
192
|
```bash
|
|
172
|
-
formo alerts create --name "High value tx" --
|
|
173
|
-
--
|
|
193
|
+
formo alerts create --name "High value tx" --trigger-type event \
|
|
194
|
+
--trigger-filters '[{"name":"event","operator":"equals","value":"transaction"}]' \
|
|
174
195
|
--recipient '[{"type":"email","value":["alerts@myapp.com"]}]'
|
|
175
196
|
```
|
|
176
197
|
|
|
@@ -180,11 +201,18 @@ Same options as `create`. Replaces the alert configuration.
|
|
|
180
201
|
### `alerts delete <alertId>`
|
|
181
202
|
Delete an alert.
|
|
182
203
|
|
|
183
|
-
### `alerts toggle <alertId> --status <active|
|
|
184
|
-
Toggle an alert between `active` and `
|
|
204
|
+
### `alerts toggle <alertId> --status <active|inactive>`
|
|
205
|
+
Toggle an alert between `active` and `inactive`.
|
|
185
206
|
|
|
186
207
|
```bash
|
|
187
|
-
formo alerts toggle alert_abc123 --status
|
|
208
|
+
formo alerts toggle alert_abc123 --status inactive
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### `alerts test <alertId>`
|
|
212
|
+
Send a test alert delivery with optional sample payloads.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
formo alerts test alert_abc123 --sample-event '{"event":"transaction","revenue":250}'
|
|
188
216
|
```
|
|
189
217
|
|
|
190
218
|
---
|
|
@@ -203,19 +231,21 @@ Get a single board by ID.
|
|
|
203
231
|
|
|
204
232
|
| Option | Description |
|
|
205
233
|
|---|---|
|
|
206
|
-
| `--
|
|
234
|
+
| `--title` | Board title |
|
|
207
235
|
| `--description` | Optional board description |
|
|
236
|
+
| `--is-public` | Make the board publicly viewable |
|
|
208
237
|
|
|
209
238
|
```bash
|
|
210
|
-
formo boards create --
|
|
239
|
+
formo boards create --title "Revenue Metrics" --description "Weekly revenue tracking"
|
|
211
240
|
```
|
|
212
241
|
|
|
213
242
|
### `boards update <boardId>`
|
|
214
243
|
|
|
215
244
|
| Option | Description |
|
|
216
245
|
|---|---|
|
|
217
|
-
| `--
|
|
246
|
+
| `--title` | New board title |
|
|
218
247
|
| `--description` | New board description |
|
|
248
|
+
| `--is-public` | Update public visibility |
|
|
219
249
|
|
|
220
250
|
### `boards delete <boardId>`
|
|
221
251
|
Delete a board.
|
|
@@ -226,19 +256,37 @@ Delete a board.
|
|
|
226
256
|
|
|
227
257
|
Chart commands. Charts live inside a board. Requires `charts:read` / `charts:write`.
|
|
228
258
|
|
|
229
|
-
### `charts list --
|
|
259
|
+
### `charts list --board-id <boardId>`
|
|
230
260
|
List all charts in a board.
|
|
231
261
|
|
|
232
|
-
### `charts get <chartId> --
|
|
262
|
+
### `charts get <chartId> --board-id <boardId>`
|
|
233
263
|
Get a single chart by ID.
|
|
234
264
|
|
|
235
|
-
### `charts
|
|
236
|
-
|
|
265
|
+
### `charts meta --board-id <boardId>`
|
|
266
|
+
List lightweight chart metadata without executing chart queries.
|
|
267
|
+
|
|
268
|
+
### `charts create --board-id <boardId> [options]`
|
|
269
|
+
Create a chart from typed flags or a raw JSON body.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
formo charts create --board-id brd_123 --title "Daily Active Users" \
|
|
273
|
+
--chart-type line \
|
|
274
|
+
--query "SELECT toDate(timestamp) AS date, countDistinct(address) AS users FROM events GROUP BY date ORDER BY date" \
|
|
275
|
+
--x-axis date --y-axis users
|
|
276
|
+
|
|
277
|
+
formo charts create --board-id brd_123 --body '{"title":"Recent Events","chart_type":"table","query":"SELECT * FROM events LIMIT 10"}'
|
|
278
|
+
```
|
|
237
279
|
|
|
238
|
-
### `charts update <chartId> --
|
|
280
|
+
### `charts update <chartId> --board-id <boardId> --body '<json>'`
|
|
239
281
|
Update a chart.
|
|
240
282
|
|
|
241
|
-
### `charts
|
|
283
|
+
### `charts query <chartId> --board-id <boardId> --date-from <YYYY-MM-DD> --date-to <YYYY-MM-DD>`
|
|
284
|
+
Execute a saved chart that uses `{{date_from}}` / `{{date_to}}` variables.
|
|
285
|
+
|
|
286
|
+
### `charts move|duplicate|reorder`
|
|
287
|
+
Move a chart to another board, duplicate a chart, or reorder charts in a board.
|
|
288
|
+
|
|
289
|
+
### `charts delete <chartId> --board-id <boardId>`
|
|
242
290
|
Delete a chart.
|
|
243
291
|
|
|
244
292
|
---
|
|
@@ -250,6 +298,12 @@ Smart contract commands. Requires `contracts:read` / `contracts:write`.
|
|
|
250
298
|
### `contracts list`
|
|
251
299
|
List all tracked contracts. Returns `{ data: Contract[], deploy: { last_deployed_at, diff }, total, page, size, has_more }`.
|
|
252
300
|
|
|
301
|
+
### `contracts get <chain> <address>`
|
|
302
|
+
Get a single tracked contract.
|
|
303
|
+
|
|
304
|
+
### `contracts recommendations`
|
|
305
|
+
List contracts the project already interacts with but has not added yet.
|
|
306
|
+
|
|
253
307
|
### `contracts create`
|
|
254
308
|
|
|
255
309
|
| Option | Description |
|
|
@@ -257,13 +311,15 @@ List all tracked contracts. Returns `{ data: Contract[], deploy: { last_deployed
|
|
|
257
311
|
| `--address` | Contract address (`0x…`) |
|
|
258
312
|
| `--chain` | Chain ID (e.g. `1`, `137`) |
|
|
259
313
|
| `--name` | Human-readable contract name |
|
|
260
|
-
| `--abi` | Contract ABI as a JSON string |
|
|
261
|
-
| `--events` |
|
|
314
|
+
| `--abi` | Contract ABI as a JSON string; sent stringified to the API |
|
|
315
|
+
| `--events` | JSON array of ABI event objects to monitor |
|
|
316
|
+
| `--start-block` | Optional start block |
|
|
317
|
+
| `--include-in-pipeline` | Include this contract in the Goldsky events pipeline (`true` by default in the API) |
|
|
262
318
|
|
|
263
319
|
```bash
|
|
264
320
|
formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --chain 1 \
|
|
265
321
|
--name "UNI Token" --abi '[{"type":"event","name":"Transfer","inputs":[]}]' \
|
|
266
|
-
--events '{"Transfer":
|
|
322
|
+
--events '[{"type":"event","name":"Transfer","inputs":[]}]'
|
|
267
323
|
```
|
|
268
324
|
|
|
269
325
|
### `contracts update <chain> <address>`
|
|
@@ -272,7 +328,12 @@ formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --ch
|
|
|
272
328
|
|---|---|
|
|
273
329
|
| `--name` | Updated contract name |
|
|
274
330
|
| `--abi` | Updated ABI |
|
|
275
|
-
| `--events` | Updated
|
|
331
|
+
| `--events` | Updated JSON array of ABI event objects |
|
|
332
|
+
| `--start-block` | Optional start block |
|
|
333
|
+
| `--include-in-pipeline` | Include or exclude this contract from the Goldsky events pipeline |
|
|
334
|
+
|
|
335
|
+
### `contracts pipeline <chain> <address> --include-in-pipeline <true|false>`
|
|
336
|
+
Toggle pipeline inclusion without re-sending the full ABI/events payload.
|
|
276
337
|
|
|
277
338
|
### `contracts delete <chain> <address>`
|
|
278
339
|
Remove a tracked contract.
|
|
@@ -291,7 +352,7 @@ List all user segments.
|
|
|
291
352
|
| Option | Description |
|
|
292
353
|
|---|---|
|
|
293
354
|
| `--title` | Segment title |
|
|
294
|
-
| `--
|
|
355
|
+
| `--filter-sets` | JSON array of filter set strings defining the segment |
|
|
295
356
|
|
|
296
357
|
### `segments delete <segmentId>`
|
|
297
358
|
Delete a user segment.
|
|
@@ -313,6 +374,31 @@ formo query run "SELECT address, net_worth_usd FROM wallet_profiles ORDER BY net
|
|
|
313
374
|
|
|
314
375
|
---
|
|
315
376
|
|
|
377
|
+
## `formo analytics`
|
|
378
|
+
|
|
379
|
+
Pre-built analytics pipes — the same data that powers the Formo dashboard — without writing SQL. Each pipe is a subcommand: `formo analytics <pipe>`.
|
|
380
|
+
|
|
381
|
+
**Pipes:** `kpis`, `event_timeseries`, `funnel`, `flow`, `frequency`, `lifecycle`, `retention`, `revenue_overview`, `revenue_by_metric`, `revenue_timeseries`, `volume_by_metric`, `top_chains`, `top_events`, `top_locations`, `top_pages`, `top_sources`, `top_wallets`
|
|
382
|
+
|
|
383
|
+
| Option | Description |
|
|
384
|
+
|---|---|
|
|
385
|
+
| `--date-from` | Inclusive start date `YYYY-MM-DD` (default: 7 days before `--date-to`) |
|
|
386
|
+
| `--date-to` | Inclusive end date `YYYY-MM-DD` (default: today) |
|
|
387
|
+
| `--filters` | JSON array of `[{field,op,value}]`. Use `in`/`notIn` with a pipe-delimited value (e.g. `"chrome\|firefox"`) |
|
|
388
|
+
| `--params` | JSON object of pipe-specific params merged into the query (e.g. `{"limit":10,"group_by":"device"}`) |
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
formo analytics kpis
|
|
392
|
+
formo analytics kpis --date-from 2026-04-01 --date-to 2026-04-30 --params '{"group_by":"device"}'
|
|
393
|
+
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}'
|
|
394
|
+
formo analytics top_wallets --date-from 2026-04-01 --date-to 2026-04-30 --params '{"limit":10}'
|
|
395
|
+
formo analytics retention --filters '[{"field":"location","op":"equals","value":"US"}]'
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
> Requires `query:read` scope. Run `formo analytics <pipe> --help` for the pipe-specific params accepted via `--params`.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
316
402
|
## `formo import`
|
|
317
403
|
|
|
318
404
|
### `import wallets`
|
|
@@ -322,10 +408,24 @@ Bulk-import wallet addresses into the project via the events API.
|
|
|
322
408
|
| Option | Description |
|
|
323
409
|
|---|---|
|
|
324
410
|
| `--addresses` | JSON array of wallet address strings |
|
|
325
|
-
| `--
|
|
411
|
+
| `--rows` | JSON array of `{address,properties?}` objects |
|
|
326
412
|
|
|
327
413
|
```bash
|
|
328
|
-
formo import wallets --addresses '["0xabc...","0xdef..."]'
|
|
414
|
+
formo import wallets --addresses '["0xabc...","0xdef..."]'
|
|
415
|
+
formo import wallets --rows '[{"address":"0xabc...","properties":{"display_name":"Alice"}}]'
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## `formo events`
|
|
421
|
+
|
|
422
|
+
### `events ingest`
|
|
423
|
+
|
|
424
|
+
Send raw analytics events to `events.formo.so`. This command uses a project SDK write key, not the workspace API key.
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
export FORMO_WRITE_KEY=formo_write_key_xxx
|
|
428
|
+
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"}'
|
|
329
429
|
```
|
|
330
430
|
|
|
331
431
|
---
|
|
@@ -336,16 +436,30 @@ formo import wallets --addresses '["0xabc...","0xdef..."]' --writeKey write_key_
|
|
|
336
436
|
|
|
337
437
|
```json
|
|
338
438
|
[
|
|
339
|
-
{ "field": "net_worth_usd", "op": "gt", "value": 10000 },
|
|
340
|
-
{ "field": "
|
|
439
|
+
{ "field": "users.net_worth_usd", "op": "gt", "value": 10000 },
|
|
440
|
+
{ "field": "chains.1.balance", "op": "gte", "value": 1000 }
|
|
341
441
|
]
|
|
342
442
|
```
|
|
343
443
|
|
|
444
|
+
> **The `field` must be a typed path.** A bare name like `net_worth_usd` is
|
|
445
|
+
> silently ignored by the API (no error, no filtering — the search returns
|
|
446
|
+
> everything). Always prefix the field with its type.
|
|
447
|
+
|
|
344
448
|
| Field | Type | Description |
|
|
345
449
|
|---|---|---|
|
|
346
|
-
| `field` | `string` |
|
|
450
|
+
| `field` | `string` | Typed path (see prefixes below) |
|
|
347
451
|
| `op` | `string` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin` |
|
|
348
452
|
| `value` | `any` | Value to compare against |
|
|
453
|
+
| `scope` | `string` | _(token filters only)_ `any` or `protocol` |
|
|
454
|
+
| `appId` | `string` | _(token filters with `scope: protocol`)_ e.g. `aave-v3` |
|
|
455
|
+
|
|
456
|
+
| Prefix | Examples |
|
|
457
|
+
|---|---|
|
|
458
|
+
| `users.` | `users.net_worth_usd`, `users.volume`, `users.revenue`, `users.points`, `users.device`, `users.location`, `users.lifecycle`, `users.ens`, `users.farcaster` |
|
|
459
|
+
| `chains.` | `chains.balance` (any chain), `chains.1.balance` (Ethereum) |
|
|
460
|
+
| `apps.` | `apps.uniswap-v3.balance` |
|
|
461
|
+
| `tokens.` | `tokens.0xA0b8…48.balance` |
|
|
462
|
+
| `labels.` | `labels.coinbase.verified_account` |
|
|
349
463
|
|
|
350
464
|
Combine multiple conditions with `--logic and` (default) or `--logic or`.
|
|
351
465
|
|
|
@@ -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('--triggerFilters 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
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Cli } from 'incur';
|
|
2
|
+
export declare const analytics: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
+
export interface AnalyticsOptions {
|
|
4
|
+
dateFrom?: string;
|
|
5
|
+
dateTo?: string;
|
|
6
|
+
filters?: string;
|
|
7
|
+
params?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build the query-string params for an analytics pipe request.
|
|
11
|
+
*
|
|
12
|
+
* - `dateFrom`/`dateTo` map to the API's snake_case `date_from`/`date_to`.
|
|
13
|
+
* All pipes, including `funnel` and `flow`, use snake_case.
|
|
14
|
+
* - `filters` is a JSON array of `{ field, op, value }` objects, re-serialized
|
|
15
|
+
* as a JSON string (the pipe expects a JSON-encoded array in the query).
|
|
16
|
+
* - `params` is a JSON object of any pipe-specific params (e.g. funnel
|
|
17
|
+
* `steps`, kpis `group_by`, `limit`). Object/array values are JSON-encoded
|
|
18
|
+
* (pipes like funnel expect `steps` as a JSON-encoded string); primitives
|
|
19
|
+
* pass through unchanged. Reserved keys (the date/filters flags) are
|
|
20
|
+
* rejected, and the validated flags below always take precedence.
|
|
21
|
+
*
|
|
22
|
+
* Exported for unit testing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildAnalyticsParams(options: AnalyticsOptions): Record<string, string | number | boolean>;
|
|
25
|
+
export declare function runAnalytics(pipe: string, options: AnalyticsOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|