@sensiblestats/widget-sdk 0.67.0 → 0.69.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @sensiblestats/widget-sdk
2
2
 
3
+ ## 0.69.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Send `sport: "nba"` on NBA pins, slips and host slip events, with qualified ids (`nba:game:{id}`, `nba:market:{key}`) on pin events and the bare game id on slip events. `SignalInput` and `WidgetEventInput` gain an optional `sport`; each sport in the SDK's sport map gains a `wireKey` (`nba` for basketball, none for NFL, which sends nothing new). Football bodies are unchanged. A basketball slip pick keeps its `matchId`. Release only after ChatAssistantAPI and WidgetGateway carrying u592 are deployed: an older server would read the `nba:` ids as football.
8
+
9
+ ## 0.68.0
10
+
11
+ ### Minor Changes
12
+
13
+ - NFL in Following: monitor card, pin, slip on insights and the pre-kickoff market
14
+
3
15
  ## 0.67.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -40,8 +40,10 @@ __export(index_exports, {
40
40
  isLimitCode: () => isLimitCode,
41
41
  matchKey: () => matchKey,
42
42
  mayPinOrSlip: () => mayPinOrSlip,
43
+ qualifiedId: () => qualifiedId,
43
44
  slipSportOf: () => slipSportOf,
44
- sportOf: () => sportOf
45
+ sportOf: () => sportOf,
46
+ toWireSport: () => toWireSport
45
47
  });
46
48
  module.exports = __toCommonJS(index_exports);
47
49
 
@@ -505,7 +507,8 @@ function toSignalWireBody(input) {
505
507
  operatorUserId: input.operatorUserId,
506
508
  anonymousUserId: input.anonymousUserId,
507
509
  dashboardLayout: input.dashboardLayout,
508
- tileIndex: input.tileIndex
510
+ tileIndex: input.tileIndex,
511
+ sport: input.sport
509
512
  };
510
513
  }
511
514
 
@@ -792,8 +795,8 @@ function isAddToSlipResult(v) {
792
795
 
793
796
  // src/sports.ts
794
797
  var SPORTS = {
795
- basketball: { slipPrefix: "bb:", monitorPrefix: "nba:", label: "NBA", slippable: true },
796
- americanfootball: { slipPrefix: "af:", monitorPrefix: "nfl:", label: "NFL", slippable: false }
798
+ basketball: { slipPrefix: "bb:", monitorPrefix: "nba:", label: "NBA", slippable: true, wireKey: "nba" },
799
+ americanfootball: { slipPrefix: "af:", monitorPrefix: "nfl:", label: "NFL", slippable: true, wireKey: void 0 }
797
800
  };
798
801
  function sportOf(v) {
799
802
  return typeof v === "string" && Object.prototype.hasOwnProperty.call(SPORTS, v) ? v : void 0;
@@ -806,6 +809,14 @@ function slipSportOf(v) {
806
809
  const sport = sportOf(v);
807
810
  return sport !== void 0 && SPORTS[sport].slippable ? sport : void 0;
808
811
  }
812
+ function toWireSport(v) {
813
+ const sport = sportOf(v);
814
+ return sport === void 0 ? void 0 : SPORTS[sport].wireKey;
815
+ }
816
+ function qualifiedId(sport, type, id) {
817
+ const wire = toWireSport(sport);
818
+ return wire ? `${wire}:${type}:${id}` : id;
819
+ }
809
820
  // Annotate the CommonJS export names for ESM import in node:
810
821
  0 && (module.exports = {
811
822
  AuthError,
@@ -828,7 +839,9 @@ function slipSportOf(v) {
828
839
  isLimitCode,
829
840
  matchKey,
830
841
  mayPinOrSlip,
842
+ qualifiedId,
831
843
  slipSportOf,
832
- sportOf
844
+ sportOf,
845
+ toWireSport
833
846
  });
834
847
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/ndjson.ts","../src/chat.ts","../src/signals.ts","../src/conversation.ts","../src/eventLog.ts","../src/client.ts","../src/matchKey.ts","../src/types.ts","../src/sports.ts"],"sourcesContent":["export { StatsWidgetClient } from './client'\nexport { Conversation } from './conversation'\nexport { matchKey } from './matchKey'\nexport type { ChatCallbacks, ChatHandle } from './chat'\nexport { SIGNAL_TYPE_CODES, ENTITY_TYPE_CODES } from './signals'\nexport {\n WidgetSdkError, AuthError, ForbiddenError, RateLimitError, UpstreamError, NetworkError, ParseError,\n LimitError, LIMIT_CODES, isLimitCode,\n} from './errors'\nexport type { LimitCode, LimitDetails } from './errors'\nexport type {\n StatsWidgetClientOptions, FetchLike, UserContext, ChatInput, ChatGrounding, ChatPreset, PageContext,\n SignalType, SignalEntityType, SignalInput,\n SlipSport, SlipSelection, AddToSlipRejectReason, AddToSlipResult, AddToSlipHandler,\n} from './types'\nexport { isAddToSlipResult } from './types'\nexport { SPORTS, sportOf, slipSportOf, mayPinOrSlip } from './sports'\nexport type { SportSpec, NonFootballSport } from './sports'\nexport { createNdjsonParser } from './ndjson'\nexport type { NdjsonParser } from './ndjson'\nexport { createEventLogger } from './eventLog'\nexport type {\n WidgetEventName, WidgetEntityEventName, WidgetPopupEventName, WidgetPopupAskEventName, WidgetOpenEventName, WidgetEntityType, WidgetEventInput,\n WidgetPopupEventInput, WidgetPopupAskEventInput, WidgetOpenEventInput, WidgetLogInput, WireEvent, EventBatch, EventLoggerOptions, EventLogger,\n} from './eventLog'\nexport type {\n ChatEvent, ProgressEventData, AnswerEventData, EntityCard, EntityCardStat, EntityCardScope, EntityCardEventData,\n ActionButtonEventData, IntentChipEventData, ActionsLoadingEventData,\n TurnCompleteEventData, StreamErrorEventData,\n BettingInsight, BettingInsightOdds, BettingInsightEventData,\n NbaInsightSelection, NbaGameValue, NbaListedTeammate, NbaPropReasonEvidence, NbaLinePoint, NbaLineLane,\n NbaInjuryEvent, NbaLineMoveEvidence, NbaSplitRow, NbaTeammateOutEvidence, NbaCoHitLeg, NbaJointGame,\n NbaCoHitEvidence, NbaLadderRung, NbaLadderStat, NbaLadderEvidence,\n NbaMatchupTeam, NbaMatchupPosition, NbaMatchupEvidence, NbaQuarterRung, NbaQuarterStat, NbaQuarterLadderEvidence,\n NbaSettleLine, NbaSettlePlayer, NbaSettleSummary, NbaSettleRecapEvidence, NbaInsight, NbaInsightEventData,\n NflInsightKind, NflInsightSelection, NflPropReasonGame, NflPropReasonEvidence, NflLadderRung, NflLadderEvidence,\n NflInjuryPlayer, NflInjuryReportEvidence, NflLineMoveLane, NflLineMoveEvidence, NflAtsGame, NflAtsRecordEvidence,\n NflMatchupEvidence, NflSettleRecapLine, NflSettleRecapPlayer, NflSettleRecapSummary, NflSettleRecapEvidence,\n NflInsight, NflInsightEventData,\n MarketOddsRow, MarketOddsCard, MarketOddsCardInsight, MarketOddsLiveBlock, MarketOddsEventData,\n ComboCard, ComboLeg, ComboReplacedLeg, ComboCardEventData,\n PresetPick, PresetSinglesCell, PresetComboCell, PresetMarketCell, PresetGrid, PresetGridOptions,\n OddsMovementPoint, OddsMovementCard, OddsMovementEventData,\n GreetingDashboard, GreetingDashboardTile, GreetingDashboardLayout, GreetingDashboardSpan, GreetingDashboardTileEmphasis, GreetingDashboardSignalRef,\n ClubFanDashboardPayload, ClubFanDashboardCard, ClubFanDashboardHeadToHead,\n FixtureCard, FixtureCardData, FormMatch, CountdownCard, CountdownData,\n InjuriesCard, InjuriesCardData, InjuryRow,\n ReasonToBetCard, ReasonToBetData, WhereToWatchCard, WhereToWatchData,\n CongestedWeekCard, CongestedWeekData, CongestedWeekEntry,\n TransfersCard, TransfersData, TransferRow,\n LinksCard, LinksData, LinkRow,\n PostMatchResultCard, PostMatchResultData,\n PostMatchGoalsCard, PostMatchGoalsData, PostMatchGoalLine,\n PostMatchStatsCard, PostMatchStatsData, PostMatchStatRow,\n PostMatchTopPerformerCard, PostMatchTopPerformerData,\n PostMatchNextCard, PostMatchNextData,\n RestingNextCard, RestingNextData,\n RestingStandingsCard, RestingStandingsData,\n RestingSeasonCard, RestingSeasonData,\n RestingFormCard, RestingFormData,\n LiveScoreCard, LiveScoreData, LiveTimelineCard, LiveTimelineData, LiveEventLine,\n LiveStatsCard, LiveStatsData, LiveStatRow, MomentumPoint,\n PinKind, PinRef, MonitorPhase, HeadToHead, FormAndH2H,\n LiveMonitorStatPrice, LiveMonitorStatRow, LiveMonitorEvent,\n LiveMonitorFact, LiveMonitorMatch, LiveMonitorMarket, LiveMonitorSnapshot,\n MonitorSport, LiveMonitorBasketball,\n AvailableMarket, MarketOddsBlock,\n PlayerPropPrice, PlayerPropStat, PlayerPropGame, PlayerPropsBundle,\n ScheduleSport, ScheduleMatch, ScheduleGroup, SchedulePayload, LeagueStarResult, MatchState, StatesPayload,\n GameSummary, GameListPayload, GameStatePayload,\n SubmitPlayBody, SubmitPlayResult,\n GameResultPayload,\n LeaderboardRow, AllTimeRow, LeaderboardPayload, LeaderboardChampion,\n ClubFixture, ClubFixturesPayload, ClubStandingRow, ClubStandingsPayload, ClubSquadPlayer, ClubSquadPayload,\n ClubPlayerSeasonStats, ClubSquadStatsPayload, ClubPlayerDetailPayload,\n ClubPlayerAvailability, ClubPlayerAvailabilityStatus, ClubNextFixture, ClubMatchLogRow, ClubPlayerPerformance, ClubPerformanceMetric, ClubRecordEntry, ClubRecordsPayload,\n} from './events'\n","export class WidgetSdkError extends Error {\n readonly code: string\n readonly status?: number\n constructor(message: string, code: string, status?: number) {\n super(message)\n this.name = new.target.name\n this.code = code\n this.status = status\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\nexport class AuthError extends WidgetSdkError {\n constructor(message = 'Invalid or missing public key') { super(message, 'unauthorized', 401) }\n}\nexport class ForbiddenError extends WidgetSdkError {\n constructor(message = 'Origin not allowed or widget disabled') { super(message, 'forbidden', 403) }\n}\nexport class RateLimitError extends WidgetSdkError {\n readonly retryAfter?: number\n constructor(retryAfter?: number, message = 'Rate limited') { super(message, 'rate_limited', 429); this.retryAfter = retryAfter }\n}\n// B4 Q7: the codes a brand's limit refuses with. Any other 429 stays a plain RateLimitError.\nexport const LIMIT_CODES = ['daily_cap', 'quota_exhausted', 'assistant_paused'] as const\nexport type LimitCode = (typeof LIMIT_CODES)[number]\nexport function isLimitCode(code: unknown): code is LimitCode {\n return typeof code === 'string' && (LIMIT_CODES as readonly string[]).includes(code)\n}\nexport interface LimitDetails {\n limitCode: LimitCode\n resetsAt?: string\n /** The brand's or the built-in text, already in the user's language. */\n message?: string\n}\nexport class LimitError extends RateLimitError {\n readonly limitCode: LimitCode\n readonly resetsAt?: string\n readonly limitMessage?: string\n constructor(details: LimitDetails, retryAfter?: number) {\n super(retryAfter, details.message ?? 'Limit reached')\n this.limitCode = details.limitCode\n this.resetsAt = details.resetsAt\n this.limitMessage = details.message\n }\n}\nexport class UpstreamError extends WidgetSdkError {\n constructor(status: number, message = 'Upstream error') { super(message, 'upstream_error', status) }\n}\nexport class NetworkError extends WidgetSdkError {\n readonly cause?: unknown\n constructor(message = 'Network request failed', cause?: unknown) { super(message, 'network_error'); this.cause = cause }\n}\nexport class ParseError extends WidgetSdkError {\n readonly line?: string\n constructor(message = 'Malformed NDJSON line', line?: string) { super(message, 'parse_error'); this.line = line }\n}\n","import { AuthError, ForbiddenError, isLimitCode, LimitError, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayBody, SubmitPlayResult,\n} from './events'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\n client?: string\n}\n\nexport function headersFor(cfg: ResolvedConfig, json: boolean): Record<string, string> {\n const h: Record<string, string> = json ? { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey } : { 'X-SS-Public-Key': cfg.publicKey }\n if (cfg.client) h['X-SS-Client'] = cfg.client\n return h\n}\n\nfunction endpoint(cfg: ResolvedConfig, path: string): string {\n return `${cfg.baseUrl.replace(/\\/+$/, '')}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`\n}\n\nexport function toWidgetError(status: number, retryAfterHeader: string | null): WidgetSdkError {\n switch (status) {\n case 401: return new AuthError()\n case 403: return new ForbiddenError()\n case 429: {\n const n = retryAfterHeader != null ? Number(retryAfterHeader) : undefined\n return new RateLimitError(Number.isFinite(n) ? (n as number) : undefined)\n }\n default: return new UpstreamError(status)\n }\n}\n\n// B4 Q7: a limit refusal is a 429 whose problem+json body names the limit. The gateway's own per-minute 429 sets\n// Retry-After without exposing it to browsers, so a missing header is normal: the body's retryAfterSeconds covers\n// it, and no countdown is shown when neither is present.\nexport async function chatError(res: Response): Promise<WidgetSdkError> {\n const base = toWidgetError(res.status, res.headers.get('Retry-After'))\n if (!(base instanceof RateLimitError)) return base\n let body: unknown\n try { body = await res.json() } catch { return base }\n if (typeof body !== 'object' || body === null) return base\n const b = body as Record<string, unknown>\n if (!isLimitCode(b.errorCode)) return base\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() !== '' ? v : undefined)\n const header = res.headers.get('Retry-After')?.trim()\n const headerRetry = header != null && /^\\d+$/.test(header) ? Number(header) : undefined\n const bodyRetry = typeof b.retryAfterSeconds === 'number' && Number.isFinite(b.retryAfterSeconds) && b.retryAfterSeconds >= 0 ? b.retryAfterSeconds : undefined\n return new LimitError(\n { limitCode: b.errorCode, resetsAt: text(b.resetsAt), message: text(b.message) },\n headerRetry ?? bodyRetry,\n )\n}\n\nfunction isAbort(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nasync function send(cfg: ResolvedConfig, path: string, body: object, signal?: AbortSignal): Promise<Response> {\n try {\n return await cfg.fetch(endpoint(cfg, path), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n signal,\n })\n } catch (error) {\n if (isAbort(error)) throw error\n throw new NetworkError('Network request failed', error)\n }\n}\n\nexport async function postChat(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): Promise<Response> {\n const res = await send(cfg, 'chat', input, signal)\n if (!res.ok || res.body == null) throw await chatError(res)\n return res\n}\n\nexport async function postSignal(cfg: ResolvedConfig, wireBody: object, signal?: AbortSignal): Promise<void> {\n const res = await send(cfg, 'signals', wireBody, signal)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\nexport async function postEvents(cfg: ResolvedConfig, batch: object): Promise<void> {\n const res = await send(cfg, 'events', batch)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\n// Best-effort tail flush on page hide/unload. Uses fetch keepalive (not sendBeacon) because the\n// gateway requires the X-SS-Public-Key header, which sendBeacon cannot set. Both the synchronous\n// call and the returned promise are guarded -- an async rejection (real network failure, or\n// Chrome's ~64KB keepalive body cap) must never surface as an unhandled rejection, since this\n// runs inside an operator-embedded widget during page-hide and would show up as noise in the\n// OPERATOR's own error monitoring.\nexport function postEventsKeepalive(cfg: ResolvedConfig, batch: object): void {\n try {\n void cfg.fetch(endpoint(cfg, 'events'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(batch),\n keepalive: true,\n }).catch(() => { /* best-effort tail flush -- swallow async rejection too */ })\n } catch {\n /* best-effort tail flush -- never throw on unload */\n }\n}\n\nexport async function getLiveDashboard(cfg: ResolvedConfig): Promise<ClubFanDashboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-dashboard'), { method: 'GET', headers: headersFor(cfg, false) })\n // 204 is the definitive \"not live / match over\" signal -- the poll loop stops on it.\n // Any other non-ok status (e.g. a transient 502/503/504) must throw rather than return\n // null, so the poll loop's per-tick try/catch retries on the next tick instead of stopping.\n if (res.status === 204) return null\n if (!res.ok) throw new Error(`live-dashboard ${res.status}`)\n return (await res.json()) as ClubFanDashboardPayload\n}\n\n// 404 is the definitive \"live monitor disabled for this operator\" signal -- the poll loop\n// stops and the tabs disable. Any other non-ok status must throw so the per-tick\n// try/catch retries next tick instead of silently disabling the feature.\nexport async function postLiveMonitor(cfg: ResolvedConfig, pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n const body: { pins: PinRef[]; locale?: string } = { pins }\n if (locale) body.locale = locale\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor ${res.status}`)\n return (await res.json()) as LiveMonitorSnapshot\n}\n\nexport async function postMarketOdds(\n cfg: ResolvedConfig, matchId: number, marketDeveloperName: string, sport?: 'basketball',\n): Promise<MarketOddsBlock | null> {\n const body: { matchId: number; marketDeveloperName: string; sport?: 'basketball' } = { matchId, marketDeveloperName }\n if (sport) body.sport = sport\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/market'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/market ${res.status}`)\n return (await res.json()) as MarketOddsBlock\n}\n\nexport async function postPlayerProps(cfg: ResolvedConfig, matchId: number): Promise<PlayerPropsBundle | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/props'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ matchId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/props ${res.status}`)\n return (await res.json()) as PlayerPropsBundle\n}\n\n// 404 mirrors postLiveMonitor: the definitive \"live monitor disabled for this operator\" signal.\n// Every other non-ok status throws so the caller's per-tick catch retries next tick.\nexport async function postSchedule(\n cfg: ResolvedConfig, localDate: string, utcOffsetMinutes: number,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<SchedulePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/schedule'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ['basketball'], operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/schedule ${res.status}`)\n return (await res.json()) as SchedulePayload\n}\n\nexport async function postLeagueStar(\n cfg: ResolvedConfig, competitionId: number, starred: boolean,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<LeagueStarResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `leagues/${competitionId}/star`), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ starred, operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leagues/star ${res.status}`)\n return (await res.json()) as LeagueStarResult\n}\n\nexport async function postStates(\n cfg: ResolvedConfig, matchIds: number[], nbaGameIds?: number[],\n): Promise<StatesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/states'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(nbaGameIds?.length ? { matchIds, nbaGameIds } : { matchIds }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/states ${res.status}`)\n return (await res.json()) as StatesPayload\n}\n\nfunction q(parts: Record<string, string | number | undefined>): string {\n const kept = Object.entries(parts)\n .filter(([, v]) => v !== undefined && v !== '')\n .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)\n return kept.length ? `?${kept.join('&')}` : ''\n}\n\nexport async function getGames(cfg: ResolvedConfig, operatorUserId?: string, gameDay?: string): Promise<GameListPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games' + q({ operatorUserId, gameDay })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`games ${res.status}`)\n return (await res.json()) as GameListPayload\n}\n\nexport async function getGameConfig(cfg: ResolvedConfig, gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}` + q({ fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-config ${res.status}`)\n return (await res.json()) as GameStatePayload\n}\n\nexport async function getGameResult(cfg: ResolvedConfig, gameId: string, operatorUserId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({ operatorUserId, fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-result ${res.status}`)\n return (await res.json()) as GameResultPayload\n}\n\nexport async function postPlay(cfg: ResolvedConfig, gameId: string, body: SubmitPlayBody, locale?: string): Promise<SubmitPlayResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`play ${res.status}`)\n return (await res.json()) as SubmitPlayResult\n}\n\nexport async function getLeaderboard(cfg: ResolvedConfig, operatorUserId?: string, week?: string): Promise<LeaderboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games/leaderboard' + q({ operatorUserId, week })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leaderboard ${res.status}`)\n return (await res.json()) as LeaderboardPayload\n}\n\nexport async function getClubFixtures(cfg: ResolvedConfig, competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/fixtures' + q({ competitionId, limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-fixtures ${res.status}`)\n return (await res.json()) as ClubFixturesPayload\n}\n\nexport async function getClubStandings(cfg: ResolvedConfig, competitionId?: number): Promise<ClubStandingsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/standings' + q({ competitionId })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-standings ${res.status}`)\n return (await res.json()) as ClubStandingsPayload\n}\n\nexport async function getClubSquad(cfg: ResolvedConfig): Promise<ClubSquadPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad ${res.status}`)\n return (await res.json()) as ClubSquadPayload\n}\n\nexport async function getClubSquadStats(cfg: ResolvedConfig): Promise<ClubSquadStatsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad/stats'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad-stats ${res.status}`)\n return (await res.json()) as ClubSquadStatsPayload\n}\n\nexport async function getClubPlayerDetail(cfg: ResolvedConfig, playerId: number): Promise<ClubPlayerDetailPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `club/player/${encodeURIComponent(String(playerId))}`), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-player ${res.status}`)\n return (await res.json()) as ClubPlayerDetailPayload\n}\n\nexport async function getClubRecords(cfg: ResolvedConfig, limit?: number): Promise<ClubRecordsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/records' + q({ limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-records ${res.status}`)\n return (await res.json()) as ClubRecordsPayload\n}\n\n// Onboarding presets stage 2 (contract §1). 404 is the definitive \"no presets for this visitor\"\n// answer (flag off, not a betting operator, or cool-off). 503 and every other non-ok status throw:\n// the widget keeps any grid it already has and asks again on the next panel open.\n// operatorUserId is optional, passed as the games routes pass it: the cool-off check (D3) needs it,\n// and a request without it is an anonymous visitor.\nexport async function getPricePresets(\n cfg: ResolvedConfig, locale: string, operatorUserId?: string, options?: PresetGridOptions,\n): Promise<PresetGrid | null> {\n const res = await cfg.fetch(endpoint(cfg, 'price-presets' + q({ locale, operatorUserId, pool: options?.pool })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`price-presets ${res.status}`)\n return (await res.json()) as PresetGrid\n}\n","import { ParseError } from './errors'\n\nexport interface NdjsonParser {\n push(text: string): unknown[]\n flush(): unknown[]\n}\n\nfunction parseLine(line: string): unknown | undefined {\n const trimmed = line.trim()\n if (trimmed === '') return undefined\n try {\n return JSON.parse(trimmed)\n } catch {\n throw new ParseError('Malformed NDJSON line', line)\n }\n}\n\nexport function createNdjsonParser(): NdjsonParser {\n let buffer = ''\n return {\n push(text: string): unknown[] {\n buffer += text\n const out: unknown[] = []\n let idx: number\n while ((idx = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, idx)\n buffer = buffer.slice(idx + 1)\n const parsed = parseLine(line)\n if (parsed !== undefined) out.push(parsed)\n }\n return out\n },\n flush(): unknown[] {\n const rest = buffer\n buffer = ''\n const parsed = parseLine(rest)\n return parsed === undefined ? [] : [parsed]\n },\n }\n}\n","import { WidgetSdkError } from './errors'\nimport type {\n ActionButtonEventData, ActionsLoadingEventData, AnswerEventData, ChatEvent,\n EntityCardEventData, IntentChipEventData, ProgressEventData, StreamErrorEventData, TurnCompleteEventData,\n} from './events'\nimport { postChat, type ResolvedConfig } from './http'\nimport { createNdjsonParser } from './ndjson'\nimport type { ChatInput } from './types'\n\nexport interface ChatCallbacks {\n onProgress?(data: ProgressEventData): void\n onAnswer?(data: AnswerEventData): void\n onEntityCard?(data: EntityCardEventData): void\n onActionButton?(data: ActionButtonEventData): void\n onIntentChip?(data: IntentChipEventData): void\n onActionsLoading?(data: ActionsLoadingEventData): void\n onError?(error: StreamErrorEventData | WidgetSdkError): void\n onComplete?(data: TurnCompleteEventData): void\n}\n\nexport interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {\n cancel(): void\n}\n\nfunction dispatch(ev: ChatEvent, cb: ChatCallbacks): void {\n switch (ev.type) {\n case 'progress': cb.onProgress?.(ev.data); break\n case 'answer': cb.onAnswer?.(ev.data); break\n case 'entity_card': cb.onEntityCard?.(ev.data); break\n case 'action_button': cb.onActionButton?.(ev.data); break\n case 'intent_chip': cb.onIntentChip?.(ev.data); break\n case 'actions_loading': cb.onActionsLoading?.(ev.data); break\n case 'turn_complete': cb.onComplete?.(ev.data); break\n case 'error': cb.onError?.(ev.data); break\n }\n}\n\nasync function* streamEvents(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): AsyncGenerator<ChatEvent> {\n const res = await postChat(cfg, input, signal)\n const reader = res.body!.getReader()\n const decoder = new TextDecoder()\n const parser = createNdjsonParser()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj as ChatEvent\n }\n for (const obj of parser.flush()) yield obj as ChatEvent\n } finally {\n await reader.cancel().catch(() => {})\n }\n}\n\nexport function runChat(\n cfg: ResolvedConfig,\n input: ChatInput,\n callbacks?: ChatCallbacks,\n opts?: { signal?: AbortSignal; tap?: (ev: ChatEvent) => void },\n): ChatHandle {\n const controller = new AbortController()\n const external = opts?.signal\n if (external) {\n if (external.aborted) controller.abort()\n else external.addEventListener('abort', () => controller.abort(), { once: true })\n }\n\n async function* source(): AsyncGenerator<ChatEvent> {\n for await (const ev of streamEvents(cfg, input, controller.signal)) {\n opts?.tap?.(ev)\n yield ev\n }\n }\n\n const iterator = source()\n let consumed = false\n\n async function drive(): Promise<void> {\n try {\n for await (const ev of iterator) { if (callbacks) dispatch(ev, callbacks) }\n } catch (error) {\n if (callbacks?.onError && error instanceof WidgetSdkError) { callbacks.onError(error); return }\n throw error\n }\n }\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ChatEvent> {\n if (consumed) throw new Error('chat stream already consumed')\n consumed = true\n return iterator\n },\n then<TResult1 = void, TResult2 = never>(\n onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n if (consumed) return Promise.resolve().then(onfulfilled, onrejected)\n consumed = true\n return drive().then(onfulfilled, onrejected)\n },\n cancel(): void { controller.abort() },\n }\n}\n","import type { SignalEntityType, SignalInput, SignalType } from './types'\n\nexport const SIGNAL_TYPE_CODES: Record<SignalType, number> = {\n MatchPageView: 1, PlayerPageView: 2, TeamPageView: 3, MarketView: 4,\n SearchQuery: 5, SessionDepth: 6, TimeOnPage: 7, InsightViewed: 8,\n InsightMarketClicked: 9, BetPlacedFromInsight: 10, InsightScrollDepth: 11,\n ToolCall: 12, EntityMention: 13, Handoff: 14, FollowUpQuery: 15, RecommendationDismissed: 16,\n}\n\nexport const ENTITY_TYPE_CODES: Record<SignalEntityType, number> = {\n Match: 1, Team: 2, Player: 3, Competition: 4, Market: 5,\n Article: 6, Session: 7, Query: 8, Conversation: 9,\n}\n\nexport function toSignalWireBody(input: SignalInput): {\n signalType: number; entityType: number; entityName?: string; entityId?: string\n operatorUserId?: string; anonymousUserId?: string; dashboardLayout?: string; tileIndex?: number\n} {\n const signalType = SIGNAL_TYPE_CODES[input.signalType]\n const entityType = ENTITY_TYPE_CODES[input.entityType]\n if (signalType === undefined) throw new Error(`Unknown signalType: ${String(input.signalType)}`)\n if (entityType === undefined) throw new Error(`Unknown entityType: ${String(input.entityType)}`)\n return {\n signalType, entityType, entityName: input.entityName, entityId: input.entityId,\n operatorUserId: input.operatorUserId, anonymousUserId: input.anonymousUserId,\n dashboardLayout: input.dashboardLayout, tileIndex: input.tileIndex,\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayResult,\n} from './events'\nimport {\n getClubFixtures, getClubPlayerDetail, getClubRecords, getClubSquad, getClubSquadStats, getClubStandings, getGameConfig, getGameResult, getGames, getLeaderboard, getLiveDashboard, getPricePresets,\n postLeagueStar, postLiveMonitor, postMarketOdds, postPlayerProps, postPlay, postSchedule, postSignal, postStates, type ResolvedConfig,\n} from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: SignalInput): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n const anonymousUserId = operatorUserId ? undefined : (input.anonymousUserId ?? this.context?.anonymousUserId)\n if (!operatorUserId && !anonymousUserId) {\n throw new Error('operatorUserId or anonymousUserId is required (set it on conversation() or pass it to sendSignal)')\n }\n if (!input.entityId && !input.entityName) {\n throw new Error('entityId or entityName is required')\n }\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId, anonymousUserId }))\n }\n\n getLiveDashboard(): Promise<ClubFanDashboardPayload | null> {\n return getLiveDashboard(this.cfg)\n }\n\n getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n return postLiveMonitor(this.cfg, pins, locale)\n }\n\n getMarketOdds(matchId: number, marketDeveloperName: string, sport?: 'basketball'): Promise<MarketOddsBlock | null> {\n return postMarketOdds(this.cfg, matchId, marketDeveloperName, sport)\n }\n\n getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null> {\n return postPlayerProps(this.cfg, matchId)\n }\n\n getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null> {\n return getPricePresets(this.cfg, locale, this.context?.operatorUserId, options)\n }\n\n getSchedule(\n localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<SchedulePayload | null> {\n return postSchedule(this.cfg, localDate, utcOffsetMinutes, operatorUserId, anonymousUserId)\n }\n\n starLeague(\n competitionId: number, starred: boolean, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<LeagueStarResult | null> {\n return postLeagueStar(this.cfg, competitionId, starred, operatorUserId, anonymousUserId)\n }\n\n getStates(matchIds: number[], nbaGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds)\n }\n\n getGames(gameDay?: string): Promise<GameListPayload | null> {\n return getGames(this.cfg, this.context?.operatorUserId, gameDay)\n }\n\n getGameConfig(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n return getGameConfig(this.cfg, gameId, fixtureId, gameDay, locale)\n }\n\n getGameResult(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return getGameResult(this.cfg, gameId, operatorUserId, fixtureId, gameDay, locale)\n }\n\n postPlay(gameId: string, answerJson: string, gameDay: string, fixtureId?: number, locale?: string): Promise<SubmitPlayResult | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return postPlay(this.cfg, gameId, { operatorUserId, gameDay, answerJson, fixtureId }, locale)\n }\n\n getLeaderboard(week?: string): Promise<LeaderboardPayload | null> {\n return getLeaderboard(this.cfg, this.context?.operatorUserId, week)\n }\n\n getClubFixtures(competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n return getClubFixtures(this.cfg, competitionId, limit)\n }\n getClubStandings(competitionId?: number): Promise<ClubStandingsPayload | null> {\n return getClubStandings(this.cfg, competitionId)\n }\n getClubSquad(): Promise<ClubSquadPayload | null> {\n return getClubSquad(this.cfg)\n }\n getClubSquadStats(): Promise<ClubSquadStatsPayload | null> {\n return getClubSquadStats(this.cfg)\n }\n getClubPlayerDetail(playerId: number): Promise<ClubPlayerDetailPayload | null> {\n return getClubPlayerDetail(this.cfg, playerId)\n }\n getClubRecords(limit?: number): Promise<ClubRecordsPayload | null> {\n return getClubRecords(this.cfg, limit)\n }\n}\n","export type WidgetEntityEventName =\n | 'pin_add' | 'pin_remove' | 'slip_click' | 'slip_result'\n | 'insight_expand' | 'tile_tap' | 'chip_tap'\n | 'slip_remove' | 'bet_placed' | 'match_view' | 'match_open'\n\nexport type WidgetPopupEventName = 'popup_shown' | 'popup_opened' | 'popup_dismissed'\n\nexport type WidgetPopupAskEventName = 'popup_ask_tap'\n\nexport type WidgetOpenEventName = 'widget_open'\n\nexport type WidgetEventName = WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName\n\nexport type WidgetEntityType = 'match' | 'team' | 'player' | 'competition' | 'market'\n\nexport interface WidgetEventInput {\n name: WidgetEntityEventName\n entityType: WidgetEntityType\n entityId?: string\n entityName?: string\n marketDeveloperName?: string\n outcome?: string\n /** Football match id of the slip selection (slip_click / slip_result). */\n matchId?: number\n /** The raw odds label as stored (\"Home\", \"Over\", \"Home/Draw\"), never a joined display string. Max 64. */\n selection?: string\n /** The raw line (\"2.5\"). Max 32; omit when empty. */\n line?: string\n /** Decimal price shown when the selection was added. */\n odds?: number\n}\n\n/** Launcher popup telemetry: counted server-side, never tied to an entity. */\nexport type WidgetPopupEventInput =\n { name: WidgetPopupEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\n/** A tap on one of the launcher bubble's asks. `outcome` carries the ask's position, \"0\" or \"1\"\n * (contract §5): the gateway forwards only the fields of its own event model, and outcome is its\n * one free-text field. */\nexport type WidgetPopupAskEventInput =\n { name: WidgetPopupAskEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\n/** The panel opening: entity-free, each open is added to the user's count for the day. */\nexport type WidgetOpenEventInput =\n { name: WidgetOpenEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\nexport type WidgetLogInput = WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput\n\nexport type WireEvent = WidgetLogInput & {\n seq: number\n at: number\n}\n\nexport interface EventBatch {\n v: 1\n sessionId: string\n conversationId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /**\n * Events dropped after exhausting delivery attempts during a PRIOR flush cycle — not a count of\n * this batch's own events. Rides whichever batch is built next after the drop, then is omitted\n * (0/undefined) once a clean cycle passes without a new failure.\n */\n dropped?: number\n /**\n * Failed delivery attempts from a PRIOR flush cycle — not retries of this batch's own events.\n * Rides whichever batch is built next after the failure, then is omitted (0/undefined) once a\n * clean cycle passes without a new failure.\n */\n retries?: number\n events: WireEvent[]\n}\n\nexport interface EventLoggerOptions {\n /** Normal delivery (fetch). Rejecting triggers the retry/backoff loop. */\n flush: (batch: EventBatch) => Promise<void>\n /** Best-effort tail flush on page hide/unload (fetch keepalive). Never awaited. */\n flushKeepalive: (batch: EventBatch) => void\n /** Injectable clock (tests). Defaults to Date.now. */\n now?: () => number\n batchIntervalMs?: number\n maxBatch?: number\n maxAttempts?: number\n}\n\nexport interface EventLogger {\n log(input: WidgetLogInput): void\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void\n flushNow(): Promise<void>\n flushOnHide(): void\n dispose(): void\n /** Undoes dispose(). React StrictMode runs an effect's cleanup and then its setup again on the\n * same logger, so the widget's setup has to be able to bring a disposed logger back. */\n resume(): void\n}\n\nconst IMMEDIATE: ReadonlySet<WidgetEventName> = new Set([\n 'pin_add', 'pin_remove', 'slip_click', 'slip_result', 'slip_remove', 'bet_placed',\n])\n\n// Queued without arming the batch timer: the event leaves with the next flush of any cause. A match\n// page view fires for every visitor, so it must never start a request of its own.\nconst DEFERRED: ReadonlySet<WidgetEventName> = new Set(['match_view'])\n\nconst DEFAULT_BATCH_INTERVAL_MS = 10_000\nconst DEFAULT_MAX_BATCH = 50\nconst DEFAULT_MAX_ATTEMPTS = 3\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction makeSessionId(): string {\n const c: Crypto | undefined = globalThis.crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`\n}\n\nclass EventLoggerImpl implements EventLogger {\n private readonly sessionId = makeSessionId()\n private readonly now: () => number\n private readonly batchIntervalMs: number\n private readonly maxBatch: number\n private readonly maxAttempts: number\n\n private queue: WireEvent[] = []\n private seq = 0\n private retries = 0\n private dropped = 0\n private identity: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string } = {}\n private timer: ReturnType<typeof setTimeout> | null = null\n private inFlight: Promise<void> | null = null\n private disposed = false\n\n constructor(private readonly opts: EventLoggerOptions) {\n this.now = opts.now ?? (() => Date.now())\n this.batchIntervalMs = opts.batchIntervalMs ?? DEFAULT_BATCH_INTERVAL_MS\n this.maxBatch = opts.maxBatch ?? DEFAULT_MAX_BATCH\n this.maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n }\n\n log(input: WidgetLogInput): void {\n if (this.disposed) return\n const event: WireEvent = { ...input, seq: ++this.seq, at: this.now() }\n this.queue.push(event)\n if (IMMEDIATE.has(input.name)) {\n this.trigger()\n } else if (this.queue.length >= this.maxBatch) {\n this.trigger()\n } else if (!DEFERRED.has(input.name)) {\n this.armTimer()\n }\n }\n\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void {\n this.identity = { ...this.identity, ...id }\n }\n\n async flushNow(): Promise<void> {\n if (this.inFlight) await this.inFlight\n if (this.queue.length > 0) await this.doFlush()\n }\n\n flushOnHide(): void {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n this.opts.flushKeepalive(batch)\n }\n\n dispose(): void {\n this.disposed = true\n this.clearTimer()\n }\n\n resume(): void {\n this.disposed = false\n }\n\n private armTimer(): void {\n if (this.timer !== null) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.trigger()\n }, this.batchIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer === null) return\n clearTimeout(this.timer)\n this.timer = null\n }\n\n private trigger(): void {\n if (this.disposed) return\n if (this.inFlight) return\n this.inFlight = this.doFlush().finally(() => {\n this.inFlight = null\n // An immediate (or maxBatch-triggered) log() call that arrived while this flush was\n // in-flight was a no-op above -- drain it now instead of stranding it until some later\n // log()/flushNow()/dispose() call. Guarded by the disposed check at the top of trigger()\n // itself, so a straggler queued just before dispose() does not fire a flush after it.\n if (this.queue.length > 0) this.trigger()\n })\n }\n\n /**\n * Snapshots the queue + carry-over counters (see EventBatch.dropped/retries) into a batch and\n * resets both for the next cycle. Returns null only when there is truly nothing to report --\n * an empty queue AND no pending dropped/retries -- so a pending counter-only report (queue\n * drained by an exhausted flush, nothing logged since) still gets built and delivered.\n */\n private buildBatch(): EventBatch | null {\n if (this.queue.length === 0 && this.retries === 0 && this.dropped === 0) return null\n const events = this.queue\n this.queue = []\n const batch: EventBatch = { v: 1, sessionId: this.sessionId, ...this.identity, events }\n if (this.retries > 0) batch.retries = this.retries\n if (this.dropped > 0) batch.dropped = this.dropped\n this.retries = 0\n this.dropped = 0\n return batch\n }\n\n private async doFlush(): Promise<void> {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n try {\n await this.opts.flush(batch)\n return\n } catch {\n this.retries++\n if (attempt >= this.maxAttempts) {\n this.dropped += batch.events.length\n return\n }\n await delay(2 ** attempt * 50)\n }\n }\n }\n}\n\nexport function createEventLogger(opts: EventLoggerOptions): EventLogger {\n return new EventLoggerImpl(opts)\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { createEventLogger, type EventLogger } from './eventLog'\nimport { postEvents, postEventsKeepalive, postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, StatsWidgetClientOptions, UserContext } from './types'\n\nconst DEFAULT_BASE_URL = 'https://widget.sensiblestats.com'\n\nexport class StatsWidgetClient {\n private readonly cfg: ResolvedConfig\n\n constructor(options: StatsWidgetClientOptions) {\n if (!options.operatorId) throw new Error('operatorId is required')\n if (!options.publicKey) throw new Error('publicKey is required')\n const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined)\n if (!fetchImpl) throw new Error('No fetch implementation available; pass options.fetch')\n this.cfg = {\n operatorId: options.operatorId,\n publicKey: options.publicKey,\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetch: fetchImpl,\n client: options.client,\n }\n }\n\n chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n return runChat(this.cfg, input, callbacks)\n }\n\n async sendSignal(input: SignalInput): Promise<void> {\n await postSignal(this.cfg, toSignalWireBody(input))\n }\n\n conversation(context?: UserContext): Conversation {\n return new Conversation(this.cfg, context)\n }\n\n createEventLogger(identity?: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): EventLogger {\n const logger = createEventLogger({\n flush: (batch) => postEvents(this.cfg, batch),\n flushKeepalive: (batch) => postEventsKeepalive(this.cfg, batch),\n })\n if (identity) logger.setIdentity(identity)\n return logger\n }\n}\n","export function matchKey(sport: string | undefined, id: number): string {\n return `${sport ?? 'football'}:${id}`\n}\n","import type { SlipSport } from './sports'\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>\n\nexport interface StatsWidgetClientOptions {\n operatorId: string\n publicKey: string\n baseUrl?: string\n /** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */\n fetch?: FetchLike\n /** Sent as X-SS-Client; set by widget-react. */\n client?: string\n}\n\nexport interface UserContext {\n operatorUserId?: string\n defaultLanguage?: string\n anonymousUserId?: string\n}\n\nexport interface ChatGrounding {\n kind?: string\n matchId?: number\n opponentTeamId?: number\n teamId?: number\n competitionId?: number\n season?: string\n subject?: string\n personaHint?: string\n sport?: string\n}\n\n/** The page the widget sits on. Sent on greeting requests only, so the greeting can lead with that page. */\nexport interface PageContext {\n sport: 'football' | 'nba'\n kind?: 'section' | 'competition' | 'match'\n matchId?: string | number\n competitionId?: string | number\n}\n\n/** Onboarding presets stage 2 (contract §3): what a tool's Send asked for. Sent only from a tool's\n * Send, beside the full sentence in `message`. The server ignores it unless every value is valid. */\nexport interface ChatPreset {\n kind: 'max_price' | 'min_price' | 'combo' | 'market'\n /** max_price, min_price */\n price?: number\n /** max_price, min_price */\n count?: number\n /** combo */\n total?: number\n /** combo */\n legs?: number\n /** market */\n marketDeveloperName?: string\n /** The picks or legs the tool showed, in the order shown (R12: the answer reprices exactly these). */\n matchOddsIds: number[]\n /** The same picks' matchId, index for index with matchOddsIds (from the grid). */\n matchIds: number[]\n}\n\nexport interface ChatInput {\n message: string\n conversationId?: string\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap). Authoritative over `message` when present. */\n actionRef?: string\n userContext?: UserContext\n grounding?: ChatGrounding\n /** Features this client can draw (e.g. \"price_presets\"). The server sends nothing that needs a\n * feature the list does not name; an absent list means today's responses. */\n clientCapabilities?: string[]\n /** Onboarding presets stage 2: set only by a preset tool's Send (contract §3). */\n preset?: ChatPreset\n page?: PageContext\n}\n\nexport type SignalType =\n | 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView'\n | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed'\n | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth'\n | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed'\n\nexport type SignalEntityType =\n | 'Match' | 'Team' | 'Player' | 'Competition' | 'Market'\n | 'Article' | 'Session' | 'Query' | 'Conversation'\n\nexport interface SignalInput {\n signalType: SignalType\n entityType: SignalEntityType\n /** Either this or entityId is required -- an operator's UI mostly knows a display name. */\n entityName?: string\n /** Either this or entityName is required -- a dashboard tile knows its entity by id. */\n entityId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /** Greeting dashboard layout this signal came from, when it is a dashboard tap. */\n dashboardLayout?: string\n /** Zero-based tile position within the dashboard, when it is a dashboard tap. */\n tileIndex?: number\n}\n\nexport type { SlipSport }\n\nexport interface SlipSelection {\n matchOddsId: number\n matchId: number\n oddsDecimal: number\n quotedAtUtc?: string\n insightId?: string\n conversationId?: string\n sport?: SlipSport\n}\n\nexport type AddToSlipRejectReason =\n | 'suspended' | 'closed' | 'login_required'\n | 'not_found' | 'limit' | 'unsupported'\n\nexport type AddToSlipResult =\n | { status: 'added'; slip?: { selectionCount: number; totalOddsDecimal?: number } }\n | { status: 'duplicate' }\n | { status: 'price_changed'; newOddsDecimal: number; accepted: boolean }\n | { status: 'rejected'; reason: AddToSlipRejectReason; message?: string }\n\nexport type AddToSlipHandler = (\n selection: SlipSelection,\n) => Promise<AddToSlipResult | void> | AddToSlipResult | void\n\nconst REJECT_REASONS = ['suspended', 'closed', 'login_required', 'not_found', 'limit', 'unsupported']\n\nexport function isAddToSlipResult(v: unknown): v is AddToSlipResult {\n if (typeof v !== 'object' || v === null) return false\n const o = v as Record<string, unknown>\n switch (o.status) {\n case 'added':\n case 'duplicate':\n return true\n case 'price_changed':\n return typeof o.newOddsDecimal === 'number'\n && Number.isFinite(o.newOddsDecimal)\n && typeof o.accepted === 'boolean'\n case 'rejected':\n return typeof o.reason === 'string'\n && REJECT_REASONS.includes(o.reason)\n default:\n return false\n }\n}\n","export interface SportSpec { readonly slipPrefix: string; readonly monitorPrefix: string; readonly label: string; readonly slippable: boolean }\n\nexport const SPORTS = {\n basketball: { slipPrefix: 'bb:', monitorPrefix: 'nba:', label: 'NBA', slippable: true },\n americanfootball: { slipPrefix: 'af:', monitorPrefix: 'nfl:', label: 'NFL', slippable: false },\n} as const satisfies Record<string, SportSpec>\n\nexport type NonFootballSport = keyof typeof SPORTS\n/** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */\nexport type SlipSport = { [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never }[NonFootballSport]\n\n/** undefined means football: every sport the map does not know is football. */\nexport function sportOf(v: unknown): NonFootballSport | undefined {\n return typeof v === 'string' && Object.prototype.hasOwnProperty.call(SPORTS, v) ? (v as NonFootballSport) : undefined\n}\n\n/** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */\nexport function mayPinOrSlip(v: unknown): boolean {\n const sport = sportOf(v)\n return sport === undefined || SPORTS[sport].slippable\n}\n\n/** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */\nexport function slipSportOf(v: unknown): SlipSport | undefined {\n const sport = sportOf(v)\n return sport !== undefined && SPORTS[sport].slippable ? (sport as SlipSport) : undefined\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/ndjson.ts","../src/chat.ts","../src/signals.ts","../src/conversation.ts","../src/eventLog.ts","../src/client.ts","../src/matchKey.ts","../src/types.ts","../src/sports.ts"],"sourcesContent":["export { StatsWidgetClient } from './client'\nexport { Conversation } from './conversation'\nexport { matchKey } from './matchKey'\nexport type { ChatCallbacks, ChatHandle } from './chat'\nexport { SIGNAL_TYPE_CODES, ENTITY_TYPE_CODES } from './signals'\nexport {\n WidgetSdkError, AuthError, ForbiddenError, RateLimitError, UpstreamError, NetworkError, ParseError,\n LimitError, LIMIT_CODES, isLimitCode,\n} from './errors'\nexport type { LimitCode, LimitDetails } from './errors'\nexport type {\n StatsWidgetClientOptions, FetchLike, UserContext, ChatInput, ChatGrounding, ChatPreset, PageContext,\n SignalType, SignalEntityType, SignalInput,\n SlipSport, SlipSelection, AddToSlipRejectReason, AddToSlipResult, AddToSlipHandler,\n} from './types'\nexport { isAddToSlipResult } from './types'\nexport { SPORTS, sportOf, slipSportOf, mayPinOrSlip, toWireSport, qualifiedId } from './sports'\nexport type { SportSpec, NonFootballSport, WireSport, QualifiedType } from './sports'\nexport { createNdjsonParser } from './ndjson'\nexport type { NdjsonParser } from './ndjson'\nexport { createEventLogger } from './eventLog'\nexport type {\n WidgetEventName, WidgetEntityEventName, WidgetPopupEventName, WidgetPopupAskEventName, WidgetOpenEventName, WidgetEntityType, WidgetEventInput,\n WidgetPopupEventInput, WidgetPopupAskEventInput, WidgetOpenEventInput, WidgetLogInput, WireEvent, EventBatch, EventLoggerOptions, EventLogger,\n} from './eventLog'\nexport type {\n ChatEvent, ProgressEventData, AnswerEventData, EntityCard, EntityCardStat, EntityCardScope, EntityCardEventData,\n ActionButtonEventData, IntentChipEventData, ActionsLoadingEventData,\n TurnCompleteEventData, StreamErrorEventData,\n BettingInsight, BettingInsightOdds, BettingInsightEventData,\n NbaInsightSelection, NbaGameValue, NbaListedTeammate, NbaPropReasonEvidence, NbaLinePoint, NbaLineLane,\n NbaInjuryEvent, NbaLineMoveEvidence, NbaSplitRow, NbaTeammateOutEvidence, NbaCoHitLeg, NbaJointGame,\n NbaCoHitEvidence, NbaLadderRung, NbaLadderStat, NbaLadderEvidence,\n NbaMatchupTeam, NbaMatchupPosition, NbaMatchupEvidence, NbaQuarterRung, NbaQuarterStat, NbaQuarterLadderEvidence,\n NbaSettleLine, NbaSettlePlayer, NbaSettleSummary, NbaSettleRecapEvidence, NbaInsight, NbaInsightEventData,\n NflInsightKind, NflInsightSelection, NflPropReasonGame, NflPropReasonEvidence, NflLadderRung, NflLadderEvidence,\n NflInjuryPlayer, NflInjuryReportEvidence, NflLineMoveLane, NflLineMoveEvidence, NflAtsGame, NflAtsRecordEvidence,\n NflMatchupEvidence, NflSettleRecapLine, NflSettleRecapPlayer, NflSettleRecapSummary, NflSettleRecapEvidence,\n NflInsight, NflInsightEventData,\n MarketOddsRow, MarketOddsCard, MarketOddsCardInsight, MarketOddsLiveBlock, MarketOddsEventData,\n ComboCard, ComboLeg, ComboReplacedLeg, ComboCardEventData,\n PresetPick, PresetSinglesCell, PresetComboCell, PresetMarketCell, PresetGrid, PresetGridOptions,\n OddsMovementPoint, OddsMovementCard, OddsMovementEventData,\n GreetingDashboard, GreetingDashboardTile, GreetingDashboardLayout, GreetingDashboardSpan, GreetingDashboardTileEmphasis, GreetingDashboardSignalRef,\n ClubFanDashboardPayload, ClubFanDashboardCard, ClubFanDashboardHeadToHead,\n FixtureCard, FixtureCardData, FormMatch, CountdownCard, CountdownData,\n InjuriesCard, InjuriesCardData, InjuryRow,\n ReasonToBetCard, ReasonToBetData, WhereToWatchCard, WhereToWatchData,\n CongestedWeekCard, CongestedWeekData, CongestedWeekEntry,\n TransfersCard, TransfersData, TransferRow,\n LinksCard, LinksData, LinkRow,\n PostMatchResultCard, PostMatchResultData,\n PostMatchGoalsCard, PostMatchGoalsData, PostMatchGoalLine,\n PostMatchStatsCard, PostMatchStatsData, PostMatchStatRow,\n PostMatchTopPerformerCard, PostMatchTopPerformerData,\n PostMatchNextCard, PostMatchNextData,\n RestingNextCard, RestingNextData,\n RestingStandingsCard, RestingStandingsData,\n RestingSeasonCard, RestingSeasonData,\n RestingFormCard, RestingFormData,\n LiveScoreCard, LiveScoreData, LiveTimelineCard, LiveTimelineData, LiveEventLine,\n LiveStatsCard, LiveStatsData, LiveStatRow, MomentumPoint,\n PinKind, PinRef, MonitorPhase, HeadToHead, FormAndH2H,\n LiveMonitorStatPrice, LiveMonitorStatRow, LiveMonitorEvent,\n LiveMonitorFact, LiveMonitorMatch, LiveMonitorMarket, LiveMonitorSnapshot,\n MonitorSport, LiveMonitorBasketball, LiveMonitorAmericanFootball,\n AvailableMarket, MarketOddsBlock,\n PlayerPropPrice, PlayerPropStat, PlayerPropGame, PlayerPropsBundle,\n ScheduleSport, ScheduleMatch, ScheduleGroup, SchedulePayload, LeagueStarResult, MatchState, StatesPayload,\n GameSummary, GameListPayload, GameStatePayload,\n SubmitPlayBody, SubmitPlayResult,\n GameResultPayload,\n LeaderboardRow, AllTimeRow, LeaderboardPayload, LeaderboardChampion,\n ClubFixture, ClubFixturesPayload, ClubStandingRow, ClubStandingsPayload, ClubSquadPlayer, ClubSquadPayload,\n ClubPlayerSeasonStats, ClubSquadStatsPayload, ClubPlayerDetailPayload,\n ClubPlayerAvailability, ClubPlayerAvailabilityStatus, ClubNextFixture, ClubMatchLogRow, ClubPlayerPerformance, ClubPerformanceMetric, ClubRecordEntry, ClubRecordsPayload,\n} from './events'\n","export class WidgetSdkError extends Error {\n readonly code: string\n readonly status?: number\n constructor(message: string, code: string, status?: number) {\n super(message)\n this.name = new.target.name\n this.code = code\n this.status = status\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\nexport class AuthError extends WidgetSdkError {\n constructor(message = 'Invalid or missing public key') { super(message, 'unauthorized', 401) }\n}\nexport class ForbiddenError extends WidgetSdkError {\n constructor(message = 'Origin not allowed or widget disabled') { super(message, 'forbidden', 403) }\n}\nexport class RateLimitError extends WidgetSdkError {\n readonly retryAfter?: number\n constructor(retryAfter?: number, message = 'Rate limited') { super(message, 'rate_limited', 429); this.retryAfter = retryAfter }\n}\n// B4 Q7: the codes a brand's limit refuses with. Any other 429 stays a plain RateLimitError.\nexport const LIMIT_CODES = ['daily_cap', 'quota_exhausted', 'assistant_paused'] as const\nexport type LimitCode = (typeof LIMIT_CODES)[number]\nexport function isLimitCode(code: unknown): code is LimitCode {\n return typeof code === 'string' && (LIMIT_CODES as readonly string[]).includes(code)\n}\nexport interface LimitDetails {\n limitCode: LimitCode\n resetsAt?: string\n /** The brand's or the built-in text, already in the user's language. */\n message?: string\n}\nexport class LimitError extends RateLimitError {\n readonly limitCode: LimitCode\n readonly resetsAt?: string\n readonly limitMessage?: string\n constructor(details: LimitDetails, retryAfter?: number) {\n super(retryAfter, details.message ?? 'Limit reached')\n this.limitCode = details.limitCode\n this.resetsAt = details.resetsAt\n this.limitMessage = details.message\n }\n}\nexport class UpstreamError extends WidgetSdkError {\n constructor(status: number, message = 'Upstream error') { super(message, 'upstream_error', status) }\n}\nexport class NetworkError extends WidgetSdkError {\n readonly cause?: unknown\n constructor(message = 'Network request failed', cause?: unknown) { super(message, 'network_error'); this.cause = cause }\n}\nexport class ParseError extends WidgetSdkError {\n readonly line?: string\n constructor(message = 'Malformed NDJSON line', line?: string) { super(message, 'parse_error'); this.line = line }\n}\n","import { AuthError, ForbiddenError, isLimitCode, LimitError, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayBody, SubmitPlayResult,\n} from './events'\nimport type { SlipSport } from './sports'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\n client?: string\n}\n\nexport function headersFor(cfg: ResolvedConfig, json: boolean): Record<string, string> {\n const h: Record<string, string> = json ? { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey } : { 'X-SS-Public-Key': cfg.publicKey }\n if (cfg.client) h['X-SS-Client'] = cfg.client\n return h\n}\n\nfunction endpoint(cfg: ResolvedConfig, path: string): string {\n return `${cfg.baseUrl.replace(/\\/+$/, '')}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`\n}\n\nexport function toWidgetError(status: number, retryAfterHeader: string | null): WidgetSdkError {\n switch (status) {\n case 401: return new AuthError()\n case 403: return new ForbiddenError()\n case 429: {\n const n = retryAfterHeader != null ? Number(retryAfterHeader) : undefined\n return new RateLimitError(Number.isFinite(n) ? (n as number) : undefined)\n }\n default: return new UpstreamError(status)\n }\n}\n\n// B4 Q7: a limit refusal is a 429 whose problem+json body names the limit. The gateway's own per-minute 429 sets\n// Retry-After without exposing it to browsers, so a missing header is normal: the body's retryAfterSeconds covers\n// it, and no countdown is shown when neither is present.\nexport async function chatError(res: Response): Promise<WidgetSdkError> {\n const base = toWidgetError(res.status, res.headers.get('Retry-After'))\n if (!(base instanceof RateLimitError)) return base\n let body: unknown\n try { body = await res.json() } catch { return base }\n if (typeof body !== 'object' || body === null) return base\n const b = body as Record<string, unknown>\n if (!isLimitCode(b.errorCode)) return base\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() !== '' ? v : undefined)\n const header = res.headers.get('Retry-After')?.trim()\n const headerRetry = header != null && /^\\d+$/.test(header) ? Number(header) : undefined\n const bodyRetry = typeof b.retryAfterSeconds === 'number' && Number.isFinite(b.retryAfterSeconds) && b.retryAfterSeconds >= 0 ? b.retryAfterSeconds : undefined\n return new LimitError(\n { limitCode: b.errorCode, resetsAt: text(b.resetsAt), message: text(b.message) },\n headerRetry ?? bodyRetry,\n )\n}\n\nfunction isAbort(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nasync function send(cfg: ResolvedConfig, path: string, body: object, signal?: AbortSignal): Promise<Response> {\n try {\n return await cfg.fetch(endpoint(cfg, path), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n signal,\n })\n } catch (error) {\n if (isAbort(error)) throw error\n throw new NetworkError('Network request failed', error)\n }\n}\n\nexport async function postChat(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): Promise<Response> {\n const res = await send(cfg, 'chat', input, signal)\n if (!res.ok || res.body == null) throw await chatError(res)\n return res\n}\n\nexport async function postSignal(cfg: ResolvedConfig, wireBody: object, signal?: AbortSignal): Promise<void> {\n const res = await send(cfg, 'signals', wireBody, signal)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\nexport async function postEvents(cfg: ResolvedConfig, batch: object): Promise<void> {\n const res = await send(cfg, 'events', batch)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\n// Best-effort tail flush on page hide/unload. Uses fetch keepalive (not sendBeacon) because the\n// gateway requires the X-SS-Public-Key header, which sendBeacon cannot set. Both the synchronous\n// call and the returned promise are guarded -- an async rejection (real network failure, or\n// Chrome's ~64KB keepalive body cap) must never surface as an unhandled rejection, since this\n// runs inside an operator-embedded widget during page-hide and would show up as noise in the\n// OPERATOR's own error monitoring.\nexport function postEventsKeepalive(cfg: ResolvedConfig, batch: object): void {\n try {\n void cfg.fetch(endpoint(cfg, 'events'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(batch),\n keepalive: true,\n }).catch(() => { /* best-effort tail flush -- swallow async rejection too */ })\n } catch {\n /* best-effort tail flush -- never throw on unload */\n }\n}\n\nexport async function getLiveDashboard(cfg: ResolvedConfig): Promise<ClubFanDashboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-dashboard'), { method: 'GET', headers: headersFor(cfg, false) })\n // 204 is the definitive \"not live / match over\" signal -- the poll loop stops on it.\n // Any other non-ok status (e.g. a transient 502/503/504) must throw rather than return\n // null, so the poll loop's per-tick try/catch retries on the next tick instead of stopping.\n if (res.status === 204) return null\n if (!res.ok) throw new Error(`live-dashboard ${res.status}`)\n return (await res.json()) as ClubFanDashboardPayload\n}\n\n// 404 is the definitive \"live monitor disabled for this operator\" signal -- the poll loop\n// stops and the tabs disable. Any other non-ok status must throw so the per-tick\n// try/catch retries next tick instead of silently disabling the feature.\nexport async function postLiveMonitor(cfg: ResolvedConfig, pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n const body: { pins: PinRef[]; locale?: string } = { pins }\n if (locale) body.locale = locale\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor ${res.status}`)\n return (await res.json()) as LiveMonitorSnapshot\n}\n\nexport async function postMarketOdds(\n cfg: ResolvedConfig, matchId: number, marketDeveloperName: string, sport?: SlipSport,\n): Promise<MarketOddsBlock | null> {\n const body: { matchId: number; marketDeveloperName: string; sport?: SlipSport } = { matchId, marketDeveloperName }\n if (sport) body.sport = sport\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/market'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/market ${res.status}`)\n return (await res.json()) as MarketOddsBlock\n}\n\nexport async function postPlayerProps(cfg: ResolvedConfig, matchId: number): Promise<PlayerPropsBundle | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/props'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ matchId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/props ${res.status}`)\n return (await res.json()) as PlayerPropsBundle\n}\n\n// 404 mirrors postLiveMonitor: the definitive \"live monitor disabled for this operator\" signal.\n// Every other non-ok status throws so the caller's per-tick catch retries next tick.\nexport async function postSchedule(\n cfg: ResolvedConfig, localDate: string, utcOffsetMinutes: number,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<SchedulePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/schedule'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ['basketball'], operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/schedule ${res.status}`)\n return (await res.json()) as SchedulePayload\n}\n\nexport async function postLeagueStar(\n cfg: ResolvedConfig, competitionId: number, starred: boolean,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<LeagueStarResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `leagues/${competitionId}/star`), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ starred, operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leagues/star ${res.status}`)\n return (await res.json()) as LeagueStarResult\n}\n\nexport async function postStates(\n cfg: ResolvedConfig, matchIds: number[], nbaGameIds?: number[],\n): Promise<StatesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/states'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(nbaGameIds?.length ? { matchIds, nbaGameIds } : { matchIds }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/states ${res.status}`)\n return (await res.json()) as StatesPayload\n}\n\nfunction q(parts: Record<string, string | number | undefined>): string {\n const kept = Object.entries(parts)\n .filter(([, v]) => v !== undefined && v !== '')\n .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)\n return kept.length ? `?${kept.join('&')}` : ''\n}\n\nexport async function getGames(cfg: ResolvedConfig, operatorUserId?: string, gameDay?: string): Promise<GameListPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games' + q({ operatorUserId, gameDay })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`games ${res.status}`)\n return (await res.json()) as GameListPayload\n}\n\nexport async function getGameConfig(cfg: ResolvedConfig, gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}` + q({ fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-config ${res.status}`)\n return (await res.json()) as GameStatePayload\n}\n\nexport async function getGameResult(cfg: ResolvedConfig, gameId: string, operatorUserId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({ operatorUserId, fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-result ${res.status}`)\n return (await res.json()) as GameResultPayload\n}\n\nexport async function postPlay(cfg: ResolvedConfig, gameId: string, body: SubmitPlayBody, locale?: string): Promise<SubmitPlayResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`play ${res.status}`)\n return (await res.json()) as SubmitPlayResult\n}\n\nexport async function getLeaderboard(cfg: ResolvedConfig, operatorUserId?: string, week?: string): Promise<LeaderboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games/leaderboard' + q({ operatorUserId, week })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leaderboard ${res.status}`)\n return (await res.json()) as LeaderboardPayload\n}\n\nexport async function getClubFixtures(cfg: ResolvedConfig, competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/fixtures' + q({ competitionId, limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-fixtures ${res.status}`)\n return (await res.json()) as ClubFixturesPayload\n}\n\nexport async function getClubStandings(cfg: ResolvedConfig, competitionId?: number): Promise<ClubStandingsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/standings' + q({ competitionId })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-standings ${res.status}`)\n return (await res.json()) as ClubStandingsPayload\n}\n\nexport async function getClubSquad(cfg: ResolvedConfig): Promise<ClubSquadPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad ${res.status}`)\n return (await res.json()) as ClubSquadPayload\n}\n\nexport async function getClubSquadStats(cfg: ResolvedConfig): Promise<ClubSquadStatsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad/stats'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad-stats ${res.status}`)\n return (await res.json()) as ClubSquadStatsPayload\n}\n\nexport async function getClubPlayerDetail(cfg: ResolvedConfig, playerId: number): Promise<ClubPlayerDetailPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `club/player/${encodeURIComponent(String(playerId))}`), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-player ${res.status}`)\n return (await res.json()) as ClubPlayerDetailPayload\n}\n\nexport async function getClubRecords(cfg: ResolvedConfig, limit?: number): Promise<ClubRecordsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/records' + q({ limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-records ${res.status}`)\n return (await res.json()) as ClubRecordsPayload\n}\n\n// Onboarding presets stage 2 (contract §1). 404 is the definitive \"no presets for this visitor\"\n// answer (flag off, not a betting operator, or cool-off). 503 and every other non-ok status throw:\n// the widget keeps any grid it already has and asks again on the next panel open.\n// operatorUserId is optional, passed as the games routes pass it: the cool-off check (D3) needs it,\n// and a request without it is an anonymous visitor.\nexport async function getPricePresets(\n cfg: ResolvedConfig, locale: string, operatorUserId?: string, options?: PresetGridOptions,\n): Promise<PresetGrid | null> {\n const res = await cfg.fetch(endpoint(cfg, 'price-presets' + q({ locale, operatorUserId, pool: options?.pool })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`price-presets ${res.status}`)\n return (await res.json()) as PresetGrid\n}\n","import { ParseError } from './errors'\n\nexport interface NdjsonParser {\n push(text: string): unknown[]\n flush(): unknown[]\n}\n\nfunction parseLine(line: string): unknown | undefined {\n const trimmed = line.trim()\n if (trimmed === '') return undefined\n try {\n return JSON.parse(trimmed)\n } catch {\n throw new ParseError('Malformed NDJSON line', line)\n }\n}\n\nexport function createNdjsonParser(): NdjsonParser {\n let buffer = ''\n return {\n push(text: string): unknown[] {\n buffer += text\n const out: unknown[] = []\n let idx: number\n while ((idx = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, idx)\n buffer = buffer.slice(idx + 1)\n const parsed = parseLine(line)\n if (parsed !== undefined) out.push(parsed)\n }\n return out\n },\n flush(): unknown[] {\n const rest = buffer\n buffer = ''\n const parsed = parseLine(rest)\n return parsed === undefined ? [] : [parsed]\n },\n }\n}\n","import { WidgetSdkError } from './errors'\nimport type {\n ActionButtonEventData, ActionsLoadingEventData, AnswerEventData, ChatEvent,\n EntityCardEventData, IntentChipEventData, ProgressEventData, StreamErrorEventData, TurnCompleteEventData,\n} from './events'\nimport { postChat, type ResolvedConfig } from './http'\nimport { createNdjsonParser } from './ndjson'\nimport type { ChatInput } from './types'\n\nexport interface ChatCallbacks {\n onProgress?(data: ProgressEventData): void\n onAnswer?(data: AnswerEventData): void\n onEntityCard?(data: EntityCardEventData): void\n onActionButton?(data: ActionButtonEventData): void\n onIntentChip?(data: IntentChipEventData): void\n onActionsLoading?(data: ActionsLoadingEventData): void\n onError?(error: StreamErrorEventData | WidgetSdkError): void\n onComplete?(data: TurnCompleteEventData): void\n}\n\nexport interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {\n cancel(): void\n}\n\nfunction dispatch(ev: ChatEvent, cb: ChatCallbacks): void {\n switch (ev.type) {\n case 'progress': cb.onProgress?.(ev.data); break\n case 'answer': cb.onAnswer?.(ev.data); break\n case 'entity_card': cb.onEntityCard?.(ev.data); break\n case 'action_button': cb.onActionButton?.(ev.data); break\n case 'intent_chip': cb.onIntentChip?.(ev.data); break\n case 'actions_loading': cb.onActionsLoading?.(ev.data); break\n case 'turn_complete': cb.onComplete?.(ev.data); break\n case 'error': cb.onError?.(ev.data); break\n }\n}\n\nasync function* streamEvents(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): AsyncGenerator<ChatEvent> {\n const res = await postChat(cfg, input, signal)\n const reader = res.body!.getReader()\n const decoder = new TextDecoder()\n const parser = createNdjsonParser()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj as ChatEvent\n }\n for (const obj of parser.flush()) yield obj as ChatEvent\n } finally {\n await reader.cancel().catch(() => {})\n }\n}\n\nexport function runChat(\n cfg: ResolvedConfig,\n input: ChatInput,\n callbacks?: ChatCallbacks,\n opts?: { signal?: AbortSignal; tap?: (ev: ChatEvent) => void },\n): ChatHandle {\n const controller = new AbortController()\n const external = opts?.signal\n if (external) {\n if (external.aborted) controller.abort()\n else external.addEventListener('abort', () => controller.abort(), { once: true })\n }\n\n async function* source(): AsyncGenerator<ChatEvent> {\n for await (const ev of streamEvents(cfg, input, controller.signal)) {\n opts?.tap?.(ev)\n yield ev\n }\n }\n\n const iterator = source()\n let consumed = false\n\n async function drive(): Promise<void> {\n try {\n for await (const ev of iterator) { if (callbacks) dispatch(ev, callbacks) }\n } catch (error) {\n if (callbacks?.onError && error instanceof WidgetSdkError) { callbacks.onError(error); return }\n throw error\n }\n }\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ChatEvent> {\n if (consumed) throw new Error('chat stream already consumed')\n consumed = true\n return iterator\n },\n then<TResult1 = void, TResult2 = never>(\n onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n if (consumed) return Promise.resolve().then(onfulfilled, onrejected)\n consumed = true\n return drive().then(onfulfilled, onrejected)\n },\n cancel(): void { controller.abort() },\n }\n}\n","import type { SignalEntityType, SignalInput, SignalType } from './types'\n\nexport const SIGNAL_TYPE_CODES: Record<SignalType, number> = {\n MatchPageView: 1, PlayerPageView: 2, TeamPageView: 3, MarketView: 4,\n SearchQuery: 5, SessionDepth: 6, TimeOnPage: 7, InsightViewed: 8,\n InsightMarketClicked: 9, BetPlacedFromInsight: 10, InsightScrollDepth: 11,\n ToolCall: 12, EntityMention: 13, Handoff: 14, FollowUpQuery: 15, RecommendationDismissed: 16,\n}\n\nexport const ENTITY_TYPE_CODES: Record<SignalEntityType, number> = {\n Match: 1, Team: 2, Player: 3, Competition: 4, Market: 5,\n Article: 6, Session: 7, Query: 8, Conversation: 9,\n}\n\nexport function toSignalWireBody(input: SignalInput): {\n signalType: number; entityType: number; entityName?: string; entityId?: string\n operatorUserId?: string; anonymousUserId?: string; dashboardLayout?: string; tileIndex?: number\n sport?: string\n} {\n const signalType = SIGNAL_TYPE_CODES[input.signalType]\n const entityType = ENTITY_TYPE_CODES[input.entityType]\n if (signalType === undefined) throw new Error(`Unknown signalType: ${String(input.signalType)}`)\n if (entityType === undefined) throw new Error(`Unknown entityType: ${String(input.entityType)}`)\n return {\n signalType, entityType, entityName: input.entityName, entityId: input.entityId,\n operatorUserId: input.operatorUserId, anonymousUserId: input.anonymousUserId,\n dashboardLayout: input.dashboardLayout, tileIndex: input.tileIndex, sport: input.sport,\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayResult,\n} from './events'\nimport {\n getClubFixtures, getClubPlayerDetail, getClubRecords, getClubSquad, getClubSquadStats, getClubStandings, getGameConfig, getGameResult, getGames, getLeaderboard, getLiveDashboard, getPricePresets,\n postLeagueStar, postLiveMonitor, postMarketOdds, postPlayerProps, postPlay, postSchedule, postSignal, postStates, type ResolvedConfig,\n} from './http'\nimport { toSignalWireBody } from './signals'\nimport type { SlipSport } from './sports'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: SignalInput): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n const anonymousUserId = operatorUserId ? undefined : (input.anonymousUserId ?? this.context?.anonymousUserId)\n if (!operatorUserId && !anonymousUserId) {\n throw new Error('operatorUserId or anonymousUserId is required (set it on conversation() or pass it to sendSignal)')\n }\n if (!input.entityId && !input.entityName) {\n throw new Error('entityId or entityName is required')\n }\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId, anonymousUserId }))\n }\n\n getLiveDashboard(): Promise<ClubFanDashboardPayload | null> {\n return getLiveDashboard(this.cfg)\n }\n\n getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n return postLiveMonitor(this.cfg, pins, locale)\n }\n\n getMarketOdds(matchId: number, marketDeveloperName: string, sport?: SlipSport): Promise<MarketOddsBlock | null> {\n return postMarketOdds(this.cfg, matchId, marketDeveloperName, sport)\n }\n\n getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null> {\n return postPlayerProps(this.cfg, matchId)\n }\n\n getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null> {\n return getPricePresets(this.cfg, locale, this.context?.operatorUserId, options)\n }\n\n getSchedule(\n localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<SchedulePayload | null> {\n return postSchedule(this.cfg, localDate, utcOffsetMinutes, operatorUserId, anonymousUserId)\n }\n\n starLeague(\n competitionId: number, starred: boolean, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<LeagueStarResult | null> {\n return postLeagueStar(this.cfg, competitionId, starred, operatorUserId, anonymousUserId)\n }\n\n getStates(matchIds: number[], nbaGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds)\n }\n\n getGames(gameDay?: string): Promise<GameListPayload | null> {\n return getGames(this.cfg, this.context?.operatorUserId, gameDay)\n }\n\n getGameConfig(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n return getGameConfig(this.cfg, gameId, fixtureId, gameDay, locale)\n }\n\n getGameResult(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return getGameResult(this.cfg, gameId, operatorUserId, fixtureId, gameDay, locale)\n }\n\n postPlay(gameId: string, answerJson: string, gameDay: string, fixtureId?: number, locale?: string): Promise<SubmitPlayResult | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return postPlay(this.cfg, gameId, { operatorUserId, gameDay, answerJson, fixtureId }, locale)\n }\n\n getLeaderboard(week?: string): Promise<LeaderboardPayload | null> {\n return getLeaderboard(this.cfg, this.context?.operatorUserId, week)\n }\n\n getClubFixtures(competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n return getClubFixtures(this.cfg, competitionId, limit)\n }\n getClubStandings(competitionId?: number): Promise<ClubStandingsPayload | null> {\n return getClubStandings(this.cfg, competitionId)\n }\n getClubSquad(): Promise<ClubSquadPayload | null> {\n return getClubSquad(this.cfg)\n }\n getClubSquadStats(): Promise<ClubSquadStatsPayload | null> {\n return getClubSquadStats(this.cfg)\n }\n getClubPlayerDetail(playerId: number): Promise<ClubPlayerDetailPayload | null> {\n return getClubPlayerDetail(this.cfg, playerId)\n }\n getClubRecords(limit?: number): Promise<ClubRecordsPayload | null> {\n return getClubRecords(this.cfg, limit)\n }\n}\n","export type WidgetEntityEventName =\n | 'pin_add' | 'pin_remove' | 'slip_click' | 'slip_result'\n | 'insight_expand' | 'tile_tap' | 'chip_tap'\n | 'slip_remove' | 'bet_placed' | 'match_view' | 'match_open'\n\nexport type WidgetPopupEventName = 'popup_shown' | 'popup_opened' | 'popup_dismissed'\n\nexport type WidgetPopupAskEventName = 'popup_ask_tap'\n\nexport type WidgetOpenEventName = 'widget_open'\n\nexport type WidgetEventName = WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName\n\nexport type WidgetEntityType = 'match' | 'team' | 'player' | 'competition' | 'market'\n\nexport interface WidgetEventInput {\n name: WidgetEntityEventName\n entityType: WidgetEntityType\n entityId?: string\n entityName?: string\n marketDeveloperName?: string\n outcome?: string\n /** Football match id of the slip selection (slip_click / slip_result). */\n matchId?: number\n /** The raw odds label as stored (\"Home\", \"Over\", \"Home/Draw\"), never a joined display string. Max 64. */\n selection?: string\n /** The raw line (\"2.5\"). Max 32; omit when empty. */\n line?: string\n /** Decimal price shown when the selection was added. */\n odds?: number\n /** Wire sport key ('nba'); absent means football. */\n sport?: string\n}\n\n/** Launcher popup telemetry: counted server-side, never tied to an entity. */\nexport type WidgetPopupEventInput =\n { name: WidgetPopupEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\n/** A tap on one of the launcher bubble's asks. `outcome` carries the ask's position, \"0\" or \"1\"\n * (contract §5): the gateway forwards only the fields of its own event model, and outcome is its\n * one free-text field. */\nexport type WidgetPopupAskEventInput =\n { name: WidgetPopupAskEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\n/** The panel opening: entity-free, each open is added to the user's count for the day. */\nexport type WidgetOpenEventInput =\n { name: WidgetOpenEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\nexport type WidgetLogInput = WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput\n\nexport type WireEvent = WidgetLogInput & {\n seq: number\n at: number\n}\n\nexport interface EventBatch {\n v: 1\n sessionId: string\n conversationId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /**\n * Events dropped after exhausting delivery attempts during a PRIOR flush cycle — not a count of\n * this batch's own events. Rides whichever batch is built next after the drop, then is omitted\n * (0/undefined) once a clean cycle passes without a new failure.\n */\n dropped?: number\n /**\n * Failed delivery attempts from a PRIOR flush cycle — not retries of this batch's own events.\n * Rides whichever batch is built next after the failure, then is omitted (0/undefined) once a\n * clean cycle passes without a new failure.\n */\n retries?: number\n events: WireEvent[]\n}\n\nexport interface EventLoggerOptions {\n /** Normal delivery (fetch). Rejecting triggers the retry/backoff loop. */\n flush: (batch: EventBatch) => Promise<void>\n /** Best-effort tail flush on page hide/unload (fetch keepalive). Never awaited. */\n flushKeepalive: (batch: EventBatch) => void\n /** Injectable clock (tests). Defaults to Date.now. */\n now?: () => number\n batchIntervalMs?: number\n maxBatch?: number\n maxAttempts?: number\n}\n\nexport interface EventLogger {\n log(input: WidgetLogInput): void\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void\n flushNow(): Promise<void>\n flushOnHide(): void\n dispose(): void\n /** Undoes dispose(). React StrictMode runs an effect's cleanup and then its setup again on the\n * same logger, so the widget's setup has to be able to bring a disposed logger back. */\n resume(): void\n}\n\nconst IMMEDIATE: ReadonlySet<WidgetEventName> = new Set([\n 'pin_add', 'pin_remove', 'slip_click', 'slip_result', 'slip_remove', 'bet_placed',\n])\n\n// Queued without arming the batch timer: the event leaves with the next flush of any cause. A match\n// page view fires for every visitor, so it must never start a request of its own.\nconst DEFERRED: ReadonlySet<WidgetEventName> = new Set(['match_view'])\n\nconst DEFAULT_BATCH_INTERVAL_MS = 10_000\nconst DEFAULT_MAX_BATCH = 50\nconst DEFAULT_MAX_ATTEMPTS = 3\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction makeSessionId(): string {\n const c: Crypto | undefined = globalThis.crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`\n}\n\nclass EventLoggerImpl implements EventLogger {\n private readonly sessionId = makeSessionId()\n private readonly now: () => number\n private readonly batchIntervalMs: number\n private readonly maxBatch: number\n private readonly maxAttempts: number\n\n private queue: WireEvent[] = []\n private seq = 0\n private retries = 0\n private dropped = 0\n private identity: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string } = {}\n private timer: ReturnType<typeof setTimeout> | null = null\n private inFlight: Promise<void> | null = null\n private disposed = false\n\n constructor(private readonly opts: EventLoggerOptions) {\n this.now = opts.now ?? (() => Date.now())\n this.batchIntervalMs = opts.batchIntervalMs ?? DEFAULT_BATCH_INTERVAL_MS\n this.maxBatch = opts.maxBatch ?? DEFAULT_MAX_BATCH\n this.maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n }\n\n log(input: WidgetLogInput): void {\n if (this.disposed) return\n const event: WireEvent = { ...input, seq: ++this.seq, at: this.now() }\n this.queue.push(event)\n if (IMMEDIATE.has(input.name)) {\n this.trigger()\n } else if (this.queue.length >= this.maxBatch) {\n this.trigger()\n } else if (!DEFERRED.has(input.name)) {\n this.armTimer()\n }\n }\n\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void {\n this.identity = { ...this.identity, ...id }\n }\n\n async flushNow(): Promise<void> {\n if (this.inFlight) await this.inFlight\n if (this.queue.length > 0) await this.doFlush()\n }\n\n flushOnHide(): void {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n this.opts.flushKeepalive(batch)\n }\n\n dispose(): void {\n this.disposed = true\n this.clearTimer()\n }\n\n resume(): void {\n this.disposed = false\n }\n\n private armTimer(): void {\n if (this.timer !== null) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.trigger()\n }, this.batchIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer === null) return\n clearTimeout(this.timer)\n this.timer = null\n }\n\n private trigger(): void {\n if (this.disposed) return\n if (this.inFlight) return\n this.inFlight = this.doFlush().finally(() => {\n this.inFlight = null\n // An immediate (or maxBatch-triggered) log() call that arrived while this flush was\n // in-flight was a no-op above -- drain it now instead of stranding it until some later\n // log()/flushNow()/dispose() call. Guarded by the disposed check at the top of trigger()\n // itself, so a straggler queued just before dispose() does not fire a flush after it.\n if (this.queue.length > 0) this.trigger()\n })\n }\n\n /**\n * Snapshots the queue + carry-over counters (see EventBatch.dropped/retries) into a batch and\n * resets both for the next cycle. Returns null only when there is truly nothing to report --\n * an empty queue AND no pending dropped/retries -- so a pending counter-only report (queue\n * drained by an exhausted flush, nothing logged since) still gets built and delivered.\n */\n private buildBatch(): EventBatch | null {\n if (this.queue.length === 0 && this.retries === 0 && this.dropped === 0) return null\n const events = this.queue\n this.queue = []\n const batch: EventBatch = { v: 1, sessionId: this.sessionId, ...this.identity, events }\n if (this.retries > 0) batch.retries = this.retries\n if (this.dropped > 0) batch.dropped = this.dropped\n this.retries = 0\n this.dropped = 0\n return batch\n }\n\n private async doFlush(): Promise<void> {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n try {\n await this.opts.flush(batch)\n return\n } catch {\n this.retries++\n if (attempt >= this.maxAttempts) {\n this.dropped += batch.events.length\n return\n }\n await delay(2 ** attempt * 50)\n }\n }\n }\n}\n\nexport function createEventLogger(opts: EventLoggerOptions): EventLogger {\n return new EventLoggerImpl(opts)\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { createEventLogger, type EventLogger } from './eventLog'\nimport { postEvents, postEventsKeepalive, postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, StatsWidgetClientOptions, UserContext } from './types'\n\nconst DEFAULT_BASE_URL = 'https://widget.sensiblestats.com'\n\nexport class StatsWidgetClient {\n private readonly cfg: ResolvedConfig\n\n constructor(options: StatsWidgetClientOptions) {\n if (!options.operatorId) throw new Error('operatorId is required')\n if (!options.publicKey) throw new Error('publicKey is required')\n const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined)\n if (!fetchImpl) throw new Error('No fetch implementation available; pass options.fetch')\n this.cfg = {\n operatorId: options.operatorId,\n publicKey: options.publicKey,\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetch: fetchImpl,\n client: options.client,\n }\n }\n\n chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n return runChat(this.cfg, input, callbacks)\n }\n\n async sendSignal(input: SignalInput): Promise<void> {\n await postSignal(this.cfg, toSignalWireBody(input))\n }\n\n conversation(context?: UserContext): Conversation {\n return new Conversation(this.cfg, context)\n }\n\n createEventLogger(identity?: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): EventLogger {\n const logger = createEventLogger({\n flush: (batch) => postEvents(this.cfg, batch),\n flushKeepalive: (batch) => postEventsKeepalive(this.cfg, batch),\n })\n if (identity) logger.setIdentity(identity)\n return logger\n }\n}\n","export function matchKey(sport: string | undefined, id: number): string {\n return `${sport ?? 'football'}:${id}`\n}\n","import type { SlipSport } from './sports'\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>\n\nexport interface StatsWidgetClientOptions {\n operatorId: string\n publicKey: string\n baseUrl?: string\n /** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */\n fetch?: FetchLike\n /** Sent as X-SS-Client; set by widget-react. */\n client?: string\n}\n\nexport interface UserContext {\n operatorUserId?: string\n defaultLanguage?: string\n anonymousUserId?: string\n}\n\nexport interface ChatGrounding {\n kind?: string\n matchId?: number\n opponentTeamId?: number\n teamId?: number\n competitionId?: number\n season?: string\n subject?: string\n personaHint?: string\n sport?: string\n}\n\n/** The page the widget sits on. Sent on greeting requests only, so the greeting can lead with that page. */\nexport interface PageContext {\n sport: 'football' | 'nba'\n kind?: 'section' | 'competition' | 'match'\n matchId?: string | number\n competitionId?: string | number\n}\n\n/** Onboarding presets stage 2 (contract §3): what a tool's Send asked for. Sent only from a tool's\n * Send, beside the full sentence in `message`. The server ignores it unless every value is valid. */\nexport interface ChatPreset {\n kind: 'max_price' | 'min_price' | 'combo' | 'market'\n /** max_price, min_price */\n price?: number\n /** max_price, min_price */\n count?: number\n /** combo */\n total?: number\n /** combo */\n legs?: number\n /** market */\n marketDeveloperName?: string\n /** The picks or legs the tool showed, in the order shown (R12: the answer reprices exactly these). */\n matchOddsIds: number[]\n /** The same picks' matchId, index for index with matchOddsIds (from the grid). */\n matchIds: number[]\n}\n\nexport interface ChatInput {\n message: string\n conversationId?: string\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap). Authoritative over `message` when present. */\n actionRef?: string\n userContext?: UserContext\n grounding?: ChatGrounding\n /** Features this client can draw (e.g. \"price_presets\"). The server sends nothing that needs a\n * feature the list does not name; an absent list means today's responses. */\n clientCapabilities?: string[]\n /** Onboarding presets stage 2: set only by a preset tool's Send (contract §3). */\n preset?: ChatPreset\n page?: PageContext\n}\n\nexport type SignalType =\n | 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView'\n | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed'\n | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth'\n | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed'\n\nexport type SignalEntityType =\n | 'Match' | 'Team' | 'Player' | 'Competition' | 'Market'\n | 'Article' | 'Session' | 'Query' | 'Conversation'\n\nexport interface SignalInput {\n signalType: SignalType\n entityType: SignalEntityType\n /** Either this or entityId is required -- an operator's UI mostly knows a display name. */\n entityName?: string\n /** Either this or entityName is required -- a dashboard tile knows its entity by id. */\n entityId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /** Greeting dashboard layout this signal came from, when it is a dashboard tap. */\n dashboardLayout?: string\n /** Zero-based tile position within the dashboard, when it is a dashboard tap. */\n tileIndex?: number\n /** Wire sport key ('nba'); absent means football. Set by the widget, never by an operator. */\n sport?: string\n}\n\nexport type { SlipSport }\n\nexport interface SlipSelection {\n matchOddsId: number\n matchId: number\n oddsDecimal: number\n quotedAtUtc?: string\n insightId?: string\n conversationId?: string\n sport?: SlipSport\n}\n\nexport type AddToSlipRejectReason =\n | 'suspended' | 'closed' | 'login_required'\n | 'not_found' | 'limit' | 'unsupported'\n\nexport type AddToSlipResult =\n | { status: 'added'; slip?: { selectionCount: number; totalOddsDecimal?: number } }\n | { status: 'duplicate' }\n | { status: 'price_changed'; newOddsDecimal: number; accepted: boolean }\n | { status: 'rejected'; reason: AddToSlipRejectReason; message?: string }\n\nexport type AddToSlipHandler = (\n selection: SlipSelection,\n) => Promise<AddToSlipResult | void> | AddToSlipResult | void\n\nconst REJECT_REASONS = ['suspended', 'closed', 'login_required', 'not_found', 'limit', 'unsupported']\n\nexport function isAddToSlipResult(v: unknown): v is AddToSlipResult {\n if (typeof v !== 'object' || v === null) return false\n const o = v as Record<string, unknown>\n switch (o.status) {\n case 'added':\n case 'duplicate':\n return true\n case 'price_changed':\n return typeof o.newOddsDecimal === 'number'\n && Number.isFinite(o.newOddsDecimal)\n && typeof o.accepted === 'boolean'\n case 'rejected':\n return typeof o.reason === 'string'\n && REJECT_REASONS.includes(o.reason)\n default:\n return false\n }\n}\n","export interface SportSpec { readonly slipPrefix: string; readonly monitorPrefix: string; readonly label: string; readonly slippable: boolean; readonly wireKey: string | undefined }\n\nexport const SPORTS = {\n basketball: { slipPrefix: 'bb:', monitorPrefix: 'nba:', label: 'NBA', slippable: true, wireKey: 'nba' },\n americanfootball: { slipPrefix: 'af:', monitorPrefix: 'nfl:', label: 'NFL', slippable: true, wireKey: undefined },\n} as const satisfies Record<string, SportSpec>\n\nexport type NonFootballSport = keyof typeof SPORTS\n/** The sport keys the server accepts on a signal or widget event: only a sport with a wireKey. */\nexport type WireSport = NonNullable<(typeof SPORTS)[NonFootballSport]['wireKey']>\nexport type QualifiedType = 'game' | 'team' | 'player' | 'competition' | 'market'\n/** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */\nexport type SlipSport = { [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never }[NonFootballSport]\n\n/** undefined means football: every sport the map does not know is football. */\nexport function sportOf(v: unknown): NonFootballSport | undefined {\n return typeof v === 'string' && Object.prototype.hasOwnProperty.call(SPORTS, v) ? (v as NonFootballSport) : undefined\n}\n\n/** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */\nexport function mayPinOrSlip(v: unknown): boolean {\n const sport = sportOf(v)\n return sport === undefined || SPORTS[sport].slippable\n}\n\n/** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */\nexport function slipSportOf(v: unknown): SlipSport | undefined {\n const sport = sportOf(v)\n return sport !== undefined && SPORTS[sport].slippable ? (sport as SlipSport) : undefined\n}\n\n/** The key the server reads as `sport`; undefined for football and for a sport without a wireKey (NFL sends nothing). */\nexport function toWireSport(v: unknown): WireSport | undefined {\n const sport = sportOf(v)\n return sport === undefined ? undefined : (SPORTS[sport].wireKey as WireSport | undefined)\n}\n\nexport function qualifiedId(sport: unknown, type: QualifiedType, id: string): string {\n const wire = toWireSport(sport)\n return wire ? `${wire}:${type}:${id}` : id\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -40,6 +40,47 @@ declare class ParseError extends WidgetSdkError {
40
40
  constructor(message?: string, line?: string);
41
41
  }
42
42
 
43
+ interface SportSpec {
44
+ readonly slipPrefix: string;
45
+ readonly monitorPrefix: string;
46
+ readonly label: string;
47
+ readonly slippable: boolean;
48
+ readonly wireKey: string | undefined;
49
+ }
50
+ declare const SPORTS: {
51
+ readonly basketball: {
52
+ readonly slipPrefix: "bb:";
53
+ readonly monitorPrefix: "nba:";
54
+ readonly label: "NBA";
55
+ readonly slippable: true;
56
+ readonly wireKey: "nba";
57
+ };
58
+ readonly americanfootball: {
59
+ readonly slipPrefix: "af:";
60
+ readonly monitorPrefix: "nfl:";
61
+ readonly label: "NFL";
62
+ readonly slippable: true;
63
+ readonly wireKey: undefined;
64
+ };
65
+ };
66
+ type NonFootballSport = keyof typeof SPORTS;
67
+ /** The sport keys the server accepts on a signal or widget event: only a sport with a wireKey. */
68
+ type WireSport = NonNullable<(typeof SPORTS)[NonFootballSport]['wireKey']>;
69
+ type QualifiedType = 'game' | 'team' | 'player' | 'competition' | 'market';
70
+ /** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */
71
+ type SlipSport = {
72
+ [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never;
73
+ }[NonFootballSport];
74
+ /** undefined means football: every sport the map does not know is football. */
75
+ declare function sportOf(v: unknown): NonFootballSport | undefined;
76
+ /** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */
77
+ declare function mayPinOrSlip(v: unknown): boolean;
78
+ /** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */
79
+ declare function slipSportOf(v: unknown): SlipSport | undefined;
80
+ /** The key the server reads as `sport`; undefined for football and for a sport without a wireKey (NFL sends nothing). */
81
+ declare function toWireSport(v: unknown): WireSport | undefined;
82
+ declare function qualifiedId(sport: unknown, type: QualifiedType, id: string): string;
83
+
43
84
  interface ProgressEventData {
44
85
  phase: string;
45
86
  message: string;
@@ -710,6 +751,7 @@ interface NflInsightSelection {
710
751
  line?: string | null;
711
752
  price: number;
712
753
  quotedAtUtc: string;
754
+ matchOddsId?: number | null;
713
755
  }
714
756
  interface NflPropReasonGame {
715
757
  week: number;
@@ -1140,7 +1182,7 @@ interface PinRef {
1140
1182
  matchOddsId?: number | null;
1141
1183
  withHistory?: boolean;
1142
1184
  /** Absent reads as football on the server, so football pins and stored pins stay unchanged. */
1143
- sport?: 'basketball';
1185
+ sport?: SlipSport;
1144
1186
  }
1145
1187
  interface LiveMonitorStatPrice {
1146
1188
  marketDeveloperName: string;
@@ -1188,7 +1230,7 @@ interface LiveMonitorFact {
1188
1230
  basis: string;
1189
1231
  market?: LiveMonitorStatPrice | null;
1190
1232
  }
1191
- type MonitorSport = 'football' | 'basketball';
1233
+ type MonitorSport = 'football' | SlipSport;
1192
1234
  /** Basketball block of a followed game. Away is the visitor. */
1193
1235
  interface LiveMonitorBasketball {
1194
1236
  period: number;
@@ -1204,6 +1246,18 @@ interface LiveMonitorBasketball {
1204
1246
  homeTimeoutsLeft?: number | null;
1205
1247
  awayTimeoutsLeft?: number | null;
1206
1248
  }
1249
+ /** American football block of a followed game. Away is the visitor. Period is null before kickoff and after the game. */
1250
+ interface LiveMonitorAmericanFootball {
1251
+ period: number | null;
1252
+ clock: string | null;
1253
+ statusText: string | null;
1254
+ homeAbbreviation: string;
1255
+ awayAbbreviation: string;
1256
+ homeNickname: string;
1257
+ awayNickname: string;
1258
+ homePeriods: (number | null)[];
1259
+ awayPeriods: (number | null)[];
1260
+ }
1207
1261
  interface LiveMonitorMatch {
1208
1262
  matchId: number;
1209
1263
  phase: MonitorPhase;
@@ -1234,6 +1288,8 @@ interface LiveMonitorMatch {
1234
1288
  sport?: MonitorSport;
1235
1289
  /** Set only on a basketball match. */
1236
1290
  basketball?: LiveMonitorBasketball | null;
1291
+ /** Set only on an American football match. */
1292
+ americanFootball?: LiveMonitorAmericanFootball | null;
1237
1293
  [key: string]: unknown;
1238
1294
  }
1239
1295
  interface LiveMonitorMarket {
@@ -1261,7 +1317,7 @@ interface LiveMonitorSnapshot {
1261
1317
  serverNowUtc: string;
1262
1318
  nextPollSeconds: number;
1263
1319
  }
1264
- type ScheduleSport = 'football' | 'basketball';
1320
+ type ScheduleSport = 'football' | 'basketball' | 'americanfootball';
1265
1321
  interface ScheduleMatch {
1266
1322
  matchId: number;
1267
1323
  /** Absent means football. */
@@ -1543,38 +1599,6 @@ interface ClubRecordsPayload {
1543
1599
  sinceSeasonName: string | null;
1544
1600
  }
1545
1601
 
1546
- interface SportSpec {
1547
- readonly slipPrefix: string;
1548
- readonly monitorPrefix: string;
1549
- readonly label: string;
1550
- readonly slippable: boolean;
1551
- }
1552
- declare const SPORTS: {
1553
- readonly basketball: {
1554
- readonly slipPrefix: "bb:";
1555
- readonly monitorPrefix: "nba:";
1556
- readonly label: "NBA";
1557
- readonly slippable: true;
1558
- };
1559
- readonly americanfootball: {
1560
- readonly slipPrefix: "af:";
1561
- readonly monitorPrefix: "nfl:";
1562
- readonly label: "NFL";
1563
- readonly slippable: false;
1564
- };
1565
- };
1566
- type NonFootballSport = keyof typeof SPORTS;
1567
- /** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */
1568
- type SlipSport = {
1569
- [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never;
1570
- }[NonFootballSport];
1571
- /** undefined means football: every sport the map does not know is football. */
1572
- declare function sportOf(v: unknown): NonFootballSport | undefined;
1573
- /** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */
1574
- declare function mayPinOrSlip(v: unknown): boolean;
1575
- /** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */
1576
- declare function slipSportOf(v: unknown): SlipSport | undefined;
1577
-
1578
1602
  type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
1579
1603
  interface StatsWidgetClientOptions {
1580
1604
  operatorId: string;
@@ -1657,6 +1681,8 @@ interface SignalInput {
1657
1681
  dashboardLayout?: string;
1658
1682
  /** Zero-based tile position within the dashboard, when it is a dashboard tap. */
1659
1683
  tileIndex?: number;
1684
+ /** Wire sport key ('nba'); absent means football. Set by the widget, never by an operator. */
1685
+ sport?: string;
1660
1686
  }
1661
1687
 
1662
1688
  interface SlipSelection {
@@ -1720,7 +1746,7 @@ declare class Conversation {
1720
1746
  sendSignal(input: SignalInput): Promise<void>;
1721
1747
  getLiveDashboard(): Promise<ClubFanDashboardPayload | null>;
1722
1748
  getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null>;
1723
- getMarketOdds(matchId: number, marketDeveloperName: string, sport?: 'basketball'): Promise<MarketOddsBlock | null>;
1749
+ getMarketOdds(matchId: number, marketDeveloperName: string, sport?: SlipSport): Promise<MarketOddsBlock | null>;
1724
1750
  getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null>;
1725
1751
  getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null>;
1726
1752
  getSchedule(localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string): Promise<SchedulePayload | null>;
@@ -1760,6 +1786,8 @@ interface WidgetEventInput {
1760
1786
  line?: string;
1761
1787
  /** Decimal price shown when the selection was added. */
1762
1788
  odds?: number;
1789
+ /** Wire sport key ('nba'); absent means football. */
1790
+ sport?: string;
1763
1791
  }
1764
1792
  /** Launcher popup telemetry: counted server-side, never tied to an entity. */
1765
1793
  type WidgetPopupEventInput = {
@@ -1858,4 +1886,4 @@ interface NdjsonParser {
1858
1886
  }
1859
1887
  declare function createNdjsonParser(): NdjsonParser;
1860
1888
 
1861
- export { type ActionButtonEventData, type ActionsLoadingEventData, type AddToSlipHandler, type AddToSlipRejectReason, type AddToSlipResult, type AllTimeRow, type AnswerEventData, AuthError, type AvailableMarket, type BettingInsight, type BettingInsightEventData, type BettingInsightOdds, type ChatCallbacks, type ChatEvent, type ChatGrounding, type ChatHandle, type ChatInput, type ChatPreset, type ClubFanDashboardCard, type ClubFanDashboardHeadToHead, type ClubFanDashboardPayload, type ClubFixture, type ClubFixturesPayload, type ClubMatchLogRow, type ClubNextFixture, type ClubPerformanceMetric, type ClubPlayerAvailability, type ClubPlayerAvailabilityStatus, type ClubPlayerDetailPayload, type ClubPlayerPerformance, type ClubPlayerSeasonStats, type ClubRecordEntry, type ClubRecordsPayload, type ClubSquadPayload, type ClubSquadPlayer, type ClubSquadStatsPayload, type ClubStandingRow, type ClubStandingsPayload, type ComboCard, type ComboCardEventData, type ComboLeg, type ComboReplacedLeg, type CongestedWeekCard, type CongestedWeekData, type CongestedWeekEntry, Conversation, type CountdownCard, type CountdownData, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type EntityCardScope, type EntityCardStat, type EventBatch, type EventLogger, type EventLoggerOptions, type FetchLike, type FixtureCard, type FixtureCardData, ForbiddenError, type FormAndH2H, type FormMatch, type GameListPayload, type GameResultPayload, type GameStatePayload, type GameSummary, type GreetingDashboard, type GreetingDashboardLayout, type GreetingDashboardSignalRef, type GreetingDashboardSpan, type GreetingDashboardTile, type GreetingDashboardTileEmphasis, type HeadToHead, type InjuriesCard, type InjuriesCardData, type InjuryRow, type IntentChipEventData, LIMIT_CODES, type LeaderboardChampion, type LeaderboardPayload, type LeaderboardRow, type LeagueStarResult, type LimitCode, type LimitDetails, LimitError, type LinkRow, type LinksCard, type LinksData, type LiveEventLine, type LiveMonitorBasketball, type LiveMonitorEvent, type LiveMonitorFact, type LiveMonitorMarket, type LiveMonitorMatch, type LiveMonitorSnapshot, type LiveMonitorStatPrice, type LiveMonitorStatRow, type LiveScoreCard, type LiveScoreData, type LiveStatRow, type LiveStatsCard, type LiveStatsData, type LiveTimelineCard, type LiveTimelineData, type MarketOddsBlock, type MarketOddsCard, type MarketOddsCardInsight, type MarketOddsEventData, type MarketOddsLiveBlock, type MarketOddsRow, type MatchState, type MomentumPoint, type MonitorPhase, type MonitorSport, type NbaCoHitEvidence, type NbaCoHitLeg, type NbaGameValue, type NbaInjuryEvent, type NbaInsight, type NbaInsightEventData, type NbaInsightSelection, type NbaJointGame, type NbaLadderEvidence, type NbaLadderRung, type NbaLadderStat, type NbaLineLane, type NbaLineMoveEvidence, type NbaLinePoint, type NbaListedTeammate, type NbaMatchupEvidence, type NbaMatchupPosition, type NbaMatchupTeam, type NbaPropReasonEvidence, type NbaQuarterLadderEvidence, type NbaQuarterRung, type NbaQuarterStat, type NbaSettleLine, type NbaSettlePlayer, type NbaSettleRecapEvidence, type NbaSettleSummary, type NbaSplitRow, type NbaTeammateOutEvidence, type NdjsonParser, NetworkError, type NflAtsGame, type NflAtsRecordEvidence, type NflInjuryPlayer, type NflInjuryReportEvidence, type NflInsight, type NflInsightEventData, type NflInsightKind, type NflInsightSelection, type NflLadderEvidence, type NflLadderRung, type NflLineMoveEvidence, type NflLineMoveLane, type NflMatchupEvidence, type NflPropReasonEvidence, type NflPropReasonGame, type NflSettleRecapEvidence, type NflSettleRecapLine, type NflSettleRecapPlayer, type NflSettleRecapSummary, type NonFootballSport, type OddsMovementCard, type OddsMovementEventData, type OddsMovementPoint, type PageContext, ParseError, type PinKind, type PinRef, type PlayerPropGame, type PlayerPropPrice, type PlayerPropStat, type PlayerPropsBundle, type PostMatchGoalLine, type PostMatchGoalsCard, type PostMatchGoalsData, type PostMatchNextCard, type PostMatchNextData, type PostMatchResultCard, type PostMatchResultData, type PostMatchStatRow, type PostMatchStatsCard, type PostMatchStatsData, type PostMatchTopPerformerCard, type PostMatchTopPerformerData, type PresetComboCell, type PresetGrid, type PresetGridOptions, type PresetMarketCell, type PresetPick, type PresetSinglesCell, type ProgressEventData, RateLimitError, type ReasonToBetCard, type ReasonToBetData, type RestingFormCard, type RestingFormData, type RestingNextCard, type RestingNextData, type RestingSeasonCard, type RestingSeasonData, type RestingStandingsCard, type RestingStandingsData, SIGNAL_TYPE_CODES, SPORTS, type ScheduleGroup, type ScheduleMatch, type SchedulePayload, type ScheduleSport, type SignalEntityType, type SignalInput, type SignalType, type SlipSelection, type SlipSport, type SportSpec, type StatesPayload, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type SubmitPlayBody, type SubmitPlayResult, type TransferRow, type TransfersCard, type TransfersData, type TurnCompleteEventData, UpstreamError, type UserContext, type WhereToWatchCard, type WhereToWatchData, type WidgetEntityEventName, type WidgetEntityType, type WidgetEventInput, type WidgetEventName, type WidgetLogInput, type WidgetOpenEventInput, type WidgetOpenEventName, type WidgetPopupAskEventInput, type WidgetPopupAskEventName, type WidgetPopupEventInput, type WidgetPopupEventName, WidgetSdkError, type WireEvent, createEventLogger, createNdjsonParser, isAddToSlipResult, isLimitCode, matchKey, mayPinOrSlip, slipSportOf, sportOf };
1889
+ export { type ActionButtonEventData, type ActionsLoadingEventData, type AddToSlipHandler, type AddToSlipRejectReason, type AddToSlipResult, type AllTimeRow, type AnswerEventData, AuthError, type AvailableMarket, type BettingInsight, type BettingInsightEventData, type BettingInsightOdds, type ChatCallbacks, type ChatEvent, type ChatGrounding, type ChatHandle, type ChatInput, type ChatPreset, type ClubFanDashboardCard, type ClubFanDashboardHeadToHead, type ClubFanDashboardPayload, type ClubFixture, type ClubFixturesPayload, type ClubMatchLogRow, type ClubNextFixture, type ClubPerformanceMetric, type ClubPlayerAvailability, type ClubPlayerAvailabilityStatus, type ClubPlayerDetailPayload, type ClubPlayerPerformance, type ClubPlayerSeasonStats, type ClubRecordEntry, type ClubRecordsPayload, type ClubSquadPayload, type ClubSquadPlayer, type ClubSquadStatsPayload, type ClubStandingRow, type ClubStandingsPayload, type ComboCard, type ComboCardEventData, type ComboLeg, type ComboReplacedLeg, type CongestedWeekCard, type CongestedWeekData, type CongestedWeekEntry, Conversation, type CountdownCard, type CountdownData, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type EntityCardScope, type EntityCardStat, type EventBatch, type EventLogger, type EventLoggerOptions, type FetchLike, type FixtureCard, type FixtureCardData, ForbiddenError, type FormAndH2H, type FormMatch, type GameListPayload, type GameResultPayload, type GameStatePayload, type GameSummary, type GreetingDashboard, type GreetingDashboardLayout, type GreetingDashboardSignalRef, type GreetingDashboardSpan, type GreetingDashboardTile, type GreetingDashboardTileEmphasis, type HeadToHead, type InjuriesCard, type InjuriesCardData, type InjuryRow, type IntentChipEventData, LIMIT_CODES, type LeaderboardChampion, type LeaderboardPayload, type LeaderboardRow, type LeagueStarResult, type LimitCode, type LimitDetails, LimitError, type LinkRow, type LinksCard, type LinksData, type LiveEventLine, type LiveMonitorAmericanFootball, type LiveMonitorBasketball, type LiveMonitorEvent, type LiveMonitorFact, type LiveMonitorMarket, type LiveMonitorMatch, type LiveMonitorSnapshot, type LiveMonitorStatPrice, type LiveMonitorStatRow, type LiveScoreCard, type LiveScoreData, type LiveStatRow, type LiveStatsCard, type LiveStatsData, type LiveTimelineCard, type LiveTimelineData, type MarketOddsBlock, type MarketOddsCard, type MarketOddsCardInsight, type MarketOddsEventData, type MarketOddsLiveBlock, type MarketOddsRow, type MatchState, type MomentumPoint, type MonitorPhase, type MonitorSport, type NbaCoHitEvidence, type NbaCoHitLeg, type NbaGameValue, type NbaInjuryEvent, type NbaInsight, type NbaInsightEventData, type NbaInsightSelection, type NbaJointGame, type NbaLadderEvidence, type NbaLadderRung, type NbaLadderStat, type NbaLineLane, type NbaLineMoveEvidence, type NbaLinePoint, type NbaListedTeammate, type NbaMatchupEvidence, type NbaMatchupPosition, type NbaMatchupTeam, type NbaPropReasonEvidence, type NbaQuarterLadderEvidence, type NbaQuarterRung, type NbaQuarterStat, type NbaSettleLine, type NbaSettlePlayer, type NbaSettleRecapEvidence, type NbaSettleSummary, type NbaSplitRow, type NbaTeammateOutEvidence, type NdjsonParser, NetworkError, type NflAtsGame, type NflAtsRecordEvidence, type NflInjuryPlayer, type NflInjuryReportEvidence, type NflInsight, type NflInsightEventData, type NflInsightKind, type NflInsightSelection, type NflLadderEvidence, type NflLadderRung, type NflLineMoveEvidence, type NflLineMoveLane, type NflMatchupEvidence, type NflPropReasonEvidence, type NflPropReasonGame, type NflSettleRecapEvidence, type NflSettleRecapLine, type NflSettleRecapPlayer, type NflSettleRecapSummary, type NonFootballSport, type OddsMovementCard, type OddsMovementEventData, type OddsMovementPoint, type PageContext, ParseError, type PinKind, type PinRef, type PlayerPropGame, type PlayerPropPrice, type PlayerPropStat, type PlayerPropsBundle, type PostMatchGoalLine, type PostMatchGoalsCard, type PostMatchGoalsData, type PostMatchNextCard, type PostMatchNextData, type PostMatchResultCard, type PostMatchResultData, type PostMatchStatRow, type PostMatchStatsCard, type PostMatchStatsData, type PostMatchTopPerformerCard, type PostMatchTopPerformerData, type PresetComboCell, type PresetGrid, type PresetGridOptions, type PresetMarketCell, type PresetPick, type PresetSinglesCell, type ProgressEventData, type QualifiedType, RateLimitError, type ReasonToBetCard, type ReasonToBetData, type RestingFormCard, type RestingFormData, type RestingNextCard, type RestingNextData, type RestingSeasonCard, type RestingSeasonData, type RestingStandingsCard, type RestingStandingsData, SIGNAL_TYPE_CODES, SPORTS, type ScheduleGroup, type ScheduleMatch, type SchedulePayload, type ScheduleSport, type SignalEntityType, type SignalInput, type SignalType, type SlipSelection, type SlipSport, type SportSpec, type StatesPayload, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type SubmitPlayBody, type SubmitPlayResult, type TransferRow, type TransfersCard, type TransfersData, type TurnCompleteEventData, UpstreamError, type UserContext, type WhereToWatchCard, type WhereToWatchData, type WidgetEntityEventName, type WidgetEntityType, type WidgetEventInput, type WidgetEventName, type WidgetLogInput, type WidgetOpenEventInput, type WidgetOpenEventName, type WidgetPopupAskEventInput, type WidgetPopupAskEventName, type WidgetPopupEventInput, type WidgetPopupEventName, WidgetSdkError, type WireEvent, type WireSport, createEventLogger, createNdjsonParser, isAddToSlipResult, isLimitCode, matchKey, mayPinOrSlip, qualifiedId, slipSportOf, sportOf, toWireSport };
package/dist/index.d.ts CHANGED
@@ -40,6 +40,47 @@ declare class ParseError extends WidgetSdkError {
40
40
  constructor(message?: string, line?: string);
41
41
  }
42
42
 
43
+ interface SportSpec {
44
+ readonly slipPrefix: string;
45
+ readonly monitorPrefix: string;
46
+ readonly label: string;
47
+ readonly slippable: boolean;
48
+ readonly wireKey: string | undefined;
49
+ }
50
+ declare const SPORTS: {
51
+ readonly basketball: {
52
+ readonly slipPrefix: "bb:";
53
+ readonly monitorPrefix: "nba:";
54
+ readonly label: "NBA";
55
+ readonly slippable: true;
56
+ readonly wireKey: "nba";
57
+ };
58
+ readonly americanfootball: {
59
+ readonly slipPrefix: "af:";
60
+ readonly monitorPrefix: "nfl:";
61
+ readonly label: "NFL";
62
+ readonly slippable: true;
63
+ readonly wireKey: undefined;
64
+ };
65
+ };
66
+ type NonFootballSport = keyof typeof SPORTS;
67
+ /** The sport keys the server accepts on a signal or widget event: only a sport with a wireKey. */
68
+ type WireSport = NonNullable<(typeof SPORTS)[NonFootballSport]['wireKey']>;
69
+ type QualifiedType = 'game' | 'team' | 'player' | 'competition' | 'market';
70
+ /** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */
71
+ type SlipSport = {
72
+ [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never;
73
+ }[NonFootballSport];
74
+ /** undefined means football: every sport the map does not know is football. */
75
+ declare function sportOf(v: unknown): NonFootballSport | undefined;
76
+ /** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */
77
+ declare function mayPinOrSlip(v: unknown): boolean;
78
+ /** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */
79
+ declare function slipSportOf(v: unknown): SlipSport | undefined;
80
+ /** The key the server reads as `sport`; undefined for football and for a sport without a wireKey (NFL sends nothing). */
81
+ declare function toWireSport(v: unknown): WireSport | undefined;
82
+ declare function qualifiedId(sport: unknown, type: QualifiedType, id: string): string;
83
+
43
84
  interface ProgressEventData {
44
85
  phase: string;
45
86
  message: string;
@@ -710,6 +751,7 @@ interface NflInsightSelection {
710
751
  line?: string | null;
711
752
  price: number;
712
753
  quotedAtUtc: string;
754
+ matchOddsId?: number | null;
713
755
  }
714
756
  interface NflPropReasonGame {
715
757
  week: number;
@@ -1140,7 +1182,7 @@ interface PinRef {
1140
1182
  matchOddsId?: number | null;
1141
1183
  withHistory?: boolean;
1142
1184
  /** Absent reads as football on the server, so football pins and stored pins stay unchanged. */
1143
- sport?: 'basketball';
1185
+ sport?: SlipSport;
1144
1186
  }
1145
1187
  interface LiveMonitorStatPrice {
1146
1188
  marketDeveloperName: string;
@@ -1188,7 +1230,7 @@ interface LiveMonitorFact {
1188
1230
  basis: string;
1189
1231
  market?: LiveMonitorStatPrice | null;
1190
1232
  }
1191
- type MonitorSport = 'football' | 'basketball';
1233
+ type MonitorSport = 'football' | SlipSport;
1192
1234
  /** Basketball block of a followed game. Away is the visitor. */
1193
1235
  interface LiveMonitorBasketball {
1194
1236
  period: number;
@@ -1204,6 +1246,18 @@ interface LiveMonitorBasketball {
1204
1246
  homeTimeoutsLeft?: number | null;
1205
1247
  awayTimeoutsLeft?: number | null;
1206
1248
  }
1249
+ /** American football block of a followed game. Away is the visitor. Period is null before kickoff and after the game. */
1250
+ interface LiveMonitorAmericanFootball {
1251
+ period: number | null;
1252
+ clock: string | null;
1253
+ statusText: string | null;
1254
+ homeAbbreviation: string;
1255
+ awayAbbreviation: string;
1256
+ homeNickname: string;
1257
+ awayNickname: string;
1258
+ homePeriods: (number | null)[];
1259
+ awayPeriods: (number | null)[];
1260
+ }
1207
1261
  interface LiveMonitorMatch {
1208
1262
  matchId: number;
1209
1263
  phase: MonitorPhase;
@@ -1234,6 +1288,8 @@ interface LiveMonitorMatch {
1234
1288
  sport?: MonitorSport;
1235
1289
  /** Set only on a basketball match. */
1236
1290
  basketball?: LiveMonitorBasketball | null;
1291
+ /** Set only on an American football match. */
1292
+ americanFootball?: LiveMonitorAmericanFootball | null;
1237
1293
  [key: string]: unknown;
1238
1294
  }
1239
1295
  interface LiveMonitorMarket {
@@ -1261,7 +1317,7 @@ interface LiveMonitorSnapshot {
1261
1317
  serverNowUtc: string;
1262
1318
  nextPollSeconds: number;
1263
1319
  }
1264
- type ScheduleSport = 'football' | 'basketball';
1320
+ type ScheduleSport = 'football' | 'basketball' | 'americanfootball';
1265
1321
  interface ScheduleMatch {
1266
1322
  matchId: number;
1267
1323
  /** Absent means football. */
@@ -1543,38 +1599,6 @@ interface ClubRecordsPayload {
1543
1599
  sinceSeasonName: string | null;
1544
1600
  }
1545
1601
 
1546
- interface SportSpec {
1547
- readonly slipPrefix: string;
1548
- readonly monitorPrefix: string;
1549
- readonly label: string;
1550
- readonly slippable: boolean;
1551
- }
1552
- declare const SPORTS: {
1553
- readonly basketball: {
1554
- readonly slipPrefix: "bb:";
1555
- readonly monitorPrefix: "nba:";
1556
- readonly label: "NBA";
1557
- readonly slippable: true;
1558
- };
1559
- readonly americanfootball: {
1560
- readonly slipPrefix: "af:";
1561
- readonly monitorPrefix: "nfl:";
1562
- readonly label: "NFL";
1563
- readonly slippable: false;
1564
- };
1565
- };
1566
- type NonFootballSport = keyof typeof SPORTS;
1567
- /** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */
1568
- type SlipSport = {
1569
- [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never;
1570
- }[NonFootballSport];
1571
- /** undefined means football: every sport the map does not know is football. */
1572
- declare function sportOf(v: unknown): NonFootballSport | undefined;
1573
- /** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */
1574
- declare function mayPinOrSlip(v: unknown): boolean;
1575
- /** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */
1576
- declare function slipSportOf(v: unknown): SlipSport | undefined;
1577
-
1578
1602
  type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
1579
1603
  interface StatsWidgetClientOptions {
1580
1604
  operatorId: string;
@@ -1657,6 +1681,8 @@ interface SignalInput {
1657
1681
  dashboardLayout?: string;
1658
1682
  /** Zero-based tile position within the dashboard, when it is a dashboard tap. */
1659
1683
  tileIndex?: number;
1684
+ /** Wire sport key ('nba'); absent means football. Set by the widget, never by an operator. */
1685
+ sport?: string;
1660
1686
  }
1661
1687
 
1662
1688
  interface SlipSelection {
@@ -1720,7 +1746,7 @@ declare class Conversation {
1720
1746
  sendSignal(input: SignalInput): Promise<void>;
1721
1747
  getLiveDashboard(): Promise<ClubFanDashboardPayload | null>;
1722
1748
  getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null>;
1723
- getMarketOdds(matchId: number, marketDeveloperName: string, sport?: 'basketball'): Promise<MarketOddsBlock | null>;
1749
+ getMarketOdds(matchId: number, marketDeveloperName: string, sport?: SlipSport): Promise<MarketOddsBlock | null>;
1724
1750
  getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null>;
1725
1751
  getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null>;
1726
1752
  getSchedule(localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string): Promise<SchedulePayload | null>;
@@ -1760,6 +1786,8 @@ interface WidgetEventInput {
1760
1786
  line?: string;
1761
1787
  /** Decimal price shown when the selection was added. */
1762
1788
  odds?: number;
1789
+ /** Wire sport key ('nba'); absent means football. */
1790
+ sport?: string;
1763
1791
  }
1764
1792
  /** Launcher popup telemetry: counted server-side, never tied to an entity. */
1765
1793
  type WidgetPopupEventInput = {
@@ -1858,4 +1886,4 @@ interface NdjsonParser {
1858
1886
  }
1859
1887
  declare function createNdjsonParser(): NdjsonParser;
1860
1888
 
1861
- export { type ActionButtonEventData, type ActionsLoadingEventData, type AddToSlipHandler, type AddToSlipRejectReason, type AddToSlipResult, type AllTimeRow, type AnswerEventData, AuthError, type AvailableMarket, type BettingInsight, type BettingInsightEventData, type BettingInsightOdds, type ChatCallbacks, type ChatEvent, type ChatGrounding, type ChatHandle, type ChatInput, type ChatPreset, type ClubFanDashboardCard, type ClubFanDashboardHeadToHead, type ClubFanDashboardPayload, type ClubFixture, type ClubFixturesPayload, type ClubMatchLogRow, type ClubNextFixture, type ClubPerformanceMetric, type ClubPlayerAvailability, type ClubPlayerAvailabilityStatus, type ClubPlayerDetailPayload, type ClubPlayerPerformance, type ClubPlayerSeasonStats, type ClubRecordEntry, type ClubRecordsPayload, type ClubSquadPayload, type ClubSquadPlayer, type ClubSquadStatsPayload, type ClubStandingRow, type ClubStandingsPayload, type ComboCard, type ComboCardEventData, type ComboLeg, type ComboReplacedLeg, type CongestedWeekCard, type CongestedWeekData, type CongestedWeekEntry, Conversation, type CountdownCard, type CountdownData, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type EntityCardScope, type EntityCardStat, type EventBatch, type EventLogger, type EventLoggerOptions, type FetchLike, type FixtureCard, type FixtureCardData, ForbiddenError, type FormAndH2H, type FormMatch, type GameListPayload, type GameResultPayload, type GameStatePayload, type GameSummary, type GreetingDashboard, type GreetingDashboardLayout, type GreetingDashboardSignalRef, type GreetingDashboardSpan, type GreetingDashboardTile, type GreetingDashboardTileEmphasis, type HeadToHead, type InjuriesCard, type InjuriesCardData, type InjuryRow, type IntentChipEventData, LIMIT_CODES, type LeaderboardChampion, type LeaderboardPayload, type LeaderboardRow, type LeagueStarResult, type LimitCode, type LimitDetails, LimitError, type LinkRow, type LinksCard, type LinksData, type LiveEventLine, type LiveMonitorBasketball, type LiveMonitorEvent, type LiveMonitorFact, type LiveMonitorMarket, type LiveMonitorMatch, type LiveMonitorSnapshot, type LiveMonitorStatPrice, type LiveMonitorStatRow, type LiveScoreCard, type LiveScoreData, type LiveStatRow, type LiveStatsCard, type LiveStatsData, type LiveTimelineCard, type LiveTimelineData, type MarketOddsBlock, type MarketOddsCard, type MarketOddsCardInsight, type MarketOddsEventData, type MarketOddsLiveBlock, type MarketOddsRow, type MatchState, type MomentumPoint, type MonitorPhase, type MonitorSport, type NbaCoHitEvidence, type NbaCoHitLeg, type NbaGameValue, type NbaInjuryEvent, type NbaInsight, type NbaInsightEventData, type NbaInsightSelection, type NbaJointGame, type NbaLadderEvidence, type NbaLadderRung, type NbaLadderStat, type NbaLineLane, type NbaLineMoveEvidence, type NbaLinePoint, type NbaListedTeammate, type NbaMatchupEvidence, type NbaMatchupPosition, type NbaMatchupTeam, type NbaPropReasonEvidence, type NbaQuarterLadderEvidence, type NbaQuarterRung, type NbaQuarterStat, type NbaSettleLine, type NbaSettlePlayer, type NbaSettleRecapEvidence, type NbaSettleSummary, type NbaSplitRow, type NbaTeammateOutEvidence, type NdjsonParser, NetworkError, type NflAtsGame, type NflAtsRecordEvidence, type NflInjuryPlayer, type NflInjuryReportEvidence, type NflInsight, type NflInsightEventData, type NflInsightKind, type NflInsightSelection, type NflLadderEvidence, type NflLadderRung, type NflLineMoveEvidence, type NflLineMoveLane, type NflMatchupEvidence, type NflPropReasonEvidence, type NflPropReasonGame, type NflSettleRecapEvidence, type NflSettleRecapLine, type NflSettleRecapPlayer, type NflSettleRecapSummary, type NonFootballSport, type OddsMovementCard, type OddsMovementEventData, type OddsMovementPoint, type PageContext, ParseError, type PinKind, type PinRef, type PlayerPropGame, type PlayerPropPrice, type PlayerPropStat, type PlayerPropsBundle, type PostMatchGoalLine, type PostMatchGoalsCard, type PostMatchGoalsData, type PostMatchNextCard, type PostMatchNextData, type PostMatchResultCard, type PostMatchResultData, type PostMatchStatRow, type PostMatchStatsCard, type PostMatchStatsData, type PostMatchTopPerformerCard, type PostMatchTopPerformerData, type PresetComboCell, type PresetGrid, type PresetGridOptions, type PresetMarketCell, type PresetPick, type PresetSinglesCell, type ProgressEventData, RateLimitError, type ReasonToBetCard, type ReasonToBetData, type RestingFormCard, type RestingFormData, type RestingNextCard, type RestingNextData, type RestingSeasonCard, type RestingSeasonData, type RestingStandingsCard, type RestingStandingsData, SIGNAL_TYPE_CODES, SPORTS, type ScheduleGroup, type ScheduleMatch, type SchedulePayload, type ScheduleSport, type SignalEntityType, type SignalInput, type SignalType, type SlipSelection, type SlipSport, type SportSpec, type StatesPayload, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type SubmitPlayBody, type SubmitPlayResult, type TransferRow, type TransfersCard, type TransfersData, type TurnCompleteEventData, UpstreamError, type UserContext, type WhereToWatchCard, type WhereToWatchData, type WidgetEntityEventName, type WidgetEntityType, type WidgetEventInput, type WidgetEventName, type WidgetLogInput, type WidgetOpenEventInput, type WidgetOpenEventName, type WidgetPopupAskEventInput, type WidgetPopupAskEventName, type WidgetPopupEventInput, type WidgetPopupEventName, WidgetSdkError, type WireEvent, createEventLogger, createNdjsonParser, isAddToSlipResult, isLimitCode, matchKey, mayPinOrSlip, slipSportOf, sportOf };
1889
+ export { type ActionButtonEventData, type ActionsLoadingEventData, type AddToSlipHandler, type AddToSlipRejectReason, type AddToSlipResult, type AllTimeRow, type AnswerEventData, AuthError, type AvailableMarket, type BettingInsight, type BettingInsightEventData, type BettingInsightOdds, type ChatCallbacks, type ChatEvent, type ChatGrounding, type ChatHandle, type ChatInput, type ChatPreset, type ClubFanDashboardCard, type ClubFanDashboardHeadToHead, type ClubFanDashboardPayload, type ClubFixture, type ClubFixturesPayload, type ClubMatchLogRow, type ClubNextFixture, type ClubPerformanceMetric, type ClubPlayerAvailability, type ClubPlayerAvailabilityStatus, type ClubPlayerDetailPayload, type ClubPlayerPerformance, type ClubPlayerSeasonStats, type ClubRecordEntry, type ClubRecordsPayload, type ClubSquadPayload, type ClubSquadPlayer, type ClubSquadStatsPayload, type ClubStandingRow, type ClubStandingsPayload, type ComboCard, type ComboCardEventData, type ComboLeg, type ComboReplacedLeg, type CongestedWeekCard, type CongestedWeekData, type CongestedWeekEntry, Conversation, type CountdownCard, type CountdownData, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type EntityCardScope, type EntityCardStat, type EventBatch, type EventLogger, type EventLoggerOptions, type FetchLike, type FixtureCard, type FixtureCardData, ForbiddenError, type FormAndH2H, type FormMatch, type GameListPayload, type GameResultPayload, type GameStatePayload, type GameSummary, type GreetingDashboard, type GreetingDashboardLayout, type GreetingDashboardSignalRef, type GreetingDashboardSpan, type GreetingDashboardTile, type GreetingDashboardTileEmphasis, type HeadToHead, type InjuriesCard, type InjuriesCardData, type InjuryRow, type IntentChipEventData, LIMIT_CODES, type LeaderboardChampion, type LeaderboardPayload, type LeaderboardRow, type LeagueStarResult, type LimitCode, type LimitDetails, LimitError, type LinkRow, type LinksCard, type LinksData, type LiveEventLine, type LiveMonitorAmericanFootball, type LiveMonitorBasketball, type LiveMonitorEvent, type LiveMonitorFact, type LiveMonitorMarket, type LiveMonitorMatch, type LiveMonitorSnapshot, type LiveMonitorStatPrice, type LiveMonitorStatRow, type LiveScoreCard, type LiveScoreData, type LiveStatRow, type LiveStatsCard, type LiveStatsData, type LiveTimelineCard, type LiveTimelineData, type MarketOddsBlock, type MarketOddsCard, type MarketOddsCardInsight, type MarketOddsEventData, type MarketOddsLiveBlock, type MarketOddsRow, type MatchState, type MomentumPoint, type MonitorPhase, type MonitorSport, type NbaCoHitEvidence, type NbaCoHitLeg, type NbaGameValue, type NbaInjuryEvent, type NbaInsight, type NbaInsightEventData, type NbaInsightSelection, type NbaJointGame, type NbaLadderEvidence, type NbaLadderRung, type NbaLadderStat, type NbaLineLane, type NbaLineMoveEvidence, type NbaLinePoint, type NbaListedTeammate, type NbaMatchupEvidence, type NbaMatchupPosition, type NbaMatchupTeam, type NbaPropReasonEvidence, type NbaQuarterLadderEvidence, type NbaQuarterRung, type NbaQuarterStat, type NbaSettleLine, type NbaSettlePlayer, type NbaSettleRecapEvidence, type NbaSettleSummary, type NbaSplitRow, type NbaTeammateOutEvidence, type NdjsonParser, NetworkError, type NflAtsGame, type NflAtsRecordEvidence, type NflInjuryPlayer, type NflInjuryReportEvidence, type NflInsight, type NflInsightEventData, type NflInsightKind, type NflInsightSelection, type NflLadderEvidence, type NflLadderRung, type NflLineMoveEvidence, type NflLineMoveLane, type NflMatchupEvidence, type NflPropReasonEvidence, type NflPropReasonGame, type NflSettleRecapEvidence, type NflSettleRecapLine, type NflSettleRecapPlayer, type NflSettleRecapSummary, type NonFootballSport, type OddsMovementCard, type OddsMovementEventData, type OddsMovementPoint, type PageContext, ParseError, type PinKind, type PinRef, type PlayerPropGame, type PlayerPropPrice, type PlayerPropStat, type PlayerPropsBundle, type PostMatchGoalLine, type PostMatchGoalsCard, type PostMatchGoalsData, type PostMatchNextCard, type PostMatchNextData, type PostMatchResultCard, type PostMatchResultData, type PostMatchStatRow, type PostMatchStatsCard, type PostMatchStatsData, type PostMatchTopPerformerCard, type PostMatchTopPerformerData, type PresetComboCell, type PresetGrid, type PresetGridOptions, type PresetMarketCell, type PresetPick, type PresetSinglesCell, type ProgressEventData, type QualifiedType, RateLimitError, type ReasonToBetCard, type ReasonToBetData, type RestingFormCard, type RestingFormData, type RestingNextCard, type RestingNextData, type RestingSeasonCard, type RestingSeasonData, type RestingStandingsCard, type RestingStandingsData, SIGNAL_TYPE_CODES, SPORTS, type ScheduleGroup, type ScheduleMatch, type SchedulePayload, type ScheduleSport, type SignalEntityType, type SignalInput, type SignalType, type SlipSelection, type SlipSport, type SportSpec, type StatesPayload, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type SubmitPlayBody, type SubmitPlayResult, type TransferRow, type TransfersCard, type TransfersData, type TurnCompleteEventData, UpstreamError, type UserContext, type WhereToWatchCard, type WhereToWatchData, type WidgetEntityEventName, type WidgetEntityType, type WidgetEventInput, type WidgetEventName, type WidgetLogInput, type WidgetOpenEventInput, type WidgetOpenEventName, type WidgetPopupAskEventInput, type WidgetPopupAskEventName, type WidgetPopupEventInput, type WidgetPopupEventName, WidgetSdkError, type WireEvent, type WireSport, createEventLogger, createNdjsonParser, isAddToSlipResult, isLimitCode, matchKey, mayPinOrSlip, qualifiedId, slipSportOf, sportOf, toWireSport };
package/dist/index.js CHANGED
@@ -458,7 +458,8 @@ function toSignalWireBody(input) {
458
458
  operatorUserId: input.operatorUserId,
459
459
  anonymousUserId: input.anonymousUserId,
460
460
  dashboardLayout: input.dashboardLayout,
461
- tileIndex: input.tileIndex
461
+ tileIndex: input.tileIndex,
462
+ sport: input.sport
462
463
  };
463
464
  }
464
465
 
@@ -745,8 +746,8 @@ function isAddToSlipResult(v) {
745
746
 
746
747
  // src/sports.ts
747
748
  var SPORTS = {
748
- basketball: { slipPrefix: "bb:", monitorPrefix: "nba:", label: "NBA", slippable: true },
749
- americanfootball: { slipPrefix: "af:", monitorPrefix: "nfl:", label: "NFL", slippable: false }
749
+ basketball: { slipPrefix: "bb:", monitorPrefix: "nba:", label: "NBA", slippable: true, wireKey: "nba" },
750
+ americanfootball: { slipPrefix: "af:", monitorPrefix: "nfl:", label: "NFL", slippable: true, wireKey: void 0 }
750
751
  };
751
752
  function sportOf(v) {
752
753
  return typeof v === "string" && Object.prototype.hasOwnProperty.call(SPORTS, v) ? v : void 0;
@@ -759,6 +760,14 @@ function slipSportOf(v) {
759
760
  const sport = sportOf(v);
760
761
  return sport !== void 0 && SPORTS[sport].slippable ? sport : void 0;
761
762
  }
763
+ function toWireSport(v) {
764
+ const sport = sportOf(v);
765
+ return sport === void 0 ? void 0 : SPORTS[sport].wireKey;
766
+ }
767
+ function qualifiedId(sport, type, id) {
768
+ const wire = toWireSport(sport);
769
+ return wire ? `${wire}:${type}:${id}` : id;
770
+ }
762
771
  export {
763
772
  AuthError,
764
773
  Conversation,
@@ -780,7 +789,9 @@ export {
780
789
  isLimitCode,
781
790
  matchKey,
782
791
  mayPinOrSlip,
792
+ qualifiedId,
783
793
  slipSportOf,
784
- sportOf
794
+ sportOf,
795
+ toWireSport
785
796
  };
786
797
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/ndjson.ts","../src/chat.ts","../src/signals.ts","../src/conversation.ts","../src/eventLog.ts","../src/client.ts","../src/matchKey.ts","../src/types.ts","../src/sports.ts"],"sourcesContent":["export class WidgetSdkError extends Error {\n readonly code: string\n readonly status?: number\n constructor(message: string, code: string, status?: number) {\n super(message)\n this.name = new.target.name\n this.code = code\n this.status = status\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\nexport class AuthError extends WidgetSdkError {\n constructor(message = 'Invalid or missing public key') { super(message, 'unauthorized', 401) }\n}\nexport class ForbiddenError extends WidgetSdkError {\n constructor(message = 'Origin not allowed or widget disabled') { super(message, 'forbidden', 403) }\n}\nexport class RateLimitError extends WidgetSdkError {\n readonly retryAfter?: number\n constructor(retryAfter?: number, message = 'Rate limited') { super(message, 'rate_limited', 429); this.retryAfter = retryAfter }\n}\n// B4 Q7: the codes a brand's limit refuses with. Any other 429 stays a plain RateLimitError.\nexport const LIMIT_CODES = ['daily_cap', 'quota_exhausted', 'assistant_paused'] as const\nexport type LimitCode = (typeof LIMIT_CODES)[number]\nexport function isLimitCode(code: unknown): code is LimitCode {\n return typeof code === 'string' && (LIMIT_CODES as readonly string[]).includes(code)\n}\nexport interface LimitDetails {\n limitCode: LimitCode\n resetsAt?: string\n /** The brand's or the built-in text, already in the user's language. */\n message?: string\n}\nexport class LimitError extends RateLimitError {\n readonly limitCode: LimitCode\n readonly resetsAt?: string\n readonly limitMessage?: string\n constructor(details: LimitDetails, retryAfter?: number) {\n super(retryAfter, details.message ?? 'Limit reached')\n this.limitCode = details.limitCode\n this.resetsAt = details.resetsAt\n this.limitMessage = details.message\n }\n}\nexport class UpstreamError extends WidgetSdkError {\n constructor(status: number, message = 'Upstream error') { super(message, 'upstream_error', status) }\n}\nexport class NetworkError extends WidgetSdkError {\n readonly cause?: unknown\n constructor(message = 'Network request failed', cause?: unknown) { super(message, 'network_error'); this.cause = cause }\n}\nexport class ParseError extends WidgetSdkError {\n readonly line?: string\n constructor(message = 'Malformed NDJSON line', line?: string) { super(message, 'parse_error'); this.line = line }\n}\n","import { AuthError, ForbiddenError, isLimitCode, LimitError, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayBody, SubmitPlayResult,\n} from './events'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\n client?: string\n}\n\nexport function headersFor(cfg: ResolvedConfig, json: boolean): Record<string, string> {\n const h: Record<string, string> = json ? { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey } : { 'X-SS-Public-Key': cfg.publicKey }\n if (cfg.client) h['X-SS-Client'] = cfg.client\n return h\n}\n\nfunction endpoint(cfg: ResolvedConfig, path: string): string {\n return `${cfg.baseUrl.replace(/\\/+$/, '')}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`\n}\n\nexport function toWidgetError(status: number, retryAfterHeader: string | null): WidgetSdkError {\n switch (status) {\n case 401: return new AuthError()\n case 403: return new ForbiddenError()\n case 429: {\n const n = retryAfterHeader != null ? Number(retryAfterHeader) : undefined\n return new RateLimitError(Number.isFinite(n) ? (n as number) : undefined)\n }\n default: return new UpstreamError(status)\n }\n}\n\n// B4 Q7: a limit refusal is a 429 whose problem+json body names the limit. The gateway's own per-minute 429 sets\n// Retry-After without exposing it to browsers, so a missing header is normal: the body's retryAfterSeconds covers\n// it, and no countdown is shown when neither is present.\nexport async function chatError(res: Response): Promise<WidgetSdkError> {\n const base = toWidgetError(res.status, res.headers.get('Retry-After'))\n if (!(base instanceof RateLimitError)) return base\n let body: unknown\n try { body = await res.json() } catch { return base }\n if (typeof body !== 'object' || body === null) return base\n const b = body as Record<string, unknown>\n if (!isLimitCode(b.errorCode)) return base\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() !== '' ? v : undefined)\n const header = res.headers.get('Retry-After')?.trim()\n const headerRetry = header != null && /^\\d+$/.test(header) ? Number(header) : undefined\n const bodyRetry = typeof b.retryAfterSeconds === 'number' && Number.isFinite(b.retryAfterSeconds) && b.retryAfterSeconds >= 0 ? b.retryAfterSeconds : undefined\n return new LimitError(\n { limitCode: b.errorCode, resetsAt: text(b.resetsAt), message: text(b.message) },\n headerRetry ?? bodyRetry,\n )\n}\n\nfunction isAbort(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nasync function send(cfg: ResolvedConfig, path: string, body: object, signal?: AbortSignal): Promise<Response> {\n try {\n return await cfg.fetch(endpoint(cfg, path), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n signal,\n })\n } catch (error) {\n if (isAbort(error)) throw error\n throw new NetworkError('Network request failed', error)\n }\n}\n\nexport async function postChat(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): Promise<Response> {\n const res = await send(cfg, 'chat', input, signal)\n if (!res.ok || res.body == null) throw await chatError(res)\n return res\n}\n\nexport async function postSignal(cfg: ResolvedConfig, wireBody: object, signal?: AbortSignal): Promise<void> {\n const res = await send(cfg, 'signals', wireBody, signal)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\nexport async function postEvents(cfg: ResolvedConfig, batch: object): Promise<void> {\n const res = await send(cfg, 'events', batch)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\n// Best-effort tail flush on page hide/unload. Uses fetch keepalive (not sendBeacon) because the\n// gateway requires the X-SS-Public-Key header, which sendBeacon cannot set. Both the synchronous\n// call and the returned promise are guarded -- an async rejection (real network failure, or\n// Chrome's ~64KB keepalive body cap) must never surface as an unhandled rejection, since this\n// runs inside an operator-embedded widget during page-hide and would show up as noise in the\n// OPERATOR's own error monitoring.\nexport function postEventsKeepalive(cfg: ResolvedConfig, batch: object): void {\n try {\n void cfg.fetch(endpoint(cfg, 'events'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(batch),\n keepalive: true,\n }).catch(() => { /* best-effort tail flush -- swallow async rejection too */ })\n } catch {\n /* best-effort tail flush -- never throw on unload */\n }\n}\n\nexport async function getLiveDashboard(cfg: ResolvedConfig): Promise<ClubFanDashboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-dashboard'), { method: 'GET', headers: headersFor(cfg, false) })\n // 204 is the definitive \"not live / match over\" signal -- the poll loop stops on it.\n // Any other non-ok status (e.g. a transient 502/503/504) must throw rather than return\n // null, so the poll loop's per-tick try/catch retries on the next tick instead of stopping.\n if (res.status === 204) return null\n if (!res.ok) throw new Error(`live-dashboard ${res.status}`)\n return (await res.json()) as ClubFanDashboardPayload\n}\n\n// 404 is the definitive \"live monitor disabled for this operator\" signal -- the poll loop\n// stops and the tabs disable. Any other non-ok status must throw so the per-tick\n// try/catch retries next tick instead of silently disabling the feature.\nexport async function postLiveMonitor(cfg: ResolvedConfig, pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n const body: { pins: PinRef[]; locale?: string } = { pins }\n if (locale) body.locale = locale\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor ${res.status}`)\n return (await res.json()) as LiveMonitorSnapshot\n}\n\nexport async function postMarketOdds(\n cfg: ResolvedConfig, matchId: number, marketDeveloperName: string, sport?: 'basketball',\n): Promise<MarketOddsBlock | null> {\n const body: { matchId: number; marketDeveloperName: string; sport?: 'basketball' } = { matchId, marketDeveloperName }\n if (sport) body.sport = sport\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/market'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/market ${res.status}`)\n return (await res.json()) as MarketOddsBlock\n}\n\nexport async function postPlayerProps(cfg: ResolvedConfig, matchId: number): Promise<PlayerPropsBundle | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/props'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ matchId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/props ${res.status}`)\n return (await res.json()) as PlayerPropsBundle\n}\n\n// 404 mirrors postLiveMonitor: the definitive \"live monitor disabled for this operator\" signal.\n// Every other non-ok status throws so the caller's per-tick catch retries next tick.\nexport async function postSchedule(\n cfg: ResolvedConfig, localDate: string, utcOffsetMinutes: number,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<SchedulePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/schedule'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ['basketball'], operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/schedule ${res.status}`)\n return (await res.json()) as SchedulePayload\n}\n\nexport async function postLeagueStar(\n cfg: ResolvedConfig, competitionId: number, starred: boolean,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<LeagueStarResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `leagues/${competitionId}/star`), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ starred, operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leagues/star ${res.status}`)\n return (await res.json()) as LeagueStarResult\n}\n\nexport async function postStates(\n cfg: ResolvedConfig, matchIds: number[], nbaGameIds?: number[],\n): Promise<StatesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/states'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(nbaGameIds?.length ? { matchIds, nbaGameIds } : { matchIds }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/states ${res.status}`)\n return (await res.json()) as StatesPayload\n}\n\nfunction q(parts: Record<string, string | number | undefined>): string {\n const kept = Object.entries(parts)\n .filter(([, v]) => v !== undefined && v !== '')\n .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)\n return kept.length ? `?${kept.join('&')}` : ''\n}\n\nexport async function getGames(cfg: ResolvedConfig, operatorUserId?: string, gameDay?: string): Promise<GameListPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games' + q({ operatorUserId, gameDay })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`games ${res.status}`)\n return (await res.json()) as GameListPayload\n}\n\nexport async function getGameConfig(cfg: ResolvedConfig, gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}` + q({ fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-config ${res.status}`)\n return (await res.json()) as GameStatePayload\n}\n\nexport async function getGameResult(cfg: ResolvedConfig, gameId: string, operatorUserId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({ operatorUserId, fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-result ${res.status}`)\n return (await res.json()) as GameResultPayload\n}\n\nexport async function postPlay(cfg: ResolvedConfig, gameId: string, body: SubmitPlayBody, locale?: string): Promise<SubmitPlayResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`play ${res.status}`)\n return (await res.json()) as SubmitPlayResult\n}\n\nexport async function getLeaderboard(cfg: ResolvedConfig, operatorUserId?: string, week?: string): Promise<LeaderboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games/leaderboard' + q({ operatorUserId, week })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leaderboard ${res.status}`)\n return (await res.json()) as LeaderboardPayload\n}\n\nexport async function getClubFixtures(cfg: ResolvedConfig, competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/fixtures' + q({ competitionId, limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-fixtures ${res.status}`)\n return (await res.json()) as ClubFixturesPayload\n}\n\nexport async function getClubStandings(cfg: ResolvedConfig, competitionId?: number): Promise<ClubStandingsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/standings' + q({ competitionId })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-standings ${res.status}`)\n return (await res.json()) as ClubStandingsPayload\n}\n\nexport async function getClubSquad(cfg: ResolvedConfig): Promise<ClubSquadPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad ${res.status}`)\n return (await res.json()) as ClubSquadPayload\n}\n\nexport async function getClubSquadStats(cfg: ResolvedConfig): Promise<ClubSquadStatsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad/stats'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad-stats ${res.status}`)\n return (await res.json()) as ClubSquadStatsPayload\n}\n\nexport async function getClubPlayerDetail(cfg: ResolvedConfig, playerId: number): Promise<ClubPlayerDetailPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `club/player/${encodeURIComponent(String(playerId))}`), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-player ${res.status}`)\n return (await res.json()) as ClubPlayerDetailPayload\n}\n\nexport async function getClubRecords(cfg: ResolvedConfig, limit?: number): Promise<ClubRecordsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/records' + q({ limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-records ${res.status}`)\n return (await res.json()) as ClubRecordsPayload\n}\n\n// Onboarding presets stage 2 (contract §1). 404 is the definitive \"no presets for this visitor\"\n// answer (flag off, not a betting operator, or cool-off). 503 and every other non-ok status throw:\n// the widget keeps any grid it already has and asks again on the next panel open.\n// operatorUserId is optional, passed as the games routes pass it: the cool-off check (D3) needs it,\n// and a request without it is an anonymous visitor.\nexport async function getPricePresets(\n cfg: ResolvedConfig, locale: string, operatorUserId?: string, options?: PresetGridOptions,\n): Promise<PresetGrid | null> {\n const res = await cfg.fetch(endpoint(cfg, 'price-presets' + q({ locale, operatorUserId, pool: options?.pool })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`price-presets ${res.status}`)\n return (await res.json()) as PresetGrid\n}\n","import { ParseError } from './errors'\n\nexport interface NdjsonParser {\n push(text: string): unknown[]\n flush(): unknown[]\n}\n\nfunction parseLine(line: string): unknown | undefined {\n const trimmed = line.trim()\n if (trimmed === '') return undefined\n try {\n return JSON.parse(trimmed)\n } catch {\n throw new ParseError('Malformed NDJSON line', line)\n }\n}\n\nexport function createNdjsonParser(): NdjsonParser {\n let buffer = ''\n return {\n push(text: string): unknown[] {\n buffer += text\n const out: unknown[] = []\n let idx: number\n while ((idx = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, idx)\n buffer = buffer.slice(idx + 1)\n const parsed = parseLine(line)\n if (parsed !== undefined) out.push(parsed)\n }\n return out\n },\n flush(): unknown[] {\n const rest = buffer\n buffer = ''\n const parsed = parseLine(rest)\n return parsed === undefined ? [] : [parsed]\n },\n }\n}\n","import { WidgetSdkError } from './errors'\nimport type {\n ActionButtonEventData, ActionsLoadingEventData, AnswerEventData, ChatEvent,\n EntityCardEventData, IntentChipEventData, ProgressEventData, StreamErrorEventData, TurnCompleteEventData,\n} from './events'\nimport { postChat, type ResolvedConfig } from './http'\nimport { createNdjsonParser } from './ndjson'\nimport type { ChatInput } from './types'\n\nexport interface ChatCallbacks {\n onProgress?(data: ProgressEventData): void\n onAnswer?(data: AnswerEventData): void\n onEntityCard?(data: EntityCardEventData): void\n onActionButton?(data: ActionButtonEventData): void\n onIntentChip?(data: IntentChipEventData): void\n onActionsLoading?(data: ActionsLoadingEventData): void\n onError?(error: StreamErrorEventData | WidgetSdkError): void\n onComplete?(data: TurnCompleteEventData): void\n}\n\nexport interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {\n cancel(): void\n}\n\nfunction dispatch(ev: ChatEvent, cb: ChatCallbacks): void {\n switch (ev.type) {\n case 'progress': cb.onProgress?.(ev.data); break\n case 'answer': cb.onAnswer?.(ev.data); break\n case 'entity_card': cb.onEntityCard?.(ev.data); break\n case 'action_button': cb.onActionButton?.(ev.data); break\n case 'intent_chip': cb.onIntentChip?.(ev.data); break\n case 'actions_loading': cb.onActionsLoading?.(ev.data); break\n case 'turn_complete': cb.onComplete?.(ev.data); break\n case 'error': cb.onError?.(ev.data); break\n }\n}\n\nasync function* streamEvents(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): AsyncGenerator<ChatEvent> {\n const res = await postChat(cfg, input, signal)\n const reader = res.body!.getReader()\n const decoder = new TextDecoder()\n const parser = createNdjsonParser()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj as ChatEvent\n }\n for (const obj of parser.flush()) yield obj as ChatEvent\n } finally {\n await reader.cancel().catch(() => {})\n }\n}\n\nexport function runChat(\n cfg: ResolvedConfig,\n input: ChatInput,\n callbacks?: ChatCallbacks,\n opts?: { signal?: AbortSignal; tap?: (ev: ChatEvent) => void },\n): ChatHandle {\n const controller = new AbortController()\n const external = opts?.signal\n if (external) {\n if (external.aborted) controller.abort()\n else external.addEventListener('abort', () => controller.abort(), { once: true })\n }\n\n async function* source(): AsyncGenerator<ChatEvent> {\n for await (const ev of streamEvents(cfg, input, controller.signal)) {\n opts?.tap?.(ev)\n yield ev\n }\n }\n\n const iterator = source()\n let consumed = false\n\n async function drive(): Promise<void> {\n try {\n for await (const ev of iterator) { if (callbacks) dispatch(ev, callbacks) }\n } catch (error) {\n if (callbacks?.onError && error instanceof WidgetSdkError) { callbacks.onError(error); return }\n throw error\n }\n }\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ChatEvent> {\n if (consumed) throw new Error('chat stream already consumed')\n consumed = true\n return iterator\n },\n then<TResult1 = void, TResult2 = never>(\n onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n if (consumed) return Promise.resolve().then(onfulfilled, onrejected)\n consumed = true\n return drive().then(onfulfilled, onrejected)\n },\n cancel(): void { controller.abort() },\n }\n}\n","import type { SignalEntityType, SignalInput, SignalType } from './types'\n\nexport const SIGNAL_TYPE_CODES: Record<SignalType, number> = {\n MatchPageView: 1, PlayerPageView: 2, TeamPageView: 3, MarketView: 4,\n SearchQuery: 5, SessionDepth: 6, TimeOnPage: 7, InsightViewed: 8,\n InsightMarketClicked: 9, BetPlacedFromInsight: 10, InsightScrollDepth: 11,\n ToolCall: 12, EntityMention: 13, Handoff: 14, FollowUpQuery: 15, RecommendationDismissed: 16,\n}\n\nexport const ENTITY_TYPE_CODES: Record<SignalEntityType, number> = {\n Match: 1, Team: 2, Player: 3, Competition: 4, Market: 5,\n Article: 6, Session: 7, Query: 8, Conversation: 9,\n}\n\nexport function toSignalWireBody(input: SignalInput): {\n signalType: number; entityType: number; entityName?: string; entityId?: string\n operatorUserId?: string; anonymousUserId?: string; dashboardLayout?: string; tileIndex?: number\n} {\n const signalType = SIGNAL_TYPE_CODES[input.signalType]\n const entityType = ENTITY_TYPE_CODES[input.entityType]\n if (signalType === undefined) throw new Error(`Unknown signalType: ${String(input.signalType)}`)\n if (entityType === undefined) throw new Error(`Unknown entityType: ${String(input.entityType)}`)\n return {\n signalType, entityType, entityName: input.entityName, entityId: input.entityId,\n operatorUserId: input.operatorUserId, anonymousUserId: input.anonymousUserId,\n dashboardLayout: input.dashboardLayout, tileIndex: input.tileIndex,\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayResult,\n} from './events'\nimport {\n getClubFixtures, getClubPlayerDetail, getClubRecords, getClubSquad, getClubSquadStats, getClubStandings, getGameConfig, getGameResult, getGames, getLeaderboard, getLiveDashboard, getPricePresets,\n postLeagueStar, postLiveMonitor, postMarketOdds, postPlayerProps, postPlay, postSchedule, postSignal, postStates, type ResolvedConfig,\n} from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: SignalInput): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n const anonymousUserId = operatorUserId ? undefined : (input.anonymousUserId ?? this.context?.anonymousUserId)\n if (!operatorUserId && !anonymousUserId) {\n throw new Error('operatorUserId or anonymousUserId is required (set it on conversation() or pass it to sendSignal)')\n }\n if (!input.entityId && !input.entityName) {\n throw new Error('entityId or entityName is required')\n }\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId, anonymousUserId }))\n }\n\n getLiveDashboard(): Promise<ClubFanDashboardPayload | null> {\n return getLiveDashboard(this.cfg)\n }\n\n getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n return postLiveMonitor(this.cfg, pins, locale)\n }\n\n getMarketOdds(matchId: number, marketDeveloperName: string, sport?: 'basketball'): Promise<MarketOddsBlock | null> {\n return postMarketOdds(this.cfg, matchId, marketDeveloperName, sport)\n }\n\n getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null> {\n return postPlayerProps(this.cfg, matchId)\n }\n\n getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null> {\n return getPricePresets(this.cfg, locale, this.context?.operatorUserId, options)\n }\n\n getSchedule(\n localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<SchedulePayload | null> {\n return postSchedule(this.cfg, localDate, utcOffsetMinutes, operatorUserId, anonymousUserId)\n }\n\n starLeague(\n competitionId: number, starred: boolean, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<LeagueStarResult | null> {\n return postLeagueStar(this.cfg, competitionId, starred, operatorUserId, anonymousUserId)\n }\n\n getStates(matchIds: number[], nbaGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds)\n }\n\n getGames(gameDay?: string): Promise<GameListPayload | null> {\n return getGames(this.cfg, this.context?.operatorUserId, gameDay)\n }\n\n getGameConfig(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n return getGameConfig(this.cfg, gameId, fixtureId, gameDay, locale)\n }\n\n getGameResult(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return getGameResult(this.cfg, gameId, operatorUserId, fixtureId, gameDay, locale)\n }\n\n postPlay(gameId: string, answerJson: string, gameDay: string, fixtureId?: number, locale?: string): Promise<SubmitPlayResult | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return postPlay(this.cfg, gameId, { operatorUserId, gameDay, answerJson, fixtureId }, locale)\n }\n\n getLeaderboard(week?: string): Promise<LeaderboardPayload | null> {\n return getLeaderboard(this.cfg, this.context?.operatorUserId, week)\n }\n\n getClubFixtures(competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n return getClubFixtures(this.cfg, competitionId, limit)\n }\n getClubStandings(competitionId?: number): Promise<ClubStandingsPayload | null> {\n return getClubStandings(this.cfg, competitionId)\n }\n getClubSquad(): Promise<ClubSquadPayload | null> {\n return getClubSquad(this.cfg)\n }\n getClubSquadStats(): Promise<ClubSquadStatsPayload | null> {\n return getClubSquadStats(this.cfg)\n }\n getClubPlayerDetail(playerId: number): Promise<ClubPlayerDetailPayload | null> {\n return getClubPlayerDetail(this.cfg, playerId)\n }\n getClubRecords(limit?: number): Promise<ClubRecordsPayload | null> {\n return getClubRecords(this.cfg, limit)\n }\n}\n","export type WidgetEntityEventName =\n | 'pin_add' | 'pin_remove' | 'slip_click' | 'slip_result'\n | 'insight_expand' | 'tile_tap' | 'chip_tap'\n | 'slip_remove' | 'bet_placed' | 'match_view' | 'match_open'\n\nexport type WidgetPopupEventName = 'popup_shown' | 'popup_opened' | 'popup_dismissed'\n\nexport type WidgetPopupAskEventName = 'popup_ask_tap'\n\nexport type WidgetOpenEventName = 'widget_open'\n\nexport type WidgetEventName = WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName\n\nexport type WidgetEntityType = 'match' | 'team' | 'player' | 'competition' | 'market'\n\nexport interface WidgetEventInput {\n name: WidgetEntityEventName\n entityType: WidgetEntityType\n entityId?: string\n entityName?: string\n marketDeveloperName?: string\n outcome?: string\n /** Football match id of the slip selection (slip_click / slip_result). */\n matchId?: number\n /** The raw odds label as stored (\"Home\", \"Over\", \"Home/Draw\"), never a joined display string. Max 64. */\n selection?: string\n /** The raw line (\"2.5\"). Max 32; omit when empty. */\n line?: string\n /** Decimal price shown when the selection was added. */\n odds?: number\n}\n\n/** Launcher popup telemetry: counted server-side, never tied to an entity. */\nexport type WidgetPopupEventInput =\n { name: WidgetPopupEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\n/** A tap on one of the launcher bubble's asks. `outcome` carries the ask's position, \"0\" or \"1\"\n * (contract §5): the gateway forwards only the fields of its own event model, and outcome is its\n * one free-text field. */\nexport type WidgetPopupAskEventInput =\n { name: WidgetPopupAskEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\n/** The panel opening: entity-free, each open is added to the user's count for the day. */\nexport type WidgetOpenEventInput =\n { name: WidgetOpenEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\nexport type WidgetLogInput = WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput\n\nexport type WireEvent = WidgetLogInput & {\n seq: number\n at: number\n}\n\nexport interface EventBatch {\n v: 1\n sessionId: string\n conversationId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /**\n * Events dropped after exhausting delivery attempts during a PRIOR flush cycle — not a count of\n * this batch's own events. Rides whichever batch is built next after the drop, then is omitted\n * (0/undefined) once a clean cycle passes without a new failure.\n */\n dropped?: number\n /**\n * Failed delivery attempts from a PRIOR flush cycle — not retries of this batch's own events.\n * Rides whichever batch is built next after the failure, then is omitted (0/undefined) once a\n * clean cycle passes without a new failure.\n */\n retries?: number\n events: WireEvent[]\n}\n\nexport interface EventLoggerOptions {\n /** Normal delivery (fetch). Rejecting triggers the retry/backoff loop. */\n flush: (batch: EventBatch) => Promise<void>\n /** Best-effort tail flush on page hide/unload (fetch keepalive). Never awaited. */\n flushKeepalive: (batch: EventBatch) => void\n /** Injectable clock (tests). Defaults to Date.now. */\n now?: () => number\n batchIntervalMs?: number\n maxBatch?: number\n maxAttempts?: number\n}\n\nexport interface EventLogger {\n log(input: WidgetLogInput): void\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void\n flushNow(): Promise<void>\n flushOnHide(): void\n dispose(): void\n /** Undoes dispose(). React StrictMode runs an effect's cleanup and then its setup again on the\n * same logger, so the widget's setup has to be able to bring a disposed logger back. */\n resume(): void\n}\n\nconst IMMEDIATE: ReadonlySet<WidgetEventName> = new Set([\n 'pin_add', 'pin_remove', 'slip_click', 'slip_result', 'slip_remove', 'bet_placed',\n])\n\n// Queued without arming the batch timer: the event leaves with the next flush of any cause. A match\n// page view fires for every visitor, so it must never start a request of its own.\nconst DEFERRED: ReadonlySet<WidgetEventName> = new Set(['match_view'])\n\nconst DEFAULT_BATCH_INTERVAL_MS = 10_000\nconst DEFAULT_MAX_BATCH = 50\nconst DEFAULT_MAX_ATTEMPTS = 3\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction makeSessionId(): string {\n const c: Crypto | undefined = globalThis.crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`\n}\n\nclass EventLoggerImpl implements EventLogger {\n private readonly sessionId = makeSessionId()\n private readonly now: () => number\n private readonly batchIntervalMs: number\n private readonly maxBatch: number\n private readonly maxAttempts: number\n\n private queue: WireEvent[] = []\n private seq = 0\n private retries = 0\n private dropped = 0\n private identity: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string } = {}\n private timer: ReturnType<typeof setTimeout> | null = null\n private inFlight: Promise<void> | null = null\n private disposed = false\n\n constructor(private readonly opts: EventLoggerOptions) {\n this.now = opts.now ?? (() => Date.now())\n this.batchIntervalMs = opts.batchIntervalMs ?? DEFAULT_BATCH_INTERVAL_MS\n this.maxBatch = opts.maxBatch ?? DEFAULT_MAX_BATCH\n this.maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n }\n\n log(input: WidgetLogInput): void {\n if (this.disposed) return\n const event: WireEvent = { ...input, seq: ++this.seq, at: this.now() }\n this.queue.push(event)\n if (IMMEDIATE.has(input.name)) {\n this.trigger()\n } else if (this.queue.length >= this.maxBatch) {\n this.trigger()\n } else if (!DEFERRED.has(input.name)) {\n this.armTimer()\n }\n }\n\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void {\n this.identity = { ...this.identity, ...id }\n }\n\n async flushNow(): Promise<void> {\n if (this.inFlight) await this.inFlight\n if (this.queue.length > 0) await this.doFlush()\n }\n\n flushOnHide(): void {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n this.opts.flushKeepalive(batch)\n }\n\n dispose(): void {\n this.disposed = true\n this.clearTimer()\n }\n\n resume(): void {\n this.disposed = false\n }\n\n private armTimer(): void {\n if (this.timer !== null) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.trigger()\n }, this.batchIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer === null) return\n clearTimeout(this.timer)\n this.timer = null\n }\n\n private trigger(): void {\n if (this.disposed) return\n if (this.inFlight) return\n this.inFlight = this.doFlush().finally(() => {\n this.inFlight = null\n // An immediate (or maxBatch-triggered) log() call that arrived while this flush was\n // in-flight was a no-op above -- drain it now instead of stranding it until some later\n // log()/flushNow()/dispose() call. Guarded by the disposed check at the top of trigger()\n // itself, so a straggler queued just before dispose() does not fire a flush after it.\n if (this.queue.length > 0) this.trigger()\n })\n }\n\n /**\n * Snapshots the queue + carry-over counters (see EventBatch.dropped/retries) into a batch and\n * resets both for the next cycle. Returns null only when there is truly nothing to report --\n * an empty queue AND no pending dropped/retries -- so a pending counter-only report (queue\n * drained by an exhausted flush, nothing logged since) still gets built and delivered.\n */\n private buildBatch(): EventBatch | null {\n if (this.queue.length === 0 && this.retries === 0 && this.dropped === 0) return null\n const events = this.queue\n this.queue = []\n const batch: EventBatch = { v: 1, sessionId: this.sessionId, ...this.identity, events }\n if (this.retries > 0) batch.retries = this.retries\n if (this.dropped > 0) batch.dropped = this.dropped\n this.retries = 0\n this.dropped = 0\n return batch\n }\n\n private async doFlush(): Promise<void> {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n try {\n await this.opts.flush(batch)\n return\n } catch {\n this.retries++\n if (attempt >= this.maxAttempts) {\n this.dropped += batch.events.length\n return\n }\n await delay(2 ** attempt * 50)\n }\n }\n }\n}\n\nexport function createEventLogger(opts: EventLoggerOptions): EventLogger {\n return new EventLoggerImpl(opts)\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { createEventLogger, type EventLogger } from './eventLog'\nimport { postEvents, postEventsKeepalive, postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, StatsWidgetClientOptions, UserContext } from './types'\n\nconst DEFAULT_BASE_URL = 'https://widget.sensiblestats.com'\n\nexport class StatsWidgetClient {\n private readonly cfg: ResolvedConfig\n\n constructor(options: StatsWidgetClientOptions) {\n if (!options.operatorId) throw new Error('operatorId is required')\n if (!options.publicKey) throw new Error('publicKey is required')\n const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined)\n if (!fetchImpl) throw new Error('No fetch implementation available; pass options.fetch')\n this.cfg = {\n operatorId: options.operatorId,\n publicKey: options.publicKey,\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetch: fetchImpl,\n client: options.client,\n }\n }\n\n chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n return runChat(this.cfg, input, callbacks)\n }\n\n async sendSignal(input: SignalInput): Promise<void> {\n await postSignal(this.cfg, toSignalWireBody(input))\n }\n\n conversation(context?: UserContext): Conversation {\n return new Conversation(this.cfg, context)\n }\n\n createEventLogger(identity?: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): EventLogger {\n const logger = createEventLogger({\n flush: (batch) => postEvents(this.cfg, batch),\n flushKeepalive: (batch) => postEventsKeepalive(this.cfg, batch),\n })\n if (identity) logger.setIdentity(identity)\n return logger\n }\n}\n","export function matchKey(sport: string | undefined, id: number): string {\n return `${sport ?? 'football'}:${id}`\n}\n","import type { SlipSport } from './sports'\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>\n\nexport interface StatsWidgetClientOptions {\n operatorId: string\n publicKey: string\n baseUrl?: string\n /** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */\n fetch?: FetchLike\n /** Sent as X-SS-Client; set by widget-react. */\n client?: string\n}\n\nexport interface UserContext {\n operatorUserId?: string\n defaultLanguage?: string\n anonymousUserId?: string\n}\n\nexport interface ChatGrounding {\n kind?: string\n matchId?: number\n opponentTeamId?: number\n teamId?: number\n competitionId?: number\n season?: string\n subject?: string\n personaHint?: string\n sport?: string\n}\n\n/** The page the widget sits on. Sent on greeting requests only, so the greeting can lead with that page. */\nexport interface PageContext {\n sport: 'football' | 'nba'\n kind?: 'section' | 'competition' | 'match'\n matchId?: string | number\n competitionId?: string | number\n}\n\n/** Onboarding presets stage 2 (contract §3): what a tool's Send asked for. Sent only from a tool's\n * Send, beside the full sentence in `message`. The server ignores it unless every value is valid. */\nexport interface ChatPreset {\n kind: 'max_price' | 'min_price' | 'combo' | 'market'\n /** max_price, min_price */\n price?: number\n /** max_price, min_price */\n count?: number\n /** combo */\n total?: number\n /** combo */\n legs?: number\n /** market */\n marketDeveloperName?: string\n /** The picks or legs the tool showed, in the order shown (R12: the answer reprices exactly these). */\n matchOddsIds: number[]\n /** The same picks' matchId, index for index with matchOddsIds (from the grid). */\n matchIds: number[]\n}\n\nexport interface ChatInput {\n message: string\n conversationId?: string\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap). Authoritative over `message` when present. */\n actionRef?: string\n userContext?: UserContext\n grounding?: ChatGrounding\n /** Features this client can draw (e.g. \"price_presets\"). The server sends nothing that needs a\n * feature the list does not name; an absent list means today's responses. */\n clientCapabilities?: string[]\n /** Onboarding presets stage 2: set only by a preset tool's Send (contract §3). */\n preset?: ChatPreset\n page?: PageContext\n}\n\nexport type SignalType =\n | 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView'\n | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed'\n | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth'\n | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed'\n\nexport type SignalEntityType =\n | 'Match' | 'Team' | 'Player' | 'Competition' | 'Market'\n | 'Article' | 'Session' | 'Query' | 'Conversation'\n\nexport interface SignalInput {\n signalType: SignalType\n entityType: SignalEntityType\n /** Either this or entityId is required -- an operator's UI mostly knows a display name. */\n entityName?: string\n /** Either this or entityName is required -- a dashboard tile knows its entity by id. */\n entityId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /** Greeting dashboard layout this signal came from, when it is a dashboard tap. */\n dashboardLayout?: string\n /** Zero-based tile position within the dashboard, when it is a dashboard tap. */\n tileIndex?: number\n}\n\nexport type { SlipSport }\n\nexport interface SlipSelection {\n matchOddsId: number\n matchId: number\n oddsDecimal: number\n quotedAtUtc?: string\n insightId?: string\n conversationId?: string\n sport?: SlipSport\n}\n\nexport type AddToSlipRejectReason =\n | 'suspended' | 'closed' | 'login_required'\n | 'not_found' | 'limit' | 'unsupported'\n\nexport type AddToSlipResult =\n | { status: 'added'; slip?: { selectionCount: number; totalOddsDecimal?: number } }\n | { status: 'duplicate' }\n | { status: 'price_changed'; newOddsDecimal: number; accepted: boolean }\n | { status: 'rejected'; reason: AddToSlipRejectReason; message?: string }\n\nexport type AddToSlipHandler = (\n selection: SlipSelection,\n) => Promise<AddToSlipResult | void> | AddToSlipResult | void\n\nconst REJECT_REASONS = ['suspended', 'closed', 'login_required', 'not_found', 'limit', 'unsupported']\n\nexport function isAddToSlipResult(v: unknown): v is AddToSlipResult {\n if (typeof v !== 'object' || v === null) return false\n const o = v as Record<string, unknown>\n switch (o.status) {\n case 'added':\n case 'duplicate':\n return true\n case 'price_changed':\n return typeof o.newOddsDecimal === 'number'\n && Number.isFinite(o.newOddsDecimal)\n && typeof o.accepted === 'boolean'\n case 'rejected':\n return typeof o.reason === 'string'\n && REJECT_REASONS.includes(o.reason)\n default:\n return false\n }\n}\n","export interface SportSpec { readonly slipPrefix: string; readonly monitorPrefix: string; readonly label: string; readonly slippable: boolean }\n\nexport const SPORTS = {\n basketball: { slipPrefix: 'bb:', monitorPrefix: 'nba:', label: 'NBA', slippable: true },\n americanfootball: { slipPrefix: 'af:', monitorPrefix: 'nfl:', label: 'NFL', slippable: false },\n} as const satisfies Record<string, SportSpec>\n\nexport type NonFootballSport = keyof typeof SPORTS\n/** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */\nexport type SlipSport = { [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never }[NonFootballSport]\n\n/** undefined means football: every sport the map does not know is football. */\nexport function sportOf(v: unknown): NonFootballSport | undefined {\n return typeof v === 'string' && Object.prototype.hasOwnProperty.call(SPORTS, v) ? (v as NonFootballSport) : undefined\n}\n\n/** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */\nexport function mayPinOrSlip(v: unknown): boolean {\n const sport = sportOf(v)\n return sport === undefined || SPORTS[sport].slippable\n}\n\n/** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */\nexport function slipSportOf(v: unknown): SlipSport | undefined {\n const sport = sportOf(v)\n return sport !== undefined && SPORTS[sport].slippable ? (sport as SlipSport) : undefined\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/ndjson.ts","../src/chat.ts","../src/signals.ts","../src/conversation.ts","../src/eventLog.ts","../src/client.ts","../src/matchKey.ts","../src/types.ts","../src/sports.ts"],"sourcesContent":["export class WidgetSdkError extends Error {\n readonly code: string\n readonly status?: number\n constructor(message: string, code: string, status?: number) {\n super(message)\n this.name = new.target.name\n this.code = code\n this.status = status\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\nexport class AuthError extends WidgetSdkError {\n constructor(message = 'Invalid or missing public key') { super(message, 'unauthorized', 401) }\n}\nexport class ForbiddenError extends WidgetSdkError {\n constructor(message = 'Origin not allowed or widget disabled') { super(message, 'forbidden', 403) }\n}\nexport class RateLimitError extends WidgetSdkError {\n readonly retryAfter?: number\n constructor(retryAfter?: number, message = 'Rate limited') { super(message, 'rate_limited', 429); this.retryAfter = retryAfter }\n}\n// B4 Q7: the codes a brand's limit refuses with. Any other 429 stays a plain RateLimitError.\nexport const LIMIT_CODES = ['daily_cap', 'quota_exhausted', 'assistant_paused'] as const\nexport type LimitCode = (typeof LIMIT_CODES)[number]\nexport function isLimitCode(code: unknown): code is LimitCode {\n return typeof code === 'string' && (LIMIT_CODES as readonly string[]).includes(code)\n}\nexport interface LimitDetails {\n limitCode: LimitCode\n resetsAt?: string\n /** The brand's or the built-in text, already in the user's language. */\n message?: string\n}\nexport class LimitError extends RateLimitError {\n readonly limitCode: LimitCode\n readonly resetsAt?: string\n readonly limitMessage?: string\n constructor(details: LimitDetails, retryAfter?: number) {\n super(retryAfter, details.message ?? 'Limit reached')\n this.limitCode = details.limitCode\n this.resetsAt = details.resetsAt\n this.limitMessage = details.message\n }\n}\nexport class UpstreamError extends WidgetSdkError {\n constructor(status: number, message = 'Upstream error') { super(message, 'upstream_error', status) }\n}\nexport class NetworkError extends WidgetSdkError {\n readonly cause?: unknown\n constructor(message = 'Network request failed', cause?: unknown) { super(message, 'network_error'); this.cause = cause }\n}\nexport class ParseError extends WidgetSdkError {\n readonly line?: string\n constructor(message = 'Malformed NDJSON line', line?: string) { super(message, 'parse_error'); this.line = line }\n}\n","import { AuthError, ForbiddenError, isLimitCode, LimitError, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayBody, SubmitPlayResult,\n} from './events'\nimport type { SlipSport } from './sports'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\n client?: string\n}\n\nexport function headersFor(cfg: ResolvedConfig, json: boolean): Record<string, string> {\n const h: Record<string, string> = json ? { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey } : { 'X-SS-Public-Key': cfg.publicKey }\n if (cfg.client) h['X-SS-Client'] = cfg.client\n return h\n}\n\nfunction endpoint(cfg: ResolvedConfig, path: string): string {\n return `${cfg.baseUrl.replace(/\\/+$/, '')}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`\n}\n\nexport function toWidgetError(status: number, retryAfterHeader: string | null): WidgetSdkError {\n switch (status) {\n case 401: return new AuthError()\n case 403: return new ForbiddenError()\n case 429: {\n const n = retryAfterHeader != null ? Number(retryAfterHeader) : undefined\n return new RateLimitError(Number.isFinite(n) ? (n as number) : undefined)\n }\n default: return new UpstreamError(status)\n }\n}\n\n// B4 Q7: a limit refusal is a 429 whose problem+json body names the limit. The gateway's own per-minute 429 sets\n// Retry-After without exposing it to browsers, so a missing header is normal: the body's retryAfterSeconds covers\n// it, and no countdown is shown when neither is present.\nexport async function chatError(res: Response): Promise<WidgetSdkError> {\n const base = toWidgetError(res.status, res.headers.get('Retry-After'))\n if (!(base instanceof RateLimitError)) return base\n let body: unknown\n try { body = await res.json() } catch { return base }\n if (typeof body !== 'object' || body === null) return base\n const b = body as Record<string, unknown>\n if (!isLimitCode(b.errorCode)) return base\n const text = (v: unknown): string | undefined => (typeof v === 'string' && v.trim() !== '' ? v : undefined)\n const header = res.headers.get('Retry-After')?.trim()\n const headerRetry = header != null && /^\\d+$/.test(header) ? Number(header) : undefined\n const bodyRetry = typeof b.retryAfterSeconds === 'number' && Number.isFinite(b.retryAfterSeconds) && b.retryAfterSeconds >= 0 ? b.retryAfterSeconds : undefined\n return new LimitError(\n { limitCode: b.errorCode, resetsAt: text(b.resetsAt), message: text(b.message) },\n headerRetry ?? bodyRetry,\n )\n}\n\nfunction isAbort(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nasync function send(cfg: ResolvedConfig, path: string, body: object, signal?: AbortSignal): Promise<Response> {\n try {\n return await cfg.fetch(endpoint(cfg, path), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n signal,\n })\n } catch (error) {\n if (isAbort(error)) throw error\n throw new NetworkError('Network request failed', error)\n }\n}\n\nexport async function postChat(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): Promise<Response> {\n const res = await send(cfg, 'chat', input, signal)\n if (!res.ok || res.body == null) throw await chatError(res)\n return res\n}\n\nexport async function postSignal(cfg: ResolvedConfig, wireBody: object, signal?: AbortSignal): Promise<void> {\n const res = await send(cfg, 'signals', wireBody, signal)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\nexport async function postEvents(cfg: ResolvedConfig, batch: object): Promise<void> {\n const res = await send(cfg, 'events', batch)\n if (!res.ok) throw toWidgetError(res.status, res.headers.get('Retry-After'))\n}\n\n// Best-effort tail flush on page hide/unload. Uses fetch keepalive (not sendBeacon) because the\n// gateway requires the X-SS-Public-Key header, which sendBeacon cannot set. Both the synchronous\n// call and the returned promise are guarded -- an async rejection (real network failure, or\n// Chrome's ~64KB keepalive body cap) must never surface as an unhandled rejection, since this\n// runs inside an operator-embedded widget during page-hide and would show up as noise in the\n// OPERATOR's own error monitoring.\nexport function postEventsKeepalive(cfg: ResolvedConfig, batch: object): void {\n try {\n void cfg.fetch(endpoint(cfg, 'events'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(batch),\n keepalive: true,\n }).catch(() => { /* best-effort tail flush -- swallow async rejection too */ })\n } catch {\n /* best-effort tail flush -- never throw on unload */\n }\n}\n\nexport async function getLiveDashboard(cfg: ResolvedConfig): Promise<ClubFanDashboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-dashboard'), { method: 'GET', headers: headersFor(cfg, false) })\n // 204 is the definitive \"not live / match over\" signal -- the poll loop stops on it.\n // Any other non-ok status (e.g. a transient 502/503/504) must throw rather than return\n // null, so the poll loop's per-tick try/catch retries on the next tick instead of stopping.\n if (res.status === 204) return null\n if (!res.ok) throw new Error(`live-dashboard ${res.status}`)\n return (await res.json()) as ClubFanDashboardPayload\n}\n\n// 404 is the definitive \"live monitor disabled for this operator\" signal -- the poll loop\n// stops and the tabs disable. Any other non-ok status must throw so the per-tick\n// try/catch retries next tick instead of silently disabling the feature.\nexport async function postLiveMonitor(cfg: ResolvedConfig, pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n const body: { pins: PinRef[]; locale?: string } = { pins }\n if (locale) body.locale = locale\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor ${res.status}`)\n return (await res.json()) as LiveMonitorSnapshot\n}\n\nexport async function postMarketOdds(\n cfg: ResolvedConfig, matchId: number, marketDeveloperName: string, sport?: SlipSport,\n): Promise<MarketOddsBlock | null> {\n const body: { matchId: number; marketDeveloperName: string; sport?: SlipSport } = { matchId, marketDeveloperName }\n if (sport) body.sport = sport\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/market'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/market ${res.status}`)\n return (await res.json()) as MarketOddsBlock\n}\n\nexport async function postPlayerProps(cfg: ResolvedConfig, matchId: number): Promise<PlayerPropsBundle | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/props'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ matchId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/props ${res.status}`)\n return (await res.json()) as PlayerPropsBundle\n}\n\n// 404 mirrors postLiveMonitor: the definitive \"live monitor disabled for this operator\" signal.\n// Every other non-ok status throws so the caller's per-tick catch retries next tick.\nexport async function postSchedule(\n cfg: ResolvedConfig, localDate: string, utcOffsetMinutes: number,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<SchedulePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/schedule'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ['basketball'], operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/schedule ${res.status}`)\n return (await res.json()) as SchedulePayload\n}\n\nexport async function postLeagueStar(\n cfg: ResolvedConfig, competitionId: number, starred: boolean,\n operatorUserId?: string, anonymousUserId?: string,\n): Promise<LeagueStarResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `leagues/${competitionId}/star`), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify({ starred, operatorUserId, anonymousUserId }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leagues/star ${res.status}`)\n return (await res.json()) as LeagueStarResult\n}\n\nexport async function postStates(\n cfg: ResolvedConfig, matchIds: number[], nbaGameIds?: number[],\n): Promise<StatesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'live-monitor/states'), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(nbaGameIds?.length ? { matchIds, nbaGameIds } : { matchIds }),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`live-monitor/states ${res.status}`)\n return (await res.json()) as StatesPayload\n}\n\nfunction q(parts: Record<string, string | number | undefined>): string {\n const kept = Object.entries(parts)\n .filter(([, v]) => v !== undefined && v !== '')\n .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)\n return kept.length ? `?${kept.join('&')}` : ''\n}\n\nexport async function getGames(cfg: ResolvedConfig, operatorUserId?: string, gameDay?: string): Promise<GameListPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games' + q({ operatorUserId, gameDay })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`games ${res.status}`)\n return (await res.json()) as GameListPayload\n}\n\nexport async function getGameConfig(cfg: ResolvedConfig, gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}` + q({ fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-config ${res.status}`)\n return (await res.json()) as GameStatePayload\n}\n\nexport async function getGameResult(cfg: ResolvedConfig, gameId: string, operatorUserId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({ operatorUserId, fixtureId, gameDay, locale })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`game-result ${res.status}`)\n return (await res.json()) as GameResultPayload\n}\n\nexport async function postPlay(cfg: ResolvedConfig, gameId: string, body: SubmitPlayBody, locale?: string): Promise<SubmitPlayResult | null> {\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {\n method: 'POST',\n headers: headersFor(cfg, true),\n body: JSON.stringify(body),\n })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`play ${res.status}`)\n return (await res.json()) as SubmitPlayResult\n}\n\nexport async function getLeaderboard(cfg: ResolvedConfig, operatorUserId?: string, week?: string): Promise<LeaderboardPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'games/leaderboard' + q({ operatorUserId, week })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`leaderboard ${res.status}`)\n return (await res.json()) as LeaderboardPayload\n}\n\nexport async function getClubFixtures(cfg: ResolvedConfig, competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/fixtures' + q({ competitionId, limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-fixtures ${res.status}`)\n return (await res.json()) as ClubFixturesPayload\n}\n\nexport async function getClubStandings(cfg: ResolvedConfig, competitionId?: number): Promise<ClubStandingsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/standings' + q({ competitionId })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-standings ${res.status}`)\n return (await res.json()) as ClubStandingsPayload\n}\n\nexport async function getClubSquad(cfg: ResolvedConfig): Promise<ClubSquadPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad ${res.status}`)\n return (await res.json()) as ClubSquadPayload\n}\n\nexport async function getClubSquadStats(cfg: ResolvedConfig): Promise<ClubSquadStatsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/squad/stats'), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-squad-stats ${res.status}`)\n return (await res.json()) as ClubSquadStatsPayload\n}\n\nexport async function getClubPlayerDetail(cfg: ResolvedConfig, playerId: number): Promise<ClubPlayerDetailPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, `club/player/${encodeURIComponent(String(playerId))}`), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-player ${res.status}`)\n return (await res.json()) as ClubPlayerDetailPayload\n}\n\nexport async function getClubRecords(cfg: ResolvedConfig, limit?: number): Promise<ClubRecordsPayload | null> {\n const res = await cfg.fetch(endpoint(cfg, 'club/records' + q({ limit })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`club-records ${res.status}`)\n return (await res.json()) as ClubRecordsPayload\n}\n\n// Onboarding presets stage 2 (contract §1). 404 is the definitive \"no presets for this visitor\"\n// answer (flag off, not a betting operator, or cool-off). 503 and every other non-ok status throw:\n// the widget keeps any grid it already has and asks again on the next panel open.\n// operatorUserId is optional, passed as the games routes pass it: the cool-off check (D3) needs it,\n// and a request without it is an anonymous visitor.\nexport async function getPricePresets(\n cfg: ResolvedConfig, locale: string, operatorUserId?: string, options?: PresetGridOptions,\n): Promise<PresetGrid | null> {\n const res = await cfg.fetch(endpoint(cfg, 'price-presets' + q({ locale, operatorUserId, pool: options?.pool })), { method: 'GET', headers: headersFor(cfg, false) })\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`price-presets ${res.status}`)\n return (await res.json()) as PresetGrid\n}\n","import { ParseError } from './errors'\n\nexport interface NdjsonParser {\n push(text: string): unknown[]\n flush(): unknown[]\n}\n\nfunction parseLine(line: string): unknown | undefined {\n const trimmed = line.trim()\n if (trimmed === '') return undefined\n try {\n return JSON.parse(trimmed)\n } catch {\n throw new ParseError('Malformed NDJSON line', line)\n }\n}\n\nexport function createNdjsonParser(): NdjsonParser {\n let buffer = ''\n return {\n push(text: string): unknown[] {\n buffer += text\n const out: unknown[] = []\n let idx: number\n while ((idx = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, idx)\n buffer = buffer.slice(idx + 1)\n const parsed = parseLine(line)\n if (parsed !== undefined) out.push(parsed)\n }\n return out\n },\n flush(): unknown[] {\n const rest = buffer\n buffer = ''\n const parsed = parseLine(rest)\n return parsed === undefined ? [] : [parsed]\n },\n }\n}\n","import { WidgetSdkError } from './errors'\nimport type {\n ActionButtonEventData, ActionsLoadingEventData, AnswerEventData, ChatEvent,\n EntityCardEventData, IntentChipEventData, ProgressEventData, StreamErrorEventData, TurnCompleteEventData,\n} from './events'\nimport { postChat, type ResolvedConfig } from './http'\nimport { createNdjsonParser } from './ndjson'\nimport type { ChatInput } from './types'\n\nexport interface ChatCallbacks {\n onProgress?(data: ProgressEventData): void\n onAnswer?(data: AnswerEventData): void\n onEntityCard?(data: EntityCardEventData): void\n onActionButton?(data: ActionButtonEventData): void\n onIntentChip?(data: IntentChipEventData): void\n onActionsLoading?(data: ActionsLoadingEventData): void\n onError?(error: StreamErrorEventData | WidgetSdkError): void\n onComplete?(data: TurnCompleteEventData): void\n}\n\nexport interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {\n cancel(): void\n}\n\nfunction dispatch(ev: ChatEvent, cb: ChatCallbacks): void {\n switch (ev.type) {\n case 'progress': cb.onProgress?.(ev.data); break\n case 'answer': cb.onAnswer?.(ev.data); break\n case 'entity_card': cb.onEntityCard?.(ev.data); break\n case 'action_button': cb.onActionButton?.(ev.data); break\n case 'intent_chip': cb.onIntentChip?.(ev.data); break\n case 'actions_loading': cb.onActionsLoading?.(ev.data); break\n case 'turn_complete': cb.onComplete?.(ev.data); break\n case 'error': cb.onError?.(ev.data); break\n }\n}\n\nasync function* streamEvents(cfg: ResolvedConfig, input: ChatInput, signal: AbortSignal): AsyncGenerator<ChatEvent> {\n const res = await postChat(cfg, input, signal)\n const reader = res.body!.getReader()\n const decoder = new TextDecoder()\n const parser = createNdjsonParser()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj as ChatEvent\n }\n for (const obj of parser.flush()) yield obj as ChatEvent\n } finally {\n await reader.cancel().catch(() => {})\n }\n}\n\nexport function runChat(\n cfg: ResolvedConfig,\n input: ChatInput,\n callbacks?: ChatCallbacks,\n opts?: { signal?: AbortSignal; tap?: (ev: ChatEvent) => void },\n): ChatHandle {\n const controller = new AbortController()\n const external = opts?.signal\n if (external) {\n if (external.aborted) controller.abort()\n else external.addEventListener('abort', () => controller.abort(), { once: true })\n }\n\n async function* source(): AsyncGenerator<ChatEvent> {\n for await (const ev of streamEvents(cfg, input, controller.signal)) {\n opts?.tap?.(ev)\n yield ev\n }\n }\n\n const iterator = source()\n let consumed = false\n\n async function drive(): Promise<void> {\n try {\n for await (const ev of iterator) { if (callbacks) dispatch(ev, callbacks) }\n } catch (error) {\n if (callbacks?.onError && error instanceof WidgetSdkError) { callbacks.onError(error); return }\n throw error\n }\n }\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<ChatEvent> {\n if (consumed) throw new Error('chat stream already consumed')\n consumed = true\n return iterator\n },\n then<TResult1 = void, TResult2 = never>(\n onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n if (consumed) return Promise.resolve().then(onfulfilled, onrejected)\n consumed = true\n return drive().then(onfulfilled, onrejected)\n },\n cancel(): void { controller.abort() },\n }\n}\n","import type { SignalEntityType, SignalInput, SignalType } from './types'\n\nexport const SIGNAL_TYPE_CODES: Record<SignalType, number> = {\n MatchPageView: 1, PlayerPageView: 2, TeamPageView: 3, MarketView: 4,\n SearchQuery: 5, SessionDepth: 6, TimeOnPage: 7, InsightViewed: 8,\n InsightMarketClicked: 9, BetPlacedFromInsight: 10, InsightScrollDepth: 11,\n ToolCall: 12, EntityMention: 13, Handoff: 14, FollowUpQuery: 15, RecommendationDismissed: 16,\n}\n\nexport const ENTITY_TYPE_CODES: Record<SignalEntityType, number> = {\n Match: 1, Team: 2, Player: 3, Competition: 4, Market: 5,\n Article: 6, Session: 7, Query: 8, Conversation: 9,\n}\n\nexport function toSignalWireBody(input: SignalInput): {\n signalType: number; entityType: number; entityName?: string; entityId?: string\n operatorUserId?: string; anonymousUserId?: string; dashboardLayout?: string; tileIndex?: number\n sport?: string\n} {\n const signalType = SIGNAL_TYPE_CODES[input.signalType]\n const entityType = ENTITY_TYPE_CODES[input.entityType]\n if (signalType === undefined) throw new Error(`Unknown signalType: ${String(input.signalType)}`)\n if (entityType === undefined) throw new Error(`Unknown entityType: ${String(input.entityType)}`)\n return {\n signalType, entityType, entityName: input.entityName, entityId: input.entityId,\n operatorUserId: input.operatorUserId, anonymousUserId: input.anonymousUserId,\n dashboardLayout: input.dashboardLayout, tileIndex: input.tileIndex, sport: input.sport,\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport type {\n ClubFanDashboardPayload, ClubFixturesPayload, ClubSquadPayload, ClubSquadStatsPayload, ClubPlayerDetailPayload, ClubRecordsPayload, ClubStandingsPayload, GameListPayload, GameResultPayload, GameStatePayload, LeaderboardPayload,\n LeagueStarResult, LiveMonitorSnapshot, MarketOddsBlock, PinRef, PlayerPropsBundle, PresetGrid, PresetGridOptions, SchedulePayload, StatesPayload, SubmitPlayResult,\n} from './events'\nimport {\n getClubFixtures, getClubPlayerDetail, getClubRecords, getClubSquad, getClubSquadStats, getClubStandings, getGameConfig, getGameResult, getGames, getLeaderboard, getLiveDashboard, getPricePresets,\n postLeagueStar, postLiveMonitor, postMarketOdds, postPlayerProps, postPlay, postSchedule, postSignal, postStates, type ResolvedConfig,\n} from './http'\nimport { toSignalWireBody } from './signals'\nimport type { SlipSport } from './sports'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: SignalInput): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n const anonymousUserId = operatorUserId ? undefined : (input.anonymousUserId ?? this.context?.anonymousUserId)\n if (!operatorUserId && !anonymousUserId) {\n throw new Error('operatorUserId or anonymousUserId is required (set it on conversation() or pass it to sendSignal)')\n }\n if (!input.entityId && !input.entityName) {\n throw new Error('entityId or entityName is required')\n }\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId, anonymousUserId }))\n }\n\n getLiveDashboard(): Promise<ClubFanDashboardPayload | null> {\n return getLiveDashboard(this.cfg)\n }\n\n getLiveMonitor(pins: PinRef[], locale?: string): Promise<LiveMonitorSnapshot | null> {\n return postLiveMonitor(this.cfg, pins, locale)\n }\n\n getMarketOdds(matchId: number, marketDeveloperName: string, sport?: SlipSport): Promise<MarketOddsBlock | null> {\n return postMarketOdds(this.cfg, matchId, marketDeveloperName, sport)\n }\n\n getPlayerProps(matchId: number): Promise<PlayerPropsBundle | null> {\n return postPlayerProps(this.cfg, matchId)\n }\n\n getPricePresets(locale: string, options?: PresetGridOptions): Promise<PresetGrid | null> {\n return getPricePresets(this.cfg, locale, this.context?.operatorUserId, options)\n }\n\n getSchedule(\n localDate: string, utcOffsetMinutes: number, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<SchedulePayload | null> {\n return postSchedule(this.cfg, localDate, utcOffsetMinutes, operatorUserId, anonymousUserId)\n }\n\n starLeague(\n competitionId: number, starred: boolean, operatorUserId?: string, anonymousUserId?: string,\n ): Promise<LeagueStarResult | null> {\n return postLeagueStar(this.cfg, competitionId, starred, operatorUserId, anonymousUserId)\n }\n\n getStates(matchIds: number[], nbaGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds)\n }\n\n getGames(gameDay?: string): Promise<GameListPayload | null> {\n return getGames(this.cfg, this.context?.operatorUserId, gameDay)\n }\n\n getGameConfig(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameStatePayload | null> {\n return getGameConfig(this.cfg, gameId, fixtureId, gameDay, locale)\n }\n\n getGameResult(gameId: string, fixtureId?: number, gameDay?: string, locale?: string): Promise<GameResultPayload | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return getGameResult(this.cfg, gameId, operatorUserId, fixtureId, gameDay, locale)\n }\n\n postPlay(gameId: string, answerJson: string, gameDay: string, fixtureId?: number, locale?: string): Promise<SubmitPlayResult | null> {\n const operatorUserId = this.context?.operatorUserId\n if (!operatorUserId) return Promise.resolve(null)\n return postPlay(this.cfg, gameId, { operatorUserId, gameDay, answerJson, fixtureId }, locale)\n }\n\n getLeaderboard(week?: string): Promise<LeaderboardPayload | null> {\n return getLeaderboard(this.cfg, this.context?.operatorUserId, week)\n }\n\n getClubFixtures(competitionId?: number, limit?: number): Promise<ClubFixturesPayload | null> {\n return getClubFixtures(this.cfg, competitionId, limit)\n }\n getClubStandings(competitionId?: number): Promise<ClubStandingsPayload | null> {\n return getClubStandings(this.cfg, competitionId)\n }\n getClubSquad(): Promise<ClubSquadPayload | null> {\n return getClubSquad(this.cfg)\n }\n getClubSquadStats(): Promise<ClubSquadStatsPayload | null> {\n return getClubSquadStats(this.cfg)\n }\n getClubPlayerDetail(playerId: number): Promise<ClubPlayerDetailPayload | null> {\n return getClubPlayerDetail(this.cfg, playerId)\n }\n getClubRecords(limit?: number): Promise<ClubRecordsPayload | null> {\n return getClubRecords(this.cfg, limit)\n }\n}\n","export type WidgetEntityEventName =\n | 'pin_add' | 'pin_remove' | 'slip_click' | 'slip_result'\n | 'insight_expand' | 'tile_tap' | 'chip_tap'\n | 'slip_remove' | 'bet_placed' | 'match_view' | 'match_open'\n\nexport type WidgetPopupEventName = 'popup_shown' | 'popup_opened' | 'popup_dismissed'\n\nexport type WidgetPopupAskEventName = 'popup_ask_tap'\n\nexport type WidgetOpenEventName = 'widget_open'\n\nexport type WidgetEventName = WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName\n\nexport type WidgetEntityType = 'match' | 'team' | 'player' | 'competition' | 'market'\n\nexport interface WidgetEventInput {\n name: WidgetEntityEventName\n entityType: WidgetEntityType\n entityId?: string\n entityName?: string\n marketDeveloperName?: string\n outcome?: string\n /** Football match id of the slip selection (slip_click / slip_result). */\n matchId?: number\n /** The raw odds label as stored (\"Home\", \"Over\", \"Home/Draw\"), never a joined display string. Max 64. */\n selection?: string\n /** The raw line (\"2.5\"). Max 32; omit when empty. */\n line?: string\n /** Decimal price shown when the selection was added. */\n odds?: number\n /** Wire sport key ('nba'); absent means football. */\n sport?: string\n}\n\n/** Launcher popup telemetry: counted server-side, never tied to an entity. */\nexport type WidgetPopupEventInput =\n { name: WidgetPopupEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\n/** A tap on one of the launcher bubble's asks. `outcome` carries the ask's position, \"0\" or \"1\"\n * (contract §5): the gateway forwards only the fields of its own event model, and outcome is its\n * one free-text field. */\nexport type WidgetPopupAskEventInput =\n { name: WidgetPopupAskEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\n/** The panel opening: entity-free, each open is added to the user's count for the day. */\nexport type WidgetOpenEventInput =\n { name: WidgetOpenEventName } & { [K in Exclude<keyof WidgetEventInput, 'name'>]?: never }\n\nexport type WidgetLogInput = WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput\n\nexport type WireEvent = WidgetLogInput & {\n seq: number\n at: number\n}\n\nexport interface EventBatch {\n v: 1\n sessionId: string\n conversationId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /**\n * Events dropped after exhausting delivery attempts during a PRIOR flush cycle — not a count of\n * this batch's own events. Rides whichever batch is built next after the drop, then is omitted\n * (0/undefined) once a clean cycle passes without a new failure.\n */\n dropped?: number\n /**\n * Failed delivery attempts from a PRIOR flush cycle — not retries of this batch's own events.\n * Rides whichever batch is built next after the failure, then is omitted (0/undefined) once a\n * clean cycle passes without a new failure.\n */\n retries?: number\n events: WireEvent[]\n}\n\nexport interface EventLoggerOptions {\n /** Normal delivery (fetch). Rejecting triggers the retry/backoff loop. */\n flush: (batch: EventBatch) => Promise<void>\n /** Best-effort tail flush on page hide/unload (fetch keepalive). Never awaited. */\n flushKeepalive: (batch: EventBatch) => void\n /** Injectable clock (tests). Defaults to Date.now. */\n now?: () => number\n batchIntervalMs?: number\n maxBatch?: number\n maxAttempts?: number\n}\n\nexport interface EventLogger {\n log(input: WidgetLogInput): void\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void\n flushNow(): Promise<void>\n flushOnHide(): void\n dispose(): void\n /** Undoes dispose(). React StrictMode runs an effect's cleanup and then its setup again on the\n * same logger, so the widget's setup has to be able to bring a disposed logger back. */\n resume(): void\n}\n\nconst IMMEDIATE: ReadonlySet<WidgetEventName> = new Set([\n 'pin_add', 'pin_remove', 'slip_click', 'slip_result', 'slip_remove', 'bet_placed',\n])\n\n// Queued without arming the batch timer: the event leaves with the next flush of any cause. A match\n// page view fires for every visitor, so it must never start a request of its own.\nconst DEFERRED: ReadonlySet<WidgetEventName> = new Set(['match_view'])\n\nconst DEFAULT_BATCH_INTERVAL_MS = 10_000\nconst DEFAULT_MAX_BATCH = 50\nconst DEFAULT_MAX_ATTEMPTS = 3\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction makeSessionId(): string {\n const c: Crypto | undefined = globalThis.crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`\n}\n\nclass EventLoggerImpl implements EventLogger {\n private readonly sessionId = makeSessionId()\n private readonly now: () => number\n private readonly batchIntervalMs: number\n private readonly maxBatch: number\n private readonly maxAttempts: number\n\n private queue: WireEvent[] = []\n private seq = 0\n private retries = 0\n private dropped = 0\n private identity: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string } = {}\n private timer: ReturnType<typeof setTimeout> | null = null\n private inFlight: Promise<void> | null = null\n private disposed = false\n\n constructor(private readonly opts: EventLoggerOptions) {\n this.now = opts.now ?? (() => Date.now())\n this.batchIntervalMs = opts.batchIntervalMs ?? DEFAULT_BATCH_INTERVAL_MS\n this.maxBatch = opts.maxBatch ?? DEFAULT_MAX_BATCH\n this.maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n }\n\n log(input: WidgetLogInput): void {\n if (this.disposed) return\n const event: WireEvent = { ...input, seq: ++this.seq, at: this.now() }\n this.queue.push(event)\n if (IMMEDIATE.has(input.name)) {\n this.trigger()\n } else if (this.queue.length >= this.maxBatch) {\n this.trigger()\n } else if (!DEFERRED.has(input.name)) {\n this.armTimer()\n }\n }\n\n setIdentity(id: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): void {\n this.identity = { ...this.identity, ...id }\n }\n\n async flushNow(): Promise<void> {\n if (this.inFlight) await this.inFlight\n if (this.queue.length > 0) await this.doFlush()\n }\n\n flushOnHide(): void {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n this.opts.flushKeepalive(batch)\n }\n\n dispose(): void {\n this.disposed = true\n this.clearTimer()\n }\n\n resume(): void {\n this.disposed = false\n }\n\n private armTimer(): void {\n if (this.timer !== null) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.trigger()\n }, this.batchIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer === null) return\n clearTimeout(this.timer)\n this.timer = null\n }\n\n private trigger(): void {\n if (this.disposed) return\n if (this.inFlight) return\n this.inFlight = this.doFlush().finally(() => {\n this.inFlight = null\n // An immediate (or maxBatch-triggered) log() call that arrived while this flush was\n // in-flight was a no-op above -- drain it now instead of stranding it until some later\n // log()/flushNow()/dispose() call. Guarded by the disposed check at the top of trigger()\n // itself, so a straggler queued just before dispose() does not fire a flush after it.\n if (this.queue.length > 0) this.trigger()\n })\n }\n\n /**\n * Snapshots the queue + carry-over counters (see EventBatch.dropped/retries) into a batch and\n * resets both for the next cycle. Returns null only when there is truly nothing to report --\n * an empty queue AND no pending dropped/retries -- so a pending counter-only report (queue\n * drained by an exhausted flush, nothing logged since) still gets built and delivered.\n */\n private buildBatch(): EventBatch | null {\n if (this.queue.length === 0 && this.retries === 0 && this.dropped === 0) return null\n const events = this.queue\n this.queue = []\n const batch: EventBatch = { v: 1, sessionId: this.sessionId, ...this.identity, events }\n if (this.retries > 0) batch.retries = this.retries\n if (this.dropped > 0) batch.dropped = this.dropped\n this.retries = 0\n this.dropped = 0\n return batch\n }\n\n private async doFlush(): Promise<void> {\n this.clearTimer()\n const batch = this.buildBatch()\n if (batch === null) return\n for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {\n try {\n await this.opts.flush(batch)\n return\n } catch {\n this.retries++\n if (attempt >= this.maxAttempts) {\n this.dropped += batch.events.length\n return\n }\n await delay(2 ** attempt * 50)\n }\n }\n }\n}\n\nexport function createEventLogger(opts: EventLoggerOptions): EventLogger {\n return new EventLoggerImpl(opts)\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { createEventLogger, type EventLogger } from './eventLog'\nimport { postEvents, postEventsKeepalive, postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, StatsWidgetClientOptions, UserContext } from './types'\n\nconst DEFAULT_BASE_URL = 'https://widget.sensiblestats.com'\n\nexport class StatsWidgetClient {\n private readonly cfg: ResolvedConfig\n\n constructor(options: StatsWidgetClientOptions) {\n if (!options.operatorId) throw new Error('operatorId is required')\n if (!options.publicKey) throw new Error('publicKey is required')\n const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined)\n if (!fetchImpl) throw new Error('No fetch implementation available; pass options.fetch')\n this.cfg = {\n operatorId: options.operatorId,\n publicKey: options.publicKey,\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n fetch: fetchImpl,\n client: options.client,\n }\n }\n\n chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n return runChat(this.cfg, input, callbacks)\n }\n\n async sendSignal(input: SignalInput): Promise<void> {\n await postSignal(this.cfg, toSignalWireBody(input))\n }\n\n conversation(context?: UserContext): Conversation {\n return new Conversation(this.cfg, context)\n }\n\n createEventLogger(identity?: { operatorUserId?: string; anonymousUserId?: string; conversationId?: string }): EventLogger {\n const logger = createEventLogger({\n flush: (batch) => postEvents(this.cfg, batch),\n flushKeepalive: (batch) => postEventsKeepalive(this.cfg, batch),\n })\n if (identity) logger.setIdentity(identity)\n return logger\n }\n}\n","export function matchKey(sport: string | undefined, id: number): string {\n return `${sport ?? 'football'}:${id}`\n}\n","import type { SlipSport } from './sports'\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>\n\nexport interface StatsWidgetClientOptions {\n operatorId: string\n publicKey: string\n baseUrl?: string\n /** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */\n fetch?: FetchLike\n /** Sent as X-SS-Client; set by widget-react. */\n client?: string\n}\n\nexport interface UserContext {\n operatorUserId?: string\n defaultLanguage?: string\n anonymousUserId?: string\n}\n\nexport interface ChatGrounding {\n kind?: string\n matchId?: number\n opponentTeamId?: number\n teamId?: number\n competitionId?: number\n season?: string\n subject?: string\n personaHint?: string\n sport?: string\n}\n\n/** The page the widget sits on. Sent on greeting requests only, so the greeting can lead with that page. */\nexport interface PageContext {\n sport: 'football' | 'nba'\n kind?: 'section' | 'competition' | 'match'\n matchId?: string | number\n competitionId?: string | number\n}\n\n/** Onboarding presets stage 2 (contract §3): what a tool's Send asked for. Sent only from a tool's\n * Send, beside the full sentence in `message`. The server ignores it unless every value is valid. */\nexport interface ChatPreset {\n kind: 'max_price' | 'min_price' | 'combo' | 'market'\n /** max_price, min_price */\n price?: number\n /** max_price, min_price */\n count?: number\n /** combo */\n total?: number\n /** combo */\n legs?: number\n /** market */\n marketDeveloperName?: string\n /** The picks or legs the tool showed, in the order shown (R12: the answer reprices exactly these). */\n matchOddsIds: number[]\n /** The same picks' matchId, index for index with matchOddsIds (from the grid). */\n matchIds: number[]\n}\n\nexport interface ChatInput {\n message: string\n conversationId?: string\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap). Authoritative over `message` when present. */\n actionRef?: string\n userContext?: UserContext\n grounding?: ChatGrounding\n /** Features this client can draw (e.g. \"price_presets\"). The server sends nothing that needs a\n * feature the list does not name; an absent list means today's responses. */\n clientCapabilities?: string[]\n /** Onboarding presets stage 2: set only by a preset tool's Send (contract §3). */\n preset?: ChatPreset\n page?: PageContext\n}\n\nexport type SignalType =\n | 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView'\n | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed'\n | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth'\n | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed'\n\nexport type SignalEntityType =\n | 'Match' | 'Team' | 'Player' | 'Competition' | 'Market'\n | 'Article' | 'Session' | 'Query' | 'Conversation'\n\nexport interface SignalInput {\n signalType: SignalType\n entityType: SignalEntityType\n /** Either this or entityId is required -- an operator's UI mostly knows a display name. */\n entityName?: string\n /** Either this or entityName is required -- a dashboard tile knows its entity by id. */\n entityId?: string\n operatorUserId?: string\n anonymousUserId?: string\n /** Greeting dashboard layout this signal came from, when it is a dashboard tap. */\n dashboardLayout?: string\n /** Zero-based tile position within the dashboard, when it is a dashboard tap. */\n tileIndex?: number\n /** Wire sport key ('nba'); absent means football. Set by the widget, never by an operator. */\n sport?: string\n}\n\nexport type { SlipSport }\n\nexport interface SlipSelection {\n matchOddsId: number\n matchId: number\n oddsDecimal: number\n quotedAtUtc?: string\n insightId?: string\n conversationId?: string\n sport?: SlipSport\n}\n\nexport type AddToSlipRejectReason =\n | 'suspended' | 'closed' | 'login_required'\n | 'not_found' | 'limit' | 'unsupported'\n\nexport type AddToSlipResult =\n | { status: 'added'; slip?: { selectionCount: number; totalOddsDecimal?: number } }\n | { status: 'duplicate' }\n | { status: 'price_changed'; newOddsDecimal: number; accepted: boolean }\n | { status: 'rejected'; reason: AddToSlipRejectReason; message?: string }\n\nexport type AddToSlipHandler = (\n selection: SlipSelection,\n) => Promise<AddToSlipResult | void> | AddToSlipResult | void\n\nconst REJECT_REASONS = ['suspended', 'closed', 'login_required', 'not_found', 'limit', 'unsupported']\n\nexport function isAddToSlipResult(v: unknown): v is AddToSlipResult {\n if (typeof v !== 'object' || v === null) return false\n const o = v as Record<string, unknown>\n switch (o.status) {\n case 'added':\n case 'duplicate':\n return true\n case 'price_changed':\n return typeof o.newOddsDecimal === 'number'\n && Number.isFinite(o.newOddsDecimal)\n && typeof o.accepted === 'boolean'\n case 'rejected':\n return typeof o.reason === 'string'\n && REJECT_REASONS.includes(o.reason)\n default:\n return false\n }\n}\n","export interface SportSpec { readonly slipPrefix: string; readonly monitorPrefix: string; readonly label: string; readonly slippable: boolean; readonly wireKey: string | undefined }\n\nexport const SPORTS = {\n basketball: { slipPrefix: 'bb:', monitorPrefix: 'nba:', label: 'NBA', slippable: true, wireKey: 'nba' },\n americanfootball: { slipPrefix: 'af:', monitorPrefix: 'nfl:', label: 'NFL', slippable: true, wireKey: undefined },\n} as const satisfies Record<string, SportSpec>\n\nexport type NonFootballSport = keyof typeof SPORTS\n/** The sport keys the server accepts on a signal or widget event: only a sport with a wireKey. */\nexport type WireSport = NonNullable<(typeof SPORTS)[NonFootballSport]['wireKey']>\nexport type QualifiedType = 'game' | 'team' | 'player' | 'competition' | 'market'\n/** The sports whose prices can reach an operator slip or a pin: those the map marks slippable. */\nexport type SlipSport = { [K in NonFootballSport]: (typeof SPORTS)[K]['slippable'] extends true ? K : never }[NonFootballSport]\n\n/** undefined means football: every sport the map does not know is football. */\nexport function sportOf(v: unknown): NonFootballSport | undefined {\n return typeof v === 'string' && Object.prototype.hasOwnProperty.call(SPORTS, v) ? (v as NonFootballSport) : undefined\n}\n\n/** True for football (no sport) and for a sport the map marks slippable: the only cases that may pin or slip. */\nexport function mayPinOrSlip(v: unknown): boolean {\n const sport = sportOf(v)\n return sport === undefined || SPORTS[sport].slippable\n}\n\n/** The sport when it may take a slip pick or a pin; undefined for football and for a sport that never does. */\nexport function slipSportOf(v: unknown): SlipSport | undefined {\n const sport = sportOf(v)\n return sport !== undefined && SPORTS[sport].slippable ? (sport as SlipSport) : undefined\n}\n\n/** The key the server reads as `sport`; undefined for football and for a sport without a wireKey (NFL sends nothing). */\nexport function toWireSport(v: unknown): WireSport | undefined {\n const sport = sportOf(v)\n return sport === undefined ? undefined : (SPORTS[sport].wireKey as WireSport | undefined)\n}\n\nexport function qualifiedId(sport: unknown, type: QualifiedType, id: string): string {\n const wire = toWireSport(sport)\n return wire ? `${wire}:${type}:${id}` : id\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sensiblestats/widget-sdk",
3
- "version": "0.67.0",
3
+ "version": "0.69.0",
4
4
  "description": "Headless browser SDK for the SensibleStats chat widget gateway.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",