@claudinho/core 0.8.10 → 0.8.12

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
@@ -847,6 +847,17 @@ declare function deriveFavorite(outcomes: MarketOutcome[]): MarketFavorite | und
847
847
  * draw line (a 90' group result must price the draw).
848
848
  */
849
849
  declare function mapsCleanly(match: Match, outcomes: MarketOutcome[]): boolean;
850
+ /**
851
+ * Is a (possibly cached/looked-up) signal safe to RENDER for THIS fixture? A
852
+ * signal is keyed and stored by match id, but display labels are taken from the
853
+ * *current* Match — so a cached signal must be re-checked against the fixture
854
+ * actually being shown. The guard: same match id AND the outcomes still map to
855
+ * the fixture's real teams. This fails closed when a knockout slot the feed
856
+ * resolved earlier later degrades back to a 🏳️ placeholder (the signal's own
857
+ * `ambiguous` flag was decided at fetch time, against the resolved match, so it
858
+ * can't catch this on its own).
859
+ */
860
+ declare function marketSignalRendersFor(match: Match, signal: MarketSignal): boolean;
850
861
  /** Sanity check: ≥2 priced outcomes whose probabilities sum to ~1. */
851
862
  declare function hasSaneDistribution(outcomes: MarketOutcome[]): boolean;
852
863
  /** Is the signal older than the freshness window? Unparseable timestamps are stale. */
@@ -952,29 +963,6 @@ declare class FakeMarketProvider implements MarketProvider {
952
963
  private synthesize;
953
964
  }
954
965
 
955
- /**
956
- * Polymarket public-data adapter — read-only prediction-market signals.
957
- *
958
- * STRICT read-only by design: it touches only the public Gamma events/markets
959
- * data endpoint. No auth, no wallet, no CLOB/order endpoints, no trading, and no
960
- * outbound links (sourceMarketId is opaque, never a URL). Any network/parse/host
961
- * error degrades to "no signal" — it never throws.
962
- *
963
- * Payload model (verified against the live Gamma API, see
964
- * docs/POLYMARKET_MARKET_PREDICTIONS.md): a World Cup match is a Gamma EVENT
965
- * (`fifwc-{home}-{away}-{date}`) whose payload carries the three moneyline
966
- * BINARY markets — home win / draw / away win. Each is `outcomes: ["Yes","No"]`
967
- * and the outcome's probability is its "Yes" price.
968
- *
969
- * Mapping is by event slug, which is deterministic — so by default the slug is
970
- * DERIVED from the fixture (team codes + UTC date) and every match attempts
971
- * enrichment. A hand-curated entry in mapping.2026.json overrides the derived
972
- * slug for the rare fixture whose slug doesn't follow the pattern. Because the
973
- * slug is a guess, validation FAILS CLOSED: the returned event must match the
974
- * requested slug, line up on kickoff, expose the right moneyline markets, and
975
- * resolve in regular time — otherwise no signal is produced.
976
- */
977
-
978
966
  /**
979
967
  * Optional override of the derived event slug for a fixture whose Polymarket
980
968
  * slug doesn't follow `fifwc-{home}-{away}-{date}` (e.g. an abbreviation that
@@ -1164,4 +1152,4 @@ declare function formatShareBracket(input: ShareBracketInput, options?: ShareBra
1164
1152
  /** Compact one-line-per-match bracket for narrow share contexts. */
1165
1153
  declare function formatBracketCompactLine(mv: BracketMatchView, opts?: BracketFormatOpts): string;
1166
1154
 
1167
- 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 };
1155
+ 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, marketSignalRendersFor, 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
@@ -497,6 +497,10 @@ function localDate(iso, tz) {
497
497
  timeZone: zone
498
498
  }).format(new Date(iso));
499
499
  }
500
+ function shiftUtcDate(dateISO, days) {
501
+ const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
502
+ return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
503
+ }
500
504
 
501
505
  // src/normalize.ts
502
506
  function outcomeFromScore(home, away) {
@@ -4141,14 +4145,19 @@ async function getBracket(adapter, opts = {}) {
4141
4145
  source
4142
4146
  };
4143
4147
  }
4144
- function shiftUtcDate(dateISO, days) {
4145
- const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
4146
- return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
4147
- }
4148
4148
  var EXTRA_TIME_SLACK_MS = 60 * 6e4;
4149
4149
  async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
4150
4150
  const nowMs = now.getTime();
4151
- const candidate = fixturesByTeam(code).find((m) => {
4151
+ let fixtures = allFixtures();
4152
+ let overlayFailed = false;
4153
+ try {
4154
+ if (adapter.fetchWindow) {
4155
+ fixtures = mergeLive(fixtures, await adapter.fetchWindow(KNOCKOUT_WINDOW_START, KNOCKOUT_WINDOW_END));
4156
+ }
4157
+ } catch {
4158
+ overlayFailed = true;
4159
+ }
4160
+ const candidate = fixturesByTeam(code, fixtures).find((m) => {
4152
4161
  const k = Date.parse(m.kickoff);
4153
4162
  return nowMs >= k && nowMs <= k + LIVE_WINDOW_MS + EXTRA_TIME_SLACK_MS;
4154
4163
  });
@@ -4157,8 +4166,8 @@ async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Dat
4157
4166
  const m = r.match ?? candidate;
4158
4167
  if (!isFinished(m.status)) return { ...r, match: m };
4159
4168
  }
4160
- const next = nextFixtureForTeam(code, { from: now });
4161
- return { match: next, degraded: false };
4169
+ const next = nextFixtureForTeam(code, { from: now, fixtures });
4170
+ return { match: next, degraded: overlayFailed };
4162
4171
  }
4163
4172
  async function getNextFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
4164
4173
  const base = allFixtures();
@@ -4267,6 +4276,9 @@ function mapsCleanly(match, outcomes) {
4267
4276
  if (match.stage === "GROUP" && !draw) return false;
4268
4277
  return true;
4269
4278
  }
4279
+ function marketSignalRendersFor(match, signal) {
4280
+ return signal.matchId === match.id && mapsCleanly(match, signal.outcomes);
4281
+ }
4270
4282
  function hasSaneDistribution(outcomes) {
4271
4283
  const priced = outcomes.filter((o) => Number.isFinite(o.probability) && o.probability > 0);
4272
4284
  if (priced.length < 2) return false;
@@ -4470,12 +4482,15 @@ var PolymarketProvider = class {
4470
4482
  */
4471
4483
  async resolveOne(match, options) {
4472
4484
  const entry = (this.opts.mapping ?? BUNDLED_MAPPING)[match.id];
4473
- const eventSlug = entry?.eventSlug ?? deriveEventSlug(match);
4474
- if (!eventSlug) return { checked: true };
4485
+ const slugs = entry?.eventSlug ? [entry.eventSlug] : deriveEventSlugs(match);
4486
+ if (slugs.length === 0) return { checked: true };
4475
4487
  try {
4476
- const event = await this.fetchEvent(eventSlug, options?.timeoutMs);
4477
- const signal = event ? this.toSignal(match, eventSlug, event, options) : void 0;
4478
- return { signal, checked: true };
4488
+ for (const slug of slugs) {
4489
+ const event = await this.fetchEvent(slug, options?.timeoutMs);
4490
+ const signal = event ? this.toSignal(match, slug, event, options) : void 0;
4491
+ if (signal) return { signal, checked: true };
4492
+ }
4493
+ return { checked: true };
4479
4494
  } catch {
4480
4495
  return { checked: false };
4481
4496
  }
@@ -4551,14 +4566,17 @@ var PolymarketProvider = class {
4551
4566
  return signal.ambiguous ? void 0 : signal;
4552
4567
  }
4553
4568
  };
4554
- function deriveEventSlug(match) {
4569
+ function deriveEventSlugs(match) {
4555
4570
  const home = match.home.code.toLowerCase();
4556
4571
  const away = match.away.code.toLowerCase();
4557
- if (home === away || home === "tbd" || away === "tbd") return void 0;
4558
- if (!/^[a-z]{3}$/.test(home) || !/^[a-z]{3}$/.test(away)) return void 0;
4559
- const date = match.kickoff.slice(0, 10);
4560
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
4561
- return `fifwc-${home}-${away}-${date}`;
4572
+ if (home === away || home === "tbd" || away === "tbd") return [];
4573
+ if (!/^[a-z]{3}$/.test(home) || !/^[a-z]{3}$/.test(away)) return [];
4574
+ const utcDate = match.kickoff.slice(0, 10);
4575
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(utcDate)) return [];
4576
+ return [
4577
+ `fifwc-${home}-${away}-${utcDate}`,
4578
+ `fifwc-${home}-${away}-${shiftUtcDate(utcDate, -1)}`
4579
+ ];
4562
4580
  }
4563
4581
  function slugToken(m) {
4564
4582
  return (m.slug ?? "").toLowerCase().split("-").pop() ?? "";
@@ -4979,6 +4997,7 @@ export {
4979
4997
  marketLine,
4980
4998
  marketProbabilityText,
4981
4999
  marketRelevant,
5000
+ marketSignalRendersFor,
4982
5001
  marketSourceLabel,
4983
5002
  matchFlavor,
4984
5003
  matchKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/core",
3
- "version": "0.8.10",
3
+ "version": "0.8.12",
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",