@claudinho/core 0.8.2 → 0.8.4

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
@@ -146,8 +146,10 @@ declare function resolveTz(explicit?: string): string | undefined;
146
146
  interface FormatOpts {
147
147
  tz?: string;
148
148
  locale?: string;
149
+ /** Include month and day (for multi-week schedules like the knockout bracket). */
150
+ date?: boolean;
149
151
  }
150
- /** Format a kickoff like "Thu 19:00" in the target timezone/locale. */
152
+ /** Format a kickoff like "Thu 19:00", or "Sat, Jul 4, 17:00" when `date` is set. */
151
153
  declare function formatKickoff(iso: string, opts?: FormatOpts): string;
152
154
  /** A short calendar date like "Jun 11" in the target timezone/locale. */
153
155
  declare function formatDate(iso: string, opts?: FormatOpts): string;
@@ -601,7 +603,7 @@ interface StandingsResult {
601
603
  declare function getStandings(adapter: ProviderAdapter, group?: string): Promise<StandingsResult>;
602
604
  /**
603
605
  * Knockout bracket with hybrid slot resolution: confirmed FT winners/losers from
604
- * the live overlay; group slots project only when the group is fully played.
606
+ * the live overlay; group slots project from live standings once a group has started.
605
607
  */
606
608
  declare function getBracket(adapter: ProviderAdapter, opts?: {
607
609
  stage?: Stage;
@@ -1051,7 +1053,7 @@ declare function parseTeamSlot(team: Team): SlotRef | null;
1051
1053
 
1052
1054
  /**
1053
1055
  * Resolve the bundled topology against merged knockout matches and standings.
1054
- * Group slots project only when the group is fully played; winner/loser slots
1056
+ * Group slots project from live standings once a group has started; winner/loser slots
1055
1057
  * require a confirmed FT result on the source match.
1056
1058
  */
1057
1059
  declare function buildBracketView(topology: BracketTopology, matches: Match[], tables: GroupStandings[], standingsDegraded: boolean, liveDegraded: boolean, filterStage?: string, lang?: string): BracketView;
package/dist/index.js CHANGED
@@ -451,6 +451,7 @@ function formatKickoff(iso, opts = {}) {
451
451
  const locale = safeLocale(opts.locale);
452
452
  return new Intl.DateTimeFormat(locale, {
453
453
  weekday: "short",
454
+ ...opts.date ? { month: "short", day: "numeric" } : {},
454
455
  hour: "2-digit",
455
456
  minute: "2-digit",
456
457
  hour12: false,
@@ -3341,18 +3342,17 @@ function validateThirdPlace(nodes, problems) {
3341
3342
  }
3342
3343
 
3343
3344
  // src/bracket/resolve.ts
3344
- function isGroupComplete(group, tables, standingsDegraded) {
3345
- if (standingsDegraded) return false;
3346
- const table = tables.find((t2) => t2.group === group);
3347
- if (!table?.rows.length || table.rows.length !== 4) return false;
3348
- return table.rows.every((r) => r.played >= 3);
3349
- }
3350
3345
  function teamFromStandings(group, position, tables) {
3351
3346
  const table = tables.find((t2) => t2.group === group);
3352
3347
  if (!table) return void 0;
3353
3348
  const row = table.rows[position - 1];
3354
3349
  return row?.team;
3355
3350
  }
3351
+ function hasGroupStarted(group, tables) {
3352
+ const table = tables.find((t2) => t2.group === group);
3353
+ if (!table?.rows.length) return false;
3354
+ return table.rows.some((r) => r.played > 0);
3355
+ }
3356
3356
  function resolveWinner(match) {
3357
3357
  if (!isFinished(match.status)) return void 0;
3358
3358
  if (match.winnerCode) {
@@ -3399,7 +3399,7 @@ function resolveSlot(ref, ctx) {
3399
3399
  case "seed":
3400
3400
  return tbd(ref.label);
3401
3401
  case "group": {
3402
- if (isGroupComplete(ref.group, ctx.tables, ctx.standingsDegraded)) {
3402
+ if (!ctx.standingsDegraded && hasGroupStarted(ref.group, ctx.tables)) {
3403
3403
  const team = teamFromStandings(ref.group, ref.position, ctx.tables);
3404
3404
  if (team) return participant(team, "projected");
3405
3405
  }
@@ -4733,6 +4733,9 @@ function statusTail2(m) {
4733
4733
  if (isLive(m.status)) return " LIVE";
4734
4734
  return "";
4735
4735
  }
4736
+ function formatBracketKickoff(iso, opts) {
4737
+ return formatKickoff(iso, { tz: opts.tz, locale: opts.locale, date: true });
4738
+ }
4736
4739
  function formatBracketMatchLine(mv, opts = {}) {
4737
4740
  const flags = opts.flags !== false;
4738
4741
  const home = formatParticipant(mv.home, "home", flags, opts.locale);
@@ -4741,7 +4744,7 @@ function formatBracketMatchLine(mv, opts = {}) {
4741
4744
  if (isFinished(m.status) || isLive(m.status)) {
4742
4745
  return ` ${home} ${scoreline(m)} ${away}${statusTail2(m)}`;
4743
4746
  }
4744
- const kickoff = mv.kickoff ? formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale }) : "";
4747
+ const kickoff = mv.kickoff ? formatBracketKickoff(mv.kickoff, opts) : "";
4745
4748
  return ` ${home} vs ${away}${kickoff ? ` \xB7 ${kickoff}` : ""}`;
4746
4749
  }
4747
4750
  function formatBracketList(view, opts = {}) {
@@ -4838,7 +4841,7 @@ function formatBracketCompactLine(mv, opts = {}) {
4838
4841
  const away = formatParticipant(mv.away, "away", flags, opts.locale);
4839
4842
  const m = mv.match;
4840
4843
  const mid2 = isFinished(m.status) || isLive(m.status) ? scoreline(m) : "vs";
4841
- const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale })}` : statusTail2(m);
4844
+ const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatBracketKickoff(mv.kickoff, opts)}` : statusTail2(m);
4842
4845
  return `${stageLabelI18n(opts.locale, mv.stage)} \xB7 ${home} ${mid2} ${away}${tail}`;
4843
4846
  }
4844
4847
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/core",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
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",