cito-mcp 0.6.0 → 0.6.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/dist/client.js +8 -8
- package/dist/envelope.js +4 -4
- package/dist/install.js +15 -15
- package/dist/pacing.js +2 -2
- package/dist/scrub.js +58 -20
- package/dist/tools/combat.js +96 -96
- package/dist/tools/insight.js +36 -36
- package/dist/tools/leaderboard.js +4 -4
- package/dist/tools/live.js +41 -41
- package/dist/tools/match.js +25 -21
- package/dist/tools/meta.js +69 -69
- package/dist/tools/player.js +23 -23
- package/dist/tools/rankings.js +7 -7
- package/dist/tools/resolve.js +53 -53
- package/dist/tools/schedule.js +8 -8
- package/dist/tools/standings.js +23 -23
- package/dist/tools/team.js +88 -88
- package/dist/tools/tournaments.js +2 -2
- package/dist/tools/webhooks.js +2 -2
- package/package.json +51 -52
package/dist/tools/meta.js
CHANGED
|
@@ -609,18 +609,18 @@ const GAMES_META = [
|
|
|
609
609
|
];
|
|
610
610
|
export const listCapabilities = {
|
|
611
611
|
name: 'list_capabilities',
|
|
612
|
-
description: `Curated catalog of cito-mcp tools, games, jobs, and builder recipes.
|
|
613
|
-
|
|
614
|
-
When to use:
|
|
615
|
-
- Session start or "what can you do?"
|
|
616
|
-
- Mapping app screens to tools
|
|
617
|
-
- Filtering by game or job (live_board, match_page, team_page, player_form, standings, h2h, schedule, preview, event_card, app_scaffold)
|
|
618
|
-
|
|
619
|
-
Prefer over: guessing from memory; exploring raw OpenAPI via call_api.
|
|
620
|
-
|
|
621
|
-
Do not use when: you already know the tool and have IDs — call that tool directly.
|
|
622
|
-
|
|
623
|
-
Parallel-safe: yes. API calls: 0.
|
|
612
|
+
description: `Curated catalog of cito-mcp tools, games, jobs, and builder recipes.
|
|
613
|
+
|
|
614
|
+
When to use:
|
|
615
|
+
- Session start or "what can you do?"
|
|
616
|
+
- Mapping app screens to tools
|
|
617
|
+
- Filtering by game or job (live_board, match_page, team_page, player_form, standings, h2h, schedule, preview, event_card, app_scaffold)
|
|
618
|
+
|
|
619
|
+
Prefer over: guessing from memory; exploring raw OpenAPI via call_api.
|
|
620
|
+
|
|
621
|
+
Do not use when: you already know the tool and have IDs — call that tool directly.
|
|
622
|
+
|
|
623
|
+
Parallel-safe: yes. API calls: 0.
|
|
624
624
|
Example: { "game": "cs2", "job": "live_board", "includeExamples": true }`,
|
|
625
625
|
inputSchema: {
|
|
626
626
|
type: 'object',
|
|
@@ -690,7 +690,7 @@ Example: { "game": "cs2", "job": "live_board", "includeExamples": true }`,
|
|
|
690
690
|
game: gameParse.game ?? null,
|
|
691
691
|
requestId,
|
|
692
692
|
tookMs: Date.now() - started,
|
|
693
|
-
|
|
693
|
+
apiCalls: 0,
|
|
694
694
|
data: {
|
|
695
695
|
version: CATALOG_VERSION,
|
|
696
696
|
tools,
|
|
@@ -703,18 +703,18 @@ Example: { "game": "cs2", "job": "live_board", "includeExamples": true }`,
|
|
|
703
703
|
};
|
|
704
704
|
export const apiHealth = {
|
|
705
705
|
name: 'api_health',
|
|
706
|
-
description: `API reachability, API key validity, plan tier, rate-limit headers, and best-effort included games.
|
|
707
|
-
|
|
708
|
-
When to use:
|
|
709
|
-
- Once per session before heavy work
|
|
710
|
-
- After 401/403/UNSUPPORTED_GAME/RATE_LIMIT
|
|
711
|
-
- App scaffolding entitlement checks
|
|
712
|
-
|
|
713
|
-
Prefer over: probing random game endpoints to test the key.
|
|
714
|
-
|
|
715
|
-
Do not use when: you only need live scores — use live_matches.
|
|
716
|
-
|
|
717
|
-
Parallel-safe: yes. API calls: 1–6.
|
|
706
|
+
description: `API reachability, API key validity, plan tier, rate-limit headers, and best-effort included games.
|
|
707
|
+
|
|
708
|
+
When to use:
|
|
709
|
+
- Once per session before heavy work
|
|
710
|
+
- After 401/403/UNSUPPORTED_GAME/RATE_LIMIT
|
|
711
|
+
- App scaffolding entitlement checks
|
|
712
|
+
|
|
713
|
+
Prefer over: probing random game endpoints to test the key.
|
|
714
|
+
|
|
715
|
+
Do not use when: you only need live scores — use live_matches.
|
|
716
|
+
|
|
717
|
+
Parallel-safe: yes. API calls: 1–6.
|
|
718
718
|
Example: { "includeGameProbes": true }`,
|
|
719
719
|
inputSchema: {
|
|
720
720
|
type: 'object',
|
|
@@ -726,10 +726,10 @@ Example: { "includeGameProbes": true }`,
|
|
|
726
726
|
handler: async (args, ctx) => {
|
|
727
727
|
const started = Date.now();
|
|
728
728
|
const requestId = newRequestId();
|
|
729
|
-
let
|
|
729
|
+
let apiCalls = 0;
|
|
730
730
|
let rateLimit = {};
|
|
731
731
|
const health = await fetchJson(ctx, '/health');
|
|
732
|
-
|
|
732
|
+
apiCalls += 1;
|
|
733
733
|
rateLimit = health.headers;
|
|
734
734
|
let keyValid = false;
|
|
735
735
|
let reachable = health.ok;
|
|
@@ -737,7 +737,7 @@ Example: { "includeGameProbes": true }`,
|
|
|
737
737
|
let authedStatus = health.status;
|
|
738
738
|
if (!health.ok) {
|
|
739
739
|
const fallback = await fetchJson(ctx, '/lol/leagues');
|
|
740
|
-
|
|
740
|
+
apiCalls += 1;
|
|
741
741
|
rateLimit = fallback.headers;
|
|
742
742
|
if (fallback.ok) {
|
|
743
743
|
keyValid = true;
|
|
@@ -753,14 +753,14 @@ Example: { "includeGameProbes": true }`,
|
|
|
753
753
|
source: 'api_health',
|
|
754
754
|
requestId,
|
|
755
755
|
tookMs: Date.now() - started,
|
|
756
|
-
|
|
756
|
+
apiCalls,
|
|
757
757
|
rateLimit: fallback.headers,
|
|
758
758
|
httpStatus: fallback.status,
|
|
759
759
|
});
|
|
760
760
|
}
|
|
761
761
|
else {
|
|
762
762
|
const cs2 = await fetchJson(ctx, '/cs2');
|
|
763
|
-
|
|
763
|
+
apiCalls += 1;
|
|
764
764
|
rateLimit = cs2.headers;
|
|
765
765
|
if (cs2.ok) {
|
|
766
766
|
keyValid = true;
|
|
@@ -776,7 +776,7 @@ Example: { "includeGameProbes": true }`,
|
|
|
776
776
|
}
|
|
777
777
|
else {
|
|
778
778
|
const probe = await fetchJson(ctx, '/lol/leagues');
|
|
779
|
-
|
|
779
|
+
apiCalls += 1;
|
|
780
780
|
rateLimit = { ...rateLimit, ...probe.headers };
|
|
781
781
|
keyValid = probe.ok || probe.status === 403;
|
|
782
782
|
if (probe.ok)
|
|
@@ -801,7 +801,7 @@ Example: { "includeGameProbes": true }`,
|
|
|
801
801
|
const res = await fetchJson(ctx, path);
|
|
802
802
|
return { game, path, res };
|
|
803
803
|
}));
|
|
804
|
-
|
|
804
|
+
apiCalls += results.length;
|
|
805
805
|
for (const { game, res } of results) {
|
|
806
806
|
probes.push({ game, ok: res.ok, httpStatus: res.status });
|
|
807
807
|
if (res.ok)
|
|
@@ -837,7 +837,7 @@ Example: { "includeGameProbes": true }`,
|
|
|
837
837
|
game: null,
|
|
838
838
|
requestId,
|
|
839
839
|
tookMs: Date.now() - started,
|
|
840
|
-
|
|
840
|
+
apiCalls,
|
|
841
841
|
rateLimit: mergedRateLimit,
|
|
842
842
|
data: {
|
|
843
843
|
reachable,
|
|
@@ -888,24 +888,24 @@ function pathAllowed(path) {
|
|
|
888
888
|
}
|
|
889
889
|
export const callApi = {
|
|
890
890
|
name: 'call_api',
|
|
891
|
-
description: `Power escape hatch: allowlisted Cito REST call with unshaped raw JSON in data.raw.
|
|
892
|
-
|
|
893
|
-
When to use:
|
|
894
|
-
- Long-tail paths not yet curated (Fortnite, CS2 leaderboards, niche stats)
|
|
895
|
-
- Debugging payloads while building an app
|
|
896
|
-
- User explicitly knows an OpenAPI path
|
|
897
|
-
|
|
898
|
-
Prefer curated tools for all standard jobs (live, schedule, profiles, standings, H2H, previews).
|
|
899
|
-
|
|
900
|
-
Do not use when: a curated tool covers the outcome. Avoid parallel storms; same plan rate limits apply.
|
|
901
|
-
|
|
902
|
-
Paths are relative to the API base, so "/tennis/players", not "/api/v1/tennis/players". Put query params in query or queryJson, not in the path.
|
|
903
|
-
Tennis: /tennis/h2h takes players=a,b, or player1_id and player2_id (one form is required). /tennis/players has limit up to 100 (over that is a 422; use /tennis/players/batch for a roster). /tennis/tournaments/calendar needs no year (default this year) and returns every row unless given limit. /tennis/rankings defaults to rank_max=100: pass rank_max=5000 for the whole list. /tennis/schedule returns the whole day unless given limit.
|
|
904
|
-
|
|
905
|
-
Path must start with / and match allowlisted prefixes: /health, /lol, /cs2, /dota2, /cod, /ufc, /fortnite, /apex, /tennis, /raf, /bkfc, /bellator, /pride, /strikeforce, /wec, /dream, /elitexc, /affliction, /pfl, /oktagon, /mma.
|
|
906
|
-
Rejects absolute URLs and path traversal → PATH_NOT_ALLOWED.
|
|
907
|
-
|
|
908
|
-
Parallel-safe: yes but discouraged in bulk. API calls: 1.
|
|
891
|
+
description: `Power escape hatch: allowlisted Cito REST call with unshaped raw JSON in data.raw.
|
|
892
|
+
|
|
893
|
+
When to use:
|
|
894
|
+
- Long-tail paths not yet curated (Fortnite, CS2 leaderboards, niche stats)
|
|
895
|
+
- Debugging payloads while building an app
|
|
896
|
+
- User explicitly knows an OpenAPI path
|
|
897
|
+
|
|
898
|
+
Prefer curated tools for all standard jobs (live, schedule, profiles, standings, H2H, previews).
|
|
899
|
+
|
|
900
|
+
Do not use when: a curated tool covers the outcome. Avoid parallel storms; same plan rate limits apply.
|
|
901
|
+
|
|
902
|
+
Paths are relative to the API base, so "/tennis/players", not "/api/v1/tennis/players". Put query params in query or queryJson, not in the path.
|
|
903
|
+
Tennis: /tennis/h2h takes players=a,b, or player1_id and player2_id (one form is required). /tennis/players has limit up to 100 (over that is a 422; use /tennis/players/batch for a roster). /tennis/tournaments/calendar needs no year (default this year) and returns every row unless given limit. /tennis/rankings defaults to rank_max=100: pass rank_max=5000 for the whole list. /tennis/schedule returns the whole day unless given limit.
|
|
904
|
+
|
|
905
|
+
Path must start with / and match allowlisted prefixes: /health, /lol, /cs2, /dota2, /cod, /ufc, /fortnite, /apex, /tennis, /raf, /bkfc, /bellator, /pride, /strikeforce, /wec, /dream, /elitexc, /affliction, /pfl, /oktagon, /mma.
|
|
906
|
+
Rejects absolute URLs and path traversal → PATH_NOT_ALLOWED.
|
|
907
|
+
|
|
908
|
+
Parallel-safe: yes but discouraged in bulk. API calls: 1.
|
|
909
909
|
Example: { "method": "GET", "path": "/cs2/rankings/teams", "queryJson": "{\\"page\\":1,\\"limit\\":20}" }`,
|
|
910
910
|
inputSchema: {
|
|
911
911
|
type: 'object',
|
|
@@ -998,7 +998,7 @@ Example: { "method": "GET", "path": "/cs2/rankings/teams", "queryJson": "{\\"pag
|
|
|
998
998
|
source: 'call_api',
|
|
999
999
|
requestId,
|
|
1000
1000
|
tookMs: Date.now() - started,
|
|
1001
|
-
|
|
1001
|
+
apiCalls: 1,
|
|
1002
1002
|
rateLimit: res.headers,
|
|
1003
1003
|
httpStatus: res.status,
|
|
1004
1004
|
details: { path, method, bodyPreview: present(res.text, 2000) },
|
|
@@ -1009,7 +1009,7 @@ Example: { "method": "GET", "path": "/cs2/rankings/teams", "queryJson": "{\\"pag
|
|
|
1009
1009
|
game: null,
|
|
1010
1010
|
requestId,
|
|
1011
1011
|
tookMs: Date.now() - started,
|
|
1012
|
-
|
|
1012
|
+
apiCalls: 1,
|
|
1013
1013
|
rateLimit: res.headers,
|
|
1014
1014
|
warnings: ['Unshaped raw response — prefer curated tools when available'],
|
|
1015
1015
|
data: {
|
|
@@ -1031,20 +1031,20 @@ const SPEC_OMITS = {
|
|
|
1031
1031
|
};
|
|
1032
1032
|
export const listRoutes = {
|
|
1033
1033
|
name: 'list_routes',
|
|
1034
|
-
description: `Index of raw REST routes from the live OpenAPI spec: method, path, summary, tag.
|
|
1035
|
-
|
|
1036
|
-
When to use:
|
|
1037
|
-
- You need a long-tail path for call_api and do not want to guess
|
|
1038
|
-
- Checking whether an endpoint exists before building around it
|
|
1039
|
-
- Mapping what raw data backs a curated tool
|
|
1040
|
-
|
|
1041
|
-
Prefer curated tools for standard jobs — this indexes the escape hatch, it is not a replacement for list_capabilities.
|
|
1042
|
-
|
|
1043
|
-
Do not use when: a curated tool already covers the outcome (call list_capabilities instead).
|
|
1044
|
-
|
|
1045
|
-
Note: the spec omits /lol entirely, though LoL routes work. Filtering by game=lol returns that caveat rather than an empty list.
|
|
1046
|
-
|
|
1047
|
-
Parallel-safe: yes. API calls: 1.
|
|
1034
|
+
description: `Index of raw REST routes from the live OpenAPI spec: method, path, summary, tag.
|
|
1035
|
+
|
|
1036
|
+
When to use:
|
|
1037
|
+
- You need a long-tail path for call_api and do not want to guess
|
|
1038
|
+
- Checking whether an endpoint exists before building around it
|
|
1039
|
+
- Mapping what raw data backs a curated tool
|
|
1040
|
+
|
|
1041
|
+
Prefer curated tools for standard jobs — this indexes the escape hatch, it is not a replacement for list_capabilities.
|
|
1042
|
+
|
|
1043
|
+
Do not use when: a curated tool already covers the outcome (call list_capabilities instead).
|
|
1044
|
+
|
|
1045
|
+
Note: the spec omits /lol entirely, though LoL routes work. Filtering by game=lol returns that caveat rather than an empty list.
|
|
1046
|
+
|
|
1047
|
+
Parallel-safe: yes. API calls: 1.
|
|
1048
1048
|
Example: { "game": "ufc", "q": "rankings" }`,
|
|
1049
1049
|
inputSchema: {
|
|
1050
1050
|
type: 'object',
|
|
@@ -1089,7 +1089,7 @@ Example: { "game": "ufc", "q": "rankings" }`,
|
|
|
1089
1089
|
source: 'list_routes',
|
|
1090
1090
|
requestId,
|
|
1091
1091
|
tookMs: Date.now() - started,
|
|
1092
|
-
|
|
1092
|
+
apiCalls: 1,
|
|
1093
1093
|
rateLimit: res.headers,
|
|
1094
1094
|
httpStatus: res.status,
|
|
1095
1095
|
recover: [
|
|
@@ -1151,7 +1151,7 @@ Example: { "game": "ufc", "q": "rankings" }`,
|
|
|
1151
1151
|
source: 'list_routes',
|
|
1152
1152
|
requestId,
|
|
1153
1153
|
tookMs: Date.now() - started,
|
|
1154
|
-
|
|
1154
|
+
apiCalls: 1,
|
|
1155
1155
|
rateLimit: res.headers,
|
|
1156
1156
|
});
|
|
1157
1157
|
},
|
package/dist/tools/player.js
CHANGED
|
@@ -147,7 +147,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
147
147
|
const includeTrends = args.includeTrends !== false;
|
|
148
148
|
const view = args.view === 'full' ? 'full' : args.view === 'compact' ? 'compact' : 'summary';
|
|
149
149
|
const partial = [];
|
|
150
|
-
let
|
|
150
|
+
let apiCalls = 0;
|
|
151
151
|
let rateLimit = {};
|
|
152
152
|
let primaryPath = '';
|
|
153
153
|
if (game === 'lol')
|
|
@@ -165,7 +165,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
165
165
|
let playerRaw = null;
|
|
166
166
|
if (game === 'dota2') {
|
|
167
167
|
const list = await fetchJson(ctx, '/dota2/players', { query: { search: idOrSlug, limit: 5 } });
|
|
168
|
-
|
|
168
|
+
apiCalls += 1;
|
|
169
169
|
rateLimit = list.headers;
|
|
170
170
|
if (list.ok) {
|
|
171
171
|
const rows = extractRows(list.data);
|
|
@@ -182,7 +182,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
182
182
|
}
|
|
183
183
|
else {
|
|
184
184
|
const res = await fetchJson(ctx, primaryPath);
|
|
185
|
-
|
|
185
|
+
apiCalls += 1;
|
|
186
186
|
rateLimit = res.headers;
|
|
187
187
|
if (!res.ok) {
|
|
188
188
|
return errorEnvelope({
|
|
@@ -192,7 +192,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
192
192
|
source: 'player_profile',
|
|
193
193
|
requestId,
|
|
194
194
|
tookMs: Date.now() - started,
|
|
195
|
-
|
|
195
|
+
apiCalls,
|
|
196
196
|
rateLimit: res.headers,
|
|
197
197
|
httpStatus: res.status,
|
|
198
198
|
});
|
|
@@ -210,7 +210,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
210
210
|
if (game === 'lol') {
|
|
211
211
|
tasks.push((async () => {
|
|
212
212
|
const res = await fetchJson(ctx, `/lol/players/${encodeURIComponent(idOrSlug)}/teams`);
|
|
213
|
-
|
|
213
|
+
apiCalls += 1;
|
|
214
214
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
215
215
|
if (res.ok) {
|
|
216
216
|
const rows = extractRows(res.data);
|
|
@@ -248,7 +248,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
248
248
|
const res = await fetchJson(ctx, `/lol/players/${encodeURIComponent(idOrSlug)}/matches`, {
|
|
249
249
|
query: { limit: String(recentLimit) },
|
|
250
250
|
});
|
|
251
|
-
|
|
251
|
+
apiCalls += 1;
|
|
252
252
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
253
253
|
if (res.ok) {
|
|
254
254
|
const startMs = (row) => {
|
|
@@ -269,7 +269,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
269
269
|
const names = new Map();
|
|
270
270
|
await Promise.all(slugs.map(async (sl) => {
|
|
271
271
|
const t = await fetchJson(ctx, `/lol/teams/${encodeURIComponent(sl)}`);
|
|
272
|
-
|
|
272
|
+
apiCalls += 1;
|
|
273
273
|
if (!t.ok)
|
|
274
274
|
return;
|
|
275
275
|
const body = asRecord(t.data) ?? {};
|
|
@@ -301,7 +301,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
301
301
|
if (includeTrends) {
|
|
302
302
|
tasks.push((async () => {
|
|
303
303
|
const res = await fetchJson(ctx, `/tennis/players/${encodeURIComponent(idOrSlug)}/stats`);
|
|
304
|
-
|
|
304
|
+
apiCalls += 1;
|
|
305
305
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
306
306
|
if (res.ok)
|
|
307
307
|
career = unwrapPayload(res.data);
|
|
@@ -318,7 +318,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
318
318
|
const res = await fetchJson(ctx, `/tennis/players/${encodeURIComponent(idOrSlug)}/matches`, {
|
|
319
319
|
query: { page_size: recentLimit, ...(view === 'compact' ? { view: 'summary' } : {}) },
|
|
320
320
|
});
|
|
321
|
-
|
|
321
|
+
apiCalls += 1;
|
|
322
322
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
323
323
|
if (res.ok) {
|
|
324
324
|
const envelope = asRecord(res.data) ?? {};
|
|
@@ -342,7 +342,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
342
342
|
]) {
|
|
343
343
|
tasks.push((async () => {
|
|
344
344
|
const res = await fetchJson(ctx, path);
|
|
345
|
-
|
|
345
|
+
apiCalls += 1;
|
|
346
346
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
347
347
|
if (!res.ok) {
|
|
348
348
|
partial.push(partialFromRejection(section, {
|
|
@@ -377,7 +377,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
377
377
|
const res = await fetchJson(ctx, `/dota2/players/${encodeURIComponent(idOrSlug)}/radar`, {
|
|
378
378
|
query,
|
|
379
379
|
});
|
|
380
|
-
|
|
380
|
+
apiCalls += 1;
|
|
381
381
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
382
382
|
if (res.ok) {
|
|
383
383
|
radar = res.data;
|
|
@@ -400,7 +400,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
400
400
|
if (game === 'cod') {
|
|
401
401
|
tasks.push((async () => {
|
|
402
402
|
const res = await fetchJson(ctx, `/cod/players/${encodeURIComponent(idOrSlug)}/stats`);
|
|
403
|
-
|
|
403
|
+
apiCalls += 1;
|
|
404
404
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
405
405
|
if (res.ok) {
|
|
406
406
|
seasonStats = res.data;
|
|
@@ -418,7 +418,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
418
418
|
const res = await fetchJson(ctx, `/cod/players/${encodeURIComponent(idOrSlug)}/matches`, {
|
|
419
419
|
query: { limit: recentLimit },
|
|
420
420
|
});
|
|
421
|
-
|
|
421
|
+
apiCalls += 1;
|
|
422
422
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
423
423
|
if (res.ok) {
|
|
424
424
|
recentMatches = extractRows(res.data)
|
|
@@ -438,7 +438,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
438
438
|
const fighterKey = slug || idOrSlug;
|
|
439
439
|
tasks.push((async () => {
|
|
440
440
|
const res = await fetchJson(ctx, `/ufc/fighters/${encodeURIComponent(fighterKey)}/stats`);
|
|
441
|
-
|
|
441
|
+
apiCalls += 1;
|
|
442
442
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
443
443
|
if (res.ok) {
|
|
444
444
|
const metrics = unwrapPayload(res.data);
|
|
@@ -456,7 +456,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
456
456
|
const res = await fetchJson(ctx, `/ufc/fighters/${encodeURIComponent(fighterKey)}/fights`, {
|
|
457
457
|
query: { limit: recentLimit },
|
|
458
458
|
});
|
|
459
|
-
|
|
459
|
+
apiCalls += 1;
|
|
460
460
|
rateLimit = { ...rateLimit, ...res.headers };
|
|
461
461
|
if (res.ok) {
|
|
462
462
|
recentMatches = extractRows(res.data)
|
|
@@ -477,7 +477,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
477
477
|
const hist = await fetchJson(ctx, `/ufc/fighters/${encodeURIComponent(fighterKey)}/history`, {
|
|
478
478
|
query: { limit: recentLimit },
|
|
479
479
|
});
|
|
480
|
-
|
|
480
|
+
apiCalls += 1;
|
|
481
481
|
rateLimit = { ...rateLimit, ...hist.headers };
|
|
482
482
|
if (hist.ok) {
|
|
483
483
|
recentMatches = extractRows(hist.data)
|
|
@@ -507,7 +507,7 @@ Example: { "game": "cs2", "playerId": "cs2-player-1", "recentLimit": 10, "includ
|
|
|
507
507
|
game,
|
|
508
508
|
requestId,
|
|
509
509
|
tookMs: Date.now() - started,
|
|
510
|
-
|
|
510
|
+
apiCalls,
|
|
511
511
|
rateLimit,
|
|
512
512
|
partial: partial.length ? partial : undefined,
|
|
513
513
|
entities: {
|
|
@@ -656,7 +656,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
656
656
|
source: 'player_form',
|
|
657
657
|
requestId,
|
|
658
658
|
tookMs: Date.now() - started,
|
|
659
|
-
|
|
659
|
+
apiCalls: 1,
|
|
660
660
|
httpStatus: res.status,
|
|
661
661
|
rateLimit: res.headers,
|
|
662
662
|
});
|
|
@@ -695,7 +695,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
695
695
|
game,
|
|
696
696
|
requestId,
|
|
697
697
|
tookMs: Date.now() - started,
|
|
698
|
-
|
|
698
|
+
apiCalls: 1,
|
|
699
699
|
rateLimit: res.headers,
|
|
700
700
|
entities: {
|
|
701
701
|
games: [game],
|
|
@@ -805,7 +805,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
805
805
|
source: 'player_matches',
|
|
806
806
|
requestId,
|
|
807
807
|
tookMs: Date.now() - started,
|
|
808
|
-
|
|
808
|
+
apiCalls: 1,
|
|
809
809
|
httpStatus: res.status,
|
|
810
810
|
rateLimit: res.headers,
|
|
811
811
|
recover: ['Check the player id with search_entities'],
|
|
@@ -873,7 +873,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
873
873
|
game,
|
|
874
874
|
requestId,
|
|
875
875
|
tookMs: Date.now() - started,
|
|
876
|
-
|
|
876
|
+
apiCalls: 1,
|
|
877
877
|
rateLimit: res.headers,
|
|
878
878
|
entities: { games: [game], ids: { playerId } },
|
|
879
879
|
data: {
|
|
@@ -982,7 +982,7 @@ API calls: 1.`,
|
|
|
982
982
|
source: 'player_stats',
|
|
983
983
|
requestId,
|
|
984
984
|
tookMs: Date.now() - started,
|
|
985
|
-
|
|
985
|
+
apiCalls: 1,
|
|
986
986
|
httpStatus: res.status,
|
|
987
987
|
rateLimit: res.headers,
|
|
988
988
|
recover: ['Check the player id with search_entities'],
|
|
@@ -1071,7 +1071,7 @@ API calls: 1.`,
|
|
|
1071
1071
|
game,
|
|
1072
1072
|
requestId,
|
|
1073
1073
|
tookMs: Date.now() - started,
|
|
1074
|
-
|
|
1074
|
+
apiCalls: 1,
|
|
1075
1075
|
rateLimit: res.headers,
|
|
1076
1076
|
entities: { games: [game], ids: { playerId } },
|
|
1077
1077
|
data: {
|
package/dist/tools/rankings.js
CHANGED
|
@@ -193,7 +193,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
193
193
|
source: 'rankings_movers',
|
|
194
194
|
requestId,
|
|
195
195
|
tookMs: Date.now() - started,
|
|
196
|
-
|
|
196
|
+
apiCalls: 1,
|
|
197
197
|
httpStatus: res.status,
|
|
198
198
|
rateLimit: res.headers,
|
|
199
199
|
});
|
|
@@ -248,7 +248,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
248
248
|
game,
|
|
249
249
|
requestId,
|
|
250
250
|
tookMs: Date.now() - started,
|
|
251
|
-
|
|
251
|
+
apiCalls: 1,
|
|
252
252
|
rateLimit: res.headers,
|
|
253
253
|
warnings: warnings.length ? warnings : undefined,
|
|
254
254
|
data: {
|
|
@@ -370,7 +370,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
370
370
|
source: 'player_rankings_history',
|
|
371
371
|
requestId,
|
|
372
372
|
tookMs: Date.now() - started,
|
|
373
|
-
|
|
373
|
+
apiCalls: 1,
|
|
374
374
|
httpStatus: res.status,
|
|
375
375
|
rateLimit: res.headers,
|
|
376
376
|
recover: ['Check the player id with search_entities'],
|
|
@@ -390,10 +390,10 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
390
390
|
const inWindow = sinceRaw
|
|
391
391
|
? allHistory.filter((h) => h.date !== null && h.date >= sinceRaw)
|
|
392
392
|
: allHistory;
|
|
393
|
-
const
|
|
393
|
+
const pagedApi = typeof body.total === 'number' && typeof body.order === 'string';
|
|
394
394
|
let total;
|
|
395
395
|
let history;
|
|
396
|
-
if (
|
|
396
|
+
if (pagedApi) {
|
|
397
397
|
total = body.total;
|
|
398
398
|
history = body.order === 'desc' ? [...inWindow].reverse() : inWindow;
|
|
399
399
|
}
|
|
@@ -404,7 +404,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
404
404
|
}
|
|
405
405
|
const omittedNewer = Math.min(total, (page - 1) * limit);
|
|
406
406
|
const omittedOlder = Math.max(0, total - omittedNewer - history.length);
|
|
407
|
-
const hasMore =
|
|
407
|
+
const hasMore = pagedApi && typeof body.has_next === 'boolean' ? body.has_next : omittedOlder > 0;
|
|
408
408
|
const best = history.reduce((acc, h) => {
|
|
409
409
|
if (h.rank === null)
|
|
410
410
|
return acc;
|
|
@@ -425,7 +425,7 @@ Parallel-safe: yes. API calls: 1.`,
|
|
|
425
425
|
game,
|
|
426
426
|
requestId,
|
|
427
427
|
tookMs: Date.now() - started,
|
|
428
|
-
|
|
428
|
+
apiCalls: 1,
|
|
429
429
|
rateLimit: res.headers,
|
|
430
430
|
data: {
|
|
431
431
|
title: `${pickString(body.player_name) ?? playerId} ranking history`,
|