@sensiblestats/widget-sdk 0.73.0 → 0.74.1
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 +12 -0
- package/README.md +6 -2
- package/dist/index.cjs +51 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -3
- package/dist/index.d.ts +43 -3
- package/dist/index.js +51 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @sensiblestats/widget-sdk
|
|
2
2
|
|
|
3
|
+
## 0.74.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Send the visitor ids (`operatorUserId`, `anonymousUserId`) in the `X-SS-Operator-User-Id` and `X-SS-Anonymous-User-Id` request headers on every gateway call instead of the query string and JSON body. Blank ids, and ids the gateway would reject (non-ASCII or over 128 characters), send no header; `sendSignal` then falls back to the anonymous id. Public function signatures are unchanged.
|
|
8
|
+
|
|
9
|
+
## 0.74.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- NFL Following card: pre-kickoff player props (trends, per-player roster with last-10 bars and rung hit counts, TD scorers) and a Last 5 block with head-to-head and opening-line spread chips. `getPlayerProps` and `loadPlayerProps` take an optional `sport`, `PlayerPropsBundle` gains `facts` and `form`, a price gains `hits` and a stat gains `games`. NBA calls send no `sport` and are unchanged.
|
|
14
|
+
|
|
3
15
|
## 0.73.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -22,13 +22,17 @@ for await (const ev of client.chat({ message: 'odds for Arsenal?' })) {
|
|
|
22
22
|
await client.chat({ message: 'odds for Arsenal?' }, { onAnswer: a => render(a.text) })
|
|
23
23
|
|
|
24
24
|
// Multi-turn
|
|
25
|
-
const convo = client.conversation({ operatorUserId: '
|
|
25
|
+
const convo = client.conversation({ operatorUserId: '6f1c2a9e-4b7d-4e2a-9c3f-8a5d1e7b2c40' })
|
|
26
26
|
await convo.send({ message: 'and their recent form?' })
|
|
27
27
|
|
|
28
28
|
// Signals
|
|
29
|
-
await client.sendSignal({ signalType: 'MatchPageView', entityType: 'Match', entityName: 'Arsenal vs Chelsea', operatorUserId: '
|
|
29
|
+
await client.sendSignal({ signalType: 'MatchPageView', entityType: 'Match', entityName: 'Arsenal vs Chelsea', operatorUserId: '6f1c2a9e-4b7d-4e2a-9c3f-8a5d1e7b2c40' })
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
Visitor ids (`operatorUserId`, `anonymousUserId`) are passed to the SDK as before. On the wire they travel in the `X-SS-Operator-User-Id` and `X-SS-Anonymous-User-Id` request headers on every gateway call, never in the URL or the JSON body; a blank id sends no header. Ids must be printable ASCII, at most 128 characters (surrounding spaces are trimmed); an id that does not qualify is not sent, as if it were blank.
|
|
33
|
+
|
|
34
|
+
`operatorUserId` is sent from the browser: use a random, non-guessable value you map to the user on your side (a UUID works), never an account number, email, username or sequential id.
|
|
35
|
+
|
|
32
36
|
Page grounding: `ChatInput.page` is a `PageContext` (`{ sport: 'football' | 'nba', kind?: 'section' | 'competition' | 'match', matchId?, competitionId? }`). Send it on the session-start greeting only; the server ignores it on any other request. `ChatGrounding.sport` names the sport of a tapped grounding. Greeting dashboard tiles may carry `meta` (a short line in the hero's top row where a price would go) and `imageCodes` (team abbreviations drawn as text marks when there are no images).
|
|
33
37
|
|
|
34
38
|
Errors are typed: `AuthError` (401), `ForbiddenError` (403), `RateLimitError` (429), `UpstreamError` (5xx), `NetworkError`, `ParseError`.
|
package/dist/index.cjs
CHANGED
|
@@ -110,6 +110,23 @@ function headersFor(cfg, json) {
|
|
|
110
110
|
if (cfg.client) h["X-SS-Client"] = cfg.client;
|
|
111
111
|
return h;
|
|
112
112
|
}
|
|
113
|
+
var OPERATOR_USER_ID_HEADER = "X-SS-Operator-User-Id";
|
|
114
|
+
var ANONYMOUS_USER_ID_HEADER = "X-SS-Anonymous-User-Id";
|
|
115
|
+
var SENDABLE_ID = /^[\x20-\x7E]{1,128}$/;
|
|
116
|
+
function isSendableId(id) {
|
|
117
|
+
const v = id?.trim();
|
|
118
|
+
return !!v && SENDABLE_ID.test(v);
|
|
119
|
+
}
|
|
120
|
+
function identityHeaders(operatorUserId, anonymousUserId) {
|
|
121
|
+
const h = {};
|
|
122
|
+
if (isSendableId(operatorUserId)) h[OPERATOR_USER_ID_HEADER] = operatorUserId.trim();
|
|
123
|
+
if (isSendableId(anonymousUserId)) h[ANONYMOUS_USER_ID_HEADER] = anonymousUserId.trim();
|
|
124
|
+
return h;
|
|
125
|
+
}
|
|
126
|
+
function splitIdentity(body) {
|
|
127
|
+
const { operatorUserId, anonymousUserId, ...rest } = body;
|
|
128
|
+
return { identity: identityHeaders(operatorUserId, anonymousUserId), rest };
|
|
129
|
+
}
|
|
113
130
|
function endpoint(cfg, path) {
|
|
114
131
|
return `${cfg.baseUrl.replace(/\/+$/, "")}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`;
|
|
115
132
|
}
|
|
@@ -151,11 +168,11 @@ async function chatError(res) {
|
|
|
151
168
|
function isAbort(error) {
|
|
152
169
|
return error instanceof Error && error.name === "AbortError";
|
|
153
170
|
}
|
|
154
|
-
async function send(cfg, path, body, signal) {
|
|
171
|
+
async function send(cfg, path, body, signal, identity = {}) {
|
|
155
172
|
try {
|
|
156
173
|
return await cfg.fetch(endpoint(cfg, path), {
|
|
157
174
|
method: "POST",
|
|
158
|
-
headers: headersFor(cfg, true),
|
|
175
|
+
headers: { ...headersFor(cfg, true), ...identity },
|
|
159
176
|
body: JSON.stringify(body),
|
|
160
177
|
signal
|
|
161
178
|
});
|
|
@@ -165,24 +182,35 @@ async function send(cfg, path, body, signal) {
|
|
|
165
182
|
}
|
|
166
183
|
}
|
|
167
184
|
async function postChat(cfg, input, signal) {
|
|
168
|
-
const
|
|
185
|
+
const { userContext, ...rest } = input;
|
|
186
|
+
let body = rest;
|
|
187
|
+
let identity = {};
|
|
188
|
+
if (userContext) {
|
|
189
|
+
const split = splitIdentity(userContext);
|
|
190
|
+
identity = split.identity;
|
|
191
|
+
body = Object.keys(split.rest).length > 0 ? { ...rest, userContext: split.rest } : rest;
|
|
192
|
+
}
|
|
193
|
+
const res = await send(cfg, "chat", body, signal, identity);
|
|
169
194
|
if (!res.ok || res.body == null) throw await chatError(res);
|
|
170
195
|
return res;
|
|
171
196
|
}
|
|
172
197
|
async function postSignal(cfg, wireBody, signal) {
|
|
173
|
-
const
|
|
198
|
+
const { identity, rest } = splitIdentity(wireBody);
|
|
199
|
+
const res = await send(cfg, "signals", rest, signal, identity);
|
|
174
200
|
if (!res.ok) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
175
201
|
}
|
|
176
202
|
async function postEvents(cfg, batch) {
|
|
177
|
-
const
|
|
203
|
+
const { identity, rest } = splitIdentity(batch);
|
|
204
|
+
const res = await send(cfg, "events", rest, void 0, identity);
|
|
178
205
|
if (!res.ok) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
179
206
|
}
|
|
180
207
|
function postEventsKeepalive(cfg, batch) {
|
|
181
208
|
try {
|
|
209
|
+
const { identity, rest } = splitIdentity(batch);
|
|
182
210
|
void cfg.fetch(endpoint(cfg, "events"), {
|
|
183
211
|
method: "POST",
|
|
184
|
-
headers: headersFor(cfg, true),
|
|
185
|
-
body: JSON.stringify(
|
|
212
|
+
headers: { ...headersFor(cfg, true), ...identity },
|
|
213
|
+
body: JSON.stringify(rest),
|
|
186
214
|
keepalive: true
|
|
187
215
|
}).catch(() => {
|
|
188
216
|
});
|
|
@@ -219,11 +247,11 @@ async function postMarketOdds(cfg, matchId, marketDeveloperName, sport) {
|
|
|
219
247
|
if (!res.ok) throw new Error(`live-monitor/market ${res.status}`);
|
|
220
248
|
return await res.json();
|
|
221
249
|
}
|
|
222
|
-
async function postPlayerProps(cfg, matchId) {
|
|
250
|
+
async function postPlayerProps(cfg, matchId, sport) {
|
|
223
251
|
const res = await cfg.fetch(endpoint(cfg, "live-monitor/props"), {
|
|
224
252
|
method: "POST",
|
|
225
253
|
headers: headersFor(cfg, true),
|
|
226
|
-
body: JSON.stringify({ matchId })
|
|
254
|
+
body: JSON.stringify(sport ? { matchId, sport } : { matchId })
|
|
227
255
|
});
|
|
228
256
|
if (res.status === 404) return null;
|
|
229
257
|
if (!res.ok) throw new Error(`live-monitor/props ${res.status}`);
|
|
@@ -232,8 +260,8 @@ async function postPlayerProps(cfg, matchId) {
|
|
|
232
260
|
async function postSchedule(cfg, localDate, utcOffsetMinutes, operatorUserId, anonymousUserId) {
|
|
233
261
|
const res = await cfg.fetch(endpoint(cfg, "live-monitor/schedule"), {
|
|
234
262
|
method: "POST",
|
|
235
|
-
headers: headersFor(cfg, true),
|
|
236
|
-
body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ["basketball", "americanfootball"]
|
|
263
|
+
headers: { ...headersFor(cfg, true), ...identityHeaders(operatorUserId, anonymousUserId) },
|
|
264
|
+
body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ["basketball", "americanfootball"] })
|
|
237
265
|
});
|
|
238
266
|
if (res.status === 404) return null;
|
|
239
267
|
if (!res.ok) throw new Error(`live-monitor/schedule ${res.status}`);
|
|
@@ -242,8 +270,8 @@ async function postSchedule(cfg, localDate, utcOffsetMinutes, operatorUserId, an
|
|
|
242
270
|
async function postLeagueStar(cfg, competitionId, starred, operatorUserId, anonymousUserId) {
|
|
243
271
|
const res = await cfg.fetch(endpoint(cfg, `leagues/${competitionId}/star`), {
|
|
244
272
|
method: "POST",
|
|
245
|
-
headers: headersFor(cfg, true),
|
|
246
|
-
body: JSON.stringify({ starred
|
|
273
|
+
headers: { ...headersFor(cfg, true), ...identityHeaders(operatorUserId, anonymousUserId) },
|
|
274
|
+
body: JSON.stringify({ starred })
|
|
247
275
|
});
|
|
248
276
|
if (res.status === 404) return null;
|
|
249
277
|
if (!res.ok) throw new Error(`leagues/star ${res.status}`);
|
|
@@ -268,7 +296,7 @@ function q(parts) {
|
|
|
268
296
|
return kept.length ? `?${kept.join("&")}` : "";
|
|
269
297
|
}
|
|
270
298
|
async function getGames(cfg, operatorUserId, gameDay) {
|
|
271
|
-
const res = await cfg.fetch(endpoint(cfg, "games" + q({
|
|
299
|
+
const res = await cfg.fetch(endpoint(cfg, "games" + q({ gameDay })), { method: "GET", headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } });
|
|
272
300
|
if (res.status === 404) return null;
|
|
273
301
|
if (!res.ok) throw new Error(`games ${res.status}`);
|
|
274
302
|
return await res.json();
|
|
@@ -280,23 +308,24 @@ async function getGameConfig(cfg, gameId, fixtureId, gameDay, locale) {
|
|
|
280
308
|
return await res.json();
|
|
281
309
|
}
|
|
282
310
|
async function getGameResult(cfg, gameId, operatorUserId, fixtureId, gameDay, locale) {
|
|
283
|
-
const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({
|
|
311
|
+
const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/result` + q({ fixtureId, gameDay, locale })), { method: "GET", headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } });
|
|
284
312
|
if (res.status === 404) return null;
|
|
285
313
|
if (!res.ok) throw new Error(`game-result ${res.status}`);
|
|
286
314
|
return await res.json();
|
|
287
315
|
}
|
|
288
316
|
async function postPlay(cfg, gameId, body, locale) {
|
|
317
|
+
const { identity, rest } = splitIdentity(body);
|
|
289
318
|
const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {
|
|
290
319
|
method: "POST",
|
|
291
|
-
headers: headersFor(cfg, true),
|
|
292
|
-
body: JSON.stringify(
|
|
320
|
+
headers: { ...headersFor(cfg, true), ...identity },
|
|
321
|
+
body: JSON.stringify(rest)
|
|
293
322
|
});
|
|
294
323
|
if (res.status === 404) return null;
|
|
295
324
|
if (!res.ok) throw new Error(`play ${res.status}`);
|
|
296
325
|
return await res.json();
|
|
297
326
|
}
|
|
298
327
|
async function getLeaderboard(cfg, operatorUserId, week) {
|
|
299
|
-
const res = await cfg.fetch(endpoint(cfg, "games/leaderboard" + q({
|
|
328
|
+
const res = await cfg.fetch(endpoint(cfg, "games/leaderboard" + q({ week })), { method: "GET", headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } });
|
|
300
329
|
if (res.status === 404) return null;
|
|
301
330
|
if (!res.ok) throw new Error(`leaderboard ${res.status}`);
|
|
302
331
|
return await res.json();
|
|
@@ -338,7 +367,7 @@ async function getClubRecords(cfg, limit) {
|
|
|
338
367
|
return await res.json();
|
|
339
368
|
}
|
|
340
369
|
async function getPricePresets(cfg, locale, operatorUserId, options) {
|
|
341
|
-
const res = await cfg.fetch(endpoint(cfg, "price-presets" + q({ locale,
|
|
370
|
+
const res = await cfg.fetch(endpoint(cfg, "price-presets" + q({ locale, pool: options?.pool })), { method: "GET", headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } });
|
|
342
371
|
if (res.status === 404) return null;
|
|
343
372
|
if (!res.ok) throw new Error(`price-presets ${res.status}`);
|
|
344
373
|
return await res.json();
|
|
@@ -538,7 +567,7 @@ var Conversation = class {
|
|
|
538
567
|
}
|
|
539
568
|
sendSignal(input) {
|
|
540
569
|
const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId;
|
|
541
|
-
const anonymousUserId = operatorUserId ? void 0 : input.anonymousUserId ?? this.context?.anonymousUserId;
|
|
570
|
+
const anonymousUserId = isSendableId(operatorUserId) ? void 0 : input.anonymousUserId ?? this.context?.anonymousUserId;
|
|
542
571
|
if (!operatorUserId && !anonymousUserId) {
|
|
543
572
|
throw new Error("operatorUserId or anonymousUserId is required (set it on conversation() or pass it to sendSignal)");
|
|
544
573
|
}
|
|
@@ -556,8 +585,8 @@ var Conversation = class {
|
|
|
556
585
|
getMarketOdds(matchId, marketDeveloperName, sport) {
|
|
557
586
|
return postMarketOdds(this.cfg, matchId, marketDeveloperName, sport);
|
|
558
587
|
}
|
|
559
|
-
getPlayerProps(matchId) {
|
|
560
|
-
return postPlayerProps(this.cfg, matchId);
|
|
588
|
+
getPlayerProps(matchId, sport) {
|
|
589
|
+
return postPlayerProps(this.cfg, matchId, sport);
|
|
561
590
|
}
|
|
562
591
|
getPricePresets(locale, options) {
|
|
563
592
|
return getPricePresets(this.cfg, locale, this.context?.operatorUserId, options);
|
package/dist/index.cjs.map
CHANGED
|
@@ -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, toWireSport, fromWireSport, 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, WidgetSportSwitchEventName, WidgetEntityType, WidgetEventInput,\n WidgetPopupEventInput, WidgetPopupAskEventInput, WidgetOpenEventInput, WidgetSportSwitchEventInput, 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, GreetingDashboardSet, GreetingSetChip, 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', 'americanfootball'], 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[], nflGameIds?: 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({\n matchIds,\n ...(nbaGameIds?.length ? { nbaGameIds } : {}),\n ...(nflGameIds?.length ? { nflGameIds } : {}),\n }),\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[], nflGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds, nflGameIds)\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 WidgetSportSwitchEventName = 'dashboard_sport_switch'\n\nexport type WidgetEventName =\n WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName | WidgetSportSwitchEventName\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\n/** The greeting sport switch: `outcome` is the sport switched to (a server sport key). Entity-free; the server drops an unknown outcome. */\nexport type WidgetSportSwitchEventInput =\n { name: WidgetSportSwitchEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\nexport type WidgetLogInput =\n WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput | WidgetSportSwitchEventInput\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 /** The sport the visitor last chose on the greeting's sport switch (a server sport key such as \"nba\"); a hint for the default sport. */\n rememberedSport?: 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: 'nfl' },\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. */\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\n/** A server sport key (a set's `sport`) back to the key the server reads on a signal; undefined unless the map carries it as a wireKey. */\nexport function fromWireSport(v: unknown): WireSport | undefined {\n return typeof v === 'string' && Object.values(SPORTS).some((s) => s.wireKey === v) ? (v 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":[]}
|
|
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, fromWireSport, 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, WidgetSportSwitchEventName, WidgetEntityType, WidgetEventInput,\n WidgetPopupEventInput, WidgetPopupAskEventInput, WidgetOpenEventInput, WidgetSportSwitchEventInput, 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, GreetingDashboardSet, GreetingSetChip, 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, PlayerPropStatGame, PlayerPropFact, PlayerPropsBundle,\n NflForm, NflFormGame,\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\nconst OPERATOR_USER_ID_HEADER = 'X-SS-Operator-User-Id'\nconst ANONYMOUS_USER_ID_HEADER = 'X-SS-Anonymous-User-Id'\n\n// Same rule as the gateway's VisitorIdHeaders.IsValid: printable ASCII, 1 to 128 characters.\nconst SENDABLE_ID = /^[\\x20-\\x7E]{1,128}$/\n\n// Visitor ids travel in these two headers on every gateway call, never in the query string or the JSON\n// body. The trimmed id is sent (fetch strips edge whitespace anyway). An id that is blank or that the\n// gateway would reject is left out like a blank one, so a bad id can never make fetch throw.\nexport function isSendableId(id?: string): boolean {\n const v = id?.trim()\n return !!v && SENDABLE_ID.test(v)\n}\n\nexport function identityHeaders(operatorUserId?: string, anonymousUserId?: string): Record<string, string> {\n const h: Record<string, string> = {}\n if (isSendableId(operatorUserId)) h[OPERATOR_USER_ID_HEADER] = operatorUserId!.trim()\n if (isSendableId(anonymousUserId)) h[ANONYMOUS_USER_ID_HEADER] = anonymousUserId!.trim()\n return h\n}\n\ninterface BodyIds { operatorUserId?: string; anonymousUserId?: string }\n\nfunction splitIdentity(body: object): { identity: Record<string, string>; rest: Record<string, unknown> } {\n const { operatorUserId, anonymousUserId, ...rest } = body as BodyIds & Record<string, unknown>\n return { identity: identityHeaders(operatorUserId, anonymousUserId), rest }\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(\n cfg: ResolvedConfig, path: string, body: object, signal?: AbortSignal, identity: Record<string, string> = {},\n): Promise<Response> {\n try {\n return await cfg.fetch(endpoint(cfg, path), {\n method: 'POST',\n headers: { ...headersFor(cfg, true), ...identity },\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 { userContext, ...rest } = input\n let body: object = rest\n let identity: Record<string, string> = {}\n if (userContext) {\n const split = splitIdentity(userContext)\n identity = split.identity\n body = Object.keys(split.rest).length > 0 ? { ...rest, userContext: split.rest } : rest\n }\n const res = await send(cfg, 'chat', body, signal, identity)\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 { identity, rest } = splitIdentity(wireBody)\n const res = await send(cfg, 'signals', rest, signal, identity)\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 { identity, rest } = splitIdentity(batch)\n const res = await send(cfg, 'events', rest, undefined, identity)\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 const { identity, rest } = splitIdentity(batch)\n void cfg.fetch(endpoint(cfg, 'events'), {\n method: 'POST',\n headers: { ...headersFor(cfg, true), ...identity },\n body: JSON.stringify(rest),\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, sport?: 'americanfootball'): 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(sport ? { matchId, sport } : { 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), ...identityHeaders(operatorUserId, anonymousUserId) },\n body: JSON.stringify({ localDate, utcOffsetMinutes, sports: ['basketball', 'americanfootball'] }),\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), ...identityHeaders(operatorUserId, anonymousUserId) },\n body: JSON.stringify({ starred }),\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[], nflGameIds?: 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({\n matchIds,\n ...(nbaGameIds?.length ? { nbaGameIds } : {}),\n ...(nflGameIds?.length ? { nflGameIds } : {}),\n }),\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({ gameDay })), { method: 'GET', headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } })\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({ fixtureId, gameDay, locale })), { method: 'GET', headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } })\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 { identity, rest } = splitIdentity(body)\n const res = await cfg.fetch(endpoint(cfg, `games/${encodeURIComponent(gameId)}/plays` + q({ locale })), {\n method: 'POST',\n headers: { ...headersFor(cfg, true), ...identity },\n body: JSON.stringify(rest),\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({ week })), { method: 'GET', headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } })\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, sent as the games routes send it (in its header): the cool-off check (D3)\n// needs it, 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, pool: options?.pool })), { method: 'GET', headers: { ...headersFor(cfg, false), ...identityHeaders(operatorUserId) } })\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 isSendableId,\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 = isSendableId(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, sport?: 'americanfootball'): Promise<PlayerPropsBundle | null> {\n return postPlayerProps(this.cfg, matchId, sport)\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[], nflGameIds?: number[]): Promise<StatesPayload | null> {\n return postStates(this.cfg, matchIds, nbaGameIds, nflGameIds)\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 WidgetSportSwitchEventName = 'dashboard_sport_switch'\n\nexport type WidgetEventName =\n WidgetEntityEventName | WidgetPopupEventName | WidgetPopupAskEventName | WidgetOpenEventName | WidgetSportSwitchEventName\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\n/** The greeting sport switch: `outcome` is the sport switched to (a server sport key). Entity-free; the server drops an unknown outcome. */\nexport type WidgetSportSwitchEventInput =\n { name: WidgetSportSwitchEventName; outcome: string } & { [K in Exclude<keyof WidgetEventInput, 'name' | 'outcome'>]?: never }\n\nexport type WidgetLogInput =\n WidgetEventInput | WidgetPopupEventInput | WidgetPopupAskEventInput | WidgetOpenEventInput | WidgetSportSwitchEventInput\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 /** The sport the visitor last chose on the greeting's sport switch (a server sport key such as \"nba\"); a hint for the default sport. */\n rememberedSport?: 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: 'nfl' },\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. */\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\n/** A server sport key (a set's `sport`) back to the key the server reads on a signal; undefined unless the map carries it as a wireKey. */\nexport function fromWireSport(v: unknown): WireSport | undefined {\n return typeof v === 'string' && Object.values(SPORTS).some((s) => s.wireKey === v) ? (v 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":[]}
|