@claudinho/cli 0.1.1 → 0.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 +59 -7
- package/dist/index.js +1385 -399
- package/package.json +14 -13
package/dist/index.js
CHANGED
|
@@ -3,173 +3,6 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
|
-
// src/config.ts
|
|
7
|
-
var SUPPORTED_LANGS = ["en", "es", "pt", "fr"];
|
|
8
|
-
function pickLang(explicit) {
|
|
9
|
-
const candidates = [
|
|
10
|
-
explicit,
|
|
11
|
-
process.env.CLAUDINHO_LANG,
|
|
12
|
-
process.env.LANG?.split(".")[0]?.split("_")[0]
|
|
13
|
-
];
|
|
14
|
-
for (const c of candidates) {
|
|
15
|
-
if (c && SUPPORTED_LANGS.includes(c)) {
|
|
16
|
-
return c;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return "en";
|
|
20
|
-
}
|
|
21
|
-
function pickColor(explicit) {
|
|
22
|
-
if (explicit === false) return false;
|
|
23
|
-
if (process.env.NO_COLOR) return false;
|
|
24
|
-
if (!process.stdout.isTTY) return false;
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
function isSupportedLang(s) {
|
|
28
|
-
return SUPPORTED_LANGS.includes(s);
|
|
29
|
-
}
|
|
30
|
-
function resolveConfig(opts) {
|
|
31
|
-
const langRequestedUnsupported = opts.lang && !isSupportedLang(opts.lang) ? opts.lang : void 0;
|
|
32
|
-
return {
|
|
33
|
-
lang: pickLang(opts.lang),
|
|
34
|
-
tz: opts.tz ?? process.env.CLAUDINHO_TZ ?? void 0,
|
|
35
|
-
json: opts.json ?? false,
|
|
36
|
-
color: pickColor(opts.color),
|
|
37
|
-
source: opts.source ?? process.env.CLAUDINHO_SOURCE ?? "espn",
|
|
38
|
-
langRequestedUnsupported
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/i18n.ts
|
|
43
|
-
var EN = {
|
|
44
|
-
"today.title": "Today's matches",
|
|
45
|
-
"today.on": "Matches",
|
|
46
|
-
"today.none": "No matches scheduled for this date.",
|
|
47
|
-
"live.title": "Live now",
|
|
48
|
-
"live.none": "No matches in play right now.",
|
|
49
|
-
"next.none": "No upcoming fixture found for {team}.",
|
|
50
|
-
"next.label": "Next up for {team}",
|
|
51
|
-
"next.in": "in {countdown}",
|
|
52
|
-
"table.title": "Group {group}",
|
|
53
|
-
"table.none": "No group found for {group}.",
|
|
54
|
-
"match.none": "No match found with id {id}.",
|
|
55
|
-
"status.scheduled": "scheduled",
|
|
56
|
-
"status.live": "LIVE",
|
|
57
|
-
"status.ht": "HT",
|
|
58
|
-
"status.ft": "FT",
|
|
59
|
-
"status.postponed": "postponed",
|
|
60
|
-
"status.cancelled": "cancelled",
|
|
61
|
-
"col.team": "Team",
|
|
62
|
-
"col.p": "P",
|
|
63
|
-
"col.w": "W",
|
|
64
|
-
"col.d": "D",
|
|
65
|
-
"col.l": "L",
|
|
66
|
-
"col.gd": "GD",
|
|
67
|
-
"col.pts": "Pts",
|
|
68
|
-
"err.date": "Invalid date {date}. Use YYYY-MM-DD.",
|
|
69
|
-
"warn.tz": "Unknown timezone {tz}; using system timezone.",
|
|
70
|
-
"warn.lang": "Unsupported language {lang}; using English. (supported: en, es, pt, fr)",
|
|
71
|
-
disclaimer: "Not affiliated with FIFA or Anthropic."
|
|
72
|
-
};
|
|
73
|
-
var ES = {
|
|
74
|
-
"today.title": "Partidos de hoy",
|
|
75
|
-
"today.on": "Partidos",
|
|
76
|
-
"today.none": "No hay partidos para esta fecha.",
|
|
77
|
-
"live.title": "En vivo",
|
|
78
|
-
"live.none": "No hay partidos en juego ahora mismo.",
|
|
79
|
-
"next.none": "No se encontr\xF3 pr\xF3ximo partido para {team}.",
|
|
80
|
-
"next.label": "Pr\xF3ximo de {team}",
|
|
81
|
-
"next.in": "en {countdown}",
|
|
82
|
-
"table.title": "Grupo {group}",
|
|
83
|
-
"table.none": "No se encontr\xF3 el grupo {group}.",
|
|
84
|
-
"match.none": "No se encontr\xF3 partido con id {id}.",
|
|
85
|
-
"status.scheduled": "programado",
|
|
86
|
-
"status.live": "EN VIVO",
|
|
87
|
-
"status.ht": "DESC",
|
|
88
|
-
"status.ft": "FIN",
|
|
89
|
-
"status.postponed": "aplazado",
|
|
90
|
-
"status.cancelled": "cancelado",
|
|
91
|
-
"col.team": "Equipo",
|
|
92
|
-
"col.p": "PJ",
|
|
93
|
-
"col.w": "G",
|
|
94
|
-
"col.d": "E",
|
|
95
|
-
"col.l": "P",
|
|
96
|
-
"col.gd": "DG",
|
|
97
|
-
"col.pts": "Pts",
|
|
98
|
-
"err.date": "Fecha inv\xE1lida {date}. Usa AAAA-MM-DD.",
|
|
99
|
-
"warn.tz": "Zona horaria desconocida {tz}; usando la del sistema.",
|
|
100
|
-
"warn.lang": "Idioma no soportado {lang}; usando ingl\xE9s. (disponibles: en, es, pt, fr)",
|
|
101
|
-
disclaimer: "No afiliado a FIFA ni Anthropic."
|
|
102
|
-
};
|
|
103
|
-
var PT = {
|
|
104
|
-
"today.title": "Jogos de hoje",
|
|
105
|
-
"today.on": "Jogos",
|
|
106
|
-
"today.none": "Nenhum jogo para esta data.",
|
|
107
|
-
"live.title": "Ao vivo",
|
|
108
|
-
"live.none": "Nenhum jogo em andamento agora.",
|
|
109
|
-
"next.none": "Nenhum pr\xF3ximo jogo encontrado para {team}.",
|
|
110
|
-
"next.label": "Pr\xF3ximo de {team}",
|
|
111
|
-
"next.in": "em {countdown}",
|
|
112
|
-
"table.title": "Grupo {group}",
|
|
113
|
-
"table.none": "Grupo {group} n\xE3o encontrado.",
|
|
114
|
-
"match.none": "Nenhum jogo encontrado com id {id}.",
|
|
115
|
-
"status.scheduled": "agendado",
|
|
116
|
-
"status.live": "AO VIVO",
|
|
117
|
-
"status.ht": "INT",
|
|
118
|
-
"status.ft": "FIM",
|
|
119
|
-
"status.postponed": "adiado",
|
|
120
|
-
"status.cancelled": "cancelado",
|
|
121
|
-
"col.team": "Sele\xE7\xE3o",
|
|
122
|
-
"col.p": "J",
|
|
123
|
-
"col.w": "V",
|
|
124
|
-
"col.d": "E",
|
|
125
|
-
"col.l": "D",
|
|
126
|
-
"col.gd": "SG",
|
|
127
|
-
"col.pts": "Pts",
|
|
128
|
-
"err.date": "Data inv\xE1lida {date}. Use AAAA-MM-DD.",
|
|
129
|
-
"warn.tz": "Fuso hor\xE1rio desconhecido {tz}; usando o do sistema.",
|
|
130
|
-
"warn.lang": "Idioma n\xE3o suportado {lang}; usando ingl\xEAs. (dispon\xEDveis: en, es, pt, fr)",
|
|
131
|
-
disclaimer: "N\xE3o afiliado \xE0 FIFA nem \xE0 Anthropic."
|
|
132
|
-
};
|
|
133
|
-
var FR = {
|
|
134
|
-
"today.title": "Matchs d'aujourd'hui",
|
|
135
|
-
"today.on": "Matchs",
|
|
136
|
-
"today.none": "Aucun match pr\xE9vu pour cette date.",
|
|
137
|
-
"live.title": "En direct",
|
|
138
|
-
"live.none": "Aucun match en cours pour l'instant.",
|
|
139
|
-
"next.none": "Aucun prochain match trouv\xE9 pour {team}.",
|
|
140
|
-
"next.label": "Prochain match de {team}",
|
|
141
|
-
"next.in": "dans {countdown}",
|
|
142
|
-
"table.title": "Groupe {group}",
|
|
143
|
-
"table.none": "Groupe {group} introuvable.",
|
|
144
|
-
"match.none": "Aucun match trouv\xE9 avec id {id}.",
|
|
145
|
-
"status.scheduled": "pr\xE9vu",
|
|
146
|
-
"status.live": "DIRECT",
|
|
147
|
-
"status.ht": "MT",
|
|
148
|
-
"status.ft": "FIN",
|
|
149
|
-
"status.postponed": "report\xE9",
|
|
150
|
-
"status.cancelled": "annul\xE9",
|
|
151
|
-
"col.team": "\xC9quipe",
|
|
152
|
-
"col.p": "J",
|
|
153
|
-
"col.w": "G",
|
|
154
|
-
"col.d": "N",
|
|
155
|
-
"col.l": "P",
|
|
156
|
-
"col.gd": "Diff",
|
|
157
|
-
"col.pts": "Pts",
|
|
158
|
-
"err.date": "Date invalide {date}. Utilisez AAAA-MM-JJ.",
|
|
159
|
-
"warn.tz": "Fuseau horaire inconnu {tz} ; utilisation du fuseau syst\xE8me.",
|
|
160
|
-
"warn.lang": "Langue non prise en charge {lang} ; utilisation de l\u2019anglais. (disponibles : en, es, pt, fr)",
|
|
161
|
-
disclaimer: "Non affili\xE9 \xE0 la FIFA ni \xE0 Anthropic."
|
|
162
|
-
};
|
|
163
|
-
var CATALOGS = { en: EN, es: ES, pt: PT, fr: FR };
|
|
164
|
-
function makeT(lang) {
|
|
165
|
-
const dict = CATALOGS[lang] ?? EN;
|
|
166
|
-
return (key, vars) => {
|
|
167
|
-
let s = dict[key] ?? EN[key] ?? key;
|
|
168
|
-
if (vars) for (const [k, v] of Object.entries(vars)) s = s.replace(`{${k}}`, v);
|
|
169
|
-
return s;
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
6
|
// ../core/dist/index.js
|
|
174
7
|
var REGIONAL_INDICATOR_A = 127462;
|
|
175
8
|
var TAG_BASE = 917504;
|
|
@@ -458,9 +291,18 @@ function resolveTz(explicit) {
|
|
|
458
291
|
if (fromEnv && isValidTimeZone(fromEnv)) return fromEnv;
|
|
459
292
|
return systemTz();
|
|
460
293
|
}
|
|
294
|
+
function safeLocale(locale) {
|
|
295
|
+
if (!locale) return "en";
|
|
296
|
+
try {
|
|
297
|
+
Intl.getCanonicalLocales(locale);
|
|
298
|
+
return locale;
|
|
299
|
+
} catch {
|
|
300
|
+
return "en";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
461
303
|
function formatKickoff(iso, opts = {}) {
|
|
462
304
|
const tz = resolveTz(opts.tz);
|
|
463
|
-
const locale = opts.locale
|
|
305
|
+
const locale = safeLocale(opts.locale);
|
|
464
306
|
return new Intl.DateTimeFormat(locale, {
|
|
465
307
|
weekday: "short",
|
|
466
308
|
hour: "2-digit",
|
|
@@ -499,9 +341,80 @@ function scoreline(match) {
|
|
|
499
341
|
if (!match.score) return "vs";
|
|
500
342
|
return `${match.score.home}\u2013${match.score.away}`;
|
|
501
343
|
}
|
|
344
|
+
function matchLocation(match) {
|
|
345
|
+
return [match.venue, match.city, match.country].filter(Boolean).join(", ");
|
|
346
|
+
}
|
|
502
347
|
function byKickoff(a, b) {
|
|
503
348
|
return a.kickoff.localeCompare(b.kickoff);
|
|
504
349
|
}
|
|
350
|
+
var FLAVOR_LEVELS = ["off", "subtle", "full"];
|
|
351
|
+
var DEFAULT_FLAVOR = "full";
|
|
352
|
+
function isFlavorLevel(s) {
|
|
353
|
+
return FLAVOR_LEVELS.includes(s);
|
|
354
|
+
}
|
|
355
|
+
function asFlavorLevel(s) {
|
|
356
|
+
return s && isFlavorLevel(s) ? s : DEFAULT_FLAVOR;
|
|
357
|
+
}
|
|
358
|
+
var BANKS = {
|
|
359
|
+
en: {
|
|
360
|
+
scheduled: ["the big one is coming!", "mark your calendar!", "football is in the air!"],
|
|
361
|
+
live: ["the tension is electric!", "eyes glued to the pitch!", "anything can happen!"],
|
|
362
|
+
goal: ["GOOOAL!", "what a strike!", "the stadium erupts!", "they buried it!"],
|
|
363
|
+
ft: ["the final whistle blows!", "it's all over!", "into the history books!"]
|
|
364
|
+
},
|
|
365
|
+
es: {
|
|
366
|
+
scheduled: ["\xA1se viene el partidazo!", "\xA1huele a f\xFAtbol!", "\xA1a cancha llena!"],
|
|
367
|
+
live: ["\xA1est\xE1 que arde!", "\xA1vibra el estadio!", "\xA1no despeguen los ojos!"],
|
|
368
|
+
goal: ["\xA1GOOOOL!", "\xA1qu\xE9 golazo!", "\xA1para callar bocas!", "\xA1se cae el estadio!"],
|
|
369
|
+
ft: ["\xA1suena el silbatazo final!", "\xA1se acab\xF3, se\xF1ores!", "\xA1a los libros de historia!"]
|
|
370
|
+
},
|
|
371
|
+
pt: {
|
|
372
|
+
scheduled: ["vem jog\xE3o por a\xED!", "cheira a futebol!", "est\xE1dio lotado!"],
|
|
373
|
+
live: ["est\xE1 pegando fogo!", "o est\xE1dio ferve!", "n\xE3o tire os olhos!"],
|
|
374
|
+
goal: ["GOOOL!", "que gola\xE7o!", "pra calar a boca!", "o est\xE1dio explode!"],
|
|
375
|
+
ft: ["apita o juiz, acabou!", "fim de jogo, senhores!", "pros livros de hist\xF3ria!"]
|
|
376
|
+
},
|
|
377
|
+
fr: {
|
|
378
|
+
scheduled: ["\xE7a promet, le grand match arrive !", "\xE7a sent le football !", "stade plein !"],
|
|
379
|
+
live: ["c'est bouillant !", "le stade vibre !", "ne quittez pas des yeux !"],
|
|
380
|
+
goal: ["BUUUT !", "quelle frappe !", "le stade explose !", "imparable !"],
|
|
381
|
+
ft: ["coup de sifflet final !", "c'est termin\xE9 !", "dans les livres d'histoire !"]
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
var LEVEL_MOMENTS = {
|
|
385
|
+
off: /* @__PURE__ */ new Set(),
|
|
386
|
+
subtle: /* @__PURE__ */ new Set(["goal", "ft"]),
|
|
387
|
+
full: /* @__PURE__ */ new Set(["scheduled", "live", "goal", "ft"])
|
|
388
|
+
};
|
|
389
|
+
function pick(id, bank) {
|
|
390
|
+
let h = 0;
|
|
391
|
+
for (let i = 0; i < id.length; i++) h = h * 31 + id.charCodeAt(i) >>> 0;
|
|
392
|
+
return bank.length ? bank[h % bank.length] : "";
|
|
393
|
+
}
|
|
394
|
+
function momentOf(m) {
|
|
395
|
+
switch (m.status) {
|
|
396
|
+
case "LIVE":
|
|
397
|
+
case "HT": {
|
|
398
|
+
const goals = (m.score?.home ?? 0) + (m.score?.away ?? 0);
|
|
399
|
+
return goals > 0 ? "goal" : "live";
|
|
400
|
+
}
|
|
401
|
+
case "FT":
|
|
402
|
+
return "ft";
|
|
403
|
+
case "SCHEDULED":
|
|
404
|
+
return "scheduled";
|
|
405
|
+
default:
|
|
406
|
+
return void 0;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function matchFlavor(m, opts = {}) {
|
|
410
|
+
const level = opts.level ?? DEFAULT_FLAVOR;
|
|
411
|
+
if (level === "off") return "";
|
|
412
|
+
const moment = momentOf(m);
|
|
413
|
+
if (!moment || !LEVEL_MOMENTS[level].has(moment)) return "";
|
|
414
|
+
const lang = (opts.locale ?? "en").slice(0, 2);
|
|
415
|
+
const langBank = BANKS[lang] ?? BANKS.en;
|
|
416
|
+
return langBank ? pick(m.id, langBank[moment]) : "";
|
|
417
|
+
}
|
|
505
418
|
var schedule_2026_default = [
|
|
506
419
|
{
|
|
507
420
|
id: "760415",
|
|
@@ -509,6 +422,8 @@ var schedule_2026_default = [
|
|
|
509
422
|
group: "A",
|
|
510
423
|
kickoff: "2026-06-11T19:00Z",
|
|
511
424
|
venue: "Estadio Banorte",
|
|
425
|
+
city: "Mexico City",
|
|
426
|
+
country: "Mexico",
|
|
512
427
|
home: {
|
|
513
428
|
code: "MEX",
|
|
514
429
|
name: "Mexico",
|
|
@@ -520,7 +435,7 @@ var schedule_2026_default = [
|
|
|
520
435
|
flag: "\u{1F1FF}\u{1F1E6}"
|
|
521
436
|
},
|
|
522
437
|
status: "SCHEDULED",
|
|
523
|
-
updatedAt: "2026-
|
|
438
|
+
updatedAt: "2026-06-07T07:52:54.333Z"
|
|
524
439
|
},
|
|
525
440
|
{
|
|
526
441
|
id: "760414",
|
|
@@ -528,6 +443,8 @@ var schedule_2026_default = [
|
|
|
528
443
|
group: "A",
|
|
529
444
|
kickoff: "2026-06-12T02:00Z",
|
|
530
445
|
venue: "Estadio Akron",
|
|
446
|
+
city: "Guadalajara",
|
|
447
|
+
country: "Mexico",
|
|
531
448
|
home: {
|
|
532
449
|
code: "KOR",
|
|
533
450
|
name: "South Korea",
|
|
@@ -539,7 +456,7 @@ var schedule_2026_default = [
|
|
|
539
456
|
flag: "\u{1F1E8}\u{1F1FF}"
|
|
540
457
|
},
|
|
541
458
|
status: "SCHEDULED",
|
|
542
|
-
updatedAt: "2026-
|
|
459
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
543
460
|
},
|
|
544
461
|
{
|
|
545
462
|
id: "760416",
|
|
@@ -547,6 +464,8 @@ var schedule_2026_default = [
|
|
|
547
464
|
group: "B",
|
|
548
465
|
kickoff: "2026-06-12T19:00Z",
|
|
549
466
|
venue: "BMO Field",
|
|
467
|
+
city: "Toronto",
|
|
468
|
+
country: "Canada",
|
|
550
469
|
home: {
|
|
551
470
|
code: "CAN",
|
|
552
471
|
name: "Canada",
|
|
@@ -558,7 +477,7 @@ var schedule_2026_default = [
|
|
|
558
477
|
flag: "\u{1F1E7}\u{1F1E6}"
|
|
559
478
|
},
|
|
560
479
|
status: "SCHEDULED",
|
|
561
|
-
updatedAt: "2026-
|
|
480
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
562
481
|
},
|
|
563
482
|
{
|
|
564
483
|
id: "760417",
|
|
@@ -566,6 +485,8 @@ var schedule_2026_default = [
|
|
|
566
485
|
group: "D",
|
|
567
486
|
kickoff: "2026-06-13T01:00Z",
|
|
568
487
|
venue: "SoFi Stadium",
|
|
488
|
+
city: "Inglewood, California",
|
|
489
|
+
country: "USA",
|
|
569
490
|
home: {
|
|
570
491
|
code: "USA",
|
|
571
492
|
name: "United States",
|
|
@@ -577,7 +498,7 @@ var schedule_2026_default = [
|
|
|
577
498
|
flag: "\u{1F1F5}\u{1F1FE}"
|
|
578
499
|
},
|
|
579
500
|
status: "SCHEDULED",
|
|
580
|
-
updatedAt: "2026-
|
|
501
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
581
502
|
},
|
|
582
503
|
{
|
|
583
504
|
id: "760420",
|
|
@@ -585,6 +506,8 @@ var schedule_2026_default = [
|
|
|
585
506
|
group: "B",
|
|
586
507
|
kickoff: "2026-06-13T19:00Z",
|
|
587
508
|
venue: "Levi's Stadium",
|
|
509
|
+
city: "Santa Clara, California",
|
|
510
|
+
country: "USA",
|
|
588
511
|
home: {
|
|
589
512
|
code: "QAT",
|
|
590
513
|
name: "Qatar",
|
|
@@ -596,7 +519,7 @@ var schedule_2026_default = [
|
|
|
596
519
|
flag: "\u{1F1E8}\u{1F1ED}"
|
|
597
520
|
},
|
|
598
521
|
status: "SCHEDULED",
|
|
599
|
-
updatedAt: "2026-
|
|
522
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
600
523
|
},
|
|
601
524
|
{
|
|
602
525
|
id: "760419",
|
|
@@ -604,6 +527,8 @@ var schedule_2026_default = [
|
|
|
604
527
|
group: "C",
|
|
605
528
|
kickoff: "2026-06-13T22:00Z",
|
|
606
529
|
venue: "MetLife Stadium",
|
|
530
|
+
city: "East Rutherford, New Jersey",
|
|
531
|
+
country: "USA",
|
|
607
532
|
home: {
|
|
608
533
|
code: "BRA",
|
|
609
534
|
name: "Brazil",
|
|
@@ -615,7 +540,7 @@ var schedule_2026_default = [
|
|
|
615
540
|
flag: "\u{1F1F2}\u{1F1E6}"
|
|
616
541
|
},
|
|
617
542
|
status: "SCHEDULED",
|
|
618
|
-
updatedAt: "2026-
|
|
543
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
619
544
|
},
|
|
620
545
|
{
|
|
621
546
|
id: "760418",
|
|
@@ -623,6 +548,8 @@ var schedule_2026_default = [
|
|
|
623
548
|
group: "C",
|
|
624
549
|
kickoff: "2026-06-14T01:00Z",
|
|
625
550
|
venue: "Gillette Stadium",
|
|
551
|
+
city: "Foxborough, Massachusetts",
|
|
552
|
+
country: "USA",
|
|
626
553
|
home: {
|
|
627
554
|
code: "HAI",
|
|
628
555
|
name: "Haiti",
|
|
@@ -634,7 +561,7 @@ var schedule_2026_default = [
|
|
|
634
561
|
flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}"
|
|
635
562
|
},
|
|
636
563
|
status: "SCHEDULED",
|
|
637
|
-
updatedAt: "2026-
|
|
564
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
638
565
|
},
|
|
639
566
|
{
|
|
640
567
|
id: "760421",
|
|
@@ -642,6 +569,8 @@ var schedule_2026_default = [
|
|
|
642
569
|
group: "D",
|
|
643
570
|
kickoff: "2026-06-14T04:00Z",
|
|
644
571
|
venue: "BC Place",
|
|
572
|
+
city: "Vancouver",
|
|
573
|
+
country: "Canada",
|
|
645
574
|
home: {
|
|
646
575
|
code: "AUS",
|
|
647
576
|
name: "Australia",
|
|
@@ -653,7 +582,7 @@ var schedule_2026_default = [
|
|
|
653
582
|
flag: "\u{1F1F9}\u{1F1F7}"
|
|
654
583
|
},
|
|
655
584
|
status: "SCHEDULED",
|
|
656
|
-
updatedAt: "2026-
|
|
585
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
657
586
|
},
|
|
658
587
|
{
|
|
659
588
|
id: "760422",
|
|
@@ -661,6 +590,8 @@ var schedule_2026_default = [
|
|
|
661
590
|
group: "E",
|
|
662
591
|
kickoff: "2026-06-14T17:00Z",
|
|
663
592
|
venue: "NRG Stadium",
|
|
593
|
+
city: "Houston, Texas",
|
|
594
|
+
country: "USA",
|
|
664
595
|
home: {
|
|
665
596
|
code: "GER",
|
|
666
597
|
name: "Germany",
|
|
@@ -668,11 +599,11 @@ var schedule_2026_default = [
|
|
|
668
599
|
},
|
|
669
600
|
away: {
|
|
670
601
|
code: "CUW",
|
|
671
|
-
name: "
|
|
602
|
+
name: "Cura\xE7ao",
|
|
672
603
|
flag: "\u{1F1E8}\u{1F1FC}"
|
|
673
604
|
},
|
|
674
605
|
status: "SCHEDULED",
|
|
675
|
-
updatedAt: "2026-
|
|
606
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
676
607
|
},
|
|
677
608
|
{
|
|
678
609
|
id: "760425",
|
|
@@ -680,6 +611,8 @@ var schedule_2026_default = [
|
|
|
680
611
|
group: "F",
|
|
681
612
|
kickoff: "2026-06-14T20:00Z",
|
|
682
613
|
venue: "AT&T Stadium",
|
|
614
|
+
city: "Arlington, Texas",
|
|
615
|
+
country: "USA",
|
|
683
616
|
home: {
|
|
684
617
|
code: "NED",
|
|
685
618
|
name: "Netherlands",
|
|
@@ -691,7 +624,7 @@ var schedule_2026_default = [
|
|
|
691
624
|
flag: "\u{1F1EF}\u{1F1F5}"
|
|
692
625
|
},
|
|
693
626
|
status: "SCHEDULED",
|
|
694
|
-
updatedAt: "2026-
|
|
627
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
695
628
|
},
|
|
696
629
|
{
|
|
697
630
|
id: "760423",
|
|
@@ -699,6 +632,8 @@ var schedule_2026_default = [
|
|
|
699
632
|
group: "E",
|
|
700
633
|
kickoff: "2026-06-14T23:00Z",
|
|
701
634
|
venue: "Lincoln Financial Field",
|
|
635
|
+
city: "Philadelphia, Pennsylvania",
|
|
636
|
+
country: "USA",
|
|
702
637
|
home: {
|
|
703
638
|
code: "CIV",
|
|
704
639
|
name: "Ivory Coast",
|
|
@@ -710,7 +645,7 @@ var schedule_2026_default = [
|
|
|
710
645
|
flag: "\u{1F1EA}\u{1F1E8}"
|
|
711
646
|
},
|
|
712
647
|
status: "SCHEDULED",
|
|
713
|
-
updatedAt: "2026-
|
|
648
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
714
649
|
},
|
|
715
650
|
{
|
|
716
651
|
id: "760424",
|
|
@@ -718,6 +653,8 @@ var schedule_2026_default = [
|
|
|
718
653
|
group: "F",
|
|
719
654
|
kickoff: "2026-06-15T02:00Z",
|
|
720
655
|
venue: "Estadio BBVA",
|
|
656
|
+
city: "Guadalupe",
|
|
657
|
+
country: "Mexico",
|
|
721
658
|
home: {
|
|
722
659
|
code: "SWE",
|
|
723
660
|
name: "Sweden",
|
|
@@ -729,7 +666,7 @@ var schedule_2026_default = [
|
|
|
729
666
|
flag: "\u{1F1F9}\u{1F1F3}"
|
|
730
667
|
},
|
|
731
668
|
status: "SCHEDULED",
|
|
732
|
-
updatedAt: "2026-
|
|
669
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
733
670
|
},
|
|
734
671
|
{
|
|
735
672
|
id: "760428",
|
|
@@ -737,6 +674,8 @@ var schedule_2026_default = [
|
|
|
737
674
|
group: "H",
|
|
738
675
|
kickoff: "2026-06-15T16:00Z",
|
|
739
676
|
venue: "Mercedes-Benz Stadium",
|
|
677
|
+
city: "Atlanta, Georgia",
|
|
678
|
+
country: "USA",
|
|
740
679
|
home: {
|
|
741
680
|
code: "ESP",
|
|
742
681
|
name: "Spain",
|
|
@@ -748,7 +687,7 @@ var schedule_2026_default = [
|
|
|
748
687
|
flag: "\u{1F1E8}\u{1F1FB}"
|
|
749
688
|
},
|
|
750
689
|
status: "SCHEDULED",
|
|
751
|
-
updatedAt: "2026-
|
|
690
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
752
691
|
},
|
|
753
692
|
{
|
|
754
693
|
id: "760426",
|
|
@@ -756,6 +695,8 @@ var schedule_2026_default = [
|
|
|
756
695
|
group: "G",
|
|
757
696
|
kickoff: "2026-06-15T19:00Z",
|
|
758
697
|
venue: "Lumen Field",
|
|
698
|
+
city: "Seattle, Washington",
|
|
699
|
+
country: "USA",
|
|
759
700
|
home: {
|
|
760
701
|
code: "BEL",
|
|
761
702
|
name: "Belgium",
|
|
@@ -767,7 +708,7 @@ var schedule_2026_default = [
|
|
|
767
708
|
flag: "\u{1F1EA}\u{1F1EC}"
|
|
768
709
|
},
|
|
769
710
|
status: "SCHEDULED",
|
|
770
|
-
updatedAt: "2026-
|
|
711
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
771
712
|
},
|
|
772
713
|
{
|
|
773
714
|
id: "760429",
|
|
@@ -775,6 +716,8 @@ var schedule_2026_default = [
|
|
|
775
716
|
group: "H",
|
|
776
717
|
kickoff: "2026-06-15T22:00Z",
|
|
777
718
|
venue: "Hard Rock Stadium",
|
|
719
|
+
city: "Miami Gardens, Florida",
|
|
720
|
+
country: "USA",
|
|
778
721
|
home: {
|
|
779
722
|
code: "KSA",
|
|
780
723
|
name: "Saudi Arabia",
|
|
@@ -786,7 +729,7 @@ var schedule_2026_default = [
|
|
|
786
729
|
flag: "\u{1F1FA}\u{1F1FE}"
|
|
787
730
|
},
|
|
788
731
|
status: "SCHEDULED",
|
|
789
|
-
updatedAt: "2026-
|
|
732
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
790
733
|
},
|
|
791
734
|
{
|
|
792
735
|
id: "760427",
|
|
@@ -794,6 +737,8 @@ var schedule_2026_default = [
|
|
|
794
737
|
group: "G",
|
|
795
738
|
kickoff: "2026-06-16T01:00Z",
|
|
796
739
|
venue: "SoFi Stadium",
|
|
740
|
+
city: "Inglewood, California",
|
|
741
|
+
country: "USA",
|
|
797
742
|
home: {
|
|
798
743
|
code: "IRN",
|
|
799
744
|
name: "Iran",
|
|
@@ -805,7 +750,7 @@ var schedule_2026_default = [
|
|
|
805
750
|
flag: "\u{1F1F3}\u{1F1FF}"
|
|
806
751
|
},
|
|
807
752
|
status: "SCHEDULED",
|
|
808
|
-
updatedAt: "2026-
|
|
753
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
809
754
|
},
|
|
810
755
|
{
|
|
811
756
|
id: "760432",
|
|
@@ -813,6 +758,8 @@ var schedule_2026_default = [
|
|
|
813
758
|
group: "I",
|
|
814
759
|
kickoff: "2026-06-16T19:00Z",
|
|
815
760
|
venue: "MetLife Stadium",
|
|
761
|
+
city: "East Rutherford, New Jersey",
|
|
762
|
+
country: "USA",
|
|
816
763
|
home: {
|
|
817
764
|
code: "FRA",
|
|
818
765
|
name: "France",
|
|
@@ -824,7 +771,7 @@ var schedule_2026_default = [
|
|
|
824
771
|
flag: "\u{1F1F8}\u{1F1F3}"
|
|
825
772
|
},
|
|
826
773
|
status: "SCHEDULED",
|
|
827
|
-
updatedAt: "2026-
|
|
774
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
828
775
|
},
|
|
829
776
|
{
|
|
830
777
|
id: "760430",
|
|
@@ -832,6 +779,8 @@ var schedule_2026_default = [
|
|
|
832
779
|
group: "I",
|
|
833
780
|
kickoff: "2026-06-16T22:00Z",
|
|
834
781
|
venue: "Gillette Stadium",
|
|
782
|
+
city: "Foxborough, Massachusetts",
|
|
783
|
+
country: "USA",
|
|
835
784
|
home: {
|
|
836
785
|
code: "IRQ",
|
|
837
786
|
name: "Iraq",
|
|
@@ -843,7 +792,7 @@ var schedule_2026_default = [
|
|
|
843
792
|
flag: "\u{1F1F3}\u{1F1F4}"
|
|
844
793
|
},
|
|
845
794
|
status: "SCHEDULED",
|
|
846
|
-
updatedAt: "2026-
|
|
795
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
847
796
|
},
|
|
848
797
|
{
|
|
849
798
|
id: "760433",
|
|
@@ -851,6 +800,8 @@ var schedule_2026_default = [
|
|
|
851
800
|
group: "J",
|
|
852
801
|
kickoff: "2026-06-17T01:00Z",
|
|
853
802
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
803
|
+
city: "Kansas City, Missouri",
|
|
804
|
+
country: "USA",
|
|
854
805
|
home: {
|
|
855
806
|
code: "ARG",
|
|
856
807
|
name: "Argentina",
|
|
@@ -862,7 +813,7 @@ var schedule_2026_default = [
|
|
|
862
813
|
flag: "\u{1F1E9}\u{1F1FF}"
|
|
863
814
|
},
|
|
864
815
|
status: "SCHEDULED",
|
|
865
|
-
updatedAt: "2026-
|
|
816
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
866
817
|
},
|
|
867
818
|
{
|
|
868
819
|
id: "760431",
|
|
@@ -870,6 +821,8 @@ var schedule_2026_default = [
|
|
|
870
821
|
group: "J",
|
|
871
822
|
kickoff: "2026-06-17T04:00Z",
|
|
872
823
|
venue: "Levi's Stadium",
|
|
824
|
+
city: "Santa Clara, California",
|
|
825
|
+
country: "USA",
|
|
873
826
|
home: {
|
|
874
827
|
code: "AUT",
|
|
875
828
|
name: "Austria",
|
|
@@ -881,7 +834,7 @@ var schedule_2026_default = [
|
|
|
881
834
|
flag: "\u{1F1EF}\u{1F1F4}"
|
|
882
835
|
},
|
|
883
836
|
status: "SCHEDULED",
|
|
884
|
-
updatedAt: "2026-
|
|
837
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
885
838
|
},
|
|
886
839
|
{
|
|
887
840
|
id: "760435",
|
|
@@ -889,6 +842,8 @@ var schedule_2026_default = [
|
|
|
889
842
|
group: "K",
|
|
890
843
|
kickoff: "2026-06-17T17:00Z",
|
|
891
844
|
venue: "NRG Stadium",
|
|
845
|
+
city: "Houston, Texas",
|
|
846
|
+
country: "USA",
|
|
892
847
|
home: {
|
|
893
848
|
code: "POR",
|
|
894
849
|
name: "Portugal",
|
|
@@ -900,7 +855,7 @@ var schedule_2026_default = [
|
|
|
900
855
|
flag: "\u{1F1E8}\u{1F1E9}"
|
|
901
856
|
},
|
|
902
857
|
status: "SCHEDULED",
|
|
903
|
-
updatedAt: "2026-
|
|
858
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
904
859
|
},
|
|
905
860
|
{
|
|
906
861
|
id: "760437",
|
|
@@ -908,6 +863,8 @@ var schedule_2026_default = [
|
|
|
908
863
|
group: "L",
|
|
909
864
|
kickoff: "2026-06-17T20:00Z",
|
|
910
865
|
venue: "AT&T Stadium",
|
|
866
|
+
city: "Arlington, Texas",
|
|
867
|
+
country: "USA",
|
|
911
868
|
home: {
|
|
912
869
|
code: "ENG",
|
|
913
870
|
name: "England",
|
|
@@ -919,7 +876,7 @@ var schedule_2026_default = [
|
|
|
919
876
|
flag: "\u{1F1ED}\u{1F1F7}"
|
|
920
877
|
},
|
|
921
878
|
status: "SCHEDULED",
|
|
922
|
-
updatedAt: "2026-
|
|
879
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
923
880
|
},
|
|
924
881
|
{
|
|
925
882
|
id: "760434",
|
|
@@ -927,6 +884,8 @@ var schedule_2026_default = [
|
|
|
927
884
|
group: "L",
|
|
928
885
|
kickoff: "2026-06-17T23:00Z",
|
|
929
886
|
venue: "BMO Field",
|
|
887
|
+
city: "Toronto",
|
|
888
|
+
country: "Canada",
|
|
930
889
|
home: {
|
|
931
890
|
code: "GHA",
|
|
932
891
|
name: "Ghana",
|
|
@@ -938,7 +897,7 @@ var schedule_2026_default = [
|
|
|
938
897
|
flag: "\u{1F1F5}\u{1F1E6}"
|
|
939
898
|
},
|
|
940
899
|
status: "SCHEDULED",
|
|
941
|
-
updatedAt: "2026-
|
|
900
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
942
901
|
},
|
|
943
902
|
{
|
|
944
903
|
id: "760436",
|
|
@@ -946,6 +905,8 @@ var schedule_2026_default = [
|
|
|
946
905
|
group: "K",
|
|
947
906
|
kickoff: "2026-06-18T02:00Z",
|
|
948
907
|
venue: "Estadio Banorte",
|
|
908
|
+
city: "Mexico City",
|
|
909
|
+
country: "Mexico",
|
|
949
910
|
home: {
|
|
950
911
|
code: "UZB",
|
|
951
912
|
name: "Uzbekistan",
|
|
@@ -957,7 +918,7 @@ var schedule_2026_default = [
|
|
|
957
918
|
flag: "\u{1F1E8}\u{1F1F4}"
|
|
958
919
|
},
|
|
959
920
|
status: "SCHEDULED",
|
|
960
|
-
updatedAt: "2026-
|
|
921
|
+
updatedAt: "2026-06-07T07:52:54.337Z"
|
|
961
922
|
},
|
|
962
923
|
{
|
|
963
924
|
id: "760438",
|
|
@@ -965,6 +926,8 @@ var schedule_2026_default = [
|
|
|
965
926
|
group: "A",
|
|
966
927
|
kickoff: "2026-06-18T16:00Z",
|
|
967
928
|
venue: "Mercedes-Benz Stadium",
|
|
929
|
+
city: "Atlanta, Georgia",
|
|
930
|
+
country: "USA",
|
|
968
931
|
home: {
|
|
969
932
|
code: "CZE",
|
|
970
933
|
name: "Czechia",
|
|
@@ -976,7 +939,7 @@ var schedule_2026_default = [
|
|
|
976
939
|
flag: "\u{1F1FF}\u{1F1E6}"
|
|
977
940
|
},
|
|
978
941
|
status: "SCHEDULED",
|
|
979
|
-
updatedAt: "2026-
|
|
942
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
980
943
|
},
|
|
981
944
|
{
|
|
982
945
|
id: "760439",
|
|
@@ -984,6 +947,8 @@ var schedule_2026_default = [
|
|
|
984
947
|
group: "B",
|
|
985
948
|
kickoff: "2026-06-18T19:00Z",
|
|
986
949
|
venue: "SoFi Stadium",
|
|
950
|
+
city: "Inglewood, California",
|
|
951
|
+
country: "USA",
|
|
987
952
|
home: {
|
|
988
953
|
code: "SUI",
|
|
989
954
|
name: "Switzerland",
|
|
@@ -995,7 +960,7 @@ var schedule_2026_default = [
|
|
|
995
960
|
flag: "\u{1F1E7}\u{1F1E6}"
|
|
996
961
|
},
|
|
997
962
|
status: "SCHEDULED",
|
|
998
|
-
updatedAt: "2026-
|
|
963
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
999
964
|
},
|
|
1000
965
|
{
|
|
1001
966
|
id: "760440",
|
|
@@ -1003,6 +968,8 @@ var schedule_2026_default = [
|
|
|
1003
968
|
group: "B",
|
|
1004
969
|
kickoff: "2026-06-18T22:00Z",
|
|
1005
970
|
venue: "BC Place",
|
|
971
|
+
city: "Vancouver",
|
|
972
|
+
country: "Canada",
|
|
1006
973
|
home: {
|
|
1007
974
|
code: "CAN",
|
|
1008
975
|
name: "Canada",
|
|
@@ -1014,7 +981,7 @@ var schedule_2026_default = [
|
|
|
1014
981
|
flag: "\u{1F1F6}\u{1F1E6}"
|
|
1015
982
|
},
|
|
1016
983
|
status: "SCHEDULED",
|
|
1017
|
-
updatedAt: "2026-
|
|
984
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1018
985
|
},
|
|
1019
986
|
{
|
|
1020
987
|
id: "760441",
|
|
@@ -1022,6 +989,8 @@ var schedule_2026_default = [
|
|
|
1022
989
|
group: "A",
|
|
1023
990
|
kickoff: "2026-06-19T01:00Z",
|
|
1024
991
|
venue: "Estadio Akron",
|
|
992
|
+
city: "Guadalajara",
|
|
993
|
+
country: "Mexico",
|
|
1025
994
|
home: {
|
|
1026
995
|
code: "MEX",
|
|
1027
996
|
name: "Mexico",
|
|
@@ -1033,7 +1002,7 @@ var schedule_2026_default = [
|
|
|
1033
1002
|
flag: "\u{1F1F0}\u{1F1F7}"
|
|
1034
1003
|
},
|
|
1035
1004
|
status: "SCHEDULED",
|
|
1036
|
-
updatedAt: "2026-
|
|
1005
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1037
1006
|
},
|
|
1038
1007
|
{
|
|
1039
1008
|
id: "760442",
|
|
@@ -1041,6 +1010,8 @@ var schedule_2026_default = [
|
|
|
1041
1010
|
group: "D",
|
|
1042
1011
|
kickoff: "2026-06-19T19:00Z",
|
|
1043
1012
|
venue: "Lumen Field",
|
|
1013
|
+
city: "Seattle, Washington",
|
|
1014
|
+
country: "USA",
|
|
1044
1015
|
home: {
|
|
1045
1016
|
code: "USA",
|
|
1046
1017
|
name: "United States",
|
|
@@ -1052,7 +1023,7 @@ var schedule_2026_default = [
|
|
|
1052
1023
|
flag: "\u{1F1E6}\u{1F1FA}"
|
|
1053
1024
|
},
|
|
1054
1025
|
status: "SCHEDULED",
|
|
1055
|
-
updatedAt: "2026-
|
|
1026
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1056
1027
|
},
|
|
1057
1028
|
{
|
|
1058
1029
|
id: "760445",
|
|
@@ -1060,6 +1031,8 @@ var schedule_2026_default = [
|
|
|
1060
1031
|
group: "C",
|
|
1061
1032
|
kickoff: "2026-06-19T22:00Z",
|
|
1062
1033
|
venue: "Gillette Stadium",
|
|
1034
|
+
city: "Foxborough, Massachusetts",
|
|
1035
|
+
country: "USA",
|
|
1063
1036
|
home: {
|
|
1064
1037
|
code: "SCO",
|
|
1065
1038
|
name: "Scotland",
|
|
@@ -1071,7 +1044,7 @@ var schedule_2026_default = [
|
|
|
1071
1044
|
flag: "\u{1F1F2}\u{1F1E6}"
|
|
1072
1045
|
},
|
|
1073
1046
|
status: "SCHEDULED",
|
|
1074
|
-
updatedAt: "2026-
|
|
1047
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1075
1048
|
},
|
|
1076
1049
|
{
|
|
1077
1050
|
id: "760444",
|
|
@@ -1079,6 +1052,8 @@ var schedule_2026_default = [
|
|
|
1079
1052
|
group: "C",
|
|
1080
1053
|
kickoff: "2026-06-20T00:30Z",
|
|
1081
1054
|
venue: "Lincoln Financial Field",
|
|
1055
|
+
city: "Philadelphia, Pennsylvania",
|
|
1056
|
+
country: "USA",
|
|
1082
1057
|
home: {
|
|
1083
1058
|
code: "BRA",
|
|
1084
1059
|
name: "Brazil",
|
|
@@ -1090,7 +1065,7 @@ var schedule_2026_default = [
|
|
|
1090
1065
|
flag: "\u{1F1ED}\u{1F1F9}"
|
|
1091
1066
|
},
|
|
1092
1067
|
status: "SCHEDULED",
|
|
1093
|
-
updatedAt: "2026-
|
|
1068
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1094
1069
|
},
|
|
1095
1070
|
{
|
|
1096
1071
|
id: "760443",
|
|
@@ -1098,6 +1073,8 @@ var schedule_2026_default = [
|
|
|
1098
1073
|
group: "D",
|
|
1099
1074
|
kickoff: "2026-06-20T03:00Z",
|
|
1100
1075
|
venue: "Levi's Stadium",
|
|
1076
|
+
city: "Santa Clara, California",
|
|
1077
|
+
country: "USA",
|
|
1101
1078
|
home: {
|
|
1102
1079
|
code: "TUR",
|
|
1103
1080
|
name: "T\xFCrkiye",
|
|
@@ -1109,7 +1086,7 @@ var schedule_2026_default = [
|
|
|
1109
1086
|
flag: "\u{1F1F5}\u{1F1FE}"
|
|
1110
1087
|
},
|
|
1111
1088
|
status: "SCHEDULED",
|
|
1112
|
-
updatedAt: "2026-
|
|
1089
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1113
1090
|
},
|
|
1114
1091
|
{
|
|
1115
1092
|
id: "760447",
|
|
@@ -1117,6 +1094,8 @@ var schedule_2026_default = [
|
|
|
1117
1094
|
group: "F",
|
|
1118
1095
|
kickoff: "2026-06-20T17:00Z",
|
|
1119
1096
|
venue: "NRG Stadium",
|
|
1097
|
+
city: "Houston, Texas",
|
|
1098
|
+
country: "USA",
|
|
1120
1099
|
home: {
|
|
1121
1100
|
code: "NED",
|
|
1122
1101
|
name: "Netherlands",
|
|
@@ -1128,7 +1107,7 @@ var schedule_2026_default = [
|
|
|
1128
1107
|
flag: "\u{1F1F8}\u{1F1EA}"
|
|
1129
1108
|
},
|
|
1130
1109
|
status: "SCHEDULED",
|
|
1131
|
-
updatedAt: "2026-
|
|
1110
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1132
1111
|
},
|
|
1133
1112
|
{
|
|
1134
1113
|
id: "760448",
|
|
@@ -1136,6 +1115,8 @@ var schedule_2026_default = [
|
|
|
1136
1115
|
group: "E",
|
|
1137
1116
|
kickoff: "2026-06-20T20:00Z",
|
|
1138
1117
|
venue: "BMO Field",
|
|
1118
|
+
city: "Toronto",
|
|
1119
|
+
country: "Canada",
|
|
1139
1120
|
home: {
|
|
1140
1121
|
code: "GER",
|
|
1141
1122
|
name: "Germany",
|
|
@@ -1147,7 +1128,7 @@ var schedule_2026_default = [
|
|
|
1147
1128
|
flag: "\u{1F1E8}\u{1F1EE}"
|
|
1148
1129
|
},
|
|
1149
1130
|
status: "SCHEDULED",
|
|
1150
|
-
updatedAt: "2026-
|
|
1131
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1151
1132
|
},
|
|
1152
1133
|
{
|
|
1153
1134
|
id: "760446",
|
|
@@ -1155,6 +1136,8 @@ var schedule_2026_default = [
|
|
|
1155
1136
|
group: "E",
|
|
1156
1137
|
kickoff: "2026-06-21T00:00Z",
|
|
1157
1138
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
1139
|
+
city: "Kansas City, Missouri",
|
|
1140
|
+
country: "USA",
|
|
1158
1141
|
home: {
|
|
1159
1142
|
code: "ECU",
|
|
1160
1143
|
name: "Ecuador",
|
|
@@ -1162,11 +1145,11 @@ var schedule_2026_default = [
|
|
|
1162
1145
|
},
|
|
1163
1146
|
away: {
|
|
1164
1147
|
code: "CUW",
|
|
1165
|
-
name: "
|
|
1148
|
+
name: "Cura\xE7ao",
|
|
1166
1149
|
flag: "\u{1F1E8}\u{1F1FC}"
|
|
1167
1150
|
},
|
|
1168
1151
|
status: "SCHEDULED",
|
|
1169
|
-
updatedAt: "2026-
|
|
1152
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1170
1153
|
},
|
|
1171
1154
|
{
|
|
1172
1155
|
id: "760449",
|
|
@@ -1174,6 +1157,8 @@ var schedule_2026_default = [
|
|
|
1174
1157
|
group: "F",
|
|
1175
1158
|
kickoff: "2026-06-21T04:00Z",
|
|
1176
1159
|
venue: "Estadio BBVA",
|
|
1160
|
+
city: "Guadalupe",
|
|
1161
|
+
country: "Mexico",
|
|
1177
1162
|
home: {
|
|
1178
1163
|
code: "TUN",
|
|
1179
1164
|
name: "Tunisia",
|
|
@@ -1185,7 +1170,7 @@ var schedule_2026_default = [
|
|
|
1185
1170
|
flag: "\u{1F1EF}\u{1F1F5}"
|
|
1186
1171
|
},
|
|
1187
1172
|
status: "SCHEDULED",
|
|
1188
|
-
updatedAt: "2026-
|
|
1173
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1189
1174
|
},
|
|
1190
1175
|
{
|
|
1191
1176
|
id: "760453",
|
|
@@ -1193,6 +1178,8 @@ var schedule_2026_default = [
|
|
|
1193
1178
|
group: "H",
|
|
1194
1179
|
kickoff: "2026-06-21T16:00Z",
|
|
1195
1180
|
venue: "Mercedes-Benz Stadium",
|
|
1181
|
+
city: "Atlanta, Georgia",
|
|
1182
|
+
country: "USA",
|
|
1196
1183
|
home: {
|
|
1197
1184
|
code: "ESP",
|
|
1198
1185
|
name: "Spain",
|
|
@@ -1204,7 +1191,7 @@ var schedule_2026_default = [
|
|
|
1204
1191
|
flag: "\u{1F1F8}\u{1F1E6}"
|
|
1205
1192
|
},
|
|
1206
1193
|
status: "SCHEDULED",
|
|
1207
|
-
updatedAt: "2026-
|
|
1194
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1208
1195
|
},
|
|
1209
1196
|
{
|
|
1210
1197
|
id: "760451",
|
|
@@ -1212,6 +1199,8 @@ var schedule_2026_default = [
|
|
|
1212
1199
|
group: "G",
|
|
1213
1200
|
kickoff: "2026-06-21T19:00Z",
|
|
1214
1201
|
venue: "SoFi Stadium",
|
|
1202
|
+
city: "Inglewood, California",
|
|
1203
|
+
country: "USA",
|
|
1215
1204
|
home: {
|
|
1216
1205
|
code: "BEL",
|
|
1217
1206
|
name: "Belgium",
|
|
@@ -1223,7 +1212,7 @@ var schedule_2026_default = [
|
|
|
1223
1212
|
flag: "\u{1F1EE}\u{1F1F7}"
|
|
1224
1213
|
},
|
|
1225
1214
|
status: "SCHEDULED",
|
|
1226
|
-
updatedAt: "2026-
|
|
1215
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1227
1216
|
},
|
|
1228
1217
|
{
|
|
1229
1218
|
id: "760450",
|
|
@@ -1231,6 +1220,8 @@ var schedule_2026_default = [
|
|
|
1231
1220
|
group: "H",
|
|
1232
1221
|
kickoff: "2026-06-21T22:00Z",
|
|
1233
1222
|
venue: "Hard Rock Stadium",
|
|
1223
|
+
city: "Miami Gardens, Florida",
|
|
1224
|
+
country: "USA",
|
|
1234
1225
|
home: {
|
|
1235
1226
|
code: "URU",
|
|
1236
1227
|
name: "Uruguay",
|
|
@@ -1242,7 +1233,7 @@ var schedule_2026_default = [
|
|
|
1242
1233
|
flag: "\u{1F1E8}\u{1F1FB}"
|
|
1243
1234
|
},
|
|
1244
1235
|
status: "SCHEDULED",
|
|
1245
|
-
updatedAt: "2026-
|
|
1236
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1246
1237
|
},
|
|
1247
1238
|
{
|
|
1248
1239
|
id: "760452",
|
|
@@ -1250,6 +1241,8 @@ var schedule_2026_default = [
|
|
|
1250
1241
|
group: "G",
|
|
1251
1242
|
kickoff: "2026-06-22T01:00Z",
|
|
1252
1243
|
venue: "BC Place",
|
|
1244
|
+
city: "Vancouver",
|
|
1245
|
+
country: "Canada",
|
|
1253
1246
|
home: {
|
|
1254
1247
|
code: "NZL",
|
|
1255
1248
|
name: "New Zealand",
|
|
@@ -1261,7 +1254,7 @@ var schedule_2026_default = [
|
|
|
1261
1254
|
flag: "\u{1F1EA}\u{1F1EC}"
|
|
1262
1255
|
},
|
|
1263
1256
|
status: "SCHEDULED",
|
|
1264
|
-
updatedAt: "2026-
|
|
1257
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1265
1258
|
},
|
|
1266
1259
|
{
|
|
1267
1260
|
id: "760456",
|
|
@@ -1269,6 +1262,8 @@ var schedule_2026_default = [
|
|
|
1269
1262
|
group: "J",
|
|
1270
1263
|
kickoff: "2026-06-22T17:00Z",
|
|
1271
1264
|
venue: "AT&T Stadium",
|
|
1265
|
+
city: "Arlington, Texas",
|
|
1266
|
+
country: "USA",
|
|
1272
1267
|
home: {
|
|
1273
1268
|
code: "ARG",
|
|
1274
1269
|
name: "Argentina",
|
|
@@ -1280,7 +1275,7 @@ var schedule_2026_default = [
|
|
|
1280
1275
|
flag: "\u{1F1E6}\u{1F1F9}"
|
|
1281
1276
|
},
|
|
1282
1277
|
status: "SCHEDULED",
|
|
1283
|
-
updatedAt: "2026-
|
|
1278
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1284
1279
|
},
|
|
1285
1280
|
{
|
|
1286
1281
|
id: "760457",
|
|
@@ -1288,6 +1283,8 @@ var schedule_2026_default = [
|
|
|
1288
1283
|
group: "I",
|
|
1289
1284
|
kickoff: "2026-06-22T21:00Z",
|
|
1290
1285
|
venue: "Lincoln Financial Field",
|
|
1286
|
+
city: "Philadelphia, Pennsylvania",
|
|
1287
|
+
country: "USA",
|
|
1291
1288
|
home: {
|
|
1292
1289
|
code: "FRA",
|
|
1293
1290
|
name: "France",
|
|
@@ -1299,7 +1296,7 @@ var schedule_2026_default = [
|
|
|
1299
1296
|
flag: "\u{1F1EE}\u{1F1F6}"
|
|
1300
1297
|
},
|
|
1301
1298
|
status: "SCHEDULED",
|
|
1302
|
-
updatedAt: "2026-
|
|
1299
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1303
1300
|
},
|
|
1304
1301
|
{
|
|
1305
1302
|
id: "760454",
|
|
@@ -1307,6 +1304,8 @@ var schedule_2026_default = [
|
|
|
1307
1304
|
group: "I",
|
|
1308
1305
|
kickoff: "2026-06-23T00:00Z",
|
|
1309
1306
|
venue: "MetLife Stadium",
|
|
1307
|
+
city: "East Rutherford, New Jersey",
|
|
1308
|
+
country: "USA",
|
|
1310
1309
|
home: {
|
|
1311
1310
|
code: "NOR",
|
|
1312
1311
|
name: "Norway",
|
|
@@ -1318,7 +1317,7 @@ var schedule_2026_default = [
|
|
|
1318
1317
|
flag: "\u{1F1F8}\u{1F1F3}"
|
|
1319
1318
|
},
|
|
1320
1319
|
status: "SCHEDULED",
|
|
1321
|
-
updatedAt: "2026-
|
|
1320
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1322
1321
|
},
|
|
1323
1322
|
{
|
|
1324
1323
|
id: "760455",
|
|
@@ -1326,6 +1325,8 @@ var schedule_2026_default = [
|
|
|
1326
1325
|
group: "J",
|
|
1327
1326
|
kickoff: "2026-06-23T03:00Z",
|
|
1328
1327
|
venue: "Levi's Stadium",
|
|
1328
|
+
city: "Santa Clara, California",
|
|
1329
|
+
country: "USA",
|
|
1329
1330
|
home: {
|
|
1330
1331
|
code: "JOR",
|
|
1331
1332
|
name: "Jordan",
|
|
@@ -1337,7 +1338,7 @@ var schedule_2026_default = [
|
|
|
1337
1338
|
flag: "\u{1F1E9}\u{1F1FF}"
|
|
1338
1339
|
},
|
|
1339
1340
|
status: "SCHEDULED",
|
|
1340
|
-
updatedAt: "2026-
|
|
1341
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1341
1342
|
},
|
|
1342
1343
|
{
|
|
1343
1344
|
id: "760461",
|
|
@@ -1345,6 +1346,8 @@ var schedule_2026_default = [
|
|
|
1345
1346
|
group: "K",
|
|
1346
1347
|
kickoff: "2026-06-23T17:00Z",
|
|
1347
1348
|
venue: "NRG Stadium",
|
|
1349
|
+
city: "Houston, Texas",
|
|
1350
|
+
country: "USA",
|
|
1348
1351
|
home: {
|
|
1349
1352
|
code: "POR",
|
|
1350
1353
|
name: "Portugal",
|
|
@@ -1356,7 +1359,7 @@ var schedule_2026_default = [
|
|
|
1356
1359
|
flag: "\u{1F1FA}\u{1F1FF}"
|
|
1357
1360
|
},
|
|
1358
1361
|
status: "SCHEDULED",
|
|
1359
|
-
updatedAt: "2026-
|
|
1362
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1360
1363
|
},
|
|
1361
1364
|
{
|
|
1362
1365
|
id: "760458",
|
|
@@ -1364,6 +1367,8 @@ var schedule_2026_default = [
|
|
|
1364
1367
|
group: "L",
|
|
1365
1368
|
kickoff: "2026-06-23T20:00Z",
|
|
1366
1369
|
venue: "Gillette Stadium",
|
|
1370
|
+
city: "Foxborough, Massachusetts",
|
|
1371
|
+
country: "USA",
|
|
1367
1372
|
home: {
|
|
1368
1373
|
code: "ENG",
|
|
1369
1374
|
name: "England",
|
|
@@ -1375,7 +1380,7 @@ var schedule_2026_default = [
|
|
|
1375
1380
|
flag: "\u{1F1EC}\u{1F1ED}"
|
|
1376
1381
|
},
|
|
1377
1382
|
status: "SCHEDULED",
|
|
1378
|
-
updatedAt: "2026-
|
|
1383
|
+
updatedAt: "2026-06-07T07:52:54.418Z"
|
|
1379
1384
|
},
|
|
1380
1385
|
{
|
|
1381
1386
|
id: "760460",
|
|
@@ -1383,6 +1388,8 @@ var schedule_2026_default = [
|
|
|
1383
1388
|
group: "L",
|
|
1384
1389
|
kickoff: "2026-06-23T23:00Z",
|
|
1385
1390
|
venue: "BMO Field",
|
|
1391
|
+
city: "Toronto",
|
|
1392
|
+
country: "Canada",
|
|
1386
1393
|
home: {
|
|
1387
1394
|
code: "PAN",
|
|
1388
1395
|
name: "Panama",
|
|
@@ -1394,7 +1401,7 @@ var schedule_2026_default = [
|
|
|
1394
1401
|
flag: "\u{1F1ED}\u{1F1F7}"
|
|
1395
1402
|
},
|
|
1396
1403
|
status: "SCHEDULED",
|
|
1397
|
-
updatedAt: "2026-
|
|
1404
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1398
1405
|
},
|
|
1399
1406
|
{
|
|
1400
1407
|
id: "760459",
|
|
@@ -1402,6 +1409,8 @@ var schedule_2026_default = [
|
|
|
1402
1409
|
group: "K",
|
|
1403
1410
|
kickoff: "2026-06-24T02:00Z",
|
|
1404
1411
|
venue: "Estadio Akron",
|
|
1412
|
+
city: "Guadalajara",
|
|
1413
|
+
country: "Mexico",
|
|
1405
1414
|
home: {
|
|
1406
1415
|
code: "COL",
|
|
1407
1416
|
name: "Colombia",
|
|
@@ -1413,7 +1422,7 @@ var schedule_2026_default = [
|
|
|
1413
1422
|
flag: "\u{1F1E8}\u{1F1E9}"
|
|
1414
1423
|
},
|
|
1415
1424
|
status: "SCHEDULED",
|
|
1416
|
-
updatedAt: "2026-
|
|
1425
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1417
1426
|
},
|
|
1418
1427
|
{
|
|
1419
1428
|
id: "760462",
|
|
@@ -1421,6 +1430,8 @@ var schedule_2026_default = [
|
|
|
1421
1430
|
group: "B",
|
|
1422
1431
|
kickoff: "2026-06-24T19:00Z",
|
|
1423
1432
|
venue: "Lumen Field",
|
|
1433
|
+
city: "Seattle, Washington",
|
|
1434
|
+
country: "USA",
|
|
1424
1435
|
home: {
|
|
1425
1436
|
code: "BIH",
|
|
1426
1437
|
name: "Bosnia-Herzegovina",
|
|
@@ -1432,7 +1443,7 @@ var schedule_2026_default = [
|
|
|
1432
1443
|
flag: "\u{1F1F6}\u{1F1E6}"
|
|
1433
1444
|
},
|
|
1434
1445
|
status: "SCHEDULED",
|
|
1435
|
-
updatedAt: "2026-
|
|
1446
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1436
1447
|
},
|
|
1437
1448
|
{
|
|
1438
1449
|
id: "760463",
|
|
@@ -1440,6 +1451,8 @@ var schedule_2026_default = [
|
|
|
1440
1451
|
group: "B",
|
|
1441
1452
|
kickoff: "2026-06-24T19:00Z",
|
|
1442
1453
|
venue: "BC Place",
|
|
1454
|
+
city: "Vancouver",
|
|
1455
|
+
country: "Canada",
|
|
1443
1456
|
home: {
|
|
1444
1457
|
code: "SUI",
|
|
1445
1458
|
name: "Switzerland",
|
|
@@ -1451,7 +1464,7 @@ var schedule_2026_default = [
|
|
|
1451
1464
|
flag: "\u{1F1E8}\u{1F1E6}"
|
|
1452
1465
|
},
|
|
1453
1466
|
status: "SCHEDULED",
|
|
1454
|
-
updatedAt: "2026-
|
|
1467
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1455
1468
|
},
|
|
1456
1469
|
{
|
|
1457
1470
|
id: "760464",
|
|
@@ -1459,6 +1472,8 @@ var schedule_2026_default = [
|
|
|
1459
1472
|
group: "C",
|
|
1460
1473
|
kickoff: "2026-06-24T22:00Z",
|
|
1461
1474
|
venue: "Mercedes-Benz Stadium",
|
|
1475
|
+
city: "Atlanta, Georgia",
|
|
1476
|
+
country: "USA",
|
|
1462
1477
|
home: {
|
|
1463
1478
|
code: "MAR",
|
|
1464
1479
|
name: "Morocco",
|
|
@@ -1470,7 +1485,7 @@ var schedule_2026_default = [
|
|
|
1470
1485
|
flag: "\u{1F1ED}\u{1F1F9}"
|
|
1471
1486
|
},
|
|
1472
1487
|
status: "SCHEDULED",
|
|
1473
|
-
updatedAt: "2026-
|
|
1488
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1474
1489
|
},
|
|
1475
1490
|
{
|
|
1476
1491
|
id: "760465",
|
|
@@ -1478,6 +1493,8 @@ var schedule_2026_default = [
|
|
|
1478
1493
|
group: "C",
|
|
1479
1494
|
kickoff: "2026-06-24T22:00Z",
|
|
1480
1495
|
venue: "Hard Rock Stadium",
|
|
1496
|
+
city: "Miami Gardens, Florida",
|
|
1497
|
+
country: "USA",
|
|
1481
1498
|
home: {
|
|
1482
1499
|
code: "SCO",
|
|
1483
1500
|
name: "Scotland",
|
|
@@ -1489,7 +1506,7 @@ var schedule_2026_default = [
|
|
|
1489
1506
|
flag: "\u{1F1E7}\u{1F1F7}"
|
|
1490
1507
|
},
|
|
1491
1508
|
status: "SCHEDULED",
|
|
1492
|
-
updatedAt: "2026-
|
|
1509
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1493
1510
|
},
|
|
1494
1511
|
{
|
|
1495
1512
|
id: "760467",
|
|
@@ -1497,6 +1514,8 @@ var schedule_2026_default = [
|
|
|
1497
1514
|
group: "A",
|
|
1498
1515
|
kickoff: "2026-06-25T01:00Z",
|
|
1499
1516
|
venue: "Estadio Banorte",
|
|
1517
|
+
city: "Mexico City",
|
|
1518
|
+
country: "Mexico",
|
|
1500
1519
|
home: {
|
|
1501
1520
|
code: "CZE",
|
|
1502
1521
|
name: "Czechia",
|
|
@@ -1508,7 +1527,7 @@ var schedule_2026_default = [
|
|
|
1508
1527
|
flag: "\u{1F1F2}\u{1F1FD}"
|
|
1509
1528
|
},
|
|
1510
1529
|
status: "SCHEDULED",
|
|
1511
|
-
updatedAt: "2026-
|
|
1530
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1512
1531
|
},
|
|
1513
1532
|
{
|
|
1514
1533
|
id: "760466",
|
|
@@ -1516,6 +1535,8 @@ var schedule_2026_default = [
|
|
|
1516
1535
|
group: "A",
|
|
1517
1536
|
kickoff: "2026-06-25T01:00Z",
|
|
1518
1537
|
venue: "Estadio BBVA",
|
|
1538
|
+
city: "Guadalupe",
|
|
1539
|
+
country: "Mexico",
|
|
1519
1540
|
home: {
|
|
1520
1541
|
code: "RSA",
|
|
1521
1542
|
name: "South Africa",
|
|
@@ -1527,7 +1548,7 @@ var schedule_2026_default = [
|
|
|
1527
1548
|
flag: "\u{1F1F0}\u{1F1F7}"
|
|
1528
1549
|
},
|
|
1529
1550
|
status: "SCHEDULED",
|
|
1530
|
-
updatedAt: "2026-
|
|
1551
|
+
updatedAt: "2026-06-07T07:52:54.419Z"
|
|
1531
1552
|
},
|
|
1532
1553
|
{
|
|
1533
1554
|
id: "760473",
|
|
@@ -1535,9 +1556,11 @@ var schedule_2026_default = [
|
|
|
1535
1556
|
group: "E",
|
|
1536
1557
|
kickoff: "2026-06-25T20:00Z",
|
|
1537
1558
|
venue: "Lincoln Financial Field",
|
|
1559
|
+
city: "Philadelphia, Pennsylvania",
|
|
1560
|
+
country: "USA",
|
|
1538
1561
|
home: {
|
|
1539
1562
|
code: "CUW",
|
|
1540
|
-
name: "
|
|
1563
|
+
name: "Cura\xE7ao",
|
|
1541
1564
|
flag: "\u{1F1E8}\u{1F1FC}"
|
|
1542
1565
|
},
|
|
1543
1566
|
away: {
|
|
@@ -1546,7 +1569,7 @@ var schedule_2026_default = [
|
|
|
1546
1569
|
flag: "\u{1F1E8}\u{1F1EE}"
|
|
1547
1570
|
},
|
|
1548
1571
|
status: "SCHEDULED",
|
|
1549
|
-
updatedAt: "2026-
|
|
1572
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1550
1573
|
},
|
|
1551
1574
|
{
|
|
1552
1575
|
id: "760468",
|
|
@@ -1554,6 +1577,8 @@ var schedule_2026_default = [
|
|
|
1554
1577
|
group: "E",
|
|
1555
1578
|
kickoff: "2026-06-25T20:00Z",
|
|
1556
1579
|
venue: "MetLife Stadium",
|
|
1580
|
+
city: "East Rutherford, New Jersey",
|
|
1581
|
+
country: "USA",
|
|
1557
1582
|
home: {
|
|
1558
1583
|
code: "ECU",
|
|
1559
1584
|
name: "Ecuador",
|
|
@@ -1565,7 +1590,7 @@ var schedule_2026_default = [
|
|
|
1565
1590
|
flag: "\u{1F1E9}\u{1F1EA}"
|
|
1566
1591
|
},
|
|
1567
1592
|
status: "SCHEDULED",
|
|
1568
|
-
updatedAt: "2026-
|
|
1593
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1569
1594
|
},
|
|
1570
1595
|
{
|
|
1571
1596
|
id: "760471",
|
|
@@ -1573,6 +1598,8 @@ var schedule_2026_default = [
|
|
|
1573
1598
|
group: "F",
|
|
1574
1599
|
kickoff: "2026-06-25T23:00Z",
|
|
1575
1600
|
venue: "AT&T Stadium",
|
|
1601
|
+
city: "Arlington, Texas",
|
|
1602
|
+
country: "USA",
|
|
1576
1603
|
home: {
|
|
1577
1604
|
code: "JPN",
|
|
1578
1605
|
name: "Japan",
|
|
@@ -1584,7 +1611,7 @@ var schedule_2026_default = [
|
|
|
1584
1611
|
flag: "\u{1F1F8}\u{1F1EA}"
|
|
1585
1612
|
},
|
|
1586
1613
|
status: "SCHEDULED",
|
|
1587
|
-
updatedAt: "2026-
|
|
1614
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1588
1615
|
},
|
|
1589
1616
|
{
|
|
1590
1617
|
id: "760472",
|
|
@@ -1592,6 +1619,8 @@ var schedule_2026_default = [
|
|
|
1592
1619
|
group: "F",
|
|
1593
1620
|
kickoff: "2026-06-25T23:00Z",
|
|
1594
1621
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
1622
|
+
city: "Kansas City, Missouri",
|
|
1623
|
+
country: "USA",
|
|
1595
1624
|
home: {
|
|
1596
1625
|
code: "TUN",
|
|
1597
1626
|
name: "Tunisia",
|
|
@@ -1603,7 +1632,7 @@ var schedule_2026_default = [
|
|
|
1603
1632
|
flag: "\u{1F1F3}\u{1F1F1}"
|
|
1604
1633
|
},
|
|
1605
1634
|
status: "SCHEDULED",
|
|
1606
|
-
updatedAt: "2026-
|
|
1635
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1607
1636
|
},
|
|
1608
1637
|
{
|
|
1609
1638
|
id: "760469",
|
|
@@ -1611,6 +1640,8 @@ var schedule_2026_default = [
|
|
|
1611
1640
|
group: "D",
|
|
1612
1641
|
kickoff: "2026-06-26T02:00Z",
|
|
1613
1642
|
venue: "Levi's Stadium",
|
|
1643
|
+
city: "Santa Clara, California",
|
|
1644
|
+
country: "USA",
|
|
1614
1645
|
home: {
|
|
1615
1646
|
code: "PAR",
|
|
1616
1647
|
name: "Paraguay",
|
|
@@ -1622,7 +1653,7 @@ var schedule_2026_default = [
|
|
|
1622
1653
|
flag: "\u{1F1E6}\u{1F1FA}"
|
|
1623
1654
|
},
|
|
1624
1655
|
status: "SCHEDULED",
|
|
1625
|
-
updatedAt: "2026-
|
|
1656
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1626
1657
|
},
|
|
1627
1658
|
{
|
|
1628
1659
|
id: "760470",
|
|
@@ -1630,6 +1661,8 @@ var schedule_2026_default = [
|
|
|
1630
1661
|
group: "D",
|
|
1631
1662
|
kickoff: "2026-06-26T02:00Z",
|
|
1632
1663
|
venue: "SoFi Stadium",
|
|
1664
|
+
city: "Inglewood, California",
|
|
1665
|
+
country: "USA",
|
|
1633
1666
|
home: {
|
|
1634
1667
|
code: "TUR",
|
|
1635
1668
|
name: "T\xFCrkiye",
|
|
@@ -1641,7 +1674,7 @@ var schedule_2026_default = [
|
|
|
1641
1674
|
flag: "\u{1F1FA}\u{1F1F8}"
|
|
1642
1675
|
},
|
|
1643
1676
|
status: "SCHEDULED",
|
|
1644
|
-
updatedAt: "2026-
|
|
1677
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1645
1678
|
},
|
|
1646
1679
|
{
|
|
1647
1680
|
id: "760475",
|
|
@@ -1649,6 +1682,8 @@ var schedule_2026_default = [
|
|
|
1649
1682
|
group: "I",
|
|
1650
1683
|
kickoff: "2026-06-26T19:00Z",
|
|
1651
1684
|
venue: "Gillette Stadium",
|
|
1685
|
+
city: "Foxborough, Massachusetts",
|
|
1686
|
+
country: "USA",
|
|
1652
1687
|
home: {
|
|
1653
1688
|
code: "NOR",
|
|
1654
1689
|
name: "Norway",
|
|
@@ -1660,7 +1695,7 @@ var schedule_2026_default = [
|
|
|
1660
1695
|
flag: "\u{1F1EB}\u{1F1F7}"
|
|
1661
1696
|
},
|
|
1662
1697
|
status: "SCHEDULED",
|
|
1663
|
-
updatedAt: "2026-
|
|
1698
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1664
1699
|
},
|
|
1665
1700
|
{
|
|
1666
1701
|
id: "760474",
|
|
@@ -1668,6 +1703,8 @@ var schedule_2026_default = [
|
|
|
1668
1703
|
group: "I",
|
|
1669
1704
|
kickoff: "2026-06-26T19:00Z",
|
|
1670
1705
|
venue: "BMO Field",
|
|
1706
|
+
city: "Toronto",
|
|
1707
|
+
country: "Canada",
|
|
1671
1708
|
home: {
|
|
1672
1709
|
code: "SEN",
|
|
1673
1710
|
name: "Senegal",
|
|
@@ -1679,7 +1716,7 @@ var schedule_2026_default = [
|
|
|
1679
1716
|
flag: "\u{1F1EE}\u{1F1F6}"
|
|
1680
1717
|
},
|
|
1681
1718
|
status: "SCHEDULED",
|
|
1682
|
-
updatedAt: "2026-
|
|
1719
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1683
1720
|
},
|
|
1684
1721
|
{
|
|
1685
1722
|
id: "760478",
|
|
@@ -1687,6 +1724,8 @@ var schedule_2026_default = [
|
|
|
1687
1724
|
group: "H",
|
|
1688
1725
|
kickoff: "2026-06-27T00:00Z",
|
|
1689
1726
|
venue: "NRG Stadium",
|
|
1727
|
+
city: "Houston, Texas",
|
|
1728
|
+
country: "USA",
|
|
1690
1729
|
home: {
|
|
1691
1730
|
code: "CPV",
|
|
1692
1731
|
name: "Cape Verde",
|
|
@@ -1698,7 +1737,7 @@ var schedule_2026_default = [
|
|
|
1698
1737
|
flag: "\u{1F1F8}\u{1F1E6}"
|
|
1699
1738
|
},
|
|
1700
1739
|
status: "SCHEDULED",
|
|
1701
|
-
updatedAt: "2026-
|
|
1740
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1702
1741
|
},
|
|
1703
1742
|
{
|
|
1704
1743
|
id: "760479",
|
|
@@ -1706,6 +1745,8 @@ var schedule_2026_default = [
|
|
|
1706
1745
|
group: "H",
|
|
1707
1746
|
kickoff: "2026-06-27T00:00Z",
|
|
1708
1747
|
venue: "Estadio Akron",
|
|
1748
|
+
city: "Guadalajara",
|
|
1749
|
+
country: "Mexico",
|
|
1709
1750
|
home: {
|
|
1710
1751
|
code: "URU",
|
|
1711
1752
|
name: "Uruguay",
|
|
@@ -1717,7 +1758,7 @@ var schedule_2026_default = [
|
|
|
1717
1758
|
flag: "\u{1F1EA}\u{1F1F8}"
|
|
1718
1759
|
},
|
|
1719
1760
|
status: "SCHEDULED",
|
|
1720
|
-
updatedAt: "2026-
|
|
1761
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1721
1762
|
},
|
|
1722
1763
|
{
|
|
1723
1764
|
id: "760476",
|
|
@@ -1725,6 +1766,8 @@ var schedule_2026_default = [
|
|
|
1725
1766
|
group: "G",
|
|
1726
1767
|
kickoff: "2026-06-27T03:00Z",
|
|
1727
1768
|
venue: "Lumen Field",
|
|
1769
|
+
city: "Seattle, Washington",
|
|
1770
|
+
country: "USA",
|
|
1728
1771
|
home: {
|
|
1729
1772
|
code: "EGY",
|
|
1730
1773
|
name: "Egypt",
|
|
@@ -1736,7 +1779,7 @@ var schedule_2026_default = [
|
|
|
1736
1779
|
flag: "\u{1F1EE}\u{1F1F7}"
|
|
1737
1780
|
},
|
|
1738
1781
|
status: "SCHEDULED",
|
|
1739
|
-
updatedAt: "2026-
|
|
1782
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1740
1783
|
},
|
|
1741
1784
|
{
|
|
1742
1785
|
id: "760477",
|
|
@@ -1744,6 +1787,8 @@ var schedule_2026_default = [
|
|
|
1744
1787
|
group: "G",
|
|
1745
1788
|
kickoff: "2026-06-27T03:00Z",
|
|
1746
1789
|
venue: "BC Place",
|
|
1790
|
+
city: "Vancouver",
|
|
1791
|
+
country: "Canada",
|
|
1747
1792
|
home: {
|
|
1748
1793
|
code: "NZL",
|
|
1749
1794
|
name: "New Zealand",
|
|
@@ -1755,7 +1800,7 @@ var schedule_2026_default = [
|
|
|
1755
1800
|
flag: "\u{1F1E7}\u{1F1EA}"
|
|
1756
1801
|
},
|
|
1757
1802
|
status: "SCHEDULED",
|
|
1758
|
-
updatedAt: "2026-
|
|
1803
|
+
updatedAt: "2026-06-07T07:52:54.511Z"
|
|
1759
1804
|
},
|
|
1760
1805
|
{
|
|
1761
1806
|
id: "760480",
|
|
@@ -1763,6 +1808,8 @@ var schedule_2026_default = [
|
|
|
1763
1808
|
group: "L",
|
|
1764
1809
|
kickoff: "2026-06-27T21:00Z",
|
|
1765
1810
|
venue: "Lincoln Financial Field",
|
|
1811
|
+
city: "Philadelphia, Pennsylvania",
|
|
1812
|
+
country: "USA",
|
|
1766
1813
|
home: {
|
|
1767
1814
|
code: "CRO",
|
|
1768
1815
|
name: "Croatia",
|
|
@@ -1774,7 +1821,7 @@ var schedule_2026_default = [
|
|
|
1774
1821
|
flag: "\u{1F1EC}\u{1F1ED}"
|
|
1775
1822
|
},
|
|
1776
1823
|
status: "SCHEDULED",
|
|
1777
|
-
updatedAt: "2026-
|
|
1824
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1778
1825
|
},
|
|
1779
1826
|
{
|
|
1780
1827
|
id: "760485",
|
|
@@ -1782,6 +1829,8 @@ var schedule_2026_default = [
|
|
|
1782
1829
|
group: "L",
|
|
1783
1830
|
kickoff: "2026-06-27T21:00Z",
|
|
1784
1831
|
venue: "MetLife Stadium",
|
|
1832
|
+
city: "East Rutherford, New Jersey",
|
|
1833
|
+
country: "USA",
|
|
1785
1834
|
home: {
|
|
1786
1835
|
code: "PAN",
|
|
1787
1836
|
name: "Panama",
|
|
@@ -1793,7 +1842,7 @@ var schedule_2026_default = [
|
|
|
1793
1842
|
flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}"
|
|
1794
1843
|
},
|
|
1795
1844
|
status: "SCHEDULED",
|
|
1796
|
-
updatedAt: "2026-
|
|
1845
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1797
1846
|
},
|
|
1798
1847
|
{
|
|
1799
1848
|
id: "760481",
|
|
@@ -1801,6 +1850,8 @@ var schedule_2026_default = [
|
|
|
1801
1850
|
group: "K",
|
|
1802
1851
|
kickoff: "2026-06-27T23:30Z",
|
|
1803
1852
|
venue: "Hard Rock Stadium",
|
|
1853
|
+
city: "Miami Gardens, Florida",
|
|
1854
|
+
country: "USA",
|
|
1804
1855
|
home: {
|
|
1805
1856
|
code: "COL",
|
|
1806
1857
|
name: "Colombia",
|
|
@@ -1812,7 +1863,7 @@ var schedule_2026_default = [
|
|
|
1812
1863
|
flag: "\u{1F1F5}\u{1F1F9}"
|
|
1813
1864
|
},
|
|
1814
1865
|
status: "SCHEDULED",
|
|
1815
|
-
updatedAt: "2026-
|
|
1866
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1816
1867
|
},
|
|
1817
1868
|
{
|
|
1818
1869
|
id: "760482",
|
|
@@ -1820,6 +1871,8 @@ var schedule_2026_default = [
|
|
|
1820
1871
|
group: "K",
|
|
1821
1872
|
kickoff: "2026-06-27T23:30Z",
|
|
1822
1873
|
venue: "Mercedes-Benz Stadium",
|
|
1874
|
+
city: "Atlanta, Georgia",
|
|
1875
|
+
country: "USA",
|
|
1823
1876
|
home: {
|
|
1824
1877
|
code: "COD",
|
|
1825
1878
|
name: "Congo DR",
|
|
@@ -1831,7 +1884,7 @@ var schedule_2026_default = [
|
|
|
1831
1884
|
flag: "\u{1F1FA}\u{1F1FF}"
|
|
1832
1885
|
},
|
|
1833
1886
|
status: "SCHEDULED",
|
|
1834
|
-
updatedAt: "2026-
|
|
1887
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1835
1888
|
},
|
|
1836
1889
|
{
|
|
1837
1890
|
id: "760484",
|
|
@@ -1839,6 +1892,8 @@ var schedule_2026_default = [
|
|
|
1839
1892
|
group: "J",
|
|
1840
1893
|
kickoff: "2026-06-28T02:00Z",
|
|
1841
1894
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
1895
|
+
city: "Kansas City, Missouri",
|
|
1896
|
+
country: "USA",
|
|
1842
1897
|
home: {
|
|
1843
1898
|
code: "ALG",
|
|
1844
1899
|
name: "Algeria",
|
|
@@ -1850,7 +1905,7 @@ var schedule_2026_default = [
|
|
|
1850
1905
|
flag: "\u{1F1E6}\u{1F1F9}"
|
|
1851
1906
|
},
|
|
1852
1907
|
status: "SCHEDULED",
|
|
1853
|
-
updatedAt: "2026-
|
|
1908
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1854
1909
|
},
|
|
1855
1910
|
{
|
|
1856
1911
|
id: "760483",
|
|
@@ -1858,6 +1913,8 @@ var schedule_2026_default = [
|
|
|
1858
1913
|
group: "J",
|
|
1859
1914
|
kickoff: "2026-06-28T02:00Z",
|
|
1860
1915
|
venue: "AT&T Stadium",
|
|
1916
|
+
city: "Arlington, Texas",
|
|
1917
|
+
country: "USA",
|
|
1861
1918
|
home: {
|
|
1862
1919
|
code: "JOR",
|
|
1863
1920
|
name: "Jordan",
|
|
@@ -1869,13 +1926,15 @@ var schedule_2026_default = [
|
|
|
1869
1926
|
flag: "\u{1F1E6}\u{1F1F7}"
|
|
1870
1927
|
},
|
|
1871
1928
|
status: "SCHEDULED",
|
|
1872
|
-
updatedAt: "2026-
|
|
1929
|
+
updatedAt: "2026-06-07T07:52:54.512Z"
|
|
1873
1930
|
},
|
|
1874
1931
|
{
|
|
1875
1932
|
id: "760486",
|
|
1876
1933
|
stage: "R32",
|
|
1877
1934
|
kickoff: "2026-06-28T19:00Z",
|
|
1878
1935
|
venue: "SoFi Stadium",
|
|
1936
|
+
city: "Inglewood, California",
|
|
1937
|
+
country: "USA",
|
|
1879
1938
|
home: {
|
|
1880
1939
|
code: "2A",
|
|
1881
1940
|
name: "Group A 2nd Place",
|
|
@@ -1887,13 +1946,15 @@ var schedule_2026_default = [
|
|
|
1887
1946
|
flag: "\u{1F3F3}\uFE0F"
|
|
1888
1947
|
},
|
|
1889
1948
|
status: "SCHEDULED",
|
|
1890
|
-
updatedAt: "2026-
|
|
1949
|
+
updatedAt: "2026-06-07T07:52:54.540Z"
|
|
1891
1950
|
},
|
|
1892
1951
|
{
|
|
1893
1952
|
id: "760487",
|
|
1894
1953
|
stage: "R32",
|
|
1895
1954
|
kickoff: "2026-06-29T17:00Z",
|
|
1896
1955
|
venue: "NRG Stadium",
|
|
1956
|
+
city: "Houston, Texas",
|
|
1957
|
+
country: "USA",
|
|
1897
1958
|
home: {
|
|
1898
1959
|
code: "1C",
|
|
1899
1960
|
name: "Group C Winner",
|
|
@@ -1905,13 +1966,15 @@ var schedule_2026_default = [
|
|
|
1905
1966
|
flag: "\u{1F3F3}\uFE0F"
|
|
1906
1967
|
},
|
|
1907
1968
|
status: "SCHEDULED",
|
|
1908
|
-
updatedAt: "2026-
|
|
1969
|
+
updatedAt: "2026-06-07T07:52:54.540Z"
|
|
1909
1970
|
},
|
|
1910
1971
|
{
|
|
1911
1972
|
id: "760489",
|
|
1912
1973
|
stage: "R32",
|
|
1913
1974
|
kickoff: "2026-06-29T20:30Z",
|
|
1914
1975
|
venue: "Gillette Stadium",
|
|
1976
|
+
city: "Foxborough, Massachusetts",
|
|
1977
|
+
country: "USA",
|
|
1915
1978
|
home: {
|
|
1916
1979
|
code: "1E",
|
|
1917
1980
|
name: "Group E Winner",
|
|
@@ -1923,13 +1986,15 @@ var schedule_2026_default = [
|
|
|
1923
1986
|
flag: "\u{1F3F3}\uFE0F"
|
|
1924
1987
|
},
|
|
1925
1988
|
status: "SCHEDULED",
|
|
1926
|
-
updatedAt: "2026-
|
|
1989
|
+
updatedAt: "2026-06-07T07:52:54.540Z"
|
|
1927
1990
|
},
|
|
1928
1991
|
{
|
|
1929
1992
|
id: "760488",
|
|
1930
1993
|
stage: "R32",
|
|
1931
1994
|
kickoff: "2026-06-30T01:00Z",
|
|
1932
1995
|
venue: "Estadio BBVA",
|
|
1996
|
+
city: "Guadalupe",
|
|
1997
|
+
country: "Mexico",
|
|
1933
1998
|
home: {
|
|
1934
1999
|
code: "1F",
|
|
1935
2000
|
name: "Group F Winner",
|
|
@@ -1941,13 +2006,15 @@ var schedule_2026_default = [
|
|
|
1941
2006
|
flag: "\u{1F3F3}\uFE0F"
|
|
1942
2007
|
},
|
|
1943
2008
|
status: "SCHEDULED",
|
|
1944
|
-
updatedAt: "2026-
|
|
2009
|
+
updatedAt: "2026-06-07T07:52:54.540Z"
|
|
1945
2010
|
},
|
|
1946
2011
|
{
|
|
1947
2012
|
id: "760490",
|
|
1948
2013
|
stage: "R32",
|
|
1949
2014
|
kickoff: "2026-06-30T17:00Z",
|
|
1950
2015
|
venue: "AT&T Stadium",
|
|
2016
|
+
city: "Arlington, Texas",
|
|
2017
|
+
country: "USA",
|
|
1951
2018
|
home: {
|
|
1952
2019
|
code: "2E",
|
|
1953
2020
|
name: "Group E 2nd Place",
|
|
@@ -1959,13 +2026,15 @@ var schedule_2026_default = [
|
|
|
1959
2026
|
flag: "\u{1F3F3}\uFE0F"
|
|
1960
2027
|
},
|
|
1961
2028
|
status: "SCHEDULED",
|
|
1962
|
-
updatedAt: "2026-
|
|
2029
|
+
updatedAt: "2026-06-07T07:52:54.540Z"
|
|
1963
2030
|
},
|
|
1964
2031
|
{
|
|
1965
2032
|
id: "760492",
|
|
1966
2033
|
stage: "R32",
|
|
1967
2034
|
kickoff: "2026-06-30T21:00Z",
|
|
1968
2035
|
venue: "MetLife Stadium",
|
|
2036
|
+
city: "East Rutherford, New Jersey",
|
|
2037
|
+
country: "USA",
|
|
1969
2038
|
home: {
|
|
1970
2039
|
code: "1I",
|
|
1971
2040
|
name: "Group I Winner",
|
|
@@ -1977,13 +2046,15 @@ var schedule_2026_default = [
|
|
|
1977
2046
|
flag: "\u{1F3F3}\uFE0F"
|
|
1978
2047
|
},
|
|
1979
2048
|
status: "SCHEDULED",
|
|
1980
|
-
updatedAt: "2026-
|
|
2049
|
+
updatedAt: "2026-06-07T07:52:54.541Z"
|
|
1981
2050
|
},
|
|
1982
2051
|
{
|
|
1983
2052
|
id: "760491",
|
|
1984
2053
|
stage: "R32",
|
|
1985
2054
|
kickoff: "2026-07-01T01:00Z",
|
|
1986
2055
|
venue: "Estadio Banorte",
|
|
2056
|
+
city: "Mexico City",
|
|
2057
|
+
country: "Mexico",
|
|
1987
2058
|
home: {
|
|
1988
2059
|
code: "1A",
|
|
1989
2060
|
name: "Group A Winner",
|
|
@@ -1995,13 +2066,15 @@ var schedule_2026_default = [
|
|
|
1995
2066
|
flag: "\u{1F3F3}\uFE0F"
|
|
1996
2067
|
},
|
|
1997
2068
|
status: "SCHEDULED",
|
|
1998
|
-
updatedAt: "2026-
|
|
2069
|
+
updatedAt: "2026-06-07T07:52:54.541Z"
|
|
1999
2070
|
},
|
|
2000
2071
|
{
|
|
2001
2072
|
id: "760495",
|
|
2002
2073
|
stage: "R32",
|
|
2003
2074
|
kickoff: "2026-07-01T16:00Z",
|
|
2004
2075
|
venue: "Mercedes-Benz Stadium",
|
|
2076
|
+
city: "Atlanta, Georgia",
|
|
2077
|
+
country: "USA",
|
|
2005
2078
|
home: {
|
|
2006
2079
|
code: "1L",
|
|
2007
2080
|
name: "Group L Winner",
|
|
@@ -2013,13 +2086,15 @@ var schedule_2026_default = [
|
|
|
2013
2086
|
flag: "\u{1F3F3}\uFE0F"
|
|
2014
2087
|
},
|
|
2015
2088
|
status: "SCHEDULED",
|
|
2016
|
-
updatedAt: "2026-
|
|
2089
|
+
updatedAt: "2026-06-07T07:52:54.541Z"
|
|
2017
2090
|
},
|
|
2018
2091
|
{
|
|
2019
2092
|
id: "760493",
|
|
2020
2093
|
stage: "R32",
|
|
2021
2094
|
kickoff: "2026-07-01T20:00Z",
|
|
2022
2095
|
venue: "Lumen Field",
|
|
2096
|
+
city: "Seattle, Washington",
|
|
2097
|
+
country: "USA",
|
|
2023
2098
|
home: {
|
|
2024
2099
|
code: "1G",
|
|
2025
2100
|
name: "Group G Winner",
|
|
@@ -2031,13 +2106,15 @@ var schedule_2026_default = [
|
|
|
2031
2106
|
flag: "\u{1F3F3}\uFE0F"
|
|
2032
2107
|
},
|
|
2033
2108
|
status: "SCHEDULED",
|
|
2034
|
-
updatedAt: "2026-
|
|
2109
|
+
updatedAt: "2026-06-07T07:52:54.541Z"
|
|
2035
2110
|
},
|
|
2036
2111
|
{
|
|
2037
2112
|
id: "760494",
|
|
2038
2113
|
stage: "R32",
|
|
2039
2114
|
kickoff: "2026-07-02T00:00Z",
|
|
2040
2115
|
venue: "Levi's Stadium",
|
|
2116
|
+
city: "Santa Clara, California",
|
|
2117
|
+
country: "USA",
|
|
2041
2118
|
home: {
|
|
2042
2119
|
code: "1D",
|
|
2043
2120
|
name: "Group D Winner",
|
|
@@ -2049,13 +2126,15 @@ var schedule_2026_default = [
|
|
|
2049
2126
|
flag: "\u{1F3F3}\uFE0F"
|
|
2050
2127
|
},
|
|
2051
2128
|
status: "SCHEDULED",
|
|
2052
|
-
updatedAt: "2026-
|
|
2129
|
+
updatedAt: "2026-06-07T07:52:54.541Z"
|
|
2053
2130
|
},
|
|
2054
2131
|
{
|
|
2055
2132
|
id: "760497",
|
|
2056
2133
|
stage: "R32",
|
|
2057
2134
|
kickoff: "2026-07-02T19:00Z",
|
|
2058
2135
|
venue: "SoFi Stadium",
|
|
2136
|
+
city: "Inglewood, California",
|
|
2137
|
+
country: "USA",
|
|
2059
2138
|
home: {
|
|
2060
2139
|
code: "1H",
|
|
2061
2140
|
name: "Group H Winner",
|
|
@@ -2067,13 +2146,15 @@ var schedule_2026_default = [
|
|
|
2067
2146
|
flag: "\u{1F3F3}\uFE0F"
|
|
2068
2147
|
},
|
|
2069
2148
|
status: "SCHEDULED",
|
|
2070
|
-
updatedAt: "2026-
|
|
2149
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2071
2150
|
},
|
|
2072
2151
|
{
|
|
2073
2152
|
id: "760496",
|
|
2074
2153
|
stage: "R32",
|
|
2075
2154
|
kickoff: "2026-07-02T23:00Z",
|
|
2076
2155
|
venue: "BMO Field",
|
|
2156
|
+
city: "Toronto",
|
|
2157
|
+
country: "Canada",
|
|
2077
2158
|
home: {
|
|
2078
2159
|
code: "2K",
|
|
2079
2160
|
name: "Group K 2nd Place",
|
|
@@ -2085,13 +2166,15 @@ var schedule_2026_default = [
|
|
|
2085
2166
|
flag: "\u{1F3F3}\uFE0F"
|
|
2086
2167
|
},
|
|
2087
2168
|
status: "SCHEDULED",
|
|
2088
|
-
updatedAt: "2026-
|
|
2169
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2089
2170
|
},
|
|
2090
2171
|
{
|
|
2091
2172
|
id: "760498",
|
|
2092
2173
|
stage: "R32",
|
|
2093
2174
|
kickoff: "2026-07-03T03:00Z",
|
|
2094
2175
|
venue: "BC Place",
|
|
2176
|
+
city: "Vancouver",
|
|
2177
|
+
country: "Canada",
|
|
2095
2178
|
home: {
|
|
2096
2179
|
code: "1B",
|
|
2097
2180
|
name: "Group B Winner",
|
|
@@ -2103,13 +2186,15 @@ var schedule_2026_default = [
|
|
|
2103
2186
|
flag: "\u{1F3F3}\uFE0F"
|
|
2104
2187
|
},
|
|
2105
2188
|
status: "SCHEDULED",
|
|
2106
|
-
updatedAt: "2026-
|
|
2189
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2107
2190
|
},
|
|
2108
2191
|
{
|
|
2109
2192
|
id: "760499",
|
|
2110
2193
|
stage: "R32",
|
|
2111
2194
|
kickoff: "2026-07-03T18:00Z",
|
|
2112
2195
|
venue: "AT&T Stadium",
|
|
2196
|
+
city: "Arlington, Texas",
|
|
2197
|
+
country: "USA",
|
|
2113
2198
|
home: {
|
|
2114
2199
|
code: "2D",
|
|
2115
2200
|
name: "Group D 2nd Place",
|
|
@@ -2121,13 +2206,15 @@ var schedule_2026_default = [
|
|
|
2121
2206
|
flag: "\u{1F3F3}\uFE0F"
|
|
2122
2207
|
},
|
|
2123
2208
|
status: "SCHEDULED",
|
|
2124
|
-
updatedAt: "2026-
|
|
2209
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2125
2210
|
},
|
|
2126
2211
|
{
|
|
2127
2212
|
id: "760500",
|
|
2128
2213
|
stage: "R32",
|
|
2129
2214
|
kickoff: "2026-07-03T22:00Z",
|
|
2130
2215
|
venue: "Hard Rock Stadium",
|
|
2216
|
+
city: "Miami Gardens, Florida",
|
|
2217
|
+
country: "USA",
|
|
2131
2218
|
home: {
|
|
2132
2219
|
code: "1J",
|
|
2133
2220
|
name: "Group J Winner",
|
|
@@ -2139,13 +2226,15 @@ var schedule_2026_default = [
|
|
|
2139
2226
|
flag: "\u{1F3F3}\uFE0F"
|
|
2140
2227
|
},
|
|
2141
2228
|
status: "SCHEDULED",
|
|
2142
|
-
updatedAt: "2026-
|
|
2229
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2143
2230
|
},
|
|
2144
2231
|
{
|
|
2145
2232
|
id: "760501",
|
|
2146
2233
|
stage: "R32",
|
|
2147
2234
|
kickoff: "2026-07-04T01:30Z",
|
|
2148
2235
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
2236
|
+
city: "Kansas City, Missouri",
|
|
2237
|
+
country: "USA",
|
|
2149
2238
|
home: {
|
|
2150
2239
|
code: "1K",
|
|
2151
2240
|
name: "Group K Winner",
|
|
@@ -2157,13 +2246,15 @@ var schedule_2026_default = [
|
|
|
2157
2246
|
flag: "\u{1F3F3}\uFE0F"
|
|
2158
2247
|
},
|
|
2159
2248
|
status: "SCHEDULED",
|
|
2160
|
-
updatedAt: "2026-
|
|
2249
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2161
2250
|
},
|
|
2162
2251
|
{
|
|
2163
2252
|
id: "760502",
|
|
2164
2253
|
stage: "R16",
|
|
2165
2254
|
kickoff: "2026-07-04T17:00Z",
|
|
2166
2255
|
venue: "NRG Stadium",
|
|
2256
|
+
city: "Houston, Texas",
|
|
2257
|
+
country: "USA",
|
|
2167
2258
|
home: {
|
|
2168
2259
|
code: "RD32",
|
|
2169
2260
|
name: "Round of 32 1 Winner",
|
|
@@ -2175,13 +2266,15 @@ var schedule_2026_default = [
|
|
|
2175
2266
|
flag: "\u{1F3F3}\uFE0F"
|
|
2176
2267
|
},
|
|
2177
2268
|
status: "SCHEDULED",
|
|
2178
|
-
updatedAt: "2026-
|
|
2269
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2179
2270
|
},
|
|
2180
2271
|
{
|
|
2181
2272
|
id: "760503",
|
|
2182
2273
|
stage: "R16",
|
|
2183
2274
|
kickoff: "2026-07-04T21:00Z",
|
|
2184
2275
|
venue: "Lincoln Financial Field",
|
|
2276
|
+
city: "Philadelphia, Pennsylvania",
|
|
2277
|
+
country: "USA",
|
|
2185
2278
|
home: {
|
|
2186
2279
|
code: "RD32",
|
|
2187
2280
|
name: "Round of 32 2 Winner",
|
|
@@ -2193,13 +2286,15 @@ var schedule_2026_default = [
|
|
|
2193
2286
|
flag: "\u{1F3F3}\uFE0F"
|
|
2194
2287
|
},
|
|
2195
2288
|
status: "SCHEDULED",
|
|
2196
|
-
updatedAt: "2026-
|
|
2289
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2197
2290
|
},
|
|
2198
2291
|
{
|
|
2199
2292
|
id: "760504",
|
|
2200
2293
|
stage: "R16",
|
|
2201
2294
|
kickoff: "2026-07-05T20:00Z",
|
|
2202
2295
|
venue: "MetLife Stadium",
|
|
2296
|
+
city: "East Rutherford, New Jersey",
|
|
2297
|
+
country: "USA",
|
|
2203
2298
|
home: {
|
|
2204
2299
|
code: "RD32",
|
|
2205
2300
|
name: "Round of 32 4 Winner",
|
|
@@ -2211,13 +2306,15 @@ var schedule_2026_default = [
|
|
|
2211
2306
|
flag: "\u{1F3F3}\uFE0F"
|
|
2212
2307
|
},
|
|
2213
2308
|
status: "SCHEDULED",
|
|
2214
|
-
updatedAt: "2026-
|
|
2309
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2215
2310
|
},
|
|
2216
2311
|
{
|
|
2217
2312
|
id: "760505",
|
|
2218
2313
|
stage: "R16",
|
|
2219
2314
|
kickoff: "2026-07-06T00:00Z",
|
|
2220
2315
|
venue: "Estadio Banorte",
|
|
2316
|
+
city: "Mexico City",
|
|
2317
|
+
country: "Mexico",
|
|
2221
2318
|
home: {
|
|
2222
2319
|
code: "RD32",
|
|
2223
2320
|
name: "Round of 32 7 Winner",
|
|
@@ -2229,13 +2326,15 @@ var schedule_2026_default = [
|
|
|
2229
2326
|
flag: "\u{1F3F3}\uFE0F"
|
|
2230
2327
|
},
|
|
2231
2328
|
status: "SCHEDULED",
|
|
2232
|
-
updatedAt: "2026-
|
|
2329
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2233
2330
|
},
|
|
2234
2331
|
{
|
|
2235
2332
|
id: "760506",
|
|
2236
2333
|
stage: "R16",
|
|
2237
2334
|
kickoff: "2026-07-06T19:00Z",
|
|
2238
2335
|
venue: "AT&T Stadium",
|
|
2336
|
+
city: "Arlington, Texas",
|
|
2337
|
+
country: "USA",
|
|
2239
2338
|
home: {
|
|
2240
2339
|
code: "RD32",
|
|
2241
2340
|
name: "Round of 32 11 Winner",
|
|
@@ -2247,13 +2346,15 @@ var schedule_2026_default = [
|
|
|
2247
2346
|
flag: "\u{1F3F3}\uFE0F"
|
|
2248
2347
|
},
|
|
2249
2348
|
status: "SCHEDULED",
|
|
2250
|
-
updatedAt: "2026-
|
|
2349
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2251
2350
|
},
|
|
2252
2351
|
{
|
|
2253
2352
|
id: "760507",
|
|
2254
2353
|
stage: "R16",
|
|
2255
2354
|
kickoff: "2026-07-07T00:00Z",
|
|
2256
2355
|
venue: "Lumen Field",
|
|
2356
|
+
city: "Seattle, Washington",
|
|
2357
|
+
country: "USA",
|
|
2257
2358
|
home: {
|
|
2258
2359
|
code: "RD32",
|
|
2259
2360
|
name: "Round of 32 9 Winner",
|
|
@@ -2265,13 +2366,15 @@ var schedule_2026_default = [
|
|
|
2265
2366
|
flag: "\u{1F3F3}\uFE0F"
|
|
2266
2367
|
},
|
|
2267
2368
|
status: "SCHEDULED",
|
|
2268
|
-
updatedAt: "2026-
|
|
2369
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2269
2370
|
},
|
|
2270
2371
|
{
|
|
2271
2372
|
id: "760509",
|
|
2272
2373
|
stage: "R16",
|
|
2273
2374
|
kickoff: "2026-07-07T16:00Z",
|
|
2274
2375
|
venue: "Mercedes-Benz Stadium",
|
|
2376
|
+
city: "Atlanta, Georgia",
|
|
2377
|
+
country: "USA",
|
|
2275
2378
|
home: {
|
|
2276
2379
|
code: "RD32",
|
|
2277
2380
|
name: "Round of 32 14 Winner",
|
|
@@ -2283,13 +2386,15 @@ var schedule_2026_default = [
|
|
|
2283
2386
|
flag: "\u{1F3F3}\uFE0F"
|
|
2284
2387
|
},
|
|
2285
2388
|
status: "SCHEDULED",
|
|
2286
|
-
updatedAt: "2026-
|
|
2389
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2287
2390
|
},
|
|
2288
2391
|
{
|
|
2289
2392
|
id: "760508",
|
|
2290
2393
|
stage: "R16",
|
|
2291
2394
|
kickoff: "2026-07-07T20:00Z",
|
|
2292
2395
|
venue: "BC Place",
|
|
2396
|
+
city: "Vancouver",
|
|
2397
|
+
country: "Canada",
|
|
2293
2398
|
home: {
|
|
2294
2399
|
code: "RD32",
|
|
2295
2400
|
name: "Round of 32 13 Winner",
|
|
@@ -2301,13 +2406,15 @@ var schedule_2026_default = [
|
|
|
2301
2406
|
flag: "\u{1F3F3}\uFE0F"
|
|
2302
2407
|
},
|
|
2303
2408
|
status: "SCHEDULED",
|
|
2304
|
-
updatedAt: "2026-
|
|
2409
|
+
updatedAt: "2026-06-07T07:52:54.616Z"
|
|
2305
2410
|
},
|
|
2306
2411
|
{
|
|
2307
2412
|
id: "760510",
|
|
2308
2413
|
stage: "QF",
|
|
2309
2414
|
kickoff: "2026-07-09T20:00Z",
|
|
2310
2415
|
venue: "Gillette Stadium",
|
|
2416
|
+
city: "Foxborough, Massachusetts",
|
|
2417
|
+
country: "USA",
|
|
2311
2418
|
home: {
|
|
2312
2419
|
code: "RD16 W1",
|
|
2313
2420
|
name: "Round of 16 1 Winner",
|
|
@@ -2319,13 +2426,15 @@ var schedule_2026_default = [
|
|
|
2319
2426
|
flag: "\u{1F3F3}\uFE0F"
|
|
2320
2427
|
},
|
|
2321
2428
|
status: "SCHEDULED",
|
|
2322
|
-
updatedAt: "2026-
|
|
2429
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2323
2430
|
},
|
|
2324
2431
|
{
|
|
2325
2432
|
id: "760511",
|
|
2326
2433
|
stage: "QF",
|
|
2327
2434
|
kickoff: "2026-07-10T19:00Z",
|
|
2328
2435
|
venue: "SoFi Stadium",
|
|
2436
|
+
city: "Inglewood, California",
|
|
2437
|
+
country: "USA",
|
|
2329
2438
|
home: {
|
|
2330
2439
|
code: "RD16 W5",
|
|
2331
2440
|
name: "Round of 16 5 Winner",
|
|
@@ -2337,13 +2446,15 @@ var schedule_2026_default = [
|
|
|
2337
2446
|
flag: "\u{1F3F3}\uFE0F"
|
|
2338
2447
|
},
|
|
2339
2448
|
status: "SCHEDULED",
|
|
2340
|
-
updatedAt: "2026-
|
|
2449
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2341
2450
|
},
|
|
2342
2451
|
{
|
|
2343
2452
|
id: "760512",
|
|
2344
2453
|
stage: "QF",
|
|
2345
2454
|
kickoff: "2026-07-11T21:00Z",
|
|
2346
2455
|
venue: "Hard Rock Stadium",
|
|
2456
|
+
city: "Miami Gardens, Florida",
|
|
2457
|
+
country: "USA",
|
|
2347
2458
|
home: {
|
|
2348
2459
|
code: "RD16 W3",
|
|
2349
2460
|
name: "Round of 16 3 Winner",
|
|
@@ -2355,13 +2466,15 @@ var schedule_2026_default = [
|
|
|
2355
2466
|
flag: "\u{1F3F3}\uFE0F"
|
|
2356
2467
|
},
|
|
2357
2468
|
status: "SCHEDULED",
|
|
2358
|
-
updatedAt: "2026-
|
|
2469
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2359
2470
|
},
|
|
2360
2471
|
{
|
|
2361
2472
|
id: "760513",
|
|
2362
2473
|
stage: "QF",
|
|
2363
2474
|
kickoff: "2026-07-12T01:00Z",
|
|
2364
2475
|
venue: "GEHA Field at Arrowhead Stadium",
|
|
2476
|
+
city: "Kansas City, Missouri",
|
|
2477
|
+
country: "USA",
|
|
2365
2478
|
home: {
|
|
2366
2479
|
code: "RD16 W7",
|
|
2367
2480
|
name: "Round of 16 7 Winner",
|
|
@@ -2373,13 +2486,15 @@ var schedule_2026_default = [
|
|
|
2373
2486
|
flag: "\u{1F3F3}\uFE0F"
|
|
2374
2487
|
},
|
|
2375
2488
|
status: "SCHEDULED",
|
|
2376
|
-
updatedAt: "2026-
|
|
2489
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2377
2490
|
},
|
|
2378
2491
|
{
|
|
2379
2492
|
id: "760514",
|
|
2380
2493
|
stage: "SF",
|
|
2381
2494
|
kickoff: "2026-07-14T19:00Z",
|
|
2382
2495
|
venue: "AT&T Stadium",
|
|
2496
|
+
city: "Arlington, Texas",
|
|
2497
|
+
country: "USA",
|
|
2383
2498
|
home: {
|
|
2384
2499
|
code: "QFW1",
|
|
2385
2500
|
name: "Quarterfinal 1 Winner",
|
|
@@ -2391,13 +2506,15 @@ var schedule_2026_default = [
|
|
|
2391
2506
|
flag: "\u{1F3F3}\uFE0F"
|
|
2392
2507
|
},
|
|
2393
2508
|
status: "SCHEDULED",
|
|
2394
|
-
updatedAt: "2026-
|
|
2509
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2395
2510
|
},
|
|
2396
2511
|
{
|
|
2397
2512
|
id: "760515",
|
|
2398
2513
|
stage: "SF",
|
|
2399
2514
|
kickoff: "2026-07-15T19:00Z",
|
|
2400
2515
|
venue: "Mercedes-Benz Stadium",
|
|
2516
|
+
city: "Atlanta, Georgia",
|
|
2517
|
+
country: "USA",
|
|
2401
2518
|
home: {
|
|
2402
2519
|
code: "QFW3",
|
|
2403
2520
|
name: "Quarterfinal 3 Winner",
|
|
@@ -2409,13 +2526,15 @@ var schedule_2026_default = [
|
|
|
2409
2526
|
flag: "\u{1F3F3}\uFE0F"
|
|
2410
2527
|
},
|
|
2411
2528
|
status: "SCHEDULED",
|
|
2412
|
-
updatedAt: "2026-
|
|
2529
|
+
updatedAt: "2026-06-07T07:52:54.684Z"
|
|
2413
2530
|
},
|
|
2414
2531
|
{
|
|
2415
2532
|
id: "760516",
|
|
2416
2533
|
stage: "3P",
|
|
2417
2534
|
kickoff: "2026-07-18T21:00Z",
|
|
2418
2535
|
venue: "Hard Rock Stadium",
|
|
2536
|
+
city: "Miami Gardens, Florida",
|
|
2537
|
+
country: "USA",
|
|
2419
2538
|
home: {
|
|
2420
2539
|
code: "SF L1",
|
|
2421
2540
|
name: "Semifinal 1 Loser",
|
|
@@ -2427,13 +2546,15 @@ var schedule_2026_default = [
|
|
|
2427
2546
|
flag: "\u{1F3F3}\uFE0F"
|
|
2428
2547
|
},
|
|
2429
2548
|
status: "SCHEDULED",
|
|
2430
|
-
updatedAt: "2026-
|
|
2549
|
+
updatedAt: "2026-06-07T07:52:54.772Z"
|
|
2431
2550
|
},
|
|
2432
2551
|
{
|
|
2433
2552
|
id: "760517",
|
|
2434
2553
|
stage: "F",
|
|
2435
2554
|
kickoff: "2026-07-19T19:00Z",
|
|
2436
2555
|
venue: "MetLife Stadium",
|
|
2556
|
+
city: "East Rutherford, New Jersey",
|
|
2557
|
+
country: "USA",
|
|
2437
2558
|
home: {
|
|
2438
2559
|
code: "SFW1",
|
|
2439
2560
|
name: "Semifinal 1 Winner",
|
|
@@ -2445,16 +2566,16 @@ var schedule_2026_default = [
|
|
|
2445
2566
|
flag: "\u{1F3F3}\uFE0F"
|
|
2446
2567
|
},
|
|
2447
2568
|
status: "SCHEDULED",
|
|
2448
|
-
updatedAt: "2026-
|
|
2569
|
+
updatedAt: "2026-06-07T07:52:54.772Z"
|
|
2449
2570
|
}
|
|
2450
2571
|
];
|
|
2451
2572
|
var SCHEDULE = schedule_2026_default;
|
|
2452
2573
|
function allFixtures() {
|
|
2453
2574
|
return SCHEDULE;
|
|
2454
2575
|
}
|
|
2455
|
-
function fixturesByDate(dateISO, fixtures = SCHEDULE) {
|
|
2576
|
+
function fixturesByDate(dateISO, fixtures = SCHEDULE, tz) {
|
|
2456
2577
|
const day = dateISO.slice(0, 10);
|
|
2457
|
-
return fixtures.filter((m) => m.kickoff
|
|
2578
|
+
return fixtures.filter((m) => localDate(m.kickoff, tz) === day).sort(byKickoff);
|
|
2458
2579
|
}
|
|
2459
2580
|
function fixturesByTeam(code, fixtures = SCHEDULE) {
|
|
2460
2581
|
const c = code.toUpperCase();
|
|
@@ -2602,6 +2723,8 @@ function mapEspnEvent(ev, ctx = {}) {
|
|
|
2602
2723
|
group,
|
|
2603
2724
|
kickoff: ev.date,
|
|
2604
2725
|
venue: comp?.venue?.fullName ?? "",
|
|
2726
|
+
city: comp?.venue?.address?.city || void 0,
|
|
2727
|
+
country: comp?.venue?.address?.country || void 0,
|
|
2605
2728
|
home,
|
|
2606
2729
|
away,
|
|
2607
2730
|
score: hasScore ? { home: hs, away: as } : void 0,
|
|
@@ -2695,7 +2818,6 @@ function resolveCompetition(explicit) {
|
|
|
2695
2818
|
}
|
|
2696
2819
|
function makeAdapter(source = "espn") {
|
|
2697
2820
|
switch (source) {
|
|
2698
|
-
case "espn":
|
|
2699
2821
|
default: {
|
|
2700
2822
|
const competition = resolveCompetition();
|
|
2701
2823
|
const baseUrl = competition === DEFAULT_COMPETITION ? void 0 : competitionBase(competition);
|
|
@@ -2708,130 +2830,789 @@ function mergeLive(base, live) {
|
|
|
2708
2830
|
for (const m of live) byId.set(m.id, m);
|
|
2709
2831
|
return [...byId.values()];
|
|
2710
2832
|
}
|
|
2833
|
+
function liveSourceLabel(source) {
|
|
2834
|
+
const known = { espn: "ESPN" };
|
|
2835
|
+
return known[source] ?? source.charAt(0).toUpperCase() + source.slice(1);
|
|
2836
|
+
}
|
|
2711
2837
|
async function getMatchesForDate(adapter, dateISO) {
|
|
2712
2838
|
const base = allFixtures();
|
|
2839
|
+
const day = dateISO.slice(0, 10);
|
|
2713
2840
|
try {
|
|
2714
|
-
const live = await adapter.fetchByDate(
|
|
2715
|
-
return { matches: mergeLive(base, live), degraded: false };
|
|
2841
|
+
const live = adapter.fetchWindow ? await adapter.fetchWindow(shiftUtcDate(day, -1), shiftUtcDate(day, 1)) : await adapter.fetchByDate(day);
|
|
2842
|
+
return { matches: mergeLive(base, live), degraded: false, source: adapter.name };
|
|
2716
2843
|
} catch {
|
|
2717
2844
|
return { matches: base, degraded: true };
|
|
2718
2845
|
}
|
|
2719
2846
|
}
|
|
2847
|
+
function shiftUtcDate(dateISO, days) {
|
|
2848
|
+
const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
|
|
2849
|
+
return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
|
|
2850
|
+
}
|
|
2720
2851
|
async function getLiveMatches(adapter) {
|
|
2721
2852
|
try {
|
|
2722
|
-
return { matches: await adapter.fetchLive(), degraded: false };
|
|
2853
|
+
return { matches: await adapter.fetchLive(), degraded: false, source: adapter.name };
|
|
2723
2854
|
} catch {
|
|
2724
2855
|
return { matches: [], degraded: true };
|
|
2725
2856
|
}
|
|
2726
2857
|
}
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2858
|
+
var DEFAULT_MAX_AGE_MS = 15 * 6e4;
|
|
2859
|
+
function normalizeOutcomes(outcomes) {
|
|
2860
|
+
const sum = outcomes.reduce(
|
|
2861
|
+
(s, o) => s + (Number.isFinite(o.probability) && o.probability > 0 ? o.probability : 0),
|
|
2862
|
+
0
|
|
2863
|
+
);
|
|
2864
|
+
if (sum <= 0) return outcomes.map((o) => ({ ...o, probability: 0 }));
|
|
2865
|
+
return outcomes.map((o) => ({
|
|
2866
|
+
...o,
|
|
2867
|
+
probability: Number.isFinite(o.probability) && o.probability > 0 ? o.probability / sum : 0
|
|
2868
|
+
}));
|
|
2869
|
+
}
|
|
2870
|
+
function favoriteStrength(probability) {
|
|
2871
|
+
if (probability >= 0.65) return "clear";
|
|
2872
|
+
if (probability >= 0.52) return "slight";
|
|
2873
|
+
return "close";
|
|
2874
|
+
}
|
|
2875
|
+
function deriveFavorite(outcomes) {
|
|
2876
|
+
let top;
|
|
2877
|
+
for (const o of outcomes) {
|
|
2878
|
+
if (o.kind === "other") continue;
|
|
2879
|
+
if (!top || o.probability > top.probability) top = o;
|
|
2745
2880
|
}
|
|
2881
|
+
if (!top || top.probability <= 0 || top.kind === "other") return void 0;
|
|
2746
2882
|
return {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
red: pc.red,
|
|
2752
|
-
cyan: pc.cyan,
|
|
2753
|
-
gray: pc.gray
|
|
2883
|
+
kind: top.kind,
|
|
2884
|
+
teamCode: top.teamCode,
|
|
2885
|
+
probability: top.probability,
|
|
2886
|
+
strength: favoriteStrength(top.probability)
|
|
2754
2887
|
};
|
|
2755
2888
|
}
|
|
2756
|
-
function
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
return c.yellow(t("status.ht"));
|
|
2765
|
-
case "FT":
|
|
2766
|
-
return c.gray(t("status.ft"));
|
|
2767
|
-
case "POSTPONED":
|
|
2768
|
-
return c.red(t("status.postponed"));
|
|
2769
|
-
case "CANCELLED":
|
|
2770
|
-
return c.red(t("status.cancelled"));
|
|
2771
|
-
case "SCHEDULED":
|
|
2772
|
-
default:
|
|
2773
|
-
return "";
|
|
2889
|
+
function mapsCleanly(match, outcomes) {
|
|
2890
|
+
if (outcomes.some((o) => o.kind === "other")) return false;
|
|
2891
|
+
const home = outcomes.find((o) => o.kind === "home");
|
|
2892
|
+
const away = outcomes.find((o) => o.kind === "away");
|
|
2893
|
+
const draw = outcomes.find((o) => o.kind === "draw");
|
|
2894
|
+
if (!home || !away) return false;
|
|
2895
|
+
if (home.teamCode && home.teamCode.toUpperCase() !== match.home.code.toUpperCase()) {
|
|
2896
|
+
return false;
|
|
2774
2897
|
}
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
const home = `${m.home.flag} ${m.home.name}`;
|
|
2778
|
-
const away = `${m.away.name} ${m.away.flag}`;
|
|
2779
|
-
const mid = isLive(m.status) || m.status === "FT" ? c.bold(scoreline(m)) : c.dim("vs");
|
|
2780
|
-
const left = `${home.padEnd(22)} ${mid.padStart(3)} ${away}`;
|
|
2781
|
-
let right = "";
|
|
2782
|
-
if (m.status === "SCHEDULED") {
|
|
2783
|
-
right = c.dim(
|
|
2784
|
-
`${formatKickoff(m.kickoff, { tz: cfg.tz, locale: cfg.lang })}`
|
|
2785
|
-
);
|
|
2786
|
-
} else {
|
|
2787
|
-
right = statusToken(m, t, c);
|
|
2898
|
+
if (away.teamCode && away.teamCode.toUpperCase() !== match.away.code.toUpperCase()) {
|
|
2899
|
+
return false;
|
|
2788
2900
|
}
|
|
2789
|
-
|
|
2901
|
+
if (match.stage === "GROUP" && !draw) return false;
|
|
2902
|
+
return true;
|
|
2790
2903
|
}
|
|
2791
|
-
function
|
|
2792
|
-
|
|
2904
|
+
function hasSaneDistribution(outcomes) {
|
|
2905
|
+
const priced = outcomes.filter((o) => Number.isFinite(o.probability) && o.probability > 0);
|
|
2906
|
+
if (priced.length < 2) return false;
|
|
2907
|
+
const sum = priced.reduce((s, o) => s + o.probability, 0);
|
|
2908
|
+
return sum > 0.97 && sum < 1.03;
|
|
2793
2909
|
}
|
|
2794
|
-
function
|
|
2910
|
+
function isStaleSignal(signal, options = {}) {
|
|
2911
|
+
const maxAge = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
2912
|
+
const asOf = Date.parse(signal.asOf);
|
|
2913
|
+
if (!Number.isFinite(asOf)) return true;
|
|
2914
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
2915
|
+
return now - asOf > maxAge;
|
|
2916
|
+
}
|
|
2917
|
+
function isReliableMarketSignal(signal, options = {}) {
|
|
2918
|
+
if (options.includeUnreliable) return true;
|
|
2919
|
+
if (signal.ambiguous) return false;
|
|
2920
|
+
if (!signal.favorite) return false;
|
|
2921
|
+
if (!hasSaneDistribution(signal.outcomes)) return false;
|
|
2922
|
+
if (signal.stale || isStaleSignal(signal, options)) return false;
|
|
2923
|
+
if (options.minLiquidity != null) {
|
|
2924
|
+
if (signal.liquidity == null || signal.liquidity < options.minLiquidity) return false;
|
|
2925
|
+
}
|
|
2926
|
+
return true;
|
|
2927
|
+
}
|
|
2928
|
+
function buildMarketSignal(input) {
|
|
2929
|
+
const outcomes = normalizeOutcomes(input.outcomes);
|
|
2930
|
+
const ambiguous = input.ambiguous === true || !mapsCleanly(input.match, outcomes);
|
|
2931
|
+
const favorite = ambiguous ? void 0 : deriveFavorite(outcomes);
|
|
2932
|
+
const signal = {
|
|
2933
|
+
matchId: input.match.id,
|
|
2934
|
+
source: input.source,
|
|
2935
|
+
sourceMarketId: input.sourceMarketId,
|
|
2936
|
+
asOf: input.asOf,
|
|
2937
|
+
fetchedAt: input.fetchedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2938
|
+
outcomes,
|
|
2939
|
+
favorite,
|
|
2940
|
+
liquidity: input.liquidity,
|
|
2941
|
+
volume24h: input.volume24h,
|
|
2942
|
+
stale: false,
|
|
2943
|
+
ambiguous
|
|
2944
|
+
};
|
|
2945
|
+
signal.stale = isStaleSignal(signal, { now: input.now, maxAgeMs: input.maxAgeMs });
|
|
2946
|
+
return signal;
|
|
2947
|
+
}
|
|
2948
|
+
function pct(p) {
|
|
2949
|
+
return Math.round(p * 100);
|
|
2950
|
+
}
|
|
2951
|
+
function marketSourceLabel(source) {
|
|
2952
|
+
if (source === "polymarket") return "Polymarket";
|
|
2953
|
+
if (source === "fake") return "demo data";
|
|
2954
|
+
return source.charAt(0).toUpperCase() + source.slice(1);
|
|
2955
|
+
}
|
|
2956
|
+
function outcomeLabel(o, match) {
|
|
2957
|
+
if (o.kind === "home") return match.home.name;
|
|
2958
|
+
if (o.kind === "away") return match.away.name;
|
|
2959
|
+
if (o.kind === "draw") return "Draw";
|
|
2960
|
+
return o.label;
|
|
2961
|
+
}
|
|
2962
|
+
function utcHhmm(iso) {
|
|
2963
|
+
const t = Date.parse(iso);
|
|
2964
|
+
if (!Number.isFinite(t)) return "";
|
|
2965
|
+
return `${new Date(t).toISOString().slice(11, 16)} UTC`;
|
|
2966
|
+
}
|
|
2967
|
+
function marketFavoriteText(signal, match) {
|
|
2968
|
+
const fav = signal.favorite;
|
|
2969
|
+
if (!fav || fav.strength === "close") return "Prediction markets see this match as close.";
|
|
2970
|
+
if (fav.kind === "draw") return "Prediction markets see a draw as the top outcome.";
|
|
2971
|
+
const name = fav.kind === "home" ? match.home.name : match.away.name;
|
|
2972
|
+
return fav.strength === "clear" ? `Prediction markets favor ${name}.` : `Prediction markets slightly favor ${name}.`;
|
|
2973
|
+
}
|
|
2974
|
+
function marketProbabilityText(signal, match) {
|
|
2975
|
+
const order = ["home", "draw", "away"];
|
|
2976
|
+
const parts = [];
|
|
2977
|
+
for (const kind of order) {
|
|
2978
|
+
const o = signal.outcomes.find((x) => x.kind === kind);
|
|
2979
|
+
if (o) parts.push(`${outcomeLabel(o, match)} ${pct(o.probability)}%`);
|
|
2980
|
+
}
|
|
2981
|
+
for (const o of signal.outcomes) {
|
|
2982
|
+
if (o.kind === "other") parts.push(`${outcomeLabel(o, match)} ${pct(o.probability)}%`);
|
|
2983
|
+
}
|
|
2984
|
+
return parts.join(" \xB7 ");
|
|
2985
|
+
}
|
|
2986
|
+
function marketAttributionText(signal) {
|
|
2987
|
+
const time = utcHhmm(signal.asOf);
|
|
2988
|
+
const src = `Source: ${marketSourceLabel(signal.source)}`;
|
|
2989
|
+
return time ? `${src} \xB7 updated ${time}` : src;
|
|
2990
|
+
}
|
|
2991
|
+
function marketLine(signal, match) {
|
|
2992
|
+
return `Market: ${marketProbabilityText(signal, match)} \xB7 ${marketSourceLabel(
|
|
2993
|
+
signal.source
|
|
2994
|
+
)} \xB7 informational only`;
|
|
2995
|
+
}
|
|
2996
|
+
function marketBlock(signal, match) {
|
|
2997
|
+
const lines = [];
|
|
2998
|
+
if (signal.stale) lines.push("Market signal is stale; the reading may be out of date.");
|
|
2999
|
+
lines.push(marketFavoriteText(signal, match));
|
|
3000
|
+
lines.push(marketProbabilityText(signal, match));
|
|
3001
|
+
lines.push(`${marketAttributionText(signal)} \xB7 informational only`);
|
|
3002
|
+
return lines;
|
|
3003
|
+
}
|
|
3004
|
+
var FakeMarketProvider = class {
|
|
3005
|
+
constructor(opts = {}) {
|
|
3006
|
+
this.opts = opts;
|
|
3007
|
+
}
|
|
3008
|
+
opts;
|
|
3009
|
+
name = "fake";
|
|
3010
|
+
async findSignal(match, options) {
|
|
3011
|
+
const preset = this.opts.signals?.[match.id];
|
|
3012
|
+
if (preset) return preset;
|
|
3013
|
+
if (this.opts.synthesize) return this.synthesize(match, options);
|
|
3014
|
+
return void 0;
|
|
3015
|
+
}
|
|
3016
|
+
async findSignals(matches, options) {
|
|
3017
|
+
const signals = /* @__PURE__ */ new Map();
|
|
3018
|
+
const checked = /* @__PURE__ */ new Set();
|
|
3019
|
+
for (const m of matches) {
|
|
3020
|
+
checked.add(m.id);
|
|
3021
|
+
const s = await this.findSignal(m, options);
|
|
3022
|
+
if (s) signals.set(m.id, s);
|
|
3023
|
+
}
|
|
3024
|
+
return { signals, checked };
|
|
3025
|
+
}
|
|
3026
|
+
synthesize(match, options) {
|
|
3027
|
+
const seed = hash(`${match.home.code}-${match.away.code}`);
|
|
3028
|
+
const home = 0.3 + seed % 33 / 100;
|
|
3029
|
+
const away = 0.18 + (seed >> 3) % 23 / 100;
|
|
3030
|
+
const draw = Math.max(0.05, 1 - home - away);
|
|
3031
|
+
const outcomes = [
|
|
3032
|
+
{ kind: "home", teamCode: match.home.code, label: match.home.name, probability: home },
|
|
3033
|
+
{ kind: "draw", label: "Draw", probability: draw },
|
|
3034
|
+
{ kind: "away", teamCode: match.away.code, label: match.away.name, probability: away }
|
|
3035
|
+
];
|
|
3036
|
+
const now = this.opts.now ?? options?.now ?? /* @__PURE__ */ new Date();
|
|
3037
|
+
const asOf = new Date(now.getTime() - 6e4).toISOString();
|
|
3038
|
+
return buildMarketSignal({
|
|
3039
|
+
match,
|
|
3040
|
+
source: "fake",
|
|
3041
|
+
sourceMarketId: `fake-${match.id}`,
|
|
3042
|
+
asOf,
|
|
3043
|
+
fetchedAt: now.toISOString(),
|
|
3044
|
+
outcomes,
|
|
3045
|
+
liquidity: 5e4,
|
|
3046
|
+
now,
|
|
3047
|
+
maxAgeMs: options?.maxAgeMs
|
|
3048
|
+
});
|
|
3049
|
+
}
|
|
3050
|
+
};
|
|
3051
|
+
function hash(s) {
|
|
3052
|
+
let h = 0;
|
|
3053
|
+
for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) >>> 0;
|
|
3054
|
+
return h % 1e5;
|
|
3055
|
+
}
|
|
3056
|
+
var mapping_2026_default = {
|
|
3057
|
+
version: 1,
|
|
3058
|
+
note: "Optional matchId -> Polymarket EVENT-slug OVERRIDES. By default the slug is DERIVED from each fixture (fifwc-{home}-{away}-{UTC-date}, e.g. fifwc-mex-rsa-2026-06-11), so most matches need NO entry here. Add an entry only for a fixture whose real Polymarket slug differs (e.g. a team abbreviation that isn't the FIFA code, or a tz-shifted date). The event payload carries the three moneyline binary markets; each outcome's probability is its 'Yes' price; validation fails closed. Entry: { eventSlug, eventId? }.",
|
|
3059
|
+
markets: {}
|
|
3060
|
+
};
|
|
3061
|
+
var DEFAULT_BASE2 = "https://gamma-api.polymarket.com";
|
|
3062
|
+
var ALLOWED_HOSTS = /* @__PURE__ */ new Set(["gamma-api.polymarket.com"]);
|
|
3063
|
+
var USER_AGENT2 = "claudinho/0.0 (+https://github.com/arturogarrido/claudinho)";
|
|
3064
|
+
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
3065
|
+
var WC_SERIES_SLUG = "soccer-fifwc";
|
|
3066
|
+
var WC_SPORT = "fifwc";
|
|
3067
|
+
var KICKOFF_TOLERANCE_MS = 6 * 60 * 6e4;
|
|
3068
|
+
var NON_REGULAR_TIME = /extra time|penalt|to advance|to qualif|win the (group|tournament|cup|title)/i;
|
|
3069
|
+
var BUNDLED_MAPPING = mapping_2026_default.markets;
|
|
3070
|
+
var PolymarketProvider = class {
|
|
3071
|
+
constructor(opts = {}) {
|
|
3072
|
+
this.opts = opts;
|
|
3073
|
+
}
|
|
3074
|
+
opts;
|
|
3075
|
+
name = "polymarket";
|
|
3076
|
+
async findSignal(match, options) {
|
|
3077
|
+
return (await this.resolveOne(match, options)).signal;
|
|
3078
|
+
}
|
|
3079
|
+
async findSignals(matches, options) {
|
|
3080
|
+
const signals = /* @__PURE__ */ new Map();
|
|
3081
|
+
const checked = /* @__PURE__ */ new Set();
|
|
3082
|
+
const deadline = options?.deadlineMs != null ? Date.now() + options.deadlineMs : Number.POSITIVE_INFINITY;
|
|
3083
|
+
for (const m of matches) {
|
|
3084
|
+
if (Date.now() >= deadline) break;
|
|
3085
|
+
const r = await this.resolveOne(m, options);
|
|
3086
|
+
if (r.checked) checked.add(m.id);
|
|
3087
|
+
if (r.signal) signals.set(m.id, r.signal);
|
|
3088
|
+
}
|
|
3089
|
+
return { signals, checked };
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Resolve one match. `checked` distinguishes a DEFINITIVE result (reached the
|
|
3093
|
+
* source and found no usable market, or the fixture is unmappable) from a
|
|
3094
|
+
* provider/network error — so transient failures are retried, not
|
|
3095
|
+
* negative-cached.
|
|
3096
|
+
*/
|
|
3097
|
+
async resolveOne(match, options) {
|
|
3098
|
+
const entry = (this.opts.mapping ?? BUNDLED_MAPPING)[match.id];
|
|
3099
|
+
const eventSlug = entry?.eventSlug ?? deriveEventSlug(match);
|
|
3100
|
+
if (!eventSlug) return { checked: true };
|
|
3101
|
+
try {
|
|
3102
|
+
const event = await this.fetchEvent(eventSlug, options?.timeoutMs);
|
|
3103
|
+
const signal = event ? this.toSignal(match, eventSlug, event, options) : void 0;
|
|
3104
|
+
return { signal, checked: true };
|
|
3105
|
+
} catch {
|
|
3106
|
+
return { checked: false };
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
async fetchEvent(slug, timeoutMs) {
|
|
3110
|
+
const base = this.opts.baseUrl ?? DEFAULT_BASE2;
|
|
3111
|
+
assertAllowedHost(base);
|
|
3112
|
+
const url = `${base}/events?slug=${encodeURIComponent(slug)}`;
|
|
3113
|
+
const doFetch = this.opts.fetchImpl ?? fetch;
|
|
3114
|
+
const res = await doFetch(url, {
|
|
3115
|
+
signal: AbortSignal.timeout(timeoutMs ?? this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
3116
|
+
headers: { Accept: "application/json", "User-Agent": USER_AGENT2 }
|
|
3117
|
+
});
|
|
3118
|
+
if (res.status === 404) return void 0;
|
|
3119
|
+
if (!res.ok) {
|
|
3120
|
+
throw new Error(`Polymarket request failed: ${res.status} ${res.statusText}`);
|
|
3121
|
+
}
|
|
3122
|
+
const data = await res.json();
|
|
3123
|
+
const event = Array.isArray(data) ? data[0] : data;
|
|
3124
|
+
return event && typeof event === "object" ? event : void 0;
|
|
3125
|
+
}
|
|
3126
|
+
toSignal(match, eventSlug, event, options) {
|
|
3127
|
+
if (event.active === false || event.closed === true) return void 0;
|
|
3128
|
+
if (event.seriesSlug != null && event.seriesSlug !== WC_SERIES_SLUG && event.sport?.sport !== WC_SPORT) {
|
|
3129
|
+
return void 0;
|
|
3130
|
+
}
|
|
3131
|
+
if (event.slug != null && event.slug !== eventSlug) return void 0;
|
|
3132
|
+
const start = event.startTime ? Date.parse(event.startTime) : Number.NaN;
|
|
3133
|
+
const kick = Date.parse(match.kickoff);
|
|
3134
|
+
if (Number.isFinite(start) && Number.isFinite(kick) && Math.abs(start - kick) > KICKOFF_TOLERANCE_MS) {
|
|
3135
|
+
return void 0;
|
|
3136
|
+
}
|
|
3137
|
+
const moneyline = (event.markets ?? []).filter(
|
|
3138
|
+
(m) => (m.sportsMarketType ?? "moneyline") === "moneyline"
|
|
3139
|
+
);
|
|
3140
|
+
const homeMarket = pickMarket(moneyline, match.home.code, match.home.name);
|
|
3141
|
+
const awayMarket = pickMarket(moneyline, match.away.code, match.away.name);
|
|
3142
|
+
const drawMarket = pickDraw(moneyline);
|
|
3143
|
+
if (!homeMarket || !awayMarket) return void 0;
|
|
3144
|
+
const legIds = [homeMarket, awayMarket, drawMarket].filter((m) => m != null).map((m) => m.id ?? m.slug ?? "");
|
|
3145
|
+
if (new Set(legIds).size !== legIds.length) return void 0;
|
|
3146
|
+
const legs = [
|
|
3147
|
+
["home", homeMarket, match.home.code, match.home.name],
|
|
3148
|
+
["draw", drawMarket, void 0, "Draw"],
|
|
3149
|
+
["away", awayMarket, match.away.code, match.away.name]
|
|
3150
|
+
];
|
|
3151
|
+
const outcomes = [];
|
|
3152
|
+
let asOf = event.updatedAt;
|
|
3153
|
+
let liquidity;
|
|
3154
|
+
for (const [kind, market, teamCode, label] of legs) {
|
|
3155
|
+
if (!market) continue;
|
|
3156
|
+
if (market.closed === true || market.active === false) return void 0;
|
|
3157
|
+
if (market.description && NON_REGULAR_TIME.test(market.description)) return void 0;
|
|
3158
|
+
const yes = yesPrice(market);
|
|
3159
|
+
if (yes == null) return void 0;
|
|
3160
|
+
outcomes.push({ kind, teamCode, label, probability: yes });
|
|
3161
|
+
if (market.updatedAt && (!asOf || market.updatedAt < asOf)) asOf = market.updatedAt;
|
|
3162
|
+
const liq = numberish(market.liquidityNum ?? market.liquidity);
|
|
3163
|
+
if (liq != null) liquidity = liquidity == null ? liq : Math.min(liquidity, liq);
|
|
3164
|
+
}
|
|
3165
|
+
const rawSum = outcomes.reduce((s, o) => s + o.probability, 0);
|
|
3166
|
+
if (rawSum < 0.9 || rawSum > 1.15) return void 0;
|
|
3167
|
+
const signal = buildMarketSignal({
|
|
3168
|
+
match,
|
|
3169
|
+
source: "polymarket",
|
|
3170
|
+
sourceMarketId: event.id ?? eventSlug,
|
|
3171
|
+
asOf: asOf ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3172
|
+
outcomes,
|
|
3173
|
+
liquidity,
|
|
3174
|
+
now: options?.now ?? this.opts.now,
|
|
3175
|
+
maxAgeMs: options?.maxAgeMs ?? this.opts.maxAgeMs
|
|
3176
|
+
});
|
|
3177
|
+
return signal.ambiguous ? void 0 : signal;
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
function deriveEventSlug(match) {
|
|
3181
|
+
const home = match.home.code.toLowerCase();
|
|
3182
|
+
const away = match.away.code.toLowerCase();
|
|
3183
|
+
if (home === away || home === "tbd" || away === "tbd") return void 0;
|
|
3184
|
+
if (!/^[a-z]{3}$/.test(home) || !/^[a-z]{3}$/.test(away)) return void 0;
|
|
3185
|
+
const date = match.kickoff.slice(0, 10);
|
|
3186
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
|
|
3187
|
+
return `fifwc-${home}-${away}-${date}`;
|
|
3188
|
+
}
|
|
3189
|
+
function slugToken(m) {
|
|
3190
|
+
return (m.slug ?? "").toLowerCase().split("-").pop() ?? "";
|
|
3191
|
+
}
|
|
3192
|
+
function isDrawMarket(m) {
|
|
3193
|
+
return slugToken(m) === "draw" || (m.groupItemTitle ?? "").trim().toLowerCase().startsWith("draw");
|
|
3194
|
+
}
|
|
3195
|
+
function pickMarket(markets, teamCode, teamName) {
|
|
3196
|
+
const code = teamCode.toLowerCase();
|
|
3197
|
+
const name = teamName.trim().toLowerCase();
|
|
3198
|
+
const teamMarkets = markets.filter((m) => !isDrawMarket(m));
|
|
3199
|
+
const bySlug = teamMarkets.find((m) => slugToken(m) === code);
|
|
3200
|
+
if (bySlug) return bySlug;
|
|
3201
|
+
return teamMarkets.find((m) => (m.groupItemTitle ?? "").trim().toLowerCase() === name);
|
|
3202
|
+
}
|
|
3203
|
+
function pickDraw(markets) {
|
|
3204
|
+
return markets.find(isDrawMarket);
|
|
3205
|
+
}
|
|
3206
|
+
function assertAllowedHost(base) {
|
|
3207
|
+
let host;
|
|
3208
|
+
try {
|
|
3209
|
+
host = new URL(base).host;
|
|
3210
|
+
} catch {
|
|
3211
|
+
throw new Error(`Invalid Polymarket base URL: ${base}`);
|
|
3212
|
+
}
|
|
3213
|
+
if (!ALLOWED_HOSTS.has(host)) {
|
|
3214
|
+
throw new Error(`Polymarket host not allow-listed: ${host}`);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
function yesPrice(market) {
|
|
3218
|
+
const labels = parseJsonArray(market.outcomes);
|
|
3219
|
+
const prices = parseJsonArray(market.outcomePrices).map((p2) => Number(p2));
|
|
3220
|
+
if (labels.length === 0 || labels.length !== prices.length) return void 0;
|
|
3221
|
+
const i = labels.findIndex((l) => l.trim().toLowerCase() === "yes");
|
|
3222
|
+
if (i < 0) return void 0;
|
|
3223
|
+
const p = prices[i];
|
|
3224
|
+
return typeof p === "number" && Number.isFinite(p) && p > 0 && p <= 1 ? p : void 0;
|
|
3225
|
+
}
|
|
3226
|
+
function parseJsonArray(v) {
|
|
3227
|
+
if (Array.isArray(v)) return v.map((x) => String(x));
|
|
3228
|
+
if (typeof v === "string") {
|
|
3229
|
+
try {
|
|
3230
|
+
const parsed = JSON.parse(v);
|
|
3231
|
+
return Array.isArray(parsed) ? parsed.map((x) => String(x)) : [];
|
|
3232
|
+
} catch {
|
|
3233
|
+
return [];
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
return [];
|
|
3237
|
+
}
|
|
3238
|
+
function numberish(v) {
|
|
3239
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
|
|
3240
|
+
if (typeof v === "string") {
|
|
3241
|
+
const n = Number(v);
|
|
3242
|
+
return Number.isFinite(n) ? n : void 0;
|
|
3243
|
+
}
|
|
3244
|
+
return void 0;
|
|
3245
|
+
}
|
|
3246
|
+
function resolveMarketSource(explicit) {
|
|
3247
|
+
if (explicit) return explicit;
|
|
3248
|
+
if (typeof process !== "undefined" && process.env?.CLAUDINHO_MARKETS_SOURCE) {
|
|
3249
|
+
return process.env.CLAUDINHO_MARKETS_SOURCE;
|
|
3250
|
+
}
|
|
3251
|
+
return "polymarket";
|
|
3252
|
+
}
|
|
3253
|
+
function makeMarketProvider(source) {
|
|
3254
|
+
switch (resolveMarketSource(source)) {
|
|
3255
|
+
case "fake":
|
|
3256
|
+
return new FakeMarketProvider({ synthesize: true });
|
|
3257
|
+
case "none":
|
|
3258
|
+
case "off":
|
|
3259
|
+
return new FakeMarketProvider();
|
|
3260
|
+
// no synth → yields no signals, no network
|
|
3261
|
+
default:
|
|
3262
|
+
return new PolymarketProvider();
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
async function getMarketSignals(provider, matches, options) {
|
|
3266
|
+
try {
|
|
3267
|
+
return await provider.findSignals(matches, options);
|
|
3268
|
+
} catch {
|
|
3269
|
+
return { signals: /* @__PURE__ */ new Map(), checked: /* @__PURE__ */ new Set() };
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
// src/config.ts
|
|
3274
|
+
var SUPPORTED_LANGS = ["en", "es", "pt", "fr"];
|
|
3275
|
+
function pickLang(explicit) {
|
|
3276
|
+
const candidates = [
|
|
3277
|
+
explicit,
|
|
3278
|
+
process.env.CLAUDINHO_LANG,
|
|
3279
|
+
process.env.LANG?.split(".")[0]?.split("_")[0]
|
|
3280
|
+
];
|
|
3281
|
+
for (const c of candidates) {
|
|
3282
|
+
if (c && SUPPORTED_LANGS.includes(c)) {
|
|
3283
|
+
return c;
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
return "en";
|
|
3287
|
+
}
|
|
3288
|
+
function pickColor(explicit) {
|
|
3289
|
+
if (explicit === false) return false;
|
|
3290
|
+
if (process.env.NO_COLOR) return false;
|
|
3291
|
+
if (!process.stdout.isTTY) return false;
|
|
3292
|
+
return true;
|
|
3293
|
+
}
|
|
3294
|
+
function isSupportedLang(s) {
|
|
3295
|
+
return SUPPORTED_LANGS.includes(s);
|
|
3296
|
+
}
|
|
3297
|
+
function pickMarkets(explicit) {
|
|
3298
|
+
if (explicit === false) return false;
|
|
3299
|
+
if ((process.env.CLAUDINHO_MARKETS ?? "").toLowerCase() === "off") return false;
|
|
3300
|
+
return true;
|
|
3301
|
+
}
|
|
3302
|
+
function resolveConfig(opts) {
|
|
3303
|
+
const langRequestedUnsupported = opts.lang && !isSupportedLang(opts.lang) ? opts.lang : void 0;
|
|
3304
|
+
return {
|
|
3305
|
+
lang: pickLang(opts.lang),
|
|
3306
|
+
tz: opts.tz ?? process.env.CLAUDINHO_TZ ?? void 0,
|
|
3307
|
+
json: opts.json ?? false,
|
|
3308
|
+
color: pickColor(opts.color),
|
|
3309
|
+
source: opts.source ?? process.env.CLAUDINHO_SOURCE ?? "espn",
|
|
3310
|
+
flavor: asFlavorLevel(opts.flavor ?? process.env.CLAUDINHO_FLAVOR),
|
|
3311
|
+
markets: pickMarkets(opts.markets),
|
|
3312
|
+
langRequestedUnsupported
|
|
3313
|
+
};
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
// src/i18n.ts
|
|
3317
|
+
var EN = {
|
|
3318
|
+
"today.title": "Today's matches",
|
|
3319
|
+
"today.on": "Matches",
|
|
3320
|
+
"today.none": "No matches scheduled for this date.",
|
|
3321
|
+
"live.title": "Live now",
|
|
3322
|
+
"live.none": "No matches in play right now.",
|
|
3323
|
+
"next.none": "No upcoming fixture found for {team}.",
|
|
3324
|
+
"next.label": "Next up for {team}",
|
|
3325
|
+
"next.in": "in {countdown}",
|
|
3326
|
+
"table.title": "Group {group}",
|
|
3327
|
+
"table.none": "No group found for {group}.",
|
|
3328
|
+
"match.none": "No match found with id {id}.",
|
|
3329
|
+
"status.scheduled": "scheduled",
|
|
3330
|
+
"status.live": "LIVE",
|
|
3331
|
+
"status.ht": "HT",
|
|
3332
|
+
"status.ft": "FT",
|
|
3333
|
+
"status.postponed": "postponed",
|
|
3334
|
+
"status.cancelled": "cancelled",
|
|
3335
|
+
"col.team": "Team",
|
|
3336
|
+
"col.p": "P",
|
|
3337
|
+
"col.w": "W",
|
|
3338
|
+
"col.d": "D",
|
|
3339
|
+
"col.l": "L",
|
|
3340
|
+
"col.gd": "GD",
|
|
3341
|
+
"col.pts": "Pts",
|
|
3342
|
+
"err.date": "Invalid date {date}. Use YYYY-MM-DD.",
|
|
3343
|
+
"warn.tz": "Unknown timezone {tz}; using system timezone.",
|
|
3344
|
+
"warn.lang": "Unsupported language {lang}; using English. (supported: en, es, pt, fr)",
|
|
3345
|
+
disclaimer: "Not affiliated with FIFA or Anthropic."
|
|
3346
|
+
};
|
|
3347
|
+
var ES = {
|
|
3348
|
+
"today.title": "Partidos de hoy",
|
|
3349
|
+
"today.on": "Partidos",
|
|
3350
|
+
"today.none": "No hay partidos para esta fecha.",
|
|
3351
|
+
"live.title": "En vivo",
|
|
3352
|
+
"live.none": "No hay partidos en juego ahora mismo.",
|
|
3353
|
+
"next.none": "No se encontr\xF3 pr\xF3ximo partido para {team}.",
|
|
3354
|
+
"next.label": "Pr\xF3ximo partido de {team}",
|
|
3355
|
+
"next.in": "en {countdown}",
|
|
3356
|
+
"table.title": "Grupo {group}",
|
|
3357
|
+
"table.none": "No se encontr\xF3 el grupo {group}.",
|
|
3358
|
+
"match.none": "No se encontr\xF3 partido con id {id}.",
|
|
3359
|
+
"status.scheduled": "programado",
|
|
3360
|
+
"status.live": "EN VIVO",
|
|
3361
|
+
"status.ht": "DESC",
|
|
3362
|
+
"status.ft": "FIN",
|
|
3363
|
+
"status.postponed": "aplazado",
|
|
3364
|
+
"status.cancelled": "cancelado",
|
|
3365
|
+
"col.team": "Equipo",
|
|
3366
|
+
"col.p": "PJ",
|
|
3367
|
+
"col.w": "G",
|
|
3368
|
+
"col.d": "E",
|
|
3369
|
+
"col.l": "P",
|
|
3370
|
+
"col.gd": "DG",
|
|
3371
|
+
"col.pts": "Pts",
|
|
3372
|
+
"err.date": "Fecha inv\xE1lida {date}. Usa AAAA-MM-DD.",
|
|
3373
|
+
"warn.tz": "Zona horaria desconocida {tz}; usando la del sistema.",
|
|
3374
|
+
"warn.lang": "Idioma no soportado {lang}; usando ingl\xE9s. (disponibles: en, es, pt, fr)",
|
|
3375
|
+
disclaimer: "No afiliado a FIFA ni Anthropic."
|
|
3376
|
+
};
|
|
3377
|
+
var PT = {
|
|
3378
|
+
"today.title": "Jogos de hoje",
|
|
3379
|
+
"today.on": "Jogos",
|
|
3380
|
+
"today.none": "Nenhum jogo para esta data.",
|
|
3381
|
+
"live.title": "Ao vivo",
|
|
3382
|
+
"live.none": "Nenhum jogo em andamento agora.",
|
|
3383
|
+
"next.none": "Nenhum pr\xF3ximo jogo encontrado para {team}.",
|
|
3384
|
+
"next.label": "Pr\xF3ximo jogo de {team}",
|
|
3385
|
+
"next.in": "em {countdown}",
|
|
3386
|
+
"table.title": "Grupo {group}",
|
|
3387
|
+
"table.none": "Grupo {group} n\xE3o encontrado.",
|
|
3388
|
+
"match.none": "Nenhum jogo encontrado com id {id}.",
|
|
3389
|
+
"status.scheduled": "agendado",
|
|
3390
|
+
"status.live": "AO VIVO",
|
|
3391
|
+
"status.ht": "INT",
|
|
3392
|
+
"status.ft": "FIM",
|
|
3393
|
+
"status.postponed": "adiado",
|
|
3394
|
+
"status.cancelled": "cancelado",
|
|
3395
|
+
"col.team": "Sele\xE7\xE3o",
|
|
3396
|
+
"col.p": "J",
|
|
3397
|
+
"col.w": "V",
|
|
3398
|
+
"col.d": "E",
|
|
3399
|
+
"col.l": "D",
|
|
3400
|
+
"col.gd": "SG",
|
|
3401
|
+
"col.pts": "Pts",
|
|
3402
|
+
"err.date": "Data inv\xE1lida {date}. Use AAAA-MM-DD.",
|
|
3403
|
+
"warn.tz": "Fuso hor\xE1rio desconhecido {tz}; usando o do sistema.",
|
|
3404
|
+
"warn.lang": "Idioma n\xE3o suportado {lang}; usando ingl\xEAs. (dispon\xEDveis: en, es, pt, fr)",
|
|
3405
|
+
disclaimer: "N\xE3o afiliado \xE0 FIFA nem \xE0 Anthropic."
|
|
3406
|
+
};
|
|
3407
|
+
var FR = {
|
|
3408
|
+
"today.title": "Matchs d'aujourd'hui",
|
|
3409
|
+
"today.on": "Matchs",
|
|
3410
|
+
"today.none": "Aucun match pr\xE9vu pour cette date.",
|
|
3411
|
+
"live.title": "En direct",
|
|
3412
|
+
"live.none": "Aucun match en cours pour l'instant.",
|
|
3413
|
+
"next.none": "Aucun prochain match trouv\xE9 pour {team}.",
|
|
3414
|
+
"next.label": "Prochain match de {team}",
|
|
3415
|
+
"next.in": "dans {countdown}",
|
|
3416
|
+
"table.title": "Groupe {group}",
|
|
3417
|
+
"table.none": "Groupe {group} introuvable.",
|
|
3418
|
+
"match.none": "Aucun match trouv\xE9 avec id {id}.",
|
|
3419
|
+
"status.scheduled": "pr\xE9vu",
|
|
3420
|
+
"status.live": "DIRECT",
|
|
3421
|
+
"status.ht": "MT",
|
|
3422
|
+
"status.ft": "FIN",
|
|
3423
|
+
"status.postponed": "report\xE9",
|
|
3424
|
+
"status.cancelled": "annul\xE9",
|
|
3425
|
+
"col.team": "\xC9quipe",
|
|
3426
|
+
"col.p": "J",
|
|
3427
|
+
"col.w": "G",
|
|
3428
|
+
"col.d": "N",
|
|
3429
|
+
"col.l": "P",
|
|
3430
|
+
"col.gd": "Diff",
|
|
3431
|
+
"col.pts": "Pts",
|
|
3432
|
+
"err.date": "Date invalide {date}. Utilisez AAAA-MM-JJ.",
|
|
3433
|
+
"warn.tz": "Fuseau horaire inconnu {tz} ; utilisation du fuseau syst\xE8me.",
|
|
3434
|
+
"warn.lang": "Langue non prise en charge {lang} ; utilisation de l\u2019anglais. (disponibles : en, es, pt, fr)",
|
|
3435
|
+
disclaimer: "Non affili\xE9 \xE0 la FIFA ni \xE0 Anthropic."
|
|
3436
|
+
};
|
|
3437
|
+
var CATALOGS = { en: EN, es: ES, pt: PT, fr: FR };
|
|
3438
|
+
function makeT(lang) {
|
|
3439
|
+
const dict = CATALOGS[lang] ?? EN;
|
|
3440
|
+
return (key, vars) => {
|
|
3441
|
+
let s = dict[key] ?? EN[key] ?? key;
|
|
3442
|
+
if (vars) for (const [k, v] of Object.entries(vars)) s = s.replace(`{${k}}`, v);
|
|
3443
|
+
return s;
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3447
|
+
// src/commands.ts
|
|
3448
|
+
import Table from "cli-table3";
|
|
3449
|
+
|
|
3450
|
+
// src/format.ts
|
|
3451
|
+
import pc from "picocolors";
|
|
3452
|
+
function paint(enabled) {
|
|
3453
|
+
const id = (s) => s;
|
|
3454
|
+
if (!enabled) {
|
|
3455
|
+
return {
|
|
3456
|
+
dim: id,
|
|
3457
|
+
bold: id,
|
|
3458
|
+
green: id,
|
|
3459
|
+
yellow: id,
|
|
3460
|
+
red: id,
|
|
3461
|
+
cyan: id,
|
|
3462
|
+
gray: id
|
|
3463
|
+
};
|
|
3464
|
+
}
|
|
3465
|
+
return {
|
|
3466
|
+
dim: pc.dim,
|
|
3467
|
+
bold: pc.bold,
|
|
3468
|
+
green: pc.green,
|
|
3469
|
+
yellow: pc.yellow,
|
|
3470
|
+
red: pc.red,
|
|
3471
|
+
cyan: pc.cyan,
|
|
3472
|
+
gray: pc.gray
|
|
3473
|
+
};
|
|
3474
|
+
}
|
|
3475
|
+
function painterFor(cfg) {
|
|
3476
|
+
return paint(cfg.color);
|
|
3477
|
+
}
|
|
3478
|
+
function statusToken(m, t, c) {
|
|
3479
|
+
switch (m.status) {
|
|
3480
|
+
case "LIVE":
|
|
3481
|
+
return c.green(`${m.minute ? `${m.minute}'` : t("status.live")}`);
|
|
3482
|
+
case "HT":
|
|
3483
|
+
return c.yellow(t("status.ht"));
|
|
3484
|
+
case "FT":
|
|
3485
|
+
return c.gray(t("status.ft"));
|
|
3486
|
+
case "POSTPONED":
|
|
3487
|
+
return c.red(t("status.postponed"));
|
|
3488
|
+
case "CANCELLED":
|
|
3489
|
+
return c.red(t("status.cancelled"));
|
|
3490
|
+
default:
|
|
3491
|
+
return "";
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
function matchLine(m, cfg, t, c) {
|
|
3495
|
+
const home = `${m.home.flag} ${m.home.name}`;
|
|
3496
|
+
const away = `${m.away.name} ${m.away.flag}`;
|
|
3497
|
+
const mid = isLive(m.status) || m.status === "FT" ? c.bold(scoreline(m)) : c.dim("vs");
|
|
3498
|
+
const left = `${home.padEnd(22)} ${mid.padStart(3)} ${away}`;
|
|
3499
|
+
let right = "";
|
|
3500
|
+
if (m.status === "SCHEDULED") {
|
|
3501
|
+
right = c.dim(
|
|
3502
|
+
`${formatKickoff(m.kickoff, { tz: cfg.tz, locale: cfg.lang })}`
|
|
3503
|
+
);
|
|
3504
|
+
} else {
|
|
3505
|
+
right = statusToken(m, t, c);
|
|
3506
|
+
}
|
|
3507
|
+
const flair = matchFlavor(m, { level: cfg.flavor, locale: cfg.lang });
|
|
3508
|
+
const tail = flair ? ` ${c.dim(flair)}` : "";
|
|
3509
|
+
return ` ${left} ${right}${tail}`.trimEnd();
|
|
3510
|
+
}
|
|
3511
|
+
function header(text, c) {
|
|
3512
|
+
return c.bold(c.cyan(text));
|
|
3513
|
+
}
|
|
3514
|
+
function disclaimer(t, c) {
|
|
2795
3515
|
return c.dim(t("disclaimer"));
|
|
2796
3516
|
}
|
|
3517
|
+
function dataSource(source, c) {
|
|
3518
|
+
return source ? c.dim(`Live data: ${liveSourceLabel(source)}`) : "";
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
// src/marketCache.ts
|
|
3522
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
3523
|
+
import { homedir } from "os";
|
|
3524
|
+
import { join } from "path";
|
|
3525
|
+
var POSITIVE_TTL_MS = 10 * 6e4;
|
|
3526
|
+
var NEGATIVE_TTL_MS = 3 * 6e4;
|
|
3527
|
+
function cacheDir() {
|
|
3528
|
+
const base = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
|
|
3529
|
+
return join(base, "claudinho");
|
|
3530
|
+
}
|
|
3531
|
+
function cachePath() {
|
|
3532
|
+
return join(cacheDir(), "market-signals.json");
|
|
3533
|
+
}
|
|
3534
|
+
function readFile() {
|
|
3535
|
+
try {
|
|
3536
|
+
return JSON.parse(readFileSync(cachePath(), "utf8"));
|
|
3537
|
+
} catch {
|
|
3538
|
+
return void 0;
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
function readMarketCache(source, competition, now = Date.now()) {
|
|
3542
|
+
const signals = /* @__PURE__ */ new Map();
|
|
3543
|
+
const checked = /* @__PURE__ */ new Set();
|
|
3544
|
+
const file = readFile();
|
|
3545
|
+
if (!file || file.source !== source || file.competition !== competition) {
|
|
3546
|
+
return { signals, checked };
|
|
3547
|
+
}
|
|
3548
|
+
for (const [id, entry] of Object.entries(file.entries ?? {})) {
|
|
3549
|
+
const t = Date.parse(entry.fetchedAt);
|
|
3550
|
+
if (!Number.isFinite(t)) continue;
|
|
3551
|
+
const ttl = entry.signal ? POSITIVE_TTL_MS : NEGATIVE_TTL_MS;
|
|
3552
|
+
if (now - t > ttl) continue;
|
|
3553
|
+
checked.add(id);
|
|
3554
|
+
if (entry.signal) signals.set(id, entry.signal);
|
|
3555
|
+
}
|
|
3556
|
+
return { signals, checked };
|
|
3557
|
+
}
|
|
3558
|
+
function writeMarketCache(source, competition, attempted, fetched, now = Date.now()) {
|
|
3559
|
+
if (attempted.length === 0) return;
|
|
3560
|
+
try {
|
|
3561
|
+
const existing = readFile();
|
|
3562
|
+
const base = existing && existing.source === source && existing.competition === competition ? existing : { source, competition, entries: {} };
|
|
3563
|
+
const fetchedAt = new Date(now).toISOString();
|
|
3564
|
+
for (const id of attempted) {
|
|
3565
|
+
base.entries[id] = { fetchedAt, signal: fetched.get(id) ?? null };
|
|
3566
|
+
}
|
|
3567
|
+
mkdirSync(cacheDir(), { recursive: true });
|
|
3568
|
+
const tmp = join(cacheDir(), `market-signals.${process.pid}.tmp`);
|
|
3569
|
+
writeFileSync(tmp, JSON.stringify(base));
|
|
3570
|
+
renameSync(tmp, cachePath());
|
|
3571
|
+
} catch {
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
2797
3574
|
|
|
2798
3575
|
// src/cache.ts
|
|
2799
3576
|
import {
|
|
2800
3577
|
closeSync,
|
|
2801
|
-
mkdirSync,
|
|
3578
|
+
mkdirSync as mkdirSync2,
|
|
2802
3579
|
openSync,
|
|
2803
|
-
readFileSync,
|
|
2804
|
-
renameSync,
|
|
3580
|
+
readFileSync as readFileSync2,
|
|
3581
|
+
renameSync as renameSync2,
|
|
2805
3582
|
rmSync,
|
|
2806
3583
|
statSync,
|
|
2807
3584
|
writeSync
|
|
2808
3585
|
} from "fs";
|
|
2809
|
-
import { homedir } from "os";
|
|
2810
|
-
import { join } from "path";
|
|
3586
|
+
import { homedir as homedir2 } from "os";
|
|
3587
|
+
import { join as join2 } from "path";
|
|
2811
3588
|
var LOCK_STALE_MS = 6e4;
|
|
2812
|
-
function
|
|
2813
|
-
const base = process.env.XDG_CACHE_HOME ||
|
|
2814
|
-
return
|
|
3589
|
+
function cacheDir2() {
|
|
3590
|
+
const base = process.env.XDG_CACHE_HOME || join2(homedir2(), ".cache");
|
|
3591
|
+
return join2(base, "claudinho");
|
|
2815
3592
|
}
|
|
2816
|
-
function
|
|
2817
|
-
return
|
|
3593
|
+
function cachePath2() {
|
|
3594
|
+
return join2(cacheDir2(), "state.json");
|
|
2818
3595
|
}
|
|
2819
3596
|
function lockPath() {
|
|
2820
|
-
return
|
|
3597
|
+
return join2(cacheDir2(), "refresh.lock");
|
|
2821
3598
|
}
|
|
2822
3599
|
function readState() {
|
|
2823
3600
|
try {
|
|
2824
|
-
return JSON.parse(
|
|
3601
|
+
return JSON.parse(readFileSync2(cachePath2(), "utf8"));
|
|
2825
3602
|
} catch {
|
|
2826
3603
|
return void 0;
|
|
2827
3604
|
}
|
|
2828
3605
|
}
|
|
3606
|
+
function readCurrentState(source, competition) {
|
|
3607
|
+
const s = readState();
|
|
3608
|
+
return s && s.source === source && s.competition === competition ? s : void 0;
|
|
3609
|
+
}
|
|
2829
3610
|
function writeState(state) {
|
|
2830
|
-
const dir =
|
|
2831
|
-
|
|
2832
|
-
const tmp =
|
|
3611
|
+
const dir = cacheDir2();
|
|
3612
|
+
mkdirSync2(dir, { recursive: true });
|
|
3613
|
+
const tmp = join2(dir, `state.${process.pid}.tmp`);
|
|
2833
3614
|
writeFileSync_(tmp, JSON.stringify(state));
|
|
2834
|
-
|
|
3615
|
+
renameSync2(tmp, cachePath2());
|
|
2835
3616
|
}
|
|
2836
3617
|
function writeFileSync_(path, data) {
|
|
2837
3618
|
const fd = openSync(path, "w");
|
|
@@ -2849,7 +3630,7 @@ function ageMs(state, now = Date.now()) {
|
|
|
2849
3630
|
function lockAgeMs(now = Date.now()) {
|
|
2850
3631
|
const lp = lockPath();
|
|
2851
3632
|
try {
|
|
2852
|
-
const contents =
|
|
3633
|
+
const contents = readFileSync2(lp, "utf8");
|
|
2853
3634
|
const written = Number.parseInt(contents.split(/\s+/)[1] ?? "", 10);
|
|
2854
3635
|
if (Number.isFinite(written)) return now - written;
|
|
2855
3636
|
} catch {
|
|
@@ -2865,7 +3646,7 @@ function isLockFresh(now = Date.now()) {
|
|
|
2865
3646
|
return lockAgeMs(now) < LOCK_STALE_MS;
|
|
2866
3647
|
}
|
|
2867
3648
|
function acquireLock(now = Date.now()) {
|
|
2868
|
-
|
|
3649
|
+
mkdirSync2(cacheDir2(), { recursive: true });
|
|
2869
3650
|
const lp = lockPath();
|
|
2870
3651
|
try {
|
|
2871
3652
|
const fd = openSync(lp, "wx");
|
|
@@ -2976,9 +3757,6 @@ function renderHook(state, opts = {}) {
|
|
|
2976
3757
|
return `[Claudinho \u2014 live football scores right now]
|
|
2977
3758
|
${lines}`;
|
|
2978
3759
|
}
|
|
2979
|
-
function hookContext(opts = {}) {
|
|
2980
|
-
return renderHook(readState(), opts);
|
|
2981
|
-
}
|
|
2982
3760
|
|
|
2983
3761
|
// src/refresh.ts
|
|
2984
3762
|
import { spawn } from "child_process";
|
|
@@ -2997,7 +3775,11 @@ function liveAdapter() {
|
|
|
2997
3775
|
async function runRefresh(opts = {}) {
|
|
2998
3776
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
2999
3777
|
const source = opts.source ?? "espn";
|
|
3000
|
-
|
|
3778
|
+
const competition = resolveCompetition();
|
|
3779
|
+
const cached = readState();
|
|
3780
|
+
if (cached && cached.source === source && cached.competition === competition && ageMs(cached, now.getTime()) < MIN_REFRESH_MS) {
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3001
3783
|
if (!acquireLock()) return;
|
|
3002
3784
|
try {
|
|
3003
3785
|
let live = [];
|
|
@@ -3009,7 +3791,7 @@ async function runRefresh(opts = {}) {
|
|
|
3009
3791
|
degraded = true;
|
|
3010
3792
|
}
|
|
3011
3793
|
}
|
|
3012
|
-
writeState({ updatedAt: now.toISOString(), live, degraded, source });
|
|
3794
|
+
writeState({ updatedAt: now.toISOString(), live, degraded, source, competition });
|
|
3013
3795
|
} finally {
|
|
3014
3796
|
releaseLock();
|
|
3015
3797
|
}
|
|
@@ -3036,14 +3818,14 @@ function spawnRefresh(source) {
|
|
|
3036
3818
|
import {
|
|
3037
3819
|
copyFileSync,
|
|
3038
3820
|
existsSync,
|
|
3039
|
-
mkdirSync as
|
|
3040
|
-
readFileSync as
|
|
3041
|
-
writeFileSync
|
|
3821
|
+
mkdirSync as mkdirSync3,
|
|
3822
|
+
readFileSync as readFileSync3,
|
|
3823
|
+
writeFileSync as writeFileSync2
|
|
3042
3824
|
} from "fs";
|
|
3043
|
-
import { homedir as
|
|
3044
|
-
import { dirname, join as
|
|
3825
|
+
import { homedir as homedir3 } from "os";
|
|
3826
|
+
import { dirname, join as join3 } from "path";
|
|
3045
3827
|
function claudeSettingsPath() {
|
|
3046
|
-
return
|
|
3828
|
+
return join3(homedir3(), ".claude", "settings.json");
|
|
3047
3829
|
}
|
|
3048
3830
|
function backupOnce(path) {
|
|
3049
3831
|
const bak = `${path}.claudinho.bak`;
|
|
@@ -3059,7 +3841,7 @@ function initStatusline(opts = {}) {
|
|
|
3059
3841
|
let settings = {};
|
|
3060
3842
|
if (existsSync(path)) {
|
|
3061
3843
|
try {
|
|
3062
|
-
settings = JSON.parse(
|
|
3844
|
+
settings = JSON.parse(readFileSync3(path, "utf8"));
|
|
3063
3845
|
} catch {
|
|
3064
3846
|
return {
|
|
3065
3847
|
action: "manual",
|
|
@@ -3075,8 +3857,8 @@ ${snippet}`
|
|
|
3075
3857
|
}
|
|
3076
3858
|
backupOnce(path);
|
|
3077
3859
|
settings.statusLine = sl;
|
|
3078
|
-
|
|
3079
|
-
|
|
3860
|
+
mkdirSync3(dirname(path), { recursive: true });
|
|
3861
|
+
writeFileSync2(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
3080
3862
|
return {
|
|
3081
3863
|
action: "written",
|
|
3082
3864
|
path,
|
|
@@ -3097,7 +3879,7 @@ function initHook(opts = {}) {
|
|
|
3097
3879
|
let settings = {};
|
|
3098
3880
|
if (existsSync(path)) {
|
|
3099
3881
|
try {
|
|
3100
|
-
settings = JSON.parse(
|
|
3882
|
+
settings = JSON.parse(readFileSync3(path, "utf8"));
|
|
3101
3883
|
} catch {
|
|
3102
3884
|
return {
|
|
3103
3885
|
action: "manual",
|
|
@@ -3107,8 +3889,10 @@ ${snippet}`
|
|
|
3107
3889
|
};
|
|
3108
3890
|
}
|
|
3109
3891
|
}
|
|
3110
|
-
|
|
3111
|
-
const
|
|
3892
|
+
settings.hooks ??= {};
|
|
3893
|
+
const hooks = settings.hooks;
|
|
3894
|
+
hooks[HOOK_EVENT] ??= [];
|
|
3895
|
+
const matchers = hooks[HOOK_EVENT];
|
|
3112
3896
|
const already = matchers.some(
|
|
3113
3897
|
(m) => (m.hooks ?? []).some((h) => typeof h.command === "string" && h.command.includes("claudinho"))
|
|
3114
3898
|
);
|
|
@@ -3117,8 +3901,8 @@ ${snippet}`
|
|
|
3117
3901
|
}
|
|
3118
3902
|
backupOnce(path);
|
|
3119
3903
|
matchers.push({ hooks: [{ type: "command", command }] });
|
|
3120
|
-
|
|
3121
|
-
|
|
3904
|
+
mkdirSync3(dirname(path), { recursive: true });
|
|
3905
|
+
writeFileSync2(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
3122
3906
|
return {
|
|
3123
3907
|
action: "written",
|
|
3124
3908
|
path,
|
|
@@ -3130,6 +3914,45 @@ ${snippet}`
|
|
|
3130
3914
|
function adapterFor({ cfg, adapter }) {
|
|
3131
3915
|
return adapter ?? makeAdapter(cfg.source);
|
|
3132
3916
|
}
|
|
3917
|
+
var DEFAULT_ON_MARKET_OPTS = { deadlineMs: 2e3, timeoutMs: 2500 };
|
|
3918
|
+
var MARKETS_CMD_OPTS = { deadlineMs: 12e3, timeoutMs: 6e3 };
|
|
3919
|
+
async function marketSignalsFor(ctx, matches, opts = {}) {
|
|
3920
|
+
if (ctx.marketProvider) return (await getMarketSignals(ctx.marketProvider, matches, opts)).signals;
|
|
3921
|
+
const source = resolveMarketSource();
|
|
3922
|
+
if (source !== "polymarket") {
|
|
3923
|
+
return (await getMarketSignals(makeMarketProvider(source), matches, opts)).signals;
|
|
3924
|
+
}
|
|
3925
|
+
const competition = resolveCompetition();
|
|
3926
|
+
const { signals: cached, checked: cachedIds } = readMarketCache("polymarket", competition);
|
|
3927
|
+
const result = /* @__PURE__ */ new Map();
|
|
3928
|
+
const miss = [];
|
|
3929
|
+
for (const m of matches) {
|
|
3930
|
+
const hit = cached.get(m.id);
|
|
3931
|
+
if (hit) result.set(m.id, hit);
|
|
3932
|
+
else if (!cachedIds.has(m.id)) miss.push(m);
|
|
3933
|
+
}
|
|
3934
|
+
if (miss.length > 0) {
|
|
3935
|
+
const { signals: fetched, checked } = await getMarketSignals(
|
|
3936
|
+
makeMarketProvider("polymarket"),
|
|
3937
|
+
miss,
|
|
3938
|
+
opts
|
|
3939
|
+
);
|
|
3940
|
+
writeMarketCache("polymarket", competition, [...checked], fetched);
|
|
3941
|
+
for (const [id, s] of fetched) result.set(id, s);
|
|
3942
|
+
}
|
|
3943
|
+
return result;
|
|
3944
|
+
}
|
|
3945
|
+
async function reliableMarketSignals(ctx, matches) {
|
|
3946
|
+
if (ctx.cfg.markets === false) return /* @__PURE__ */ new Map();
|
|
3947
|
+
const raw = await marketSignalsFor(ctx, matches, DEFAULT_ON_MARKET_OPTS);
|
|
3948
|
+
const now = /* @__PURE__ */ new Date();
|
|
3949
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
3950
|
+
for (const [id, s] of raw) if (isReliableMarketSignal(s, { now })) out2.set(id, s);
|
|
3951
|
+
return out2;
|
|
3952
|
+
}
|
|
3953
|
+
async function reliableMarketSignalFor(ctx, match) {
|
|
3954
|
+
return (await reliableMarketSignals(ctx, [match])).get(match.id);
|
|
3955
|
+
}
|
|
3133
3956
|
function out(line2 = "") {
|
|
3134
3957
|
process.stdout.write(line2 + "\n");
|
|
3135
3958
|
}
|
|
@@ -3154,10 +3977,17 @@ async function cmdToday(date, ctx) {
|
|
|
3154
3977
|
precheck(cfg, t, date);
|
|
3155
3978
|
const adapter = adapterFor(ctx);
|
|
3156
3979
|
const targetDate = date ?? localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz);
|
|
3157
|
-
const { matches, degraded } = await getMatchesForDate(adapter, targetDate);
|
|
3158
|
-
const todays = fixturesByDate(targetDate, matches);
|
|
3980
|
+
const { matches, degraded, source } = await getMatchesForDate(adapter, targetDate);
|
|
3981
|
+
const todays = fixturesByDate(targetDate, matches, cfg.tz);
|
|
3982
|
+
const signals = await reliableMarketSignals(ctx, todays);
|
|
3159
3983
|
if (cfg.json) {
|
|
3160
|
-
emitJson({
|
|
3984
|
+
emitJson({
|
|
3985
|
+
date: targetDate,
|
|
3986
|
+
degraded,
|
|
3987
|
+
source: source ?? null,
|
|
3988
|
+
matches: todays,
|
|
3989
|
+
marketSignals: Object.fromEntries(signals)
|
|
3990
|
+
});
|
|
3161
3991
|
return;
|
|
3162
3992
|
}
|
|
3163
3993
|
const c = painterFor(cfg);
|
|
@@ -3168,18 +3998,24 @@ async function cmdToday(date, ctx) {
|
|
|
3168
3998
|
if (todays.length === 0) {
|
|
3169
3999
|
out(c.dim(" " + t("today.none")));
|
|
3170
4000
|
} else {
|
|
3171
|
-
for (const m of todays)
|
|
4001
|
+
for (const m of todays) {
|
|
4002
|
+
out(matchLine(m, cfg, t, c));
|
|
4003
|
+
const s = signals.get(m.id);
|
|
4004
|
+
if (s) out(" " + c.dim(marketLine(s, m)));
|
|
4005
|
+
}
|
|
3172
4006
|
}
|
|
3173
4007
|
out();
|
|
4008
|
+
const src = dataSource(source, c);
|
|
4009
|
+
if (src) out(src);
|
|
3174
4010
|
out(disclaimer(t, c));
|
|
3175
4011
|
}
|
|
3176
4012
|
async function cmdLive(ctx) {
|
|
3177
4013
|
const { cfg, t } = ctx;
|
|
3178
4014
|
precheck(cfg, t);
|
|
3179
4015
|
const adapter = adapterFor(ctx);
|
|
3180
|
-
const { matches, degraded } = await getLiveMatches(adapter);
|
|
4016
|
+
const { matches, degraded, source } = await getLiveMatches(adapter);
|
|
3181
4017
|
if (cfg.json) {
|
|
3182
|
-
emitJson({ degraded, matches });
|
|
4018
|
+
emitJson({ degraded, source: source ?? null, matches });
|
|
3183
4019
|
return;
|
|
3184
4020
|
}
|
|
3185
4021
|
const c = painterFor(cfg);
|
|
@@ -3192,6 +4028,8 @@ async function cmdLive(ctx) {
|
|
|
3192
4028
|
for (const m of matches) out(matchLine(m, cfg, t, c));
|
|
3193
4029
|
}
|
|
3194
4030
|
out();
|
|
4031
|
+
const src = dataSource(source, c);
|
|
4032
|
+
if (src) out(src);
|
|
3195
4033
|
out(disclaimer(t, c));
|
|
3196
4034
|
}
|
|
3197
4035
|
async function cmdNext(team, { cfg, t }) {
|
|
@@ -3225,19 +4063,21 @@ async function cmdTable(group, ctx) {
|
|
|
3225
4063
|
const { cfg, t } = ctx;
|
|
3226
4064
|
precheck(cfg, t);
|
|
3227
4065
|
const adapter = adapterFor(ctx);
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
} catch {
|
|
3233
|
-
}
|
|
4066
|
+
const { matches, degraded, source } = await getMatchesForDate(
|
|
4067
|
+
adapter,
|
|
4068
|
+
localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz)
|
|
4069
|
+
);
|
|
3234
4070
|
const wanted = group ? [group.toUpperCase()] : groups(matches);
|
|
3235
4071
|
if (cfg.json) {
|
|
3236
4072
|
const tables = wanted.map((g) => ({
|
|
3237
4073
|
group: g,
|
|
3238
4074
|
standings: computeStandings(fixturesByGroup(g, matches))
|
|
3239
4075
|
}));
|
|
3240
|
-
emitJson(
|
|
4076
|
+
emitJson({
|
|
4077
|
+
degraded,
|
|
4078
|
+
source: source ?? null,
|
|
4079
|
+
tables: group ? tables[0] ?? null : tables
|
|
4080
|
+
});
|
|
3241
4081
|
return;
|
|
3242
4082
|
}
|
|
3243
4083
|
const c = painterFor(cfg);
|
|
@@ -3277,6 +4117,8 @@ async function cmdTable(group, ctx) {
|
|
|
3277
4117
|
out(table.toString());
|
|
3278
4118
|
}
|
|
3279
4119
|
out();
|
|
4120
|
+
const src = dataSource(source, c);
|
|
4121
|
+
if (src) out(src);
|
|
3280
4122
|
out(disclaimer(t, c));
|
|
3281
4123
|
}
|
|
3282
4124
|
function cmdPrompt({ cfg }) {
|
|
@@ -3287,9 +4129,9 @@ function cmdPrompt({ cfg }) {
|
|
|
3287
4129
|
);
|
|
3288
4130
|
const maxRaw = Number.parseInt(process.env.CLAUDINHO_MAX ?? "", 10);
|
|
3289
4131
|
const max = Number.isFinite(maxRaw) && maxRaw > 0 ? maxRaw : void 0;
|
|
3290
|
-
const state =
|
|
4132
|
+
const state = readCurrentState(cfg.source, resolveCompetition());
|
|
3291
4133
|
out(renderPrompt(state, { team, compact, max }));
|
|
3292
|
-
if (shouldRefresh()) spawnRefresh(cfg.source);
|
|
4134
|
+
if (!state || shouldRefresh()) spawnRefresh(cfg.source);
|
|
3293
4135
|
} catch {
|
|
3294
4136
|
out("");
|
|
3295
4137
|
}
|
|
@@ -3297,9 +4139,10 @@ function cmdPrompt({ cfg }) {
|
|
|
3297
4139
|
function cmdHook({ cfg }) {
|
|
3298
4140
|
try {
|
|
3299
4141
|
const team = process.env.CLAUDINHO_TEAM;
|
|
3300
|
-
const
|
|
4142
|
+
const state = readCurrentState(cfg.source, resolveCompetition());
|
|
4143
|
+
const ctx = renderHook(state, { team });
|
|
3301
4144
|
if (ctx) out(ctx);
|
|
3302
|
-
if (shouldRefresh()) spawnRefresh(cfg.source);
|
|
4145
|
+
if (!state || shouldRefresh()) spawnRefresh(cfg.source);
|
|
3303
4146
|
} catch {
|
|
3304
4147
|
}
|
|
3305
4148
|
}
|
|
@@ -3331,15 +4174,18 @@ async function cmdMatch(id, ctx) {
|
|
|
3331
4174
|
precheck(cfg, t);
|
|
3332
4175
|
const adapter = adapterFor(ctx);
|
|
3333
4176
|
let match = allFixtures().find((m) => m.id === id);
|
|
4177
|
+
let liveSource;
|
|
3334
4178
|
try {
|
|
3335
4179
|
if (match) {
|
|
3336
4180
|
const live = await adapter.fetchByDate(match.kickoff.slice(0, 10));
|
|
3337
4181
|
match = live.find((m) => m.id === id) ?? match;
|
|
4182
|
+
liveSource = adapter.name;
|
|
3338
4183
|
}
|
|
3339
4184
|
} catch {
|
|
3340
4185
|
}
|
|
4186
|
+
const marketSignal = match ? await reliableMarketSignalFor(ctx, match) : void 0;
|
|
3341
4187
|
if (cfg.json) {
|
|
3342
|
-
emitJson({ match: match ?? null });
|
|
4188
|
+
emitJson({ match: match ?? null, source: liveSource ?? null, marketSignal: marketSignal ?? null });
|
|
3343
4189
|
return;
|
|
3344
4190
|
}
|
|
3345
4191
|
const c = painterFor(cfg);
|
|
@@ -3352,21 +4198,150 @@ async function cmdMatch(id, ctx) {
|
|
|
3352
4198
|
}
|
|
3353
4199
|
const stageLabel = match.group ? `${match.stage} ${match.group}` : match.stage;
|
|
3354
4200
|
out(header(`${match.home.name} ${scoreline(match)} ${match.away.name}`, c));
|
|
3355
|
-
out(" " + c.dim(`${stageLabel} \xB7 ${match
|
|
4201
|
+
out(" " + c.dim(`${stageLabel} \xB7 ${matchLocation(match)}`));
|
|
3356
4202
|
out(
|
|
3357
4203
|
" " + c.dim(
|
|
3358
4204
|
`${formatKickoff(match.kickoff, { tz: cfg.tz, locale: cfg.lang })} ${statusToken(match, t, c)}`.trimEnd()
|
|
3359
4205
|
)
|
|
3360
4206
|
);
|
|
4207
|
+
const flair = matchFlavor(match, { level: cfg.flavor, locale: cfg.lang });
|
|
4208
|
+
if (flair) out(" " + c.cyan(flair));
|
|
3361
4209
|
if (match.events?.length) {
|
|
3362
4210
|
out();
|
|
3363
4211
|
for (const e of match.events) {
|
|
3364
4212
|
out(` ${e.minute}' ${e.type} ${e.teamCode}${e.player ? ` \u2014 ${e.player}` : ""}`);
|
|
3365
4213
|
}
|
|
3366
4214
|
}
|
|
4215
|
+
if (marketSignal) {
|
|
4216
|
+
out();
|
|
4217
|
+
for (const mline of marketBlock(marketSignal, match)) out(" " + c.dim(mline));
|
|
4218
|
+
}
|
|
3367
4219
|
out();
|
|
4220
|
+
const src = dataSource(liveSource, c);
|
|
4221
|
+
if (src) out(src);
|
|
3368
4222
|
out(disclaimer(t, c));
|
|
3369
4223
|
}
|
|
4224
|
+
var MARKET_INFO = "Prediction-market data is informational only.";
|
|
4225
|
+
function marketDisplayable(sig) {
|
|
4226
|
+
return !sig.ambiguous && sig.favorite != null && hasSaneDistribution(sig.outcomes);
|
|
4227
|
+
}
|
|
4228
|
+
function marketHeaderLine(m) {
|
|
4229
|
+
return `${m.home.flag} ${m.home.name} vs ${m.away.name} ${m.away.flag}`;
|
|
4230
|
+
}
|
|
4231
|
+
function printMarketBlock(m, sig, c) {
|
|
4232
|
+
for (const line2 of marketBlock(sig, m)) out(" " + c.dim(line2));
|
|
4233
|
+
}
|
|
4234
|
+
async function cmdMarkets(target, team, ctx) {
|
|
4235
|
+
const { cfg, t } = ctx;
|
|
4236
|
+
if (target === "next") {
|
|
4237
|
+
precheck(cfg, t);
|
|
4238
|
+
if (!team) throw new InputError("Usage: claudinho markets next <team>");
|
|
4239
|
+
const code = team.toUpperCase();
|
|
4240
|
+
const fixture = nextFixtureForTeam(code);
|
|
4241
|
+
const sig = fixture ? (await marketSignalsFor(ctx, [fixture], MARKETS_CMD_OPTS)).get(fixture.id) : void 0;
|
|
4242
|
+
const shown = sig && marketDisplayable(sig) ? sig : void 0;
|
|
4243
|
+
if (cfg.json) {
|
|
4244
|
+
emitJson({
|
|
4245
|
+
team: code,
|
|
4246
|
+
matchId: fixture?.id ?? null,
|
|
4247
|
+
informationalOnly: true,
|
|
4248
|
+
signal: shown ?? null
|
|
4249
|
+
});
|
|
4250
|
+
return;
|
|
4251
|
+
}
|
|
4252
|
+
const c2 = painterFor(cfg);
|
|
4253
|
+
out();
|
|
4254
|
+
if (!fixture) {
|
|
4255
|
+
out(c2.dim(" " + t("next.none", { team: code })));
|
|
4256
|
+
} else {
|
|
4257
|
+
out(header(marketHeaderLine(fixture), c2));
|
|
4258
|
+
out();
|
|
4259
|
+
if (shown) printMarketBlock(fixture, shown, c2);
|
|
4260
|
+
else out(c2.dim(" No market signal for this match."));
|
|
4261
|
+
}
|
|
4262
|
+
out();
|
|
4263
|
+
out(disclaimer(t, c2));
|
|
4264
|
+
out(c2.dim(MARKET_INFO));
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
if (target && target !== "today" && !isValidDate(target)) {
|
|
4268
|
+
precheck(cfg, t);
|
|
4269
|
+
const match = allFixtures().find((m) => m.id === target);
|
|
4270
|
+
const sig = match ? (await marketSignalsFor(ctx, [match], MARKETS_CMD_OPTS)).get(match.id) : void 0;
|
|
4271
|
+
const shown = sig && marketDisplayable(sig) ? sig : void 0;
|
|
4272
|
+
if (cfg.json) {
|
|
4273
|
+
emitJson({ matchId: target, informationalOnly: true, signal: shown ?? null });
|
|
4274
|
+
return;
|
|
4275
|
+
}
|
|
4276
|
+
const c2 = painterFor(cfg);
|
|
4277
|
+
out();
|
|
4278
|
+
if (!match) {
|
|
4279
|
+
out(c2.dim(" " + t("match.none", { id: target })));
|
|
4280
|
+
} else {
|
|
4281
|
+
out(header(marketHeaderLine(match), c2));
|
|
4282
|
+
out();
|
|
4283
|
+
if (shown) printMarketBlock(match, shown, c2);
|
|
4284
|
+
else out(c2.dim(" No market signal for this match."));
|
|
4285
|
+
}
|
|
4286
|
+
out();
|
|
4287
|
+
out(disclaimer(t, c2));
|
|
4288
|
+
out(c2.dim(MARKET_INFO));
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
const explicitDate = target && target !== "today" ? target : void 0;
|
|
4292
|
+
precheck(cfg, t, explicitDate);
|
|
4293
|
+
const date = explicitDate ?? localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz);
|
|
4294
|
+
const { matches } = await getMatchesForDate(adapterFor(ctx), date);
|
|
4295
|
+
const todays = fixturesByDate(date, matches, cfg.tz);
|
|
4296
|
+
const signals = await marketSignalsFor(ctx, todays, MARKETS_CMD_OPTS);
|
|
4297
|
+
const rows = todays.map((m) => ({ match: m, signal: signals.get(m.id) })).filter(
|
|
4298
|
+
(r) => !!r.signal && marketDisplayable(r.signal)
|
|
4299
|
+
);
|
|
4300
|
+
if (cfg.json) {
|
|
4301
|
+
const marketSignals = {};
|
|
4302
|
+
for (const r of rows) marketSignals[r.match.id] = r.signal;
|
|
4303
|
+
emitJson({ date, informationalOnly: true, marketSignals });
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
const c = painterFor(cfg);
|
|
4307
|
+
out();
|
|
4308
|
+
out(header(`Market signals \xB7 ${date}`, c));
|
|
4309
|
+
out();
|
|
4310
|
+
if (rows.length === 0) {
|
|
4311
|
+
out(c.dim(` No market signals available for ${date}.`));
|
|
4312
|
+
} else {
|
|
4313
|
+
for (const { match, signal } of rows) {
|
|
4314
|
+
out(" " + c.bold(marketHeaderLine(match)));
|
|
4315
|
+
printMarketBlock(match, signal, c);
|
|
4316
|
+
out();
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
out(disclaimer(t, c));
|
|
4320
|
+
out(c.dim(MARKET_INFO));
|
|
4321
|
+
}
|
|
4322
|
+
var VIBES = [
|
|
4323
|
+
"Shipping code, watching goals.",
|
|
4324
|
+
"Green tests, green pitch.",
|
|
4325
|
+
"Pelota al pie, manos al teclado.",
|
|
4326
|
+
"Refactoring through the group stage.",
|
|
4327
|
+
"Merge conflicts can wait \u2014 it\u2019s matchday.",
|
|
4328
|
+
"One feed for the world, one vibe for the dev.",
|
|
4329
|
+
"Stoppage time and a clean stack trace.",
|
|
4330
|
+
"Coding into extra time."
|
|
4331
|
+
];
|
|
4332
|
+
function cmdVibe(ctx) {
|
|
4333
|
+
const { cfg } = ctx;
|
|
4334
|
+
const line2 = VIBES[Math.floor(Math.random() * VIBES.length)];
|
|
4335
|
+
if (cfg.json) {
|
|
4336
|
+
emitJson({ vibe: line2, tag: "#VibingLaVidaLoca" });
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
const c = painterFor(cfg);
|
|
4340
|
+
out();
|
|
4341
|
+
out(" \u26BD " + c.bold(line2));
|
|
4342
|
+
out(" " + c.cyan("#VibingLaVidaLoca"));
|
|
4343
|
+
out();
|
|
4344
|
+
}
|
|
3370
4345
|
|
|
3371
4346
|
// src/index.ts
|
|
3372
4347
|
function handlePipeError(stream) {
|
|
@@ -3377,7 +4352,7 @@ function handlePipeError(stream) {
|
|
|
3377
4352
|
}
|
|
3378
4353
|
handlePipeError(process.stdout);
|
|
3379
4354
|
handlePipeError(process.stderr);
|
|
3380
|
-
var VERSION = "0.
|
|
4355
|
+
var VERSION = "0.3.0";
|
|
3381
4356
|
var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
|
|
3382
4357
|
function ctxFrom(cmd) {
|
|
3383
4358
|
const root = cmd.parent ?? cmd;
|
|
@@ -3392,7 +4367,8 @@ function fail(err) {
|
|
|
3392
4367
|
process.exit(1);
|
|
3393
4368
|
}
|
|
3394
4369
|
var program = new Command();
|
|
3395
|
-
program.name("claudinho").description("The 2026 football tournament in your terminal.\n" + DISCLAIMER).version(VERSION, "-v, --version").option("--lang <code>", "language: en, es, pt, fr").option("--tz <zone>", "IANA timezone, e.g. America/Mexico_City").option("--json", "output JSON (for scripting)").option("--no-color", "disable ANSI colors").option("--source <name>", "live data provider (advanced)");
|
|
4370
|
+
program.name("claudinho").description("The 2026 football tournament in your terminal.\n" + DISCLAIMER).version(VERSION, "-v, --version").option("--lang <code>", "language: en, es, pt, fr").option("--tz <zone>", "IANA timezone, e.g. America/Mexico_City").option("--json", "output JSON (for scripting)").option("--no-color", "disable ANSI colors").option("--source <name>", "live data provider (advanced)").option("--flavor <level>", "commentary flair: off, subtle, full (default: full)").option("--no-markets", "hide prediction-market signals (informational odds)");
|
|
4371
|
+
program.addHelpText("after", "\n#VibingLaVidaLoca \u26BD");
|
|
3396
4372
|
program.command("today").description("show a day's fixtures (default: today)").argument("[date]", "date as YYYY-MM-DD").action(async (date, _opts, cmd) => {
|
|
3397
4373
|
try {
|
|
3398
4374
|
await cmdToday(date, ctxFrom(cmd));
|
|
@@ -3428,6 +4404,13 @@ program.command("match").description("show a single match by id").argument("<id>
|
|
|
3428
4404
|
fail(e);
|
|
3429
4405
|
}
|
|
3430
4406
|
});
|
|
4407
|
+
program.command("markets").description("show prediction-market signals (read-only, informational only)").argument("[target]", 'date (YYYY-MM-DD), match id, "today", or "next"').argument("[team]", 'team code when target is "next" (e.g. MEX)').action(async (target, team, _opts, cmd) => {
|
|
4408
|
+
try {
|
|
4409
|
+
await cmdMarkets(target, team, ctxFrom(cmd));
|
|
4410
|
+
} catch (e) {
|
|
4411
|
+
fail(e);
|
|
4412
|
+
}
|
|
4413
|
+
});
|
|
3431
4414
|
program.command("prompt").description("print a one-line status (Claude Code statusline, tmux, Starship, \u2026)").action((_opts, cmd) => {
|
|
3432
4415
|
cmdPrompt(ctxFrom(cmd));
|
|
3433
4416
|
});
|
|
@@ -3448,6 +4431,9 @@ program.command("init-hook").description("wire the live-score hook into Claude C
|
|
|
3448
4431
|
fail(e);
|
|
3449
4432
|
}
|
|
3450
4433
|
});
|
|
4434
|
+
program.command("vibe").description("print a matchday-coder one-liner (#VibingLaVidaLoca)").action((_opts, cmd) => {
|
|
4435
|
+
cmdVibe(ctxFrom(cmd));
|
|
4436
|
+
});
|
|
3451
4437
|
var refreshCmd = new Command("_refresh").description("(internal) refresh the statusline cache").action(async (_opts, cmd) => {
|
|
3452
4438
|
try {
|
|
3453
4439
|
await cmdRefresh(ctxFrom(cmd));
|