fifa-wc26 0.2.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/dist/cli.js +58 -9
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -18,6 +18,49 @@ var init_esm_shims = __esm({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
// src/render/time.ts
|
|
22
|
+
function detectTimeZone() {
|
|
23
|
+
const override = process.env.WC26_TZ?.trim();
|
|
24
|
+
if (override) {
|
|
25
|
+
try {
|
|
26
|
+
new Intl.DateTimeFormat("en-US", { timeZone: override });
|
|
27
|
+
return override;
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
33
|
+
} catch {
|
|
34
|
+
return "UTC";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function formatKickoff(iso, tz = detectTimeZone()) {
|
|
38
|
+
const d = new Date(iso);
|
|
39
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
40
|
+
try {
|
|
41
|
+
return new Intl.DateTimeFormat("sv-SE", {
|
|
42
|
+
timeZone: tz,
|
|
43
|
+
year: "numeric",
|
|
44
|
+
month: "2-digit",
|
|
45
|
+
day: "2-digit",
|
|
46
|
+
hour: "2-digit",
|
|
47
|
+
minute: "2-digit",
|
|
48
|
+
hour12: false
|
|
49
|
+
}).format(d);
|
|
50
|
+
} catch {
|
|
51
|
+
return d.toISOString().replace("T", " ").replace(/:\d{2}\.\d{3}Z$/, "");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function tzLabel(tz = detectTimeZone()) {
|
|
55
|
+
return tz || "UTC";
|
|
56
|
+
}
|
|
57
|
+
var init_time = __esm({
|
|
58
|
+
"src/render/time.ts"() {
|
|
59
|
+
"use strict";
|
|
60
|
+
init_esm_shims();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
21
64
|
// src/render/live-dashboard.tsx
|
|
22
65
|
var live_dashboard_exports = {};
|
|
23
66
|
__export(live_dashboard_exports, {
|
|
@@ -62,7 +105,7 @@ function Dashboard({ live, upcoming, stale, reason, favoriteOnly }) {
|
|
|
62
105
|
] }, m.id)),
|
|
63
106
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Upcoming" }) }),
|
|
64
107
|
upcoming.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "none" }) : upcoming.map((f) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
65
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: f.utcKickoff
|
|
108
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: formatKickoff(f.utcKickoff) }),
|
|
66
109
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
67
110
|
" ",
|
|
68
111
|
f.home.code,
|
|
@@ -82,6 +125,7 @@ var init_live_dashboard = __esm({
|
|
|
82
125
|
"src/render/live-dashboard.tsx"() {
|
|
83
126
|
"use strict";
|
|
84
127
|
init_esm_shims();
|
|
128
|
+
init_time();
|
|
85
129
|
}
|
|
86
130
|
});
|
|
87
131
|
|
|
@@ -1000,18 +1044,19 @@ async function buildRegistry(opts) {
|
|
|
1000
1044
|
}
|
|
1001
1045
|
return new ProviderRegistry(providers);
|
|
1002
1046
|
}
|
|
1003
|
-
async function runCached(key, ttlSec, fetcher, opts) {
|
|
1047
|
+
async function runCached(key, ttlSec, fetcher, opts, cacheOpts = {}) {
|
|
1048
|
+
const validate = cacheOpts.validate ?? (() => true);
|
|
1004
1049
|
if (!opts.noCache) {
|
|
1005
1050
|
const hit = await env.cache.read(key, { allowStale: false });
|
|
1006
|
-
if (hit) return { data: hit.data, stale: false };
|
|
1051
|
+
if (hit && validate(hit.data)) return { data: hit.data, stale: false };
|
|
1007
1052
|
}
|
|
1008
1053
|
try {
|
|
1009
1054
|
const { data, provider } = await fetcher();
|
|
1010
|
-
await env.cache.write(key, data, ttlSec, provider);
|
|
1055
|
+
if (validate(data)) await env.cache.write(key, data, ttlSec, provider);
|
|
1011
1056
|
return { data, stale: false };
|
|
1012
1057
|
} catch (e) {
|
|
1013
1058
|
const stale = await env.cache.read(key, { allowStale: true });
|
|
1014
|
-
if (stale) {
|
|
1059
|
+
if (stale && validate(stale.data)) {
|
|
1015
1060
|
const reason = e instanceof WC26Error ? e.code.toLowerCase() : "unreachable";
|
|
1016
1061
|
return { data: stale.data, stale: true, reason };
|
|
1017
1062
|
}
|
|
@@ -1082,6 +1127,7 @@ function renderTeamPlain(t) {
|
|
|
1082
1127
|
|
|
1083
1128
|
// src/render/pretty.ts
|
|
1084
1129
|
init_esm_shims();
|
|
1130
|
+
init_time();
|
|
1085
1131
|
import Table from "cli-table3";
|
|
1086
1132
|
import chalk from "chalk";
|
|
1087
1133
|
var stageLabel = (s) => ({
|
|
@@ -1101,13 +1147,14 @@ var colorStatus = (s) => {
|
|
|
1101
1147
|
var scoreStr2 = (f) => f.score ? `${f.score.home}-${f.score.away}` : "\u2013";
|
|
1102
1148
|
function renderFixturesPretty(fixtures, emptyMessage = "no matches") {
|
|
1103
1149
|
if (fixtures.length === 0) return chalk.dim(emptyMessage);
|
|
1150
|
+
const tz = detectTimeZone();
|
|
1104
1151
|
const t = new Table({
|
|
1105
|
-
head: [
|
|
1152
|
+
head: [`Kickoff (${tzLabel(tz)})`, "Stage", "Home", "Away", "Venue", "Score", "Status"],
|
|
1106
1153
|
style: { head: ["bold"] }
|
|
1107
1154
|
});
|
|
1108
1155
|
for (const f of fixtures) {
|
|
1109
1156
|
t.push([
|
|
1110
|
-
f.utcKickoff
|
|
1157
|
+
formatKickoff(f.utcKickoff, tz),
|
|
1111
1158
|
`${stageLabel(f.stage)}${f.group ? " " + f.group : ""}`,
|
|
1112
1159
|
`${f.home.code} ${chalk.dim(f.home.name)}`,
|
|
1113
1160
|
`${f.away.code} ${chalk.dim(f.away.name)}`,
|
|
@@ -1176,7 +1223,8 @@ function fixturesCmd(p) {
|
|
|
1176
1223
|
});
|
|
1177
1224
|
return { data: data2, provider };
|
|
1178
1225
|
},
|
|
1179
|
-
g
|
|
1226
|
+
g,
|
|
1227
|
+
{ validate: (d) => g.team || g.from || g.to || g.stage ? d.length > 0 : d.length >= 50 }
|
|
1180
1228
|
);
|
|
1181
1229
|
const filtered = data.filter(
|
|
1182
1230
|
(f) => (!q.stage || f.stage === q.stage) && (!q.teamCode || f.home.code === q.teamCode || f.away.code === q.teamCode)
|
|
@@ -1214,7 +1262,8 @@ function nextCmd(p) {
|
|
|
1214
1262
|
});
|
|
1215
1263
|
return { data: data2, provider };
|
|
1216
1264
|
},
|
|
1217
|
-
g
|
|
1265
|
+
g,
|
|
1266
|
+
{ validate: (d) => g.team ? d.length > 0 : d.length >= 50 }
|
|
1218
1267
|
);
|
|
1219
1268
|
const now = Date.now();
|
|
1220
1269
|
const out = data.filter((f) => f.status === "scheduled" && new Date(f.utcKickoff).getTime() > now).sort((a, b) => a.utcKickoff.localeCompare(b.utcKickoff)).slice(0, n);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fifa-wc26",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "FIFA World Cup 2026 CLI: fixtures, live scores, group standings, ASCII bracket, team lookup. Keyless providers, smart cache, terminal-friendly output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|