@four-meme/four-meme-ai 1.0.6 → 1.0.8

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.
@@ -1,16 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Four.meme - token rankings (REST API)
4
- * POST /meme-api/v1/private/token/query/advanced
5
- * Body: { orderBy: "Time"|"ProgressDesc"|"TradingDesc"|"Hot"|"Graduated" [, barType: "HOUR24" ] }
6
- * Usage: npx tsx token-rankings.ts <orderBy> [--barType=HOUR24]
7
- * orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated
8
- * --barType only for TradingDesc (24h volume)
4
+ * POST /meme-api/v1/public/token/ranking
5
+ *
6
+ * Backward compatible: <orderBy> where orderBy = Time | ProgressDesc | TradingDesc | Hot | Graduated
7
+ * [--barType=HOUR24|HOUR4|HOUR1|MIN30|MIN5] (only for TradingDesc; maps to VOL_* windows)
8
+ *
9
+ * You may also pass a native API RankingType directly: NEW, PROGRESS, VOL_DAY_1, HOT, DEX, VOL, LAST, CAP, …
10
+ *
11
+ * Optional filters: [--pageSize=20] [--symbol=] [--version=] [--rankingKind=]
12
+ * [--minCap=] [--maxCap=] [--minVol=] [--maxVol=] [--minHold=] [--maxHold=]
13
+ *
14
+ * Usage: npx tsx token-rankings.ts <orderOrType> [--barType=HOUR24] [filters...]
9
15
  * Output: JSON ranking list.
10
16
  */
11
17
 
12
18
  const API_BASE = 'https://four.meme/meme-api/v1';
13
19
 
20
+ const LEGACY_ORDER_BY = ['Time', 'ProgressDesc', 'TradingDesc', 'Hot', 'Graduated'] as const;
21
+
22
+ /** Legacy TradingDesc + barType → public ranking `type`. */
23
+ const BAR_TYPE_TO_VOL_TYPE: Record<string, string> = {
24
+ HOUR24: 'VOL_DAY_1',
25
+ DAY1: 'VOL_DAY_1',
26
+ HOUR4: 'VOL_HOUR_4',
27
+ HOUR1: 'VOL_HOUR_1',
28
+ MIN30: 'VOL_MIN_30',
29
+ MIN5: 'VOL_MIN_5',
30
+ };
31
+
32
+ const LEGACY_TO_TYPE: Record<string, string> = {
33
+ Time: 'NEW',
34
+ ProgressDesc: 'PROGRESS',
35
+ TradingDesc: 'VOL_DAY_1',
36
+ Hot: 'HOT',
37
+ Graduated: 'DEX',
38
+ };
39
+
40
+ /** Native ranking types allowed as the first argument (aligned with API RankingType). */
41
+ const NATIVE_RANKING_TYPES = new Set([
42
+ 'NEW',
43
+ 'PROGRESS',
44
+ 'VOL_MIN_5',
45
+ 'VOL_MIN_30',
46
+ 'VOL_HOUR_1',
47
+ 'VOL_HOUR_4',
48
+ 'VOL_DAY_1',
49
+ 'VOL',
50
+ 'LAST',
51
+ 'HOT',
52
+ 'CAP',
53
+ 'DEX',
54
+ 'BURN',
55
+ ]);
56
+
14
57
  function parseArg(name: string): string | undefined {
15
58
  const prefix = `--${name}=`;
16
59
  for (let i = 3; i < process.argv.length; i++) {
@@ -20,19 +63,84 @@ function parseArg(name: string): string | undefined {
20
63
  return undefined;
21
64
  }
22
65
 
66
+ function parseNumArg(name: string): number | undefined {
67
+ const v = parseArg(name);
68
+ if (v == null || v.trim() === '') return undefined;
69
+ const n = Number(v);
70
+ return Number.isFinite(n) ? n : undefined;
71
+ }
72
+
73
+ function resolveRankingType(first: string, barType?: string): string {
74
+ if (first === 'TradingDesc') {
75
+ if (barType && BAR_TYPE_TO_VOL_TYPE[barType]) {
76
+ return BAR_TYPE_TO_VOL_TYPE[barType];
77
+ }
78
+ return 'VOL_DAY_1';
79
+ }
80
+ if (LEGACY_TO_TYPE[first]) {
81
+ return LEGACY_TO_TYPE[first];
82
+ }
83
+ return first;
84
+ }
85
+
86
+ function normalizeLegacyOrderBy(s: string): string {
87
+ const map: Record<string, string> = {
88
+ time: 'Time',
89
+ progressdesc: 'ProgressDesc',
90
+ tradingdesc: 'TradingDesc',
91
+ hot: 'Hot',
92
+ graduated: 'Graduated',
93
+ };
94
+ return map[s.toLowerCase()] ?? s;
95
+ }
96
+
23
97
  async function main() {
24
- const orderBy = process.argv[2];
25
- const validOrderBy = ['Time', 'ProgressDesc', 'TradingDesc', 'Hot', 'Graduated'];
26
- if (!orderBy || !validOrderBy.includes(orderBy)) {
27
- console.error('Usage: npx tsx token-rankings.ts <orderBy> [--barType=HOUR24]');
28
- console.error('orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated');
98
+ const rawFirst = process.argv[2];
99
+ const first = rawFirst ? normalizeLegacyOrderBy(rawFirst) : '';
100
+ if (!first) {
101
+ console.error(
102
+ 'Usage: npx tsx token-rankings.ts <orderBy|RankingType> [--barType=HOUR24] [--pageSize=20] ...',
103
+ );
104
+ console.error(
105
+ 'Legacy orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated (barType for TradingDesc)',
106
+ );
107
+ console.error('Or native type: NEW, PROGRESS, VOL_DAY_1, HOT, DEX, VOL, LAST, CAP, BURN, ...');
29
108
  process.exit(1);
30
109
  }
31
- const body: Record<string, string> = { orderBy };
110
+
32
111
  const barType = parseArg('barType');
33
- if (barType) body.barType = barType;
112
+ let rankingType = resolveRankingType(first, barType);
113
+
114
+ const isLegacy = (LEGACY_ORDER_BY as readonly string[]).includes(first);
115
+ if (!isLegacy && !NATIVE_RANKING_TYPES.has(rankingType)) {
116
+ console.error(`Unknown ranking type: ${first}`);
117
+ console.error(
118
+ `Use legacy: ${LEGACY_ORDER_BY.join(' | ')} or native: ${[...NATIVE_RANKING_TYPES].join(', ')}`,
119
+ );
120
+ process.exit(1);
121
+ }
122
+
123
+ const pageSizeArg = parseNumArg('pageSize');
124
+ const pageSize = pageSizeArg != null ? Math.min(100, Math.max(1, pageSizeArg)) : 20;
125
+
126
+ const body: Record<string, unknown> = {
127
+ type: rankingType,
128
+ pageSize,
129
+ };
130
+
131
+ const symbol = parseArg('symbol')?.trim();
132
+ if (symbol) body.symbol = symbol;
133
+ const version = parseArg('version')?.trim();
134
+ if (version) body.version = version;
135
+ const rankingKind = parseArg('rankingKind')?.trim();
136
+ if (rankingKind) body.rankingKind = rankingKind;
137
+
138
+ for (const key of ['minCap', 'maxCap', 'minVol', 'maxVol', 'minHold', 'maxHold'] as const) {
139
+ const n = parseNumArg(key);
140
+ if (n !== undefined) body[key] = n;
141
+ }
34
142
 
35
- const url = `${API_BASE}/private/token/query/advanced`;
143
+ const url = `${API_BASE}/public/token/ranking`;
36
144
  const res = await fetch(url, {
37
145
  method: 'POST',
38
146
  headers: {
@@ -42,7 +150,7 @@ async function main() {
42
150
  body: JSON.stringify(body),
43
151
  });
44
152
  if (!res.ok) {
45
- throw new Error(`token/query/advanced failed: ${res.status} ${await res.text()}`);
153
+ throw new Error(`token/ranking failed: ${res.status} ${await res.text()}`);
46
154
  }
47
155
  const data = await res.json();
48
156
  console.log(JSON.stringify(data, null, 2));