@claudinho/core 0.4.2 → 0.4.3
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 +52 -7
- package/dist/index.js +55 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -224,6 +224,21 @@ declare function nextFixtureForTeam(code: string, opts?: {
|
|
|
224
224
|
from?: Date;
|
|
225
225
|
fixtures?: Match[];
|
|
226
226
|
}): Match | undefined;
|
|
227
|
+
/** A fixture is potentially live from kickoff until ~kickoff + 140 min. */
|
|
228
|
+
declare const LIVE_WINDOW_MS: number;
|
|
229
|
+
/** Fixtures whose live window contains `now` (cheap, static — no network). */
|
|
230
|
+
declare function fixturesInLiveWindow(now?: number, fixtures?: Match[]): Match[];
|
|
231
|
+
/**
|
|
232
|
+
* The team's in-play fixture when one is inside its live window, else the next
|
|
233
|
+
* upcoming fixture. This is "the match that matters for <team> right now":
|
|
234
|
+
* mid-match, a user (or an agent) asking about a team almost always means the
|
|
235
|
+
* one being played — `nextFixtureForTeam` alone would skip it the moment the
|
|
236
|
+
* kickoff is in the past and silently answer about next week.
|
|
237
|
+
*/
|
|
238
|
+
declare function currentOrNextFixtureForTeam(code: string, opts?: {
|
|
239
|
+
from?: Date;
|
|
240
|
+
fixtures?: Match[];
|
|
241
|
+
}): Match | undefined;
|
|
227
242
|
/** Sorted list of distinct group letters present in the schedule. */
|
|
228
243
|
declare function groups(fixtures?: Match[]): string[];
|
|
229
244
|
|
|
@@ -412,6 +427,34 @@ declare function liveSourceLabel(source: string): string;
|
|
|
412
427
|
* schedule on any provider/network error (graceful degradation).
|
|
413
428
|
*/
|
|
414
429
|
declare function getMatchesForDate(adapter: ProviderAdapter, dateISO: string): Promise<LiveResult>;
|
|
430
|
+
interface MatchByIdResult {
|
|
431
|
+
match?: Match;
|
|
432
|
+
degraded: boolean;
|
|
433
|
+
source?: string;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* The fixture a team-scoped MARKET query should be about, live-confirmed.
|
|
437
|
+
* Static window math alone fails twice at the edges: a match in extra time
|
|
438
|
+
* (now > kickoff + 140min, still LIVE) would be skipped for next week's
|
|
439
|
+
* fixture, and a just-finished match (inside the window, already FT) would be
|
|
440
|
+
* selected over the next one. So: pick the in-window candidate using a widened
|
|
441
|
+
* window, overlay live state, and fall through to the next fixture when the
|
|
442
|
+
* overlay says the candidate is finished. Degraded fetches keep the static
|
|
443
|
+
* candidate (fail-closed: the market-relevance gate then errs toward showing
|
|
444
|
+
* nothing rather than something wrong).
|
|
445
|
+
*/
|
|
446
|
+
declare function marketFixtureForTeam(adapter: ProviderAdapter, code: string, now?: Date): Promise<MatchByIdResult>;
|
|
447
|
+
/**
|
|
448
|
+
* A single match by id, with live overlay. The provider's scoreboard buckets
|
|
449
|
+
* days in its own zone (ESPN: US/Eastern), so a fixture's UTC date can differ
|
|
450
|
+
* from the scoreboard day it's filed under — a 02:00Z kickoff belongs to the
|
|
451
|
+
* previous ET evening, and fetching only the UTC date silently misses its live
|
|
452
|
+
* state (the match then renders from the static schedule as if scheduled).
|
|
453
|
+
* Fetch the ±1-day window around the fixture's UTC date instead — the same
|
|
454
|
+
* trick `getMatchesForDate` uses — and fall back to the static fixture on any
|
|
455
|
+
* provider error.
|
|
456
|
+
*/
|
|
457
|
+
declare function getMatchById(adapter: ProviderAdapter, id: string): Promise<MatchByIdResult>;
|
|
415
458
|
/** Currently-live matches; empty + degraded on error. */
|
|
416
459
|
declare function getLiveMatches(adapter: ProviderAdapter): Promise<LiveResult>;
|
|
417
460
|
|
|
@@ -520,14 +563,16 @@ interface MarketProvider {
|
|
|
520
563
|
findSignals(matches: Match[], options?: MarketSignalOptions): Promise<MarketSignalsResult>;
|
|
521
564
|
}
|
|
522
565
|
|
|
523
|
-
/**
|
|
524
|
-
* Probability normalization + the reliability gate. `isReliableMarketSignal` is
|
|
525
|
-
* the single primitive every default-on surface keys off: "show only when
|
|
526
|
-
* reliable, otherwise omit silently."
|
|
527
|
-
*/
|
|
528
|
-
|
|
529
566
|
/** Default freshness window: a signal older than this is stale (15 minutes). */
|
|
530
567
|
declare const DEFAULT_MAX_AGE_MS: number;
|
|
568
|
+
/**
|
|
569
|
+
* Market signals are pre-match and in-play reads. Once a match has finished —
|
|
570
|
+
* status `FT`, or (for static fixtures that never get a live overlay) once its
|
|
571
|
+
* live window has long passed — a "favorite" is resolved history: showing
|
|
572
|
+
* "markets favor X 100%" after full time reads as a bug, not information.
|
|
573
|
+
* An unparseable kickoff fails open (the reliability gate still applies).
|
|
574
|
+
*/
|
|
575
|
+
declare function marketRelevant(match: Match, now?: Date): boolean;
|
|
531
576
|
/**
|
|
532
577
|
* Re-scale outcome probabilities so the positive ones sum to 1. This removes
|
|
533
578
|
* market "vig" (raw prices sum to >1) and is scale-agnostic: inputs may be
|
|
@@ -763,4 +808,4 @@ interface ShareSnippetInput {
|
|
|
763
808
|
*/
|
|
764
809
|
declare function formatShareSnippet(input: ShareSnippetInput, options?: ShareSnippetOptions): string;
|
|
765
810
|
|
|
766
|
-
export { 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 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 MatchEvent, type Outcome, PolymarketProvider, type PolymarketProviderOptions, type ProviderAdapter, type ProviderCapabilities, type PunditPick, SHARE_DISCLAIMER, SHARE_HASHTAG, type ShareSnippetInput, type ShareSnippetOptions, type ShareStyle, type Stage, type StandingRow, type Status, type Team, allFixtures, asFlavorLevel, buildMarketSignal, byKickoff, competitionBase, computeStandings, countdown, deriveFavorite, favoriteStrength, fixturesByDate, fixturesByGroup, fixturesByTeam, flagEmoji, formatDate, formatKickoff, formatShareSnippet, formatTime, getLiveMatches, getMarketSignal, getMarketSignals, getMatchesForDate, groups, hasSaneDistribution, isFinished, isFlavorLevel, isLive, isReliableMarketSignal, isStaleSignal, isValidDate, isValidTimeZone, liveSourceLabel, localDate, makeAdapter, makeMarketProvider, mapEspnEvent, mapsCleanly, marketAttributionText, marketBlock, marketFavoriteText, marketLine, marketProbabilityText, marketSourceLabel, matchFlavor, matchLocation, mergeLive, nationToFlag, nationToRegion, nextFixtureForTeam, normalizeOutcomes, outcomeFromScore, resolveCompetition, resolveMarketSource, resolveTz, scoreline };
|
|
811
|
+
export { type BuildSignalInput, DEFAULT_COMPETITION, DEFAULT_FLAVOR, DEFAULT_MAX_AGE_MS, EspnAdapter, type EspnAdapterOptions, FLAVOR_LEVELS, FakeMarketProvider, type FakeMarketProviderOptions, type FavoriteStrength, type FlavorLevel, type FormatOpts, LIVE_WINDOW_MS, 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, SHARE_DISCLAIMER, SHARE_HASHTAG, type ShareSnippetInput, type ShareSnippetOptions, type ShareStyle, type Stage, type StandingRow, type Status, type Team, allFixtures, asFlavorLevel, buildMarketSignal, byKickoff, competitionBase, computeStandings, countdown, currentOrNextFixtureForTeam, deriveFavorite, favoriteStrength, fixturesByDate, fixturesByGroup, fixturesByTeam, fixturesInLiveWindow, flagEmoji, formatDate, formatKickoff, formatShareSnippet, formatTime, getLiveMatches, getMarketSignal, getMarketSignals, getMatchById, getMatchesForDate, groups, hasSaneDistribution, isFinished, isFlavorLevel, isLive, isReliableMarketSignal, isStaleSignal, isValidDate, isValidTimeZone, liveSourceLabel, localDate, makeAdapter, makeMarketProvider, mapEspnEvent, mapsCleanly, marketAttributionText, marketBlock, marketFavoriteText, marketFixtureForTeam, marketLine, marketProbabilityText, marketRelevant, marketSourceLabel, matchFlavor, matchLocation, mergeLive, nationToFlag, nationToRegion, nextFixtureForTeam, normalizeOutcomes, outcomeFromScore, resolveCompetition, resolveMarketSource, resolveTz, scoreline };
|
package/dist/index.js
CHANGED
|
@@ -2622,6 +2622,22 @@ function nextFixtureForTeam(code, opts = {}) {
|
|
|
2622
2622
|
(m) => new Date(m.kickoff).getTime() >= from.getTime()
|
|
2623
2623
|
);
|
|
2624
2624
|
}
|
|
2625
|
+
var LIVE_WINDOW_MS = 140 * 6e4;
|
|
2626
|
+
function fixturesInLiveWindow(now = Date.now(), fixtures = SCHEDULE) {
|
|
2627
|
+
return fixtures.filter((m) => {
|
|
2628
|
+
const k = Date.parse(m.kickoff);
|
|
2629
|
+
return now >= k && now <= k + LIVE_WINDOW_MS;
|
|
2630
|
+
}).sort(byKickoff);
|
|
2631
|
+
}
|
|
2632
|
+
function currentOrNextFixtureForTeam(code, opts = {}) {
|
|
2633
|
+
const from = opts.from ?? /* @__PURE__ */ new Date();
|
|
2634
|
+
const nowMs = from.getTime();
|
|
2635
|
+
const inPlay = fixturesByTeam(code, opts.fixtures ?? SCHEDULE).find((m) => {
|
|
2636
|
+
const k = Date.parse(m.kickoff);
|
|
2637
|
+
return nowMs >= k && nowMs <= k + LIVE_WINDOW_MS;
|
|
2638
|
+
});
|
|
2639
|
+
return inPlay ?? nextFixtureForTeam(code, opts);
|
|
2640
|
+
}
|
|
2625
2641
|
function groups(fixtures = SCHEDULE) {
|
|
2626
2642
|
const set = /* @__PURE__ */ new Set();
|
|
2627
2643
|
for (const m of fixtures) if (m.group) set.add(m.group);
|
|
@@ -2885,6 +2901,33 @@ function shiftUtcDate(dateISO, days) {
|
|
|
2885
2901
|
const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
|
|
2886
2902
|
return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
|
|
2887
2903
|
}
|
|
2904
|
+
var EXTRA_TIME_SLACK_MS = 60 * 6e4;
|
|
2905
|
+
async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
|
|
2906
|
+
const nowMs = now.getTime();
|
|
2907
|
+
const candidate = fixturesByTeam(code).find((m) => {
|
|
2908
|
+
const k = Date.parse(m.kickoff);
|
|
2909
|
+
return nowMs >= k && nowMs <= k + LIVE_WINDOW_MS + EXTRA_TIME_SLACK_MS;
|
|
2910
|
+
});
|
|
2911
|
+
if (candidate) {
|
|
2912
|
+
const r = await getMatchById(adapter, candidate.id);
|
|
2913
|
+
const m = r.match ?? candidate;
|
|
2914
|
+
if (!isFinished(m.status)) return { ...r, match: m };
|
|
2915
|
+
}
|
|
2916
|
+
const next = nextFixtureForTeam(code, { from: now });
|
|
2917
|
+
return { match: next, degraded: false };
|
|
2918
|
+
}
|
|
2919
|
+
async function getMatchById(adapter, id) {
|
|
2920
|
+
const base = allFixtures().find((m) => m.id === id);
|
|
2921
|
+
if (!base) return { match: void 0, degraded: false };
|
|
2922
|
+
const day = base.kickoff.slice(0, 10);
|
|
2923
|
+
try {
|
|
2924
|
+
const live = adapter.fetchWindow ? await adapter.fetchWindow(shiftUtcDate(day, -1), shiftUtcDate(day, 1)) : await adapter.fetchByDate(day);
|
|
2925
|
+
const hit = live.find((m) => m.id === id);
|
|
2926
|
+
return { match: hit ?? base, degraded: false, source: hit ? adapter.name : void 0 };
|
|
2927
|
+
} catch {
|
|
2928
|
+
return { match: base, degraded: true };
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2888
2931
|
async function getLiveMatches(adapter) {
|
|
2889
2932
|
try {
|
|
2890
2933
|
return { matches: await adapter.fetchLive(), degraded: false, source: adapter.name };
|
|
@@ -2895,6 +2938,12 @@ async function getLiveMatches(adapter) {
|
|
|
2895
2938
|
|
|
2896
2939
|
// src/markets/normalize.ts
|
|
2897
2940
|
var DEFAULT_MAX_AGE_MS = 15 * 6e4;
|
|
2941
|
+
function marketRelevant(match, now = /* @__PURE__ */ new Date()) {
|
|
2942
|
+
if (isLive(match.status)) return true;
|
|
2943
|
+
if (isFinished(match.status)) return false;
|
|
2944
|
+
const k = Date.parse(match.kickoff);
|
|
2945
|
+
return !Number.isFinite(k) || now.getTime() <= k + LIVE_WINDOW_MS;
|
|
2946
|
+
}
|
|
2898
2947
|
function normalizeOutcomes(outcomes) {
|
|
2899
2948
|
const sum = outcomes.reduce(
|
|
2900
2949
|
(s, o) => s + (Number.isFinite(o.probability) && o.probability > 0 ? o.probability : 0),
|
|
@@ -3415,6 +3464,7 @@ export {
|
|
|
3415
3464
|
EspnAdapter,
|
|
3416
3465
|
FLAVOR_LEVELS,
|
|
3417
3466
|
FakeMarketProvider,
|
|
3467
|
+
LIVE_WINDOW_MS,
|
|
3418
3468
|
PolymarketProvider,
|
|
3419
3469
|
SHARE_DISCLAIMER,
|
|
3420
3470
|
SHARE_HASHTAG,
|
|
@@ -3425,11 +3475,13 @@ export {
|
|
|
3425
3475
|
competitionBase,
|
|
3426
3476
|
computeStandings,
|
|
3427
3477
|
countdown,
|
|
3478
|
+
currentOrNextFixtureForTeam,
|
|
3428
3479
|
deriveFavorite,
|
|
3429
3480
|
favoriteStrength,
|
|
3430
3481
|
fixturesByDate,
|
|
3431
3482
|
fixturesByGroup,
|
|
3432
3483
|
fixturesByTeam,
|
|
3484
|
+
fixturesInLiveWindow,
|
|
3433
3485
|
flagEmoji,
|
|
3434
3486
|
formatDate,
|
|
3435
3487
|
formatKickoff,
|
|
@@ -3438,6 +3490,7 @@ export {
|
|
|
3438
3490
|
getLiveMatches,
|
|
3439
3491
|
getMarketSignal,
|
|
3440
3492
|
getMarketSignals,
|
|
3493
|
+
getMatchById,
|
|
3441
3494
|
getMatchesForDate,
|
|
3442
3495
|
groups,
|
|
3443
3496
|
hasSaneDistribution,
|
|
@@ -3457,8 +3510,10 @@ export {
|
|
|
3457
3510
|
marketAttributionText,
|
|
3458
3511
|
marketBlock,
|
|
3459
3512
|
marketFavoriteText,
|
|
3513
|
+
marketFixtureForTeam,
|
|
3460
3514
|
marketLine,
|
|
3461
3515
|
marketProbabilityText,
|
|
3516
|
+
marketRelevant,
|
|
3462
3517
|
marketSourceLabel,
|
|
3463
3518
|
matchFlavor,
|
|
3464
3519
|
matchLocation,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
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",
|