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.
Files changed (2) hide show
  1. package/dist/cli.js +58 -9
  2. 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.replace("T", " ").replace(".000Z", "") }),
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: ["Kickoff (UTC)", "Stage", "Home", "Away", "Venue", "Score", "Status"],
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.replace("T", " ").replace(".000Z", ""),
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.2.1",
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": {