@claudinho/core 0.8.6 → 0.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -626,6 +626,51 @@ interface MatchByIdResult {
626
626
  * nothing rather than something wrong).
627
627
  */
628
628
  declare function marketFixtureForTeam(adapter: ProviderAdapter, code: string, now?: Date): Promise<MatchByIdResult>;
629
+ interface NextFixtureResult {
630
+ fixture?: Match;
631
+ /** True when the live overlay fetch failed and only the static skeleton was used. */
632
+ degraded: boolean;
633
+ /** The provider that served the live overlay (absent when degraded). */
634
+ source?: string;
635
+ }
636
+ /**
637
+ * A team's next UPCOMING fixture, LIVE-RESOLVED across the knockout phase.
638
+ *
639
+ * The bundled schedule's knockout slots are resultless placeholders (home/away
640
+ * are slot refs like "Group A winner", never a nation — see
641
+ * {@link sanitizeBundledFixture}), so a purely static lookup goes blind the
642
+ * moment a team's last GROUP game passes: `next MEX` answers "no upcoming
643
+ * fixture" even after ESPN has confirmed Mexico's Round-of-32 tie. Overlay the
644
+ * live knockout window (the SAME single fetch {@link getBracket} uses) so the
645
+ * merged set carries the resolved nations, then pick the team's next fixture
646
+ * with kickoff ≥ now. (Strictly upcoming — the in-play match is `getLiveMatches`'
647
+ * job, preserving the pre-overlay `next` semantics.)
648
+ *
649
+ * Fails closed: on any provider error it falls back to the static result
650
+ * (`degraded: true`), so a feed outage degrades to "no fixture" rather than
651
+ * inventing one — advancement is never read from the static skeleton.
652
+ */
653
+ declare function getNextFixtureForTeam(adapter: ProviderAdapter, code: string, now?: Date): Promise<NextFixtureResult>;
654
+ interface KnockoutFixturesResult {
655
+ /** Resolved (both nations known) upcoming knockout fixtures, sorted by kickoff. */
656
+ fixtures: Match[];
657
+ /** True when the overlay fetch failed — caller must NOT cache this as "none". */
658
+ degraded: boolean;
659
+ }
660
+ /**
661
+ * The RESOLVED upcoming knockout fixtures from the live overlay — the data the
662
+ * hot-path statusline can't fetch itself but needs to show a real next-match
663
+ * countdown (e.g. "🇲🇽 vs 🇪🇨 in 2d") instead of a 🏳️ placeholder. The cold-path
664
+ * refresher calls this and caches the result; the statusline reads the cache.
665
+ *
666
+ * Returns only fixtures where BOTH nations are resolved (flag ≠ 🏳️) and kickoff
667
+ * ≥ now, so a slot ESPN hasn't filled yet is simply absent (the statusline then
668
+ * fails closed to "⚽ —", never a placeholder). **Fails closed with
669
+ * `degraded: true` on a provider error** — the caller must keep its prior cached
670
+ * fixtures rather than cache an empty list as a real "no knockouts" (a transient
671
+ * outage must never read as "your team is out").
672
+ */
673
+ declare function getKnockoutFixtures(adapter: ProviderAdapter, now?: Date): Promise<KnockoutFixturesResult>;
629
674
  /**
630
675
  * A single match by id, with live overlay. The provider's scoreboard buckets
631
676
  * days in its own zone (ESPN: US/Eastern), so a fixture's UTC date can differ
@@ -1058,6 +1103,9 @@ declare function parseTeamSlot(team: Team): SlotRef | null;
1058
1103
  */
1059
1104
  declare function buildBracketView(topology: BracketTopology, matches: Match[], tables: GroupStandings[], standingsDegraded: boolean, liveDegraded: boolean, filterStage?: string, lang?: string): BracketView;
1060
1105
 
1106
+ /** True when a team carries a real nation flag (not a bracket placeholder). */
1107
+ declare function isResolvedNation(team: Team): boolean;
1108
+
1061
1109
  /** The bundled knockout bracket topology (generated by gen:schedule). */
1062
1110
  declare function loadBracketTopology(): BracketTopology;
1063
1111
 
@@ -1099,4 +1147,4 @@ declare function formatShareBracket(input: ShareBracketInput, options?: ShareBra
1099
1147
  /** Compact one-line-per-match bracket for narrow share contexts. */
1100
1148
  declare function formatBracketCompactLine(mv: BracketMatchView, opts?: BracketFormatOpts): string;
1101
1149
 
1102
- export { BRACKET_STAGE_ORDER, type BracketFormatOpts, type BracketMatchNode, type BracketMatchView, type BracketResult, type BracketTopology, type BracketView, type BuildSignalInput, DEFAULT_COMPETITION, DEFAULT_FLAVOR, DEFAULT_MAX_AGE_MS, EspnAdapter, type EspnAdapterOptions, FLAVOR_LEVELS, FakeMarketProvider, type FakeMarketProviderOptions, type FavoriteStrength, type FlavorLevel, type FormatOpts, type GroupStandings, LIVE_WINDOW_MS, type Lang, type LedgerRow, type LiveResult, type MapContext, type MarketFavorite, type MarketMapping, type MarketMappingTable, type MarketOutcome, type MarketOutcomeKind, type MarketProvider, type MarketSignal, type MarketSignalOptions, type MarketSignalsResult, type Match, type MatchByIdResult, type MatchEvent, type Outcome, PolymarketProvider, type PolymarketProviderOptions, type ProviderAdapter, type ProviderCapabilities, type PunditPick, type ResolvedParticipant, SHARE_DISCLAIMER, SHARE_HASHTAG, type ShareBracketInput, type ShareBracketOptions, type ShareSnippetInput, type ShareSnippetOptions, type ShareStyle, type ShareTableInput, type SlotRef, type Stage, type StandingRow, type StandingsResult, type Status, type Team, allFixtures, asFlavorLevel, buildBracketTopology, buildBracketView, buildMarketSignal, byKickoff, competitionBase, computeStandings, countdown, currentOrNextFixtureForTeam, deriveFavorite, favoriteStrength, fixturesByDate, fixturesByGroup, fixturesByTeam, fixturesInLiveWindow, flagEmoji, formatBracketCompactLine, formatBracketList, formatBracketMatchLine, formatBracketTree, formatDate, formatKickoff, formatShareBracket, formatShareSnippet, formatShareTable, formatTime, getBracket, getLiveMatches, getMarketSignal, getMarketSignals, getMatchById, getMatchesForDate, getStandings, groups, hasSaneDistribution, isFinished, isFlavorLevel, isLive, isReliableMarketSignal, isStaleSignal, isValidDate, isValidTimeZone, liveSourceLabel, loadBracketTopology, localDate, makeAdapter, makeMarketProvider, mapEspnEvent, mapsCleanly, marketAttributionText, marketBlock, marketFavoriteText, marketFixtureForTeam, marketLine, marketProbabilityText, marketRelevant, marketSourceLabel, matchFlavor, matchKey, matchLocation, mergeLive, nationToFlag, nationToRegion, nextFixtureForTeam, normalizeLang, normalizeOutcomes, outcomeFromScore, parseStandings, parseTeamSlot, resolveCompetition, resolveMarketSource, resolveTz, sanitizeBundledFixture, scoreline, stageLabel, stageLabelI18n, t };
1150
+ export { BRACKET_STAGE_ORDER, type BracketFormatOpts, type BracketMatchNode, type BracketMatchView, type BracketResult, type BracketTopology, type BracketView, type BuildSignalInput, DEFAULT_COMPETITION, DEFAULT_FLAVOR, DEFAULT_MAX_AGE_MS, EspnAdapter, type EspnAdapterOptions, FLAVOR_LEVELS, FakeMarketProvider, type FakeMarketProviderOptions, type FavoriteStrength, type FlavorLevel, type FormatOpts, type GroupStandings, type KnockoutFixturesResult, LIVE_WINDOW_MS, type Lang, type LedgerRow, type LiveResult, type MapContext, type MarketFavorite, type MarketMapping, type MarketMappingTable, type MarketOutcome, type MarketOutcomeKind, type MarketProvider, type MarketSignal, type MarketSignalOptions, type MarketSignalsResult, type Match, type MatchByIdResult, type MatchEvent, type NextFixtureResult, type Outcome, PolymarketProvider, type PolymarketProviderOptions, type ProviderAdapter, type ProviderCapabilities, type PunditPick, type ResolvedParticipant, SHARE_DISCLAIMER, SHARE_HASHTAG, type ShareBracketInput, type ShareBracketOptions, type ShareSnippetInput, type ShareSnippetOptions, type ShareStyle, type ShareTableInput, type SlotRef, type Stage, type StandingRow, type StandingsResult, type Status, type Team, allFixtures, asFlavorLevel, buildBracketTopology, buildBracketView, buildMarketSignal, byKickoff, competitionBase, computeStandings, countdown, currentOrNextFixtureForTeam, deriveFavorite, favoriteStrength, fixturesByDate, fixturesByGroup, fixturesByTeam, fixturesInLiveWindow, flagEmoji, formatBracketCompactLine, formatBracketList, formatBracketMatchLine, formatBracketTree, formatDate, formatKickoff, formatShareBracket, formatShareSnippet, formatShareTable, formatTime, getBracket, getKnockoutFixtures, getLiveMatches, getMarketSignal, getMarketSignals, getMatchById, getMatchesForDate, getNextFixtureForTeam, getStandings, groups, hasSaneDistribution, isFinished, isFlavorLevel, isLive, isReliableMarketSignal, isResolvedNation, isStaleSignal, isValidDate, isValidTimeZone, liveSourceLabel, loadBracketTopology, localDate, makeAdapter, makeMarketProvider, mapEspnEvent, mapsCleanly, marketAttributionText, marketBlock, marketFavoriteText, marketFixtureForTeam, marketLine, marketProbabilityText, marketRelevant, marketSourceLabel, matchFlavor, matchKey, matchLocation, mergeLive, nationToFlag, nationToRegion, nextFixtureForTeam, normalizeLang, normalizeOutcomes, outcomeFromScore, parseStandings, parseTeamSlot, resolveCompetition, resolveMarketSource, resolveTz, sanitizeBundledFixture, scoreline, stageLabel, stageLabelI18n, t };
package/dist/index.js CHANGED
@@ -4152,6 +4152,36 @@ async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Dat
4152
4152
  const next = nextFixtureForTeam(code, { from: now });
4153
4153
  return { match: next, degraded: false };
4154
4154
  }
4155
+ async function getNextFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
4156
+ const base = allFixtures();
4157
+ let matches = base;
4158
+ let degraded = true;
4159
+ let liveById;
4160
+ try {
4161
+ const live = adapter.fetchWindow ? await adapter.fetchWindow(KNOCKOUT_WINDOW_START, KNOCKOUT_WINDOW_END) : [];
4162
+ matches = mergeLive(base, live);
4163
+ degraded = false;
4164
+ liveById = new Set(live.map((m) => m.id));
4165
+ } catch {
4166
+ }
4167
+ const fixture = nextFixtureForTeam(code, { from: now, fixtures: matches });
4168
+ const source = fixture && liveById?.has(fixture.id) ? adapter.name : void 0;
4169
+ return { fixture, degraded, source };
4170
+ }
4171
+ async function getKnockoutFixtures(adapter, now = /* @__PURE__ */ new Date()) {
4172
+ if (!adapter.fetchWindow) return { fixtures: [], degraded: true };
4173
+ let live;
4174
+ try {
4175
+ live = await adapter.fetchWindow(KNOCKOUT_WINDOW_START, KNOCKOUT_WINDOW_END);
4176
+ } catch {
4177
+ return { fixtures: [], degraded: true };
4178
+ }
4179
+ const nowMs = now.getTime();
4180
+ const fixtures = live.filter(
4181
+ (m) => m.stage !== "GROUP" && m.stage !== "FRIENDLY" && Date.parse(m.kickoff) >= nowMs && isResolvedNation(m.home) && isResolvedNation(m.away)
4182
+ ).sort(byKickoff);
4183
+ return { fixtures, degraded: false };
4184
+ }
4155
4185
  async function getMatchById(adapter, id) {
4156
4186
  const base = allFixtures().find((m) => m.id === id);
4157
4187
  if (!base) return { match: void 0, degraded: false };
@@ -4909,11 +4939,13 @@ export {
4909
4939
  formatShareTable,
4910
4940
  formatTime,
4911
4941
  getBracket,
4942
+ getKnockoutFixtures,
4912
4943
  getLiveMatches,
4913
4944
  getMarketSignal,
4914
4945
  getMarketSignals,
4915
4946
  getMatchById,
4916
4947
  getMatchesForDate,
4948
+ getNextFixtureForTeam,
4917
4949
  getStandings,
4918
4950
  groups,
4919
4951
  hasSaneDistribution,
@@ -4921,6 +4953,7 @@ export {
4921
4953
  isFlavorLevel,
4922
4954
  isLive,
4923
4955
  isReliableMarketSignal,
4956
+ isResolvedNation,
4924
4957
  isStaleSignal,
4925
4958
  isValidDate,
4926
4959
  isValidTimeZone,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/core",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "Domain model, provider adapters (ESPN), standings, bundled schedule, and the read-only Polymarket market-signal sidecar powering Claudinho. Not affiliated with FIFA or Anthropic.",
5
5
  "type": "module",
6
6
  "license": "MIT",