@formo/cli 1.0.2 → 1.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 +21 -0
- package/README.md +57 -11
- package/dist/commands/alerts.d.ts +14 -22
- package/dist/commands/alerts.js +26 -48
- package/dist/commands/analytics.d.ts +1 -1
- package/dist/commands/analytics.js +4 -12
- package/dist/commands/boards.d.ts +7 -9
- package/dist/commands/boards.js +4 -14
- package/dist/commands/charts.d.ts +11 -13
- package/dist/commands/charts.js +10 -14
- package/dist/commands/contracts.d.ts +9 -11
- package/dist/commands/contracts.js +7 -17
- package/dist/commands/events.d.ts +1 -1
- package/dist/commands/events.js +6 -5
- package/dist/commands/import.d.ts +1 -1
- package/dist/commands/import.js +3 -0
- package/dist/commands/profiles.d.ts +7 -7
- package/dist/commands/profiles.js +24 -11
- package/dist/commands/query.d.ts +1 -1
- package/dist/commands/segments.d.ts +6 -8
- package/dist/commands/segments.js +8 -22
- package/dist/index.js +40 -27
- package/dist/lib/client.d.ts +18 -3
- package/dist/lib/client.js +11 -2
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +32 -18
- package/dist/lib/pagination.d.ts +14 -0
- package/dist/lib/pagination.js +31 -0
- package/dist/lib/ui.d.ts +6 -5
- package/dist/lib/ui.js +10 -12
- package/package.json +10 -13
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,7 @@ 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).
|
|
28
45
|
|
|
29
46
|
For local development or proxying, override API hosts with:
|
|
30
47
|
|
|
@@ -87,6 +104,7 @@ Search wallet profiles with filters, sorting, and pagination. Returns a `Paginat
|
|
|
87
104
|
| Option | Description |
|
|
88
105
|
|---|---|
|
|
89
106
|
| `--address` | Filter by wallet address |
|
|
107
|
+
| `--search` | Free-text search across address and identity fields |
|
|
90
108
|
| `--page` | Page number (1-indexed, default `1`) |
|
|
91
109
|
| `--size` | Page size (default `100`, max `1000`) |
|
|
92
110
|
| `--order-by` | `last_onchain`, `first_onchain`, `net_worth_usd`, `updated_at`, `tx_count`, `first_seen`, `last_seen`, `num_sessions`, `revenue`, `volume`, `points` |
|
|
@@ -104,6 +122,20 @@ formo profiles search --conditions '[{"field":"users.net_worth_usd","op":"gt","v
|
|
|
104
122
|
formo profiles search --conditions '[{"field":"chains.1.balance","op":"gt","value":1000}]' --size 20
|
|
105
123
|
```
|
|
106
124
|
|
|
125
|
+
### Lifecycle tuning (advanced)
|
|
126
|
+
|
|
127
|
+
Both `profiles get` and `profiles search` accept optional flags to override the lifecycle stage thresholds used when computing `lifecycle`:
|
|
128
|
+
|
|
129
|
+
| Option | Description |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `--new-window-days` | Override lifecycle new-user window in days |
|
|
132
|
+
| `--churn-window-days` | Override lifecycle churn window in days |
|
|
133
|
+
| `--power-user-min-active-days` | Override lifecycle power-user minimum active days |
|
|
134
|
+
| `--power-user-window-days` | Override lifecycle power-user window in days |
|
|
135
|
+
| `--resurrected-gap-days` | Override lifecycle resurrected gap in days |
|
|
136
|
+
| `--at-risk-min-days-inactive` | Override lifecycle at-risk minimum inactive days |
|
|
137
|
+
| `--at-risk-prior-active-days-threshold` | Override lifecycle at-risk prior active days threshold |
|
|
138
|
+
|
|
107
139
|
### `profiles update <address>`
|
|
108
140
|
|
|
109
141
|
Merge-update identity properties on a wallet profile.
|
|
@@ -188,15 +220,16 @@ Get a single alert by ID.
|
|
|
188
220
|
| `--trigger-filters` | JSON array of trigger filter objects |
|
|
189
221
|
| `--recipient` | JSON array of recipient objects |
|
|
190
222
|
| `--secret` | Webhook secret |
|
|
223
|
+
| `--slack-property-keys` | JSON array of event/user property keys to include in Slack alerts |
|
|
191
224
|
|
|
192
225
|
```bash
|
|
193
226
|
formo alerts create --name "High value tx" --trigger-type event \
|
|
194
|
-
--trigger-filters '[{"name":"event","operator":"
|
|
227
|
+
--trigger-filters '[{"name":"event","operator":"eq","value":"transaction"}]' \
|
|
195
228
|
--recipient '[{"type":"email","value":["alerts@myapp.com"]}]'
|
|
196
229
|
```
|
|
197
230
|
|
|
198
231
|
### `alerts update <alertId>`
|
|
199
|
-
Same options as `create`. Replaces the alert configuration.
|
|
232
|
+
Same options as `create`. Replaces the alert configuration in full — omitted options are reset to their defaults (e.g. leaving out `--trigger-filters` clears the existing trigger filters).
|
|
200
233
|
|
|
201
234
|
### `alerts delete <alertId>`
|
|
202
235
|
Delete an alert.
|
|
@@ -254,7 +287,7 @@ Delete a board.
|
|
|
254
287
|
|
|
255
288
|
## `formo charts`
|
|
256
289
|
|
|
257
|
-
Chart commands. Charts live inside a board. Requires `
|
|
290
|
+
Chart commands. Charts live inside a board. Requires `boards:read` / `boards:write`.
|
|
258
291
|
|
|
259
292
|
### `charts list --board-id <boardId>`
|
|
260
293
|
List all charts in a board.
|
|
@@ -277,8 +310,12 @@ formo charts create --board-id brd_123 --title "Daily Active Users" \
|
|
|
277
310
|
formo charts create --board-id brd_123 --body '{"title":"Recent Events","chart_type":"table","query":"SELECT * FROM events LIMIT 10"}'
|
|
278
311
|
```
|
|
279
312
|
|
|
280
|
-
### `charts update <chartId> --board-id <boardId>
|
|
281
|
-
Update a chart.
|
|
313
|
+
### `charts update <chartId> --board-id <boardId> [options]`
|
|
314
|
+
Update a chart. Accepts the same options as `create`: a raw `--body '<json>'` and/or typed flags (`--title`, `--chart-type`, `--query`, `--description`, `--x-axis`, `--y-axis`, `--group-by`, `--steps`, `--settings`). Typed flags override matching `--body` keys.
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
formo charts update chart_abc123 --board-id brd_123 --title "Renamed chart"
|
|
318
|
+
```
|
|
282
319
|
|
|
283
320
|
### `charts query <chartId> --board-id <boardId> --date-from <YYYY-MM-DD> --date-to <YYYY-MM-DD>`
|
|
284
321
|
Execute a saved chart that uses `{{date_from}}` / `{{date_to}}` variables.
|
|
@@ -384,7 +421,7 @@ Pre-built analytics pipes — the same data that powers the Formo dashboard —
|
|
|
384
421
|
|---|---|
|
|
385
422
|
| `--date-from` | Inclusive start date `YYYY-MM-DD` (default: 7 days before `--date-to`) |
|
|
386
423
|
| `--date-to` | Inclusive end date `YYYY-MM-DD` (default: today) |
|
|
387
|
-
| `--filters` | JSON array of `[{field,op,value}]`. Use `in`/`
|
|
424
|
+
| `--filters` | JSON array of `[{field,op,value}]`. Use `in`/`nin` with a pipe-delimited value (e.g. `"chrome\|firefox"`) |
|
|
388
425
|
| `--params` | JSON object of pipe-specific params merged into the query (e.g. `{"limit":10,"group_by":"device"}`) |
|
|
389
426
|
|
|
390
427
|
```bash
|
|
@@ -392,7 +429,7 @@ formo analytics kpis
|
|
|
392
429
|
formo analytics kpis --date-from 2026-04-01 --date-to 2026-04-30 --params '{"group_by":"device"}'
|
|
393
430
|
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
431
|
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":"
|
|
432
|
+
formo analytics retention --filters '[{"field":"location","op":"eq","value":"US"}]'
|
|
396
433
|
```
|
|
397
434
|
|
|
398
435
|
> Requires `query:read` scope. Run `formo analytics <pipe> --help` for the pipe-specific params accepted via `--params`.
|
|
@@ -403,7 +440,7 @@ formo analytics retention --filters '[{"field":"location","op":"equals","value":
|
|
|
403
440
|
|
|
404
441
|
### `import wallets`
|
|
405
442
|
|
|
406
|
-
Bulk-import wallet addresses into the project via the
|
|
443
|
+
Bulk-import wallet addresses into the project via the main Formo API, authenticated with your workspace API key.
|
|
407
444
|
|
|
408
445
|
| Option | Description |
|
|
409
446
|
|---|---|
|
|
@@ -415,17 +452,26 @@ formo import wallets --addresses '["0xabc...","0xdef..."]'
|
|
|
415
452
|
formo import wallets --rows '[{"address":"0xabc...","properties":{"display_name":"Alice"}}]'
|
|
416
453
|
```
|
|
417
454
|
|
|
455
|
+
> Requires `profiles:write` scope. Only available on Scale and Enterprise plans.
|
|
456
|
+
|
|
418
457
|
---
|
|
419
458
|
|
|
420
459
|
## `formo events`
|
|
421
460
|
|
|
422
461
|
### `events ingest`
|
|
423
462
|
|
|
424
|
-
Send raw analytics events to `events.formo.so`. This command uses a project SDK write key, not the workspace API key.
|
|
463
|
+
Send raw analytics events to `events.formo.so`. This command uses a project SDK write key, not the workspace API key — pass it via `--write-key` or the `FORMO_WRITE_KEY` environment variable.
|
|
464
|
+
|
|
465
|
+
| Option | Description |
|
|
466
|
+
|---|---|
|
|
467
|
+
| `--event` | Single event as a JSON object; wrapped in an array before sending |
|
|
468
|
+
| `--events` | JSON array of event objects to send as a batch |
|
|
469
|
+
| `--write-key` | Project SDK write key (defaults to `FORMO_WRITE_KEY`) |
|
|
425
470
|
|
|
426
471
|
```bash
|
|
427
472
|
export FORMO_WRITE_KEY=formo_write_key_xxx
|
|
428
473
|
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"}'
|
|
474
|
+
formo events ingest --events '[{"type":"track","event":"First"},{"type":"track","event":"Second"}]'
|
|
429
475
|
```
|
|
430
476
|
|
|
431
477
|
---
|
|
@@ -448,7 +494,7 @@ formo events ingest --event '{"type":"track","channel":"cli","version":"1","anon
|
|
|
448
494
|
| Field | Type | Description |
|
|
449
495
|
|---|---|---|
|
|
450
496
|
| `field` | `string` | Typed path (see prefixes below) |
|
|
451
|
-
| `op` | `string` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin` |
|
|
497
|
+
| `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 |
|
|
452
498
|
| `value` | `any` | Value to compare against |
|
|
453
499
|
| `scope` | `string` | _(token filters only)_ `any` or `protocol` |
|
|
454
500
|
| `appId` | `string` | _(token filters with `scope: protocol`)_ e.g. `aave-v3` |
|
|
@@ -1,36 +1,28 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
|
+
import { type PaginationOptions } from '../lib/pagination';
|
|
3
|
+
export type { PaginationOptions };
|
|
2
4
|
export declare const alerts: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export declare function listAlertsRun(options?: PaginationOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
8
|
-
export declare function getAlertRun(alertId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
9
|
-
export interface CreateAlertOptions {
|
|
10
|
-
name: string;
|
|
11
|
-
triggerType: 'event' | 'user' | string;
|
|
12
|
-
triggerFilters?: string;
|
|
13
|
-
recipient?: string;
|
|
14
|
-
secret?: string;
|
|
15
|
-
slackPropertyKeys?: string;
|
|
16
|
-
}
|
|
17
|
-
export declare function buildAlertBody(options: CreateAlertOptions | UpdateAlertOptions): Record<string, unknown>;
|
|
18
|
-
export declare function createAlertRun(options: CreateAlertOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
19
|
-
export interface UpdateAlertOptions {
|
|
5
|
+
export declare function listAlertsRun(options?: PaginationOptions): Promise<unknown>;
|
|
6
|
+
export declare function getAlertRun(alertId: string): Promise<unknown>;
|
|
7
|
+
export interface AlertBodyOptions {
|
|
20
8
|
name: string;
|
|
21
|
-
triggerType:
|
|
9
|
+
triggerType: string;
|
|
22
10
|
triggerFilters?: string;
|
|
23
11
|
recipient?: string;
|
|
24
12
|
secret?: string;
|
|
25
13
|
slackPropertyKeys?: string;
|
|
26
14
|
}
|
|
27
|
-
export
|
|
28
|
-
export
|
|
29
|
-
export declare function
|
|
15
|
+
export type CreateAlertOptions = AlertBodyOptions;
|
|
16
|
+
export type UpdateAlertOptions = AlertBodyOptions;
|
|
17
|
+
export declare function buildAlertBody(options: AlertBodyOptions): Record<string, unknown>;
|
|
18
|
+
export declare function createAlertRun(options: CreateAlertOptions): Promise<unknown>;
|
|
19
|
+
export declare function updateAlertRun(alertId: string, options: AlertBodyOptions): Promise<unknown>;
|
|
20
|
+
export declare function deleteAlertRun(alertId: string): Promise<unknown>;
|
|
21
|
+
export declare function toggleAlertRun(alertId: string, status: string): Promise<unknown>;
|
|
30
22
|
export interface TestAlertOptions {
|
|
31
23
|
sampleEvent?: string;
|
|
32
24
|
sampleUser?: string;
|
|
33
25
|
recipientOverrides?: string;
|
|
34
26
|
}
|
|
35
27
|
export declare function buildTestAlertBody(options: TestAlertOptions): Record<string, unknown> | undefined;
|
|
36
|
-
export declare function testAlertRun(alertId: string, options?: TestAlertOptions): Promise<
|
|
28
|
+
export declare function testAlertRun(alertId: string, options?: TestAlertOptions): Promise<unknown>;
|
package/dist/commands/alerts.js
CHANGED
|
@@ -13,28 +13,19 @@ exports.testAlertRun = testAlertRun;
|
|
|
13
13
|
const incur_1 = require("incur");
|
|
14
14
|
const client_1 = require("../lib/client");
|
|
15
15
|
const json_1 = require("../lib/json");
|
|
16
|
+
const pagination_1 = require("../lib/pagination");
|
|
16
17
|
exports.alerts = incur_1.Cli.create('alerts', {
|
|
17
18
|
description: 'Project alert commands — create, list, update, and delete alerts',
|
|
18
19
|
});
|
|
19
|
-
|
|
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
|
-
}
|
|
20
|
+
// ── List alerts ──
|
|
27
21
|
function listAlertsRun(options = {}) {
|
|
28
22
|
(0, client_1.requireApiKey)();
|
|
29
23
|
const client = (0, client_1.createClient)();
|
|
30
|
-
return client.get('/v0/alerts/', { params: buildPaginationParams(options) });
|
|
24
|
+
return client.get('/v0/alerts/', { params: (0, pagination_1.buildPaginationParams)(options) });
|
|
31
25
|
}
|
|
32
26
|
exports.alerts.command('list', {
|
|
33
27
|
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
|
-
}),
|
|
28
|
+
options: incur_1.z.object(pagination_1.paginationOptionsSchema),
|
|
38
29
|
examples: [{ description: 'List all project alerts' }],
|
|
39
30
|
hint: 'Requires alerts:read scope on your API key.',
|
|
40
31
|
run({ options }) {
|
|
@@ -60,6 +51,24 @@ exports.alerts.command('get', {
|
|
|
60
51
|
return getAlertRun(args.alertId);
|
|
61
52
|
},
|
|
62
53
|
});
|
|
54
|
+
// Shared option fragment for `create` and `update` (same PUT/POST body).
|
|
55
|
+
const alertBodyOptionsSchema = {
|
|
56
|
+
name: incur_1.z.string().describe('Alert name'),
|
|
57
|
+
triggerType: incur_1.z.enum(['event', 'user']).describe('Trigger type'),
|
|
58
|
+
triggerFilters: incur_1.z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('JSON array of trigger filter objects'),
|
|
62
|
+
recipient: incur_1.z
|
|
63
|
+
.string()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('JSON array of recipient objects'),
|
|
66
|
+
secret: incur_1.z.string().optional().describe('Webhook secret for the alert'),
|
|
67
|
+
slackPropertyKeys: incur_1.z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('JSON array of event/user property keys to include in Slack alerts'),
|
|
71
|
+
};
|
|
63
72
|
function buildAlertBody(options) {
|
|
64
73
|
const body = {
|
|
65
74
|
name: options.name,
|
|
@@ -87,23 +96,7 @@ function createAlertRun(options) {
|
|
|
87
96
|
}
|
|
88
97
|
exports.alerts.command('create', {
|
|
89
98
|
description: 'Create a new project alert',
|
|
90
|
-
options: incur_1.z.object(
|
|
91
|
-
name: incur_1.z.string().describe('Alert name'),
|
|
92
|
-
triggerType: incur_1.z.enum(['event', 'user']).describe('Trigger type'),
|
|
93
|
-
triggerFilters: incur_1.z
|
|
94
|
-
.string()
|
|
95
|
-
.optional()
|
|
96
|
-
.describe('JSON array of trigger filter objects'),
|
|
97
|
-
recipient: incur_1.z
|
|
98
|
-
.string()
|
|
99
|
-
.optional()
|
|
100
|
-
.describe('JSON array of recipient objects'),
|
|
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'),
|
|
106
|
-
}),
|
|
99
|
+
options: incur_1.z.object(alertBodyOptionsSchema),
|
|
107
100
|
examples: [
|
|
108
101
|
{
|
|
109
102
|
options: { name: 'High value tx', triggerType: 'event' },
|
|
@@ -115,33 +108,18 @@ exports.alerts.command('create', {
|
|
|
115
108
|
return createAlertRun(options);
|
|
116
109
|
},
|
|
117
110
|
});
|
|
111
|
+
// ── Update an alert ──
|
|
118
112
|
function updateAlertRun(alertId, options) {
|
|
119
113
|
(0, client_1.requireApiKey)();
|
|
120
114
|
const client = (0, client_1.createClient)();
|
|
121
115
|
return client.put(`/v0/alerts/${encodeURIComponent(alertId)}`, buildAlertBody(options));
|
|
122
116
|
}
|
|
123
117
|
exports.alerts.command('update', {
|
|
124
|
-
description: 'Update an existing alert',
|
|
118
|
+
description: 'Update an existing alert (full replace — omitted options reset to defaults)',
|
|
125
119
|
args: incur_1.z.object({
|
|
126
120
|
alertId: incur_1.z.string().describe('Alert ID to update'),
|
|
127
121
|
}),
|
|
128
|
-
options: incur_1.z.object(
|
|
129
|
-
name: incur_1.z.string().describe('Alert name'),
|
|
130
|
-
triggerType: incur_1.z.enum(['event', 'user']).describe('Trigger type'),
|
|
131
|
-
triggerFilters: incur_1.z
|
|
132
|
-
.string()
|
|
133
|
-
.optional()
|
|
134
|
-
.describe('JSON array of trigger filter objects'),
|
|
135
|
-
recipient: incur_1.z
|
|
136
|
-
.string()
|
|
137
|
-
.optional()
|
|
138
|
-
.describe('JSON array of recipient objects'),
|
|
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'),
|
|
144
|
-
}),
|
|
122
|
+
options: incur_1.z.object(alertBodyOptionsSchema),
|
|
145
123
|
examples: [
|
|
146
124
|
{
|
|
147
125
|
args: { alertId: 'alert_abc123' },
|
|
@@ -22,4 +22,4 @@ export interface AnalyticsOptions {
|
|
|
22
22
|
* Exported for unit testing.
|
|
23
23
|
*/
|
|
24
24
|
export declare function buildAnalyticsParams(options: AnalyticsOptions): Record<string, string | number | boolean>;
|
|
25
|
-
export declare function runAnalytics(pipe: string, options: AnalyticsOptions): Promise<
|
|
25
|
+
export declare function runAnalytics(pipe: string, options: AnalyticsOptions): Promise<unknown>;
|
|
@@ -5,6 +5,7 @@ exports.buildAnalyticsParams = buildAnalyticsParams;
|
|
|
5
5
|
exports.runAnalytics = runAnalytics;
|
|
6
6
|
const incur_1 = require("incur");
|
|
7
7
|
const client_1 = require("../lib/client");
|
|
8
|
+
const json_1 = require("../lib/json");
|
|
8
9
|
exports.analytics = incur_1.Cli.create('analytics', {
|
|
9
10
|
description: 'Pre-built analytics query commands — KPIs, funnels, retention, revenue, and top-N breakdowns',
|
|
10
11
|
});
|
|
@@ -15,7 +16,7 @@ exports.analytics = incur_1.Cli.create('analytics', {
|
|
|
15
16
|
const PIPES = [
|
|
16
17
|
{ name: 'kpis', description: 'Traffic KPIs: visitors, pageviews, bounce rate, session duration' },
|
|
17
18
|
{ 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,
|
|
19
|
+
{ 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
20
|
{ name: 'flow', description: 'User path/flow analysis. --params: start_step / end_step (JSON {type,event,...}), global_filters, window_seconds, max_steps' },
|
|
20
21
|
{ name: 'frequency', description: 'Engagement frequency distribution' },
|
|
21
22
|
{ name: 'lifecycle', description: 'User lifecycle stages (new, returning, power, resurrected, churned)' },
|
|
@@ -62,16 +63,7 @@ function buildAnalyticsParams(options) {
|
|
|
62
63
|
const out = {};
|
|
63
64
|
// --params first, so the validated flags below override it.
|
|
64
65
|
if (options.params) {
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
parsed = JSON.parse(options.params);
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
throw new Error('--params must be a valid JSON object');
|
|
71
|
-
}
|
|
72
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
73
|
-
throw new Error('--params must be a valid JSON object');
|
|
74
|
-
}
|
|
66
|
+
const parsed = (0, json_1.parseJsonObject)(options.params, '--params');
|
|
75
67
|
for (const [key, value] of Object.entries(parsed)) {
|
|
76
68
|
if (RESERVED_PARAM_KEYS.has(key)) {
|
|
77
69
|
throw new Error(`--params may not set "${key}" — use the --date-from/--date-to/--filters flags instead`);
|
|
@@ -123,7 +115,7 @@ const sharedOptions = incur_1.z.object({
|
|
|
123
115
|
.string()
|
|
124
116
|
.optional()
|
|
125
117
|
.describe('JSON array of filter conditions: [{"field","op","value"}]. ' +
|
|
126
|
-
'Use op "in"/"
|
|
118
|
+
'Use op "in"/"nin" with a pipe-delimited value (e.g. "chrome|firefox").'),
|
|
127
119
|
params: incur_1.z
|
|
128
120
|
.string()
|
|
129
121
|
.optional()
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
|
+
import { type PaginationOptions } from '../lib/pagination';
|
|
3
|
+
export type { PaginationOptions };
|
|
2
4
|
export declare const boards: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
size?: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function listBoardsRun(options?: PaginationOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
8
|
-
export declare function getBoardRun(boardId: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
5
|
+
export declare function listBoardsRun(options?: PaginationOptions): Promise<unknown>;
|
|
6
|
+
export declare function getBoardRun(boardId: string): Promise<unknown>;
|
|
9
7
|
export interface CreateBoardOptions {
|
|
10
8
|
title?: string;
|
|
11
9
|
name?: string;
|
|
@@ -13,12 +11,12 @@ export interface CreateBoardOptions {
|
|
|
13
11
|
isPublic?: boolean;
|
|
14
12
|
}
|
|
15
13
|
export declare function buildBoardBody(options: CreateBoardOptions | UpdateBoardOptions): Record<string, unknown>;
|
|
16
|
-
export declare function createBoardRun(options: CreateBoardOptions): Promise<
|
|
14
|
+
export declare function createBoardRun(options: CreateBoardOptions): Promise<unknown>;
|
|
17
15
|
export interface UpdateBoardOptions {
|
|
18
16
|
title?: string;
|
|
19
17
|
name?: string;
|
|
20
18
|
description?: string;
|
|
21
19
|
isPublic?: boolean;
|
|
22
20
|
}
|
|
23
|
-
export declare function updateBoardRun(boardId: string, options: UpdateBoardOptions): Promise<
|
|
24
|
-
export declare function deleteBoardRun(boardId: string): Promise<
|
|
21
|
+
export declare function updateBoardRun(boardId: string, options: UpdateBoardOptions): Promise<unknown>;
|
|
22
|
+
export declare function deleteBoardRun(boardId: string): Promise<unknown>;
|
package/dist/commands/boards.js
CHANGED
|
@@ -9,29 +9,19 @@ exports.updateBoardRun = updateBoardRun;
|
|
|
9
9
|
exports.deleteBoardRun = deleteBoardRun;
|
|
10
10
|
const incur_1 = require("incur");
|
|
11
11
|
const client_1 = require("../lib/client");
|
|
12
|
+
const pagination_1 = require("../lib/pagination");
|
|
12
13
|
exports.boards = incur_1.Cli.create('boards', {
|
|
13
14
|
description: 'Dashboard board commands — create, list, update, and delete boards',
|
|
14
15
|
});
|
|
15
|
-
function buildPaginationParams(options = {}) {
|
|
16
|
-
const params = {};
|
|
17
|
-
if (options.page !== undefined)
|
|
18
|
-
params.page = options.page;
|
|
19
|
-
if (options.size !== undefined)
|
|
20
|
-
params.size = options.size;
|
|
21
|
-
return params;
|
|
22
|
-
}
|
|
23
16
|
// ── List boards ──
|
|
24
17
|
function listBoardsRun(options = {}) {
|
|
25
18
|
(0, client_1.requireApiKey)();
|
|
26
19
|
const client = (0, client_1.createClient)();
|
|
27
|
-
return client.get('/v0/boards/', { params: buildPaginationParams(options) });
|
|
20
|
+
return client.get('/v0/boards/', { params: (0, pagination_1.buildPaginationParams)(options) });
|
|
28
21
|
}
|
|
29
22
|
exports.boards.command('list', {
|
|
30
23
|
description: 'List all boards for the project',
|
|
31
|
-
options: incur_1.z.object(
|
|
32
|
-
page: incur_1.z.coerce.number().optional().describe('Page number (1-indexed, default 1)'),
|
|
33
|
-
size: incur_1.z.coerce.number().optional().describe('Page size (default 100, max 200)'),
|
|
34
|
-
}),
|
|
24
|
+
options: incur_1.z.object(pagination_1.paginationOptionsSchema),
|
|
35
25
|
examples: [{ description: 'List all dashboard boards' }],
|
|
36
26
|
hint: 'Requires boards:read scope on your API key.',
|
|
37
27
|
run({ options }) {
|
|
@@ -62,7 +52,7 @@ function buildBoardBody(options) {
|
|
|
62
52
|
const body = {};
|
|
63
53
|
if (title !== undefined) {
|
|
64
54
|
if (!title)
|
|
65
|
-
throw new Error('--title must not be empty');
|
|
55
|
+
throw new Error('--title (or its deprecated alias --name) must not be empty');
|
|
66
56
|
body.title = title;
|
|
67
57
|
}
|
|
68
58
|
if (options.description !== undefined) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
|
+
import { type PaginationOptions } from '../lib/pagination';
|
|
3
|
+
export type { PaginationOptions };
|
|
2
4
|
export declare const charts: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export interface PaginationOptions {
|
|
4
|
-
page?: number;
|
|
5
|
-
size?: number;
|
|
6
|
-
}
|
|
7
5
|
export interface ChartBodyOptions {
|
|
8
6
|
body?: string;
|
|
9
7
|
query?: string;
|
|
@@ -17,18 +15,18 @@ export interface ChartBodyOptions {
|
|
|
17
15
|
settings?: string;
|
|
18
16
|
}
|
|
19
17
|
export declare function buildChartBody(options: ChartBodyOptions): Record<string, unknown>;
|
|
20
|
-
export declare function listChartsRun(boardId: string, options?: PaginationOptions): Promise<
|
|
21
|
-
export declare function listChartSummariesRun(boardId: string, options?: PaginationOptions): Promise<
|
|
22
|
-
export declare function getChartRun(boardId: string, chartId: string): Promise<
|
|
18
|
+
export declare function listChartsRun(boardId: string, options?: PaginationOptions): Promise<unknown>;
|
|
19
|
+
export declare function listChartSummariesRun(boardId: string, options?: PaginationOptions): Promise<unknown>;
|
|
20
|
+
export declare function getChartRun(boardId: string, chartId: string): Promise<unknown>;
|
|
23
21
|
export interface QueryChartOptions {
|
|
24
22
|
dateFrom: string;
|
|
25
23
|
dateTo: string;
|
|
26
24
|
}
|
|
27
|
-
export declare function queryChartRun(boardId: string, chartId: string, options: QueryChartOptions): Promise<
|
|
28
|
-
export declare function createChartRun(boardId: string, input: string | ChartBodyOptions): Promise<
|
|
29
|
-
export declare function updateChartRun(boardId: string, chartId: string, input: string | ChartBodyOptions): Promise<
|
|
30
|
-
export declare function moveChartRun(boardId: string, chartId: string, targetBoardId: string): Promise<
|
|
25
|
+
export declare function queryChartRun(boardId: string, chartId: string, options: QueryChartOptions): Promise<unknown>;
|
|
26
|
+
export declare function createChartRun(boardId: string, input: string | ChartBodyOptions): Promise<unknown>;
|
|
27
|
+
export declare function updateChartRun(boardId: string, chartId: string, input: string | ChartBodyOptions): Promise<unknown>;
|
|
28
|
+
export declare function moveChartRun(boardId: string, chartId: string, targetBoardId: string): Promise<unknown>;
|
|
31
29
|
export declare function normalizeDuplicateChartResponse(result: unknown): unknown;
|
|
32
30
|
export declare function duplicateChartRun(boardId: string, chartId: string): Promise<unknown>;
|
|
33
|
-
export declare function reorderChartsRun(boardId: string, chartIds: string): Promise<
|
|
34
|
-
export declare function deleteChartRun(boardId: string, chartId: string): Promise<
|
|
31
|
+
export declare function reorderChartsRun(boardId: string, chartIds: string): Promise<unknown>;
|
|
32
|
+
export declare function deleteChartRun(boardId: string, chartId: string): Promise<unknown>;
|
package/dist/commands/charts.js
CHANGED
|
@@ -17,6 +17,7 @@ const incur_1 = require("incur");
|
|
|
17
17
|
const client_1 = require("../lib/client");
|
|
18
18
|
const json_1 = require("../lib/json");
|
|
19
19
|
const sql_1 = require("../lib/sql");
|
|
20
|
+
const pagination_1 = require("../lib/pagination");
|
|
20
21
|
exports.charts = incur_1.Cli.create('charts', {
|
|
21
22
|
description: 'Chart commands — create, list, query, move, duplicate, reorder, update, and delete charts within boards',
|
|
22
23
|
});
|
|
@@ -32,14 +33,6 @@ const chartTypeSchema = incur_1.z.enum([
|
|
|
32
33
|
'user_paths',
|
|
33
34
|
'retention',
|
|
34
35
|
]);
|
|
35
|
-
function buildPaginationParams(options = {}) {
|
|
36
|
-
const params = {};
|
|
37
|
-
if (options.page !== undefined)
|
|
38
|
-
params.page = options.page;
|
|
39
|
-
if (options.size !== undefined)
|
|
40
|
-
params.size = options.size;
|
|
41
|
-
return params;
|
|
42
|
-
}
|
|
43
36
|
function hasTypedChartFields(options) {
|
|
44
37
|
return [
|
|
45
38
|
options.query,
|
|
@@ -120,15 +113,14 @@ function listChartsRun(boardId, options = {}) {
|
|
|
120
113
|
(0, client_1.requireApiKey)();
|
|
121
114
|
const client = (0, client_1.createClient)();
|
|
122
115
|
return client.get(`/v0/boards/${encodeURIComponent(boardId)}/charts/`, {
|
|
123
|
-
params: buildPaginationParams(options),
|
|
116
|
+
params: (0, pagination_1.buildPaginationParams)(options),
|
|
124
117
|
});
|
|
125
118
|
}
|
|
126
119
|
exports.charts.command('list', {
|
|
127
120
|
description: 'List all charts for a board, including executed results',
|
|
128
121
|
options: incur_1.z.object({
|
|
129
122
|
boardId: incur_1.z.string().describe('Board ID to list charts from'),
|
|
130
|
-
|
|
131
|
-
size: incur_1.z.coerce.number().optional().describe('Page size (default 100, max 200)'),
|
|
123
|
+
...pagination_1.paginationOptionsSchema,
|
|
132
124
|
}),
|
|
133
125
|
examples: [
|
|
134
126
|
{
|
|
@@ -146,15 +138,14 @@ function listChartSummariesRun(boardId, options = {}) {
|
|
|
146
138
|
(0, client_1.requireApiKey)();
|
|
147
139
|
const client = (0, client_1.createClient)();
|
|
148
140
|
return client.get(`/v0/boards/${encodeURIComponent(boardId)}/charts/meta`, {
|
|
149
|
-
params: buildPaginationParams(options),
|
|
141
|
+
params: (0, pagination_1.buildPaginationParams)(options),
|
|
150
142
|
});
|
|
151
143
|
}
|
|
152
144
|
exports.charts.command('meta', {
|
|
153
145
|
description: 'List lightweight chart metadata for a board without query results',
|
|
154
146
|
options: incur_1.z.object({
|
|
155
147
|
boardId: incur_1.z.string().describe('Board ID to list chart metadata from'),
|
|
156
|
-
|
|
157
|
-
size: incur_1.z.coerce.number().optional().describe('Page size (default 100, max 200)'),
|
|
148
|
+
...pagination_1.paginationOptionsSchema,
|
|
158
149
|
}),
|
|
159
150
|
examples: [
|
|
160
151
|
{
|
|
@@ -265,6 +256,11 @@ function updateChartRun(boardId, chartId, input) {
|
|
|
265
256
|
(0, client_1.requireApiKey)();
|
|
266
257
|
const client = (0, client_1.createClient)();
|
|
267
258
|
const updates = coerceChartBody(input);
|
|
259
|
+
// The charts endpoint only supports full-body PUT, so emulate a partial
|
|
260
|
+
// update by fetching the current chart and merging flags over it. Two
|
|
261
|
+
// consequences: a concurrent edit between the GET and PUT is overwritten,
|
|
262
|
+
// and fields can't be cleared via typed flags (nulls are normalized to
|
|
263
|
+
// undefined below) — use --body with explicit nulls to clear.
|
|
268
264
|
return client
|
|
269
265
|
.get(`/v0/boards/${encodeURIComponent(boardId)}/charts/${encodeURIComponent(chartId)}`)
|
|
270
266
|
.then((current) => {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Cli } from 'incur';
|
|
2
|
+
import { type PaginationOptions } from '../lib/pagination';
|
|
3
|
+
export type { PaginationOptions };
|
|
2
4
|
export declare const contracts: Cli.Cli<{}, undefined, undefined>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export declare function listContractsRun(options?: PaginationOptions): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
8
|
-
export declare function getContractRun(chain: string, address: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
9
|
-
export declare function getContractRecommendationsRun(): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
5
|
+
export declare function listContractsRun(options?: PaginationOptions): Promise<unknown>;
|
|
6
|
+
export declare function getContractRun(chain: string, address: string): Promise<unknown>;
|
|
7
|
+
export declare function getContractRecommendationsRun(): Promise<unknown>;
|
|
10
8
|
export interface CreateContractOptions {
|
|
11
9
|
address: string;
|
|
12
10
|
chain: number;
|
|
@@ -17,7 +15,7 @@ export interface CreateContractOptions {
|
|
|
17
15
|
includeInPipeline?: boolean;
|
|
18
16
|
}
|
|
19
17
|
export declare function buildCreateContractBody(options: CreateContractOptions): Record<string, unknown>;
|
|
20
|
-
export declare function createContractRun(options: CreateContractOptions): Promise<
|
|
18
|
+
export declare function createContractRun(options: CreateContractOptions): Promise<unknown>;
|
|
21
19
|
export interface UpdateContractOptions {
|
|
22
20
|
name: string;
|
|
23
21
|
abi: string;
|
|
@@ -26,9 +24,9 @@ export interface UpdateContractOptions {
|
|
|
26
24
|
includeInPipeline?: boolean;
|
|
27
25
|
}
|
|
28
26
|
export declare function buildUpdateContractBody(chain: string | number, address: string, options: UpdateContractOptions): Record<string, unknown>;
|
|
29
|
-
export declare function updateContractRun(chain: string, address: string, options: UpdateContractOptions): Promise<
|
|
30
|
-
export declare function updateContractPipelineRun(chain: string, address: string, includeInPipeline: boolean): Promise<
|
|
27
|
+
export declare function updateContractRun(chain: string, address: string, options: UpdateContractOptions): Promise<unknown>;
|
|
28
|
+
export declare function updateContractPipelineRun(chain: string, address: string, includeInPipeline: boolean): Promise<unknown>;
|
|
31
29
|
export declare function buildUpdateContractPipelineBody(includeInPipeline: boolean): {
|
|
32
30
|
include_in_pipeline: boolean;
|
|
33
31
|
};
|
|
34
|
-
export declare function deleteContractRun(chain: string, address: string): Promise<
|
|
32
|
+
export declare function deleteContractRun(chain: string, address: string): Promise<unknown>;
|