Merge pull request #169 from GMGNAI/feat/market-hot-searches

feat(market): add hot-searches command for hot-search ranking
This commit is contained in:
GMGN.AI
2026-06-29 17:08:09 +08:00
committed by GitHub
6 changed files with 284 additions and 4 deletions
+10
View File
@@ -485,6 +485,16 @@ gmgn-cli market signal --chain sol --signal-type 12 --raw
# Token signals — multi-group: smart money OR large buys in parallel
gmgn-cli market signal --chain sol \
--groups '[{"signal_type":[12]},{"signal_type":[14,16]}]' --raw
# Hot searches — most-searched tokens (default 7-chain set, 24h)
gmgn-cli market hot-searches --raw
# Hot searches — SOL only, 1h window, top 50
gmgn-cli market hot-searches --chain sol --interval 1h --limit 50 --raw
# Hot searches — SOL with range filters (same metric names as trending)
gmgn-cli market hot-searches --chain sol --interval 1h \
--min-liquidity 10000 --min-smart-degen-count 1 --raw
```
### Portfolio
+10
View File
@@ -509,6 +509,16 @@ gmgn-cli market trenches \
gmgn-cli market trenches \
--chain sol --type new_creation \
--filter-preset safe --min-smart-degen-count 1 --sort-by smart_degen_count
# 热搜榜——搜索热度最高的代币(默认 7 链,24h)
gmgn-cli market hot-searches --raw
# 热搜榜——仅 SOL,1h 档,前 50
gmgn-cli market hot-searches --chain sol --interval 1h --limit 50 --raw
# 热搜榜——SOL 数值范围过滤(指标名与 trending 一致)
gmgn-cli market hot-searches --chain sol --interval 1h \
--min-liquidity 10000 --min-smart-degen-count 1 --raw
```
### Portfolio
+28
View File
@@ -362,6 +362,34 @@ gmgn-cli market signal --chain sol --groups '<json_array>' [--raw]
---
## market hot-searches
Query the hot-search ranking — the most-searched tokens, ranked by `visiting_count` (search heat). Cross-chain top-500; one request can cover several chains at once. API Key auth only.
```bash
# Default 7-chain set (sol/bsc/base/eth/hyperevm/megaeth/monad, each 24h):
gmgn-cli market hot-searches [--raw]
# Specific chain(s) and interval:
gmgn-cli market hot-searches --chain <chain...> [--interval <1m|5m|1h|6h|24h>] [--limit <n>] [--filter <tag...>] [--min-* <n>] [--max-* <n>] [--raw]
# Full per-param override (JSON array):
gmgn-cli market hot-searches --params '<json_array>' [--raw]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--chain` | No | Repeatable: `sol` / `bsc` / `base` / `eth` / `monad` / `megaeth` / `hyperevm` / `tron`. Omit for the default 7-chain set. |
| `--interval` | No | `1m` / `5m` / `1h` / `6h` / `24h` (default `24h`). Applies to every `--chain`. |
| `--limit` | No | Max results per chain (default `500`). |
| `--filter` | No | Repeatable **boolean** filter tags (downstream `filter.filters`). sol defaults: `renounced` / `frozen`; EVM defaults: `not_honeypot` / `verified` / `renounced`. Recognised tags: `renounced` / `frozen` (sol) / `is_burnt` / `token_burnt` / `not_wash_trading` / `not_honeypot` (EVM) / `verified` (EVM) / `locked` (EVM) / `has_social` / `distribed` / `not_risk` / `img_not_duplicate` / `social_not_duplicate` / `creator_hold` / `creator_close` / `dexscr_update_link` / `launching` / `migrated` / `hide_b20` (base) / `hide_non_b20` (base). Unknown tags are silent no-ops. |
| `--min-*` / `--max-*` | No | Numeric range bounds, **same metric names as `market trending`** (`--min-liquidity`, `--max-marketcap`, `--min-volume`, `--min-swaps`, `--min-smart-degen-count`, …, plus `--min-created`/`--max-created` durations). Translated server-side per `--interval`. `price_change_percent` only applies to `1m`/`5m`/`1h`. |
| `--params` | No | Full JSON array override — overrides `--chain` / `--interval` / `--limit` / `--filter` and range flags when provided. Filter fields are flattened onto each param (no nested `filter` object): a param accepts `filters`, `limit`, `min_created`/`max_created`, and rank-style `min_<metric>`/`max_<metric>` keys. |
**Response:** `data` is an array of `(interval, chain)` blocks; each block has `interval`, `chain`, `version`, and `tokens`. `tokens` uses the **same long-form fields as `market trending`** (`address`, `symbol`, `visiting_count`, `market_cap`, …) — the server maps the upstream shortcodes for you — and each token carries a 1-based `rank`. Ranked by search heat (`visiting_count`), max 500 per chain. **Note:** `--chain all` is not valid — pass `--chain` multiple times to aggregate across chains. Boolean tag names differ from `market trending`: this path uses `launching`/`migrated` and `img_not_duplicate`/`social_not_duplicate`.
---
## track follow-tokens
Query the followed token list for a wallet. Returns a paginated list of tokens the wallet has bookmarked on GMGN, with full market data. API Key auth only.
+151 -3
View File
@@ -1,7 +1,7 @@
---
name: gmgn-market
description: Get crypto and meme token price charts (K-line, candlestick, OHLCV), trending meme coin rankings by volume, and newly launched tokens on launchpads (pump.fun, fourmeme, letsbonk, Raydium, etc.) via GMGN API on Solana, BSC, Base, or Ethereum. Use when user asks for price chart, trending tokens, what's pumping, hot coins, new launches, token signals, or wants to discover early-stage opportunities.
argument-hint: "kline --chain <sol|bsc|base|eth> --address <token_address> --resolution <30s|1m|5m|15m|1h|4h|1d> [--from <unix_ts>] [--to <unix_ts>] | trending --chain <sol|bsc|base|eth> --interval <1m|5m|1h|6h|24h> | trenches --chain <sol|bsc|base|eth> | signal --chain <sol|bsc>"
description: Get crypto and meme token price charts (K-line, candlestick, OHLCV), trending meme coin rankings by volume, newly launched tokens on launchpads (pump.fun, fourmeme, letsbonk, Raydium, etc.), and the hot-search ranking (most-searched tokens) via GMGN API on Solana, BSC, Base, or Ethereum. Use when user asks for price chart, trending tokens, what's pumping, hot coins, most searched tokens, new launches, token signals, or wants to discover early-stage opportunities.
argument-hint: "kline --chain <sol|bsc|base|eth> --address <token_address> --resolution <30s|1m|5m|15m|1h|4h|1d> [--from <unix_ts>] [--to <unix_ts>] | trending --chain <sol|bsc|base|eth> --interval <1m|5m|1h|6h|24h> | trenches --chain <sol|bsc|base|eth> | signal --chain <sol|bsc> | hot-searches [--chain <sol|bsc|base|eth|monad|megaeth|hyperevm|tron...>] [--interval <1m|5m|1h|6h|24h>]"
metadata:
cliHelp: "gmgn-cli market --help"
---
@@ -49,10 +49,11 @@ Use the `gmgn-cli` tool to query K-line data for a token, browse trending tokens
| `market trending` | Trending tokens ranked by swap activity — use `--interval` to specify the time window (e.g. `1m` for 1-minute hottest, `1h` for 1-hour trending) |
| `market trenches` | Newly launched launchpad platform tokens — **use this when the user asks for "new tokens", "just launched tokens", "latest tokens on pump.fun/letsbonk"**. Three categories: `new_creation` (just created), `near_completion` (bonding curve almost full), `completed` (graduated to open market / DEX) |
| `market signal` | Real-time token signal feed — price spikes, smart money buys, large buys, Dex ads, CTO events, and more. Results sorted by `trigger_at` descending. **sol / bsc only. Max 50 results per group.** |
| `market hot-searches` | Hot-search ranking — the most-searched tokens, ranked by `visiting_count` (search heat). **Use this when the user asks "what tokens are people searching for", "most searched tokens", "hot search list", "热搜榜".** Supports multiple chains in a single request. |
## Supported Chains
`sol` / `bsc` / `base` / `eth` (kline / trending / trenches; signal: `sol` / `bsc` only)
`sol` / `bsc` / `base` / `eth` (kline / trending / trenches; signal: `sol` / `bsc` only; hot-searches: `sol` / `bsc` / `base` / `eth` / `monad` / `megaeth` / `hyperevm` / `tron`)
## Prerequisites
@@ -69,6 +70,7 @@ All market routes used by this skill go through GMGN's leaky-bucket limiter with
| `market trending` | `GET /v1/market/rank` | 1 |
| `market trenches` | `POST /v1/trenches` | 3 |
| `market signal` | `POST /v1/market/token_signal` | 3 |
| `market hot-searches` | `POST /v1/market/hot_searches` | 3 |
When a request returns `429`:
@@ -1041,12 +1043,158 @@ gmgn-cli market signal --chain sol \
--groups '[{"signal_type":[12,13],"mc_min":100000},{"signal_type":[6,7],"mc_min":50000,"mc_max":1000000}]' --raw
```
## `market hot-searches` Parameters
Returns the hot-search ranking — the tokens people are searching for most right now, ranked by `visiting_count` (search heat). Cross-chain top-500 ranking; one request can cover several chains at once. **Use this for "most searched tokens", "hot search list", "热搜榜", "what is everyone looking at"** — this is distinct from `market trending` (ranked by swap activity), which answers "what is being traded most."
| Option | Description |
|--------|-------------|
| `--chain <chain...>` | Repeatable. `sol` / `bsc` / `base` / `eth` / `monad` / `megaeth` / `hyperevm` / `tron`. **Omit to query the default 7-chain set** (sol / bsc / base / eth / hyperevm / megaeth / monad, each at `24h` with chain-appropriate safety filters). |
| `--interval <interval>` | `1m` / `5m` / `1h` / `6h` / `24h` (default `24h`). Applies to every `--chain` provided. |
| `--limit <n>` | Max results per chain (default `500`). |
| `--filter <tag...>` | Repeatable **boolean** filter tags (the downstream `filter.filters` array). **⚠️ SOL defaults: `renounced frozen`; EVM defaults: `not_honeypot verified renounced`.** Omitting `--filter` is NOT "no filter" — the server applies chain defaults. See the Filter Tags table below for the exact vocabulary. |
| `--min-* / --max-* <n>` | Numeric range bounds, **same metric names as `market trending`** (e.g. `--min-liquidity`, `--max-marketcap`, `--min-smart-degen-count`). Translated server-side per `--interval`. `--min-created` / `--max-created` are token-age durations. See the Range Filters table below. |
| `--params <json>` | Full override: a JSON array of param objects. When provided, `--chain` / `--interval` / `--limit` / `--filter` and all range flags are ignored. Filter fields are **flattened onto each param** (no nested `filter` object): `{ "label": "...", "chain": "...", "interval": "...", "filters": [...], "limit": 500, "min_liquidity": 1000 }` — a param accepts `filters`, `limit`, `min_created`/`max_created`, and rank-style `min_<metric>`/`max_<metric>` keys. |
### `market hot-searches` Filter Tags (`--filter` / `filter.filters`)
The downstream (gmgn rank filter-service) evaluates each tag as an AND condition — a token must pass **every** tag to stay in the list. **Unknown tags are silently accepted but do nothing** (pass-through), so an unrecognised tag will NOT filter anything — spelling matters. This tag set is the filter-service vocabulary and differs slightly from `market trending`'s tag names (see the alias note below).
**These are the only recognised tags** (anything else is a no-op):
| Tag | Chains | Passes when |
|----------------------|-------------|-------------|
| `renounced` | sol / EVM | sol: mint authority renounced (`renounced_mint == 1`); EVM: owner renounced (`is_renounced == 1`; lenient — nil passes) |
| `frozen` | sol only | freeze authority renounced (`renounced_freeze_account == 1`); non-sol always fails |
| `is_burnt` | all | LP pool burned (`burn_status == "burn"`) |
| `token_burnt` | all | creator burned tokens (`dev_token_burn_ratio > 0`) |
| `not_wash_trading` | all | not flagged as wash trading |
| `not_honeypot` | EVM | not a honeypot (`is_honeypot == 0`; lenient — nil passes) |
| `verified` | EVM | contract open-source (`is_open_source == 1`; lenient — nil passes) |
| `locked` | EVM | liquidity locked ≥ 50% (`lock_percent >= 0.5`) |
| `has_social` | all | has Twitter, Telegram, or Website |
| `distribed` | all | top-10 holder rate in (0, 0.3] (well distributed) |
| `not_risk` | all | composite low-risk filter (sol: liquidity≥4000 + mint renounced + top10<0.3 + freeze renounced + LP burned; EVM: not honeypot + liquidity≥4000 + open-source + renounced + lock≥0.5) |
| `img_not_duplicate` | all | avatar image not duplicated (`image_dup == "0"`) |
| `social_not_duplicate` | all | social links not shared (`twitter_dup == 0 && telegram_dup == 0 && website_dup == 0`) |
| `creator_hold` | all | dev still holding (not `creator_close`) |
| `creator_close` | all | dev sold/closed (`creator_token_status == "creator_close"`) |
| `dexscr_update_link` | all | social links updated on DexScreener (`> 0`) |
| `launching` | all | still on the launchpad bonding curve (`launchpad_status == "0"`); pair with `migrated` to allow both |
| `migrated` | all | graduated / migrated to DEX (`launchpad_status == "1"`); pair with `launching` to allow both |
| `hide_b20` | base only | token standard is not `b20` (no-op on non-base) |
| `hide_non_b20` | base only | token standard is `b20` (no-op on non-base) |
> **⚠️ Different names than `market trending`.** This path uses `launching` / `migrated` (NOT `is_internal_market` / `is_out_market`) and `img_not_duplicate` / `social_not_duplicate` (NOT `not_image_dup` / `not_social_dup`). Tags that `market trending` supports but this endpoint does **not** recognise (they become silent no-ops here): `dexscr_ad`, `dexscr_trending_bar`, `dexscr_boost`, `cto_flag`, `is_internal_market`, `is_out_market`, `not_image_dup`, `not_social_dup`.
### `market hot-searches` Range Filters (`--min-*` / `--max-*`)
Numeric bounds use the **same rank-style metric names as `market trending`**. They are sent flattened on each param and translated server-side to the downstream field for the param's `--interval`. Closed intervals; metrics the downstream cannot read are dropped (not silent no-ops on the wire — they are removed before the request).
| Flag pair | Type | Metric |
|------------------------------------------------------------|----------|--------|
| `--min-volume` / `--max-volume` | float | Trading volume (USD) — bound to the `--interval` window |
| `--min-swaps` / `--max-swaps` | int | Swap count — bound to the `--interval` window |
| `--min-price-change-percent` / `--max-price-change-percent` | float | Price change ratio — **only `1m` / `5m` / `1h`; dropped for `6h` / `24h`** |
| `--min-liquidity` / `--max-liquidity` | float | Liquidity (USD) |
| `--min-marketcap` / `--max-marketcap` | float | Market cap (USD) |
| `--min-history-highest-marketcap` / `--max-history-highest-marketcap` | float | All-time-high market cap (USD) |
| `--min-holder-count` / `--max-holder-count` | int | Holder count |
| `--min-gas-fee` / `--max-gas-fee` | float | Gas fee |
| `--min-renowned-count` / `--max-renowned-count` | int | KOL / renowned holder count |
| `--min-smart-degen-count` / `--max-smart-degen-count` | int | Smart-money holder count |
| `--min-bot-degen-count` / `--max-bot-degen-count` | int | Bot-degen wallet count |
| `--min-visiting-count` / `--max-visiting-count` | int | Visitor count |
| `--min-insider-rate` / `--max-insider-rate` | float | Insider trading ratio (01); tokens lacking this field are excluded |
| `--min-bundler-rate` / `--max-bundler-rate` | float | Bundle-bot trading ratio (01); tokens lacking this field are excluded |
| `--min-entrapment-ratio` / `--max-entrapment-ratio` | float | Entrapment trading ratio (01); tokens lacking this field are excluded |
| `--min-top10-holder-rate` / `--max-top10-holder-rate` | float | Top-10 holder concentration (01) |
| `--min-top70-sniper-hold-rate` / `--max-top70-sniper-hold-rate` | float | Top-70 sniper holding ratio (01) |
| `--min-dev-team-hold-rate` / `--max-dev-team-hold-rate` | float | Dev-team holding ratio (01) |
| `--min-created` / `--max-created` | duration | Token age window (`30m` / `6h` / `7d`). `min_created` = minimum age; `max_created` = maximum age |
**Notes on behaviour:**
- `--chain all` is **not** valid. To aggregate across chains, pass `--chain` multiple times (or omit `--chain` for the default 7-chain set).
- When you pass `--chain` but omit `--filter`, the **server** applies the chain-appropriate default filters — so each chain is filtered even without an explicit `--filter`.
- Different chains return different counts: a chain's token count depends on how many of its tokens made the global top-500 (sol is usually the largest; monad / megaeth are small).
## `market hot-searches` Response Fields
The response `data` is an array. Each element is one `(interval, chain)` result block:
| Field | Type | Description |
|-------|------|-------------|
| `interval` | string | The interval for this block |
| `chain` | string | The chain for this block |
| `version` | string | Subscription version — persist it for WebSocket reconnect |
| `tokens` | array | Ranked tokens (search heat desc), max 500. Each token carries a 1-based `rank` |
**Token fields are the same long-form fields as `market trending`** — the server maps the upstream shortcodes for you, so you read `visiting_count` / `market_cap` / `symbol` directly (NOT `v_c` / `mc` / `s`). Key fields:
| Field | Description |
|-------|-------------|
| `address` | Token contract address |
| `chain` | Chain |
| `name` / `symbol` | Token name / ticker |
| `price` | Current price (USD) |
| `visiting_count` | **Primary ranking key — search / visit heat** |
| `market_cap` | Market cap (USD) |
| `volume` | Volume in this interval (USD) |
| `liquidity` | Liquidity (USD) |
| `swaps` / `buys` / `sells` | Swap / buy / sell counts |
| `holder_count` | Holder count |
| `rank` | 1-based position within the block |
See the [`market trending` Response Fields](#market-trending-response-fields) section above for the full field set — hot-searches tokens use the identical `RankItem` shape.
### `market hot-searches` Usage Examples
```bash
# Default 7-chain hot-search ranking (sol/bsc/base/eth/hyperevm/megaeth/monad, each 24h)
gmgn-cli market hot-searches --raw
# SOL only, 24h hot-search list
gmgn-cli market hot-searches --chain sol --interval 24h --raw
# SOL + BSC + Base, 1h window, top 50 per chain
gmgn-cli market hot-searches --chain sol --chain bsc --chain base --interval 1h --limit 50 --raw
# SOL with custom boolean filters
gmgn-cli market hot-searches --chain sol --interval 24h \
--filter renounced --filter frozen --raw
# SOL 1h hot-searches with numeric range filters (same metric names as `market trending`)
gmgn-cli market hot-searches --chain sol --interval 1h \
--min-liquidity 10000 --min-volume 5000 --min-smart-degen-count 1 --raw
# Range filter by token age + market cap
gmgn-cli market hot-searches --chain sol --interval 24h \
--max-created 7d --min-marketcap 50000 --raw
# Full per-param override via JSON (different filters per chain, incl. ranges)
gmgn-cli market hot-searches --raw --params '[
{"label":"hot-search","chain":"sol","interval":"24h","filters":["renounced","frozen"],"limit":500,"min_liquidity":10000},
{"label":"hot-search","chain":"bsc","interval":"24h","filters":["not_honeypot","verified","renounced"],"limit":500}
]'
```
### `market hot-searches` — Output Format
Present per chain, ranked by `visiting_count` (search heat):
```
🔥 Hot Searches — {chain} ({interval})
# | Symbol | Price | MCap | Volume | Search Heat (visiting_count) | Liq
```
---
## Notes
- `market kline`: `--from` and `--to` are Unix timestamps in **seconds** — CLI converts to milliseconds automatically
- `market trending`: `--filter` and `--platform` are repeatable flags
- `market hot-searches`: `--chain` and `--filter` are repeatable flags; omit `--chain` to query the default 7-chain set. `--min-*`/`--max-*` range flags reuse the same metric names as `market trending` and are translated server-side per `--interval`
- All commands use exist auth (API Key only, no signature)
- If the user doesn't provide kline timestamps, calculate them from the current time based on their desired time range
- Use `--raw` to get single-line JSON for further processing
+18
View File
@@ -179,6 +179,20 @@ export interface TokenSignalGroup {
max_create_or_open_ts?: string;
}
// HotSearchesParam carries its filter fields flattened (no nested `filter` object):
// label/interval/chain plus optional `filters` boolean tags, `limit`, and rank-style
// numeric range bounds (min_<metric>/max_<metric>) incl. min_created/max_created.
// Extra range keys are forwarded verbatim; the service translates metric names per
// interval. See `market hot-searches` docs for the supported metric list.
export interface HotSearchesParam {
label?: string;
interval: string; // "1m" | "5m" | "1h" | "6h" | "24h"
chain: string; // "sol" | "bsc" | "base" | "eth" | "monad" | "megaeth" | "hyperevm" | "tron"
filters?: string[];
limit?: number;
[key: string]: string[] | number | string | undefined;
}
export interface PumpFeeShareInfo {
provider: string; // "solana" | "twitter" | "github"
username: string; // platform username; a SOL address when provider = "solana"
@@ -430,6 +444,10 @@ export class OpenApiClient {
return this.authExistRequest("POST", "/v1/market/token_signal", {}, { chain, groups });
}
async getHotSearches(params: HotSearchesParam[]): Promise<unknown> {
return this.authExistRequest("POST", "/v1/market/hot_searches", {}, { params });
}
// ---- User endpoints (exist auth) ----
async getUserInfo(): Promise<unknown> {
+67 -1
View File
@@ -1,5 +1,5 @@
import { Command } from "commander";
import { OpenApiClient, TokenSignalGroup } from "../client/OpenApiClient.js";
import { OpenApiClient, TokenSignalGroup, HotSearchesParam } from "../client/OpenApiClient.js";
import { getConfig } from "../config.js";
import { exitOnError, printResult } from "../output.js";
import { validateAddress, validateChain } from "../validate.js";
@@ -203,8 +203,74 @@ export function registerMarketCommands(program: Command): void {
const data = await client.getTokenSignalV2(opts["chain"] as string, groups).catch(exitOnError);
printResult(data, opts["raw"] as boolean | undefined);
});
const hotSearchesCmd = market
.command("hot-searches")
.description("Get the hot-search ranking (most-searched tokens) for one or more chains")
.option("--chain <chain...>", "Chain(s), repeatable: sol / bsc / base / eth / monad / megaeth / hyperevm / tron (default: all 7 chains)")
.option("--interval <interval>", "Time window: 1m / 5m / 1h / 6h / 24h (default 24h)", "24h")
.option("--limit <n>", "Max results per chain (default 500)", parseInt)
.option("--filter <tag...>", "Boolean filter tags, repeatable. sol defaults: renounced / frozen; EVM defaults: not_honeypot / verified / renounced")
.option("--params <json>", "Full params override: JSON array of param objects — overrides --chain/--interval/--limit/--filter and all range flags when provided")
.option("--raw", "Output raw JSON");
// Reuse the same min_*/max_* range flags as `market trending` — the hot_searches
// endpoint accepts the identical rank-style metric names inside `filter` and
// translates them server-side per interval (min_created/max_created are durations).
for (const def of RANK_RANGE_FIELDS) {
const flag = def.api.replace(/_/g, "-");
if (def.type === "int") {
hotSearchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseInt);
} else if (def.type === "float") {
hotSearchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseFloat);
} else if (def.type === "duration") {
hotSearchesCmd.option(`--${flag} <duration>`, def.desc, parseDuration);
} else {
hotSearchesCmd.option(`--${flag} <value>`, def.desc);
}
}
hotSearchesCmd.action(async (opts) => {
const interval = String(opts.interval);
if (!HOT_SEARCHES_INTERVALS.has(interval)) {
console.error(`[gmgn-cli] Invalid --interval "${interval}". Must be one of: ${[...HOT_SEARCHES_INTERVALS].join(", ")}`);
process.exit(1);
}
let params: HotSearchesParam[];
if (opts.params != null) {
try {
params = JSON.parse(opts.params as string) as HotSearchesParam[];
} catch {
console.error(`[gmgn-cli] --params must be a valid JSON array, e.g. '[{"chain":"sol","interval":"24h","filters":["renounced","frozen"],"limit":500,"min_liquidity":1000}]'`);
process.exit(1);
}
} else {
// Empty params lets the server apply its default 7-chain config. Filter fields
// are flattened directly onto each param (no nested `filter` object).
const optsMap = opts as Record<string, unknown>;
const chains: string[] = opts.chain?.length ? (opts.chain as string[]) : [];
params = chains.map((chain) => {
const param: HotSearchesParam = { label: "hot-search", chain, interval };
if (opts.filter?.length) param.filters = opts.filter as string[];
if (opts.limit != null) param.limit = opts.limit as number;
// Fold in any rank-style min_*/max_* range flags (incl. min_created/max_created).
for (const def of RANK_RANGE_FIELDS) {
const val = optsMap[apiFieldToCliKey(def.api)];
if (val != null) param[def.api] = val as number | string;
}
return param;
});
}
const client = new OpenApiClient(getConfig());
const data = await client.getHotSearches(params).catch(exitOnError);
printResult(data, opts.raw);
});
}
const HOT_SEARCHES_INTERVALS = new Set(["1m", "5m", "1h", "6h", "24h"]);
// ---- Trenches filter field definitions ----
type TrenchesFieldType = "int" | "float" | "string" | "duration";