@formo/cli 1.2.1 → 1.3.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/README.md +7 -12
- package/dist/commands/alerts.d.ts +0 -7
- package/dist/commands/alerts.js +0 -53
- package/dist/commands/analytics.js +3 -3
- package/dist/commands/charts.d.ts +1 -1
- package/dist/commands/charts.js +19 -6
- package/dist/commands/contracts.d.ts +0 -5
- package/dist/commands/contracts.js +1 -58
- package/dist/commands/profiles.d.ts +2 -0
- package/dist/commands/profiles.js +25 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -91,10 +91,12 @@ Fetch a single wallet profile by address or ENS name.
|
|
|
91
91
|
| Option | Description |
|
|
92
92
|
|---|---|
|
|
93
93
|
| `--expand` | Comma-separated fields: `apps`, `chains`, `tokens`, `labels` |
|
|
94
|
+
| `--timestamp` | ISO-8601 timestamp; return the closest stored wallet-enrichment snapshot |
|
|
94
95
|
|
|
95
96
|
```bash
|
|
96
97
|
formo profiles get 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
97
98
|
formo profiles get vitalik.eth --expand labels,chains
|
|
99
|
+
formo profiles get vitalik.eth --timestamp 2025-06-21T10:03:00Z
|
|
98
100
|
```
|
|
99
101
|
|
|
100
102
|
### `profiles search`
|
|
@@ -105,6 +107,7 @@ Search wallet profiles with filters, sorting, and pagination. Returns a `Paginat
|
|
|
105
107
|
|---|---|
|
|
106
108
|
| `--address` | Filter by wallet address |
|
|
107
109
|
| `--search` | Free-text search across address and identity fields |
|
|
110
|
+
| `--timestamp` | ISO-8601 timestamp; requires `--address` and returns the closest stored wallet-enrichment snapshot |
|
|
108
111
|
| `--page` | Page number (1-indexed, default `1`) |
|
|
109
112
|
| `--size` | Page size (default `100`, max `1000`) |
|
|
110
113
|
| `--order-by` | `last_onchain`, `first_onchain`, `net_worth_usd`, `updated_at`, `tx_count`, `first_seen`, `last_seen`, `num_sessions`, `revenue`, `volume`, `points` |
|
|
@@ -115,6 +118,7 @@ Search wallet profiles with filters, sorting, and pagination. Returns a `Paginat
|
|
|
115
118
|
|
|
116
119
|
```bash
|
|
117
120
|
formo profiles search --size 10
|
|
121
|
+
formo profiles search --address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --timestamp 2025-06-21T10:03:00Z
|
|
118
122
|
formo profiles search --order-by net_worth_usd --order-dir desc --size 5
|
|
119
123
|
formo profiles search --page 2 --size 20
|
|
120
124
|
formo profiles search --filters '[{"field":"users.net_worth_usd","op":"gt","value":10000}]' --size 20
|
|
@@ -122,6 +126,8 @@ formo profiles search --filters '[{"field":"users.net_worth_usd","op":"gt","valu
|
|
|
122
126
|
formo profiles search --filters '[{"field":"chains.balance","op":"gt","value":1000,"chain_id":"1"}]' --size 20
|
|
123
127
|
```
|
|
124
128
|
|
|
129
|
+
With `--timestamp`, wallet-enrichment fields come from the stored snapshot closest to that instant. Exact ties select the later snapshot. Expanded chains, apps, and tokens come from the selected profiling batch, while project engagement fields, identity overrides, and labels remain current. `profiles search --timestamp` requires `--address`.
|
|
130
|
+
|
|
125
131
|
### Lifecycle tuning (advanced)
|
|
126
132
|
|
|
127
133
|
Both `profiles get` and `profiles search` accept optional flags to override the lifecycle stage thresholds used when computing `lifecycle`:
|
|
@@ -241,13 +247,6 @@ Toggle an alert between `active` and `inactive`.
|
|
|
241
247
|
formo alerts toggle alert_abc123 --status inactive
|
|
242
248
|
```
|
|
243
249
|
|
|
244
|
-
### `alerts test <alertId>`
|
|
245
|
-
Send a test alert delivery with optional sample payloads.
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
formo alerts test alert_abc123 --sample-event '{"event":"transaction","revenue":250}'
|
|
249
|
-
```
|
|
250
|
-
|
|
251
250
|
---
|
|
252
251
|
|
|
253
252
|
## `formo boards`
|
|
@@ -290,7 +289,7 @@ Delete a board.
|
|
|
290
289
|
Chart commands. Charts live inside a board. Requires `boards:read` / `boards:write`.
|
|
291
290
|
|
|
292
291
|
### `charts list --board-id <boardId>`
|
|
293
|
-
List
|
|
292
|
+
List charts in a board. Returns lightweight summaries by default; pass `--results` to execute each chart’s query and include full results.
|
|
294
293
|
|
|
295
294
|
### `charts get <chartId> --board-id <boardId>`
|
|
296
295
|
Get a single chart by ID.
|
|
@@ -342,8 +341,6 @@ List all tracked contracts. Returns `{ data: Contract[], deploy: { last_deployed
|
|
|
342
341
|
### `contracts get <chain> <address>`
|
|
343
342
|
Get a single tracked contract.
|
|
344
343
|
|
|
345
|
-
### `contracts recommendations`
|
|
346
|
-
List contracts the project already interacts with but has not added yet.
|
|
347
344
|
|
|
348
345
|
### `contracts create`
|
|
349
346
|
|
|
@@ -373,8 +370,6 @@ formo contracts create --address 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 --ch
|
|
|
373
370
|
| `--start-block` | Optional start block |
|
|
374
371
|
| `--include-in-pipeline` | Include or exclude this contract from the Goldsky events pipeline |
|
|
375
372
|
|
|
376
|
-
### `contracts pipeline <chain> <address> --include-in-pipeline <true|false>`
|
|
377
|
-
Toggle pipeline inclusion without re-sending the full ABI/events payload.
|
|
378
373
|
|
|
379
374
|
### `contracts delete <chain> <address>`
|
|
380
375
|
Remove a tracked contract.
|
|
@@ -19,10 +19,3 @@ export declare function createAlertRun(options: CreateAlertOptions): Promise<unk
|
|
|
19
19
|
export declare function updateAlertRun(alertId: string, options: AlertBodyOptions): Promise<unknown>;
|
|
20
20
|
export declare function deleteAlertRun(alertId: string): Promise<unknown>;
|
|
21
21
|
export declare function toggleAlertRun(alertId: string, status: string): Promise<unknown>;
|
|
22
|
-
export interface TestAlertOptions {
|
|
23
|
-
sampleEvent?: string;
|
|
24
|
-
sampleUser?: string;
|
|
25
|
-
recipientOverrides?: string;
|
|
26
|
-
}
|
|
27
|
-
export declare function buildTestAlertBody(options: TestAlertOptions): Record<string, unknown> | undefined;
|
|
28
|
-
export declare function testAlertRun(alertId: string, options?: TestAlertOptions): Promise<unknown>;
|
package/dist/commands/alerts.js
CHANGED
|
@@ -8,8 +8,6 @@ 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;
|
|
13
11
|
const incur_1 = require("incur");
|
|
14
12
|
const client_1 = require("../lib/client");
|
|
15
13
|
const filters_1 = require("../lib/filters");
|
|
@@ -201,54 +199,3 @@ exports.alerts.command('toggle', {
|
|
|
201
199
|
return toggleAlertRun(args.alertId, options.status);
|
|
202
200
|
},
|
|
203
201
|
});
|
|
204
|
-
function buildTestAlertBody(options) {
|
|
205
|
-
const body = {};
|
|
206
|
-
if (options.sampleEvent !== undefined) {
|
|
207
|
-
body.sampleEvent = (0, json_1.parseJsonObject)(options.sampleEvent, '--sample-event');
|
|
208
|
-
}
|
|
209
|
-
if (options.sampleUser !== undefined) {
|
|
210
|
-
body.sampleUser = (0, json_1.parseJsonObject)(options.sampleUser, '--sample-user');
|
|
211
|
-
}
|
|
212
|
-
if (options.recipientOverrides !== undefined) {
|
|
213
|
-
body.recipientOverrides = (0, json_1.parseJsonArray)(options.recipientOverrides, '--recipient-overrides');
|
|
214
|
-
}
|
|
215
|
-
return Object.keys(body).length > 0 ? body : undefined;
|
|
216
|
-
}
|
|
217
|
-
function testAlertRun(alertId, options = {}) {
|
|
218
|
-
(0, client_1.requireApiKey)();
|
|
219
|
-
const client = (0, client_1.createClient)();
|
|
220
|
-
return client.post(`/v0/alerts/${encodeURIComponent(alertId)}/test`, buildTestAlertBody(options));
|
|
221
|
-
}
|
|
222
|
-
exports.alerts.command('test', {
|
|
223
|
-
description: 'Send a test delivery for an alert',
|
|
224
|
-
args: incur_1.z.object({
|
|
225
|
-
alertId: incur_1.z.string().describe('Alert ID to test'),
|
|
226
|
-
}),
|
|
227
|
-
options: incur_1.z.object({
|
|
228
|
-
sampleEvent: incur_1.z
|
|
229
|
-
.string()
|
|
230
|
-
.optional()
|
|
231
|
-
.describe('Optional JSON object to use as the sample event'),
|
|
232
|
-
sampleUser: incur_1.z
|
|
233
|
-
.string()
|
|
234
|
-
.optional()
|
|
235
|
-
.describe('Optional JSON object to use as the sample user/profile'),
|
|
236
|
-
recipientOverrides: incur_1.z
|
|
237
|
-
.string()
|
|
238
|
-
.optional()
|
|
239
|
-
.describe('Optional JSON array of recipient objects to test instead of saved recipients'),
|
|
240
|
-
}),
|
|
241
|
-
examples: [
|
|
242
|
-
{
|
|
243
|
-
args: { alertId: 'alert_abc123' },
|
|
244
|
-
options: {
|
|
245
|
-
sampleEvent: '{"event":"transaction","revenue":250}',
|
|
246
|
-
},
|
|
247
|
-
description: 'Send a test alert with a sample event',
|
|
248
|
-
},
|
|
249
|
-
],
|
|
250
|
-
hint: 'Requires alerts:write scope on your API key.',
|
|
251
|
-
run({ args, options }) {
|
|
252
|
-
return testAlertRun(args.alertId, options);
|
|
253
|
-
},
|
|
254
|
-
});
|
|
@@ -22,10 +22,10 @@ const PIPES = [
|
|
|
22
22
|
{ name: 'frequency', description: 'Engagement frequency distribution' },
|
|
23
23
|
{ name: 'lifecycle', description: 'User lifecycle stages (new, returning, power, resurrected, churned)' },
|
|
24
24
|
{ name: 'retention', description: 'Retention cohort analysis (params: id_type, event_type, event_name, min_users)' },
|
|
25
|
-
{ name: 'revenue_overview', description: 'Revenue overview with optional breakdown (params: group_by, rank_by)' },
|
|
26
|
-
{ name: 'revenue_by_metric', description: 'Revenue ranked by a metric column (params: metric_column, limit, offset)' },
|
|
25
|
+
{ name: 'revenue_overview', description: 'Revenue overview with optional breakdown (params: group_by — incl. channel_type and paid_source for ad network, rank_by)' },
|
|
26
|
+
{ name: 'revenue_by_metric', description: 'Revenue ranked by a metric column (params: metric_column — incl. channel and paid_source for ad network, limit, offset)' },
|
|
27
27
|
{ name: 'revenue_timeseries', description: 'Revenue over time (params: address)' },
|
|
28
|
-
{ name: 'volume_by_metric', description: 'Trading volume ranked by a metric column (params: metric_column, limit, offset)' },
|
|
28
|
+
{ name: 'volume_by_metric', description: 'Trading volume ranked by a metric column (params: metric_column — incl. channel and paid_source for ad network, limit, offset)' },
|
|
29
29
|
{ name: 'top_chains', description: 'Top chains by activity (params: limit, offset)' },
|
|
30
30
|
{ name: 'top_events', description: 'Top events by count (params: limit, offset, type)' },
|
|
31
31
|
{ name: 'top_locations', description: 'Top locations (params: limit, offset)' },
|
|
@@ -15,7 +15,7 @@ export interface ChartBodyOptions {
|
|
|
15
15
|
settings?: string;
|
|
16
16
|
}
|
|
17
17
|
export declare function buildChartBody(options: ChartBodyOptions): Record<string, unknown>;
|
|
18
|
-
export declare function listChartsRun(boardId: string, options?: PaginationOptions): Promise<unknown>;
|
|
18
|
+
export declare function listChartsRun(boardId: string, options?: PaginationOptions, results?: boolean): Promise<unknown>;
|
|
19
19
|
export declare function listChartSummariesRun(boardId: string, options?: PaginationOptions): Promise<unknown>;
|
|
20
20
|
export declare function getChartRun(boardId: string, chartId: string): Promise<unknown>;
|
|
21
21
|
export interface QueryChartOptions {
|
package/dist/commands/charts.js
CHANGED
|
@@ -109,35 +109,48 @@ const chartBodyOptions = incur_1.z.object({
|
|
|
109
109
|
.describe('JSON object of type-specific chart settings (for example, user_paths anchors/maxSteps/nodesPerStep or retention entryFilter/retentionFilter)'),
|
|
110
110
|
});
|
|
111
111
|
// ── List charts for a board ──
|
|
112
|
-
function listChartsRun(boardId, options = {}) {
|
|
112
|
+
function listChartsRun(boardId, options = {}, results = false) {
|
|
113
113
|
(0, client_1.requireApiKey)();
|
|
114
114
|
const client = (0, client_1.createClient)();
|
|
115
115
|
return client.get(`/v0/boards/${encodeURIComponent(boardId)}/charts/`, {
|
|
116
|
-
params:
|
|
116
|
+
params: {
|
|
117
|
+
...(0, pagination_1.buildPaginationParams)(options),
|
|
118
|
+
// The public API returns lightweight summaries unless asked to execute.
|
|
119
|
+
...(results ? { include: 'results' } : {}),
|
|
120
|
+
},
|
|
117
121
|
});
|
|
118
122
|
}
|
|
119
123
|
exports.charts.command('list', {
|
|
120
|
-
description: 'List
|
|
124
|
+
description: 'List charts for a board (summaries by default; --results executes each chart query)',
|
|
121
125
|
options: incur_1.z.object({
|
|
122
126
|
boardId: incur_1.z.string().describe('Board ID to list charts from'),
|
|
127
|
+
results: incur_1.z
|
|
128
|
+
.boolean()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe('Execute each chart query and include results (slower)'),
|
|
123
131
|
...pagination_1.paginationOptionsSchema,
|
|
124
132
|
}),
|
|
125
133
|
examples: [
|
|
126
134
|
{
|
|
127
135
|
options: { boardId: 'board_abc123' },
|
|
128
|
-
description: 'List
|
|
136
|
+
description: 'List chart summaries for a board',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
options: { boardId: 'board_abc123', results: true },
|
|
140
|
+
description: 'List charts with executed query results',
|
|
129
141
|
},
|
|
130
142
|
],
|
|
131
143
|
hint: 'Requires boards:read scope on your API key.',
|
|
132
144
|
run({ options }) {
|
|
133
|
-
return listChartsRun(options.boardId, options);
|
|
145
|
+
return listChartsRun(options.boardId, options, options.results ?? false);
|
|
134
146
|
},
|
|
135
147
|
});
|
|
136
148
|
// ── List chart metadata for a board ──
|
|
137
149
|
function listChartSummariesRun(boardId, options = {}) {
|
|
138
150
|
(0, client_1.requireApiKey)();
|
|
139
151
|
const client = (0, client_1.createClient)();
|
|
140
|
-
|
|
152
|
+
// Summaries are the list endpoint's default; /charts/meta is internal-only.
|
|
153
|
+
return client.get(`/v0/boards/${encodeURIComponent(boardId)}/charts/`, {
|
|
141
154
|
params: (0, pagination_1.buildPaginationParams)(options),
|
|
142
155
|
});
|
|
143
156
|
}
|
|
@@ -4,7 +4,6 @@ export type { PaginationOptions };
|
|
|
4
4
|
export declare const contracts: Cli.Cli<{}, undefined, undefined, undefined>;
|
|
5
5
|
export declare function listContractsRun(options?: PaginationOptions): Promise<unknown>;
|
|
6
6
|
export declare function getContractRun(chain: string, address: string): Promise<unknown>;
|
|
7
|
-
export declare function getContractRecommendationsRun(): Promise<unknown>;
|
|
8
7
|
export interface CreateContractOptions {
|
|
9
8
|
address: string;
|
|
10
9
|
chain: number;
|
|
@@ -25,8 +24,4 @@ export interface UpdateContractOptions {
|
|
|
25
24
|
}
|
|
26
25
|
export declare function buildUpdateContractBody(chain: string | number, address: string, options: UpdateContractOptions): Record<string, unknown>;
|
|
27
26
|
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>;
|
|
29
|
-
export declare function buildUpdateContractPipelineBody(includeInPipeline: boolean): {
|
|
30
|
-
include_in_pipeline: boolean;
|
|
31
|
-
};
|
|
32
27
|
export declare function deleteContractRun(chain: string, address: string): Promise<unknown>;
|
|
@@ -3,20 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.contracts = void 0;
|
|
4
4
|
exports.listContractsRun = listContractsRun;
|
|
5
5
|
exports.getContractRun = getContractRun;
|
|
6
|
-
exports.getContractRecommendationsRun = getContractRecommendationsRun;
|
|
7
6
|
exports.buildCreateContractBody = buildCreateContractBody;
|
|
8
7
|
exports.createContractRun = createContractRun;
|
|
9
8
|
exports.buildUpdateContractBody = buildUpdateContractBody;
|
|
10
9
|
exports.updateContractRun = updateContractRun;
|
|
11
|
-
exports.updateContractPipelineRun = updateContractPipelineRun;
|
|
12
|
-
exports.buildUpdateContractPipelineBody = buildUpdateContractPipelineBody;
|
|
13
10
|
exports.deleteContractRun = deleteContractRun;
|
|
14
11
|
const incur_1 = require("incur");
|
|
15
12
|
const client_1 = require("../lib/client");
|
|
16
13
|
const json_1 = require("../lib/json");
|
|
17
14
|
const pagination_1 = require("../lib/pagination");
|
|
18
15
|
exports.contracts = incur_1.Cli.create('contracts', {
|
|
19
|
-
description: 'Smart contract commands — register, list,
|
|
16
|
+
description: 'Smart contract commands — register, list, update, and remove tracked contracts',
|
|
20
17
|
});
|
|
21
18
|
function parseChain(chain) {
|
|
22
19
|
const value = typeof chain === 'number' ? chain : Number(chain);
|
|
@@ -48,25 +45,6 @@ function getContractRun(chain, address) {
|
|
|
48
45
|
const client = (0, client_1.createClient)();
|
|
49
46
|
return client.get(`/v0/contracts/${parseChain(chain)}/${encodeURIComponent(address)}`);
|
|
50
47
|
}
|
|
51
|
-
// ── Recommended contracts ──
|
|
52
|
-
function getContractRecommendationsRun() {
|
|
53
|
-
(0, client_1.requireApiKey)();
|
|
54
|
-
const client = (0, client_1.createClient)();
|
|
55
|
-
return client.get('/v0/contracts/recommendations');
|
|
56
|
-
}
|
|
57
|
-
exports.contracts.command('recommendations', {
|
|
58
|
-
description: 'List contracts the project already interacts with but has not added yet',
|
|
59
|
-
options: incur_1.z.object({}),
|
|
60
|
-
examples: [
|
|
61
|
-
{
|
|
62
|
-
description: 'Show recommended contracts to add for decoding/monitoring',
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
hint: 'Requires contracts:read scope on your API key.',
|
|
66
|
-
run() {
|
|
67
|
-
return getContractRecommendationsRun();
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
48
|
exports.contracts.command('get', {
|
|
71
49
|
description: 'Get a tracked contract by chain and address',
|
|
72
50
|
args: incur_1.z.object({
|
|
@@ -197,41 +175,6 @@ exports.contracts.command('update', {
|
|
|
197
175
|
return updateContractRun(args.chain, args.address, options);
|
|
198
176
|
},
|
|
199
177
|
});
|
|
200
|
-
// ── Toggle contract pipeline inclusion ──
|
|
201
|
-
function updateContractPipelineRun(chain, address, includeInPipeline) {
|
|
202
|
-
(0, client_1.requireApiKey)();
|
|
203
|
-
const client = (0, client_1.createClient)();
|
|
204
|
-
return client.patch(`/v0/contracts/${parseChain(chain)}/${encodeURIComponent(address)}/pipeline`, buildUpdateContractPipelineBody(includeInPipeline));
|
|
205
|
-
}
|
|
206
|
-
function buildUpdateContractPipelineBody(includeInPipeline) {
|
|
207
|
-
return { include_in_pipeline: includeInPipeline };
|
|
208
|
-
}
|
|
209
|
-
exports.contracts.command('pipeline', {
|
|
210
|
-
description: 'Toggle whether a tracked contract is included in the project events pipeline',
|
|
211
|
-
args: incur_1.z.object({
|
|
212
|
-
chain: incur_1.z.string().describe('Chain ID'),
|
|
213
|
-
address: incur_1.z.string().describe('Contract address (0x...)'),
|
|
214
|
-
}),
|
|
215
|
-
options: incur_1.z.object({
|
|
216
|
-
includeInPipeline: incur_1.z
|
|
217
|
-
.boolean()
|
|
218
|
-
.describe('true to include the contract in the pipeline, false to exclude it'),
|
|
219
|
-
}),
|
|
220
|
-
examples: [
|
|
221
|
-
{
|
|
222
|
-
args: {
|
|
223
|
-
chain: '1',
|
|
224
|
-
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
225
|
-
},
|
|
226
|
-
options: { includeInPipeline: false },
|
|
227
|
-
description: 'Keep ABI decoding but exclude this contract from pipeline deploys',
|
|
228
|
-
},
|
|
229
|
-
],
|
|
230
|
-
hint: 'Requires contracts:write scope on your API key.',
|
|
231
|
-
run({ args, options }) {
|
|
232
|
-
return updateContractPipelineRun(args.chain, args.address, options.includeInPipeline);
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
178
|
// ── Delete a contract ──
|
|
236
179
|
function deleteContractRun(chain, address) {
|
|
237
180
|
(0, client_1.requireApiKey)();
|
|
@@ -11,11 +11,13 @@ export interface LifecycleThresholdOptions {
|
|
|
11
11
|
}
|
|
12
12
|
export interface GetProfileOptions extends LifecycleThresholdOptions {
|
|
13
13
|
expand?: string;
|
|
14
|
+
timestamp?: string;
|
|
14
15
|
}
|
|
15
16
|
export declare function getProfileRun(address: string, optionsOrExpand?: GetProfileOptions | string): Promise<unknown>;
|
|
16
17
|
export interface SearchProfilesOptions extends LifecycleThresholdOptions {
|
|
17
18
|
address?: string;
|
|
18
19
|
search?: string;
|
|
20
|
+
timestamp?: string;
|
|
19
21
|
page?: number;
|
|
20
22
|
size?: number;
|
|
21
23
|
orderBy?: string;
|
|
@@ -75,6 +75,10 @@ const lifecycleThresholdOptions = {
|
|
|
75
75
|
.optional()
|
|
76
76
|
.describe('Override lifecycle at-risk prior active days threshold'),
|
|
77
77
|
};
|
|
78
|
+
const profileTimestampOption = incur_1.z
|
|
79
|
+
.string()
|
|
80
|
+
.datetime({ offset: true })
|
|
81
|
+
.optional();
|
|
78
82
|
function getProfileRun(address, optionsOrExpand = {}) {
|
|
79
83
|
(0, client_1.requireApiKey)();
|
|
80
84
|
const client = (0, client_1.createClient)();
|
|
@@ -84,6 +88,8 @@ function getProfileRun(address, optionsOrExpand = {}) {
|
|
|
84
88
|
const params = {};
|
|
85
89
|
if (options.expand)
|
|
86
90
|
params.expand = options.expand;
|
|
91
|
+
if (options.timestamp)
|
|
92
|
+
params.timestamp = options.timestamp;
|
|
87
93
|
addLifecycleThresholdParams(params, options);
|
|
88
94
|
return client.get(`/v0/profiles/${encodeURIComponent(address)}`, { params });
|
|
89
95
|
}
|
|
@@ -97,6 +103,7 @@ exports.profiles.command('get', {
|
|
|
97
103
|
.string()
|
|
98
104
|
.optional()
|
|
99
105
|
.describe('Comma-separated list of fields to expand: apps,chains,tokens,labels'),
|
|
106
|
+
timestamp: profileTimestampOption.describe('Return the wallet-enrichment snapshot closest to this ISO-8601 timestamp'),
|
|
100
107
|
...lifecycleThresholdOptions,
|
|
101
108
|
}),
|
|
102
109
|
examples: [
|
|
@@ -106,6 +113,11 @@ exports.profiles.command('get', {
|
|
|
106
113
|
options: { expand: 'labels,chains' },
|
|
107
114
|
description: 'Get profile with expanded labels and chains',
|
|
108
115
|
},
|
|
116
|
+
{
|
|
117
|
+
args: { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' },
|
|
118
|
+
options: { timestamp: '2025-06-21T10:03:00Z' },
|
|
119
|
+
description: 'Get the closest stored wallet-enrichment snapshot',
|
|
120
|
+
},
|
|
109
121
|
],
|
|
110
122
|
hint: 'Requires profiles:read scope on your API key.',
|
|
111
123
|
run({ args, options }) {
|
|
@@ -275,6 +287,9 @@ function parseSearchFilters(raw) {
|
|
|
275
287
|
return parsed;
|
|
276
288
|
}
|
|
277
289
|
function searchProfilesRun(options) {
|
|
290
|
+
if (options.timestamp && !options.address) {
|
|
291
|
+
throw new Error('--timestamp requires --address');
|
|
292
|
+
}
|
|
278
293
|
(0, client_1.requireApiKey)();
|
|
279
294
|
const client = (0, client_1.createClient)();
|
|
280
295
|
const params = {};
|
|
@@ -282,6 +297,8 @@ function searchProfilesRun(options) {
|
|
|
282
297
|
params.address = options.address;
|
|
283
298
|
if (options.search)
|
|
284
299
|
params.search = options.search;
|
|
300
|
+
if (options.timestamp)
|
|
301
|
+
params.timestamp = options.timestamp;
|
|
285
302
|
if (options.page !== undefined)
|
|
286
303
|
params.page = options.page;
|
|
287
304
|
if (options.size !== undefined)
|
|
@@ -313,6 +330,7 @@ exports.profiles.command('search', {
|
|
|
313
330
|
options: incur_1.z.object({
|
|
314
331
|
address: incur_1.z.string().optional().describe('Filter by wallet address'),
|
|
315
332
|
search: incur_1.z.string().optional().describe('Free-text search across address and identity fields'),
|
|
333
|
+
timestamp: profileTimestampOption.describe('Return the closest wallet-enrichment snapshot; requires --address'),
|
|
316
334
|
page: incur_1.z.coerce
|
|
317
335
|
.number()
|
|
318
336
|
.int()
|
|
@@ -373,6 +391,13 @@ exports.profiles.command('search', {
|
|
|
373
391
|
}),
|
|
374
392
|
examples: [
|
|
375
393
|
{ options: { size: 10 }, description: 'List first 10 profiles' },
|
|
394
|
+
{
|
|
395
|
+
options: {
|
|
396
|
+
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
|
|
397
|
+
timestamp: '2025-06-21T10:03:00Z',
|
|
398
|
+
},
|
|
399
|
+
description: 'Search the closest stored wallet-enrichment snapshot',
|
|
400
|
+
},
|
|
376
401
|
{
|
|
377
402
|
options: { orderBy: 'net_worth_usd', orderDir: 'desc', size: 5 },
|
|
378
403
|
description: 'Top 5 profiles by net worth',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formo/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"packageManager": "pnpm@11.1.2",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.12"
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"dist",
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
},
|
|
26
30
|
"scripts": {
|
|
27
31
|
"build": "tsc",
|
|
28
32
|
"prepublishOnly": "pnpm build",
|