@sensiblestats/widget-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +32 -0
- package/dist/index.cjs +353 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +144 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.js +316 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
SensibleStats Widget SDK — Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SensibleStats. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and the accompanying files (the "Software") are the proprietary and
|
|
6
|
+
confidential property of SensibleStats. The Software is licensed, not sold.
|
|
7
|
+
|
|
8
|
+
Use of the Software is permitted solely by SensibleStats operators and their
|
|
9
|
+
authorized end users, and only as necessary to integrate and operate the
|
|
10
|
+
SensibleStats chat widget in accordance with a valid, active commercial agreement
|
|
11
|
+
with SensibleStats. All rights not expressly granted are reserved by SensibleStats.
|
|
12
|
+
|
|
13
|
+
Except as permitted above, no part of the Software may be copied, modified, merged,
|
|
14
|
+
published, distributed, sublicensed, sold, reverse engineered, decompiled, or used
|
|
15
|
+
to create derivative works without the prior written consent of SensibleStats.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
18
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
19
|
+
PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL SENSIBLESTATS BE LIABLE
|
|
20
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT,
|
|
21
|
+
OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @sensiblestats/widget-sdk
|
|
2
|
+
|
|
3
|
+
Headless browser SDK for the SensibleStats chat widget gateway. Zero dependencies, typed.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
`yarn add @sensiblestats/widget-sdk`
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { StatsWidgetClient } from '@sensiblestats/widget-sdk'
|
|
13
|
+
|
|
14
|
+
const client = new StatsWidgetClient({ operatorId: 'sandbox1', publicKey: 'wgk_…' })
|
|
15
|
+
|
|
16
|
+
// Streaming chat — iterate
|
|
17
|
+
for await (const ev of client.chat({ message: 'odds for Arsenal?' })) {
|
|
18
|
+
if (ev.type === 'answer') console.log(ev.data.text)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Streaming chat — callbacks (await to run to completion)
|
|
22
|
+
await client.chat({ message: 'odds for Arsenal?' }, { onAnswer: a => render(a.text) })
|
|
23
|
+
|
|
24
|
+
// Multi-turn
|
|
25
|
+
const convo = client.conversation({ operatorUserId: 'u_42' })
|
|
26
|
+
await convo.send({ message: 'and their recent form?' })
|
|
27
|
+
|
|
28
|
+
// Signals
|
|
29
|
+
await client.sendSignal({ signalType: 'MatchPageView', entityType: 'Match', entityName: 'Arsenal vs Chelsea', operatorUserId: 'u_42' })
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Errors are typed: `AuthError` (401), `ForbiddenError` (403), `RateLimitError` (429), `UpstreamError` (5xx), `NetworkError`, `ParseError`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthError: () => AuthError,
|
|
24
|
+
Conversation: () => Conversation,
|
|
25
|
+
ENTITY_TYPE_CODES: () => ENTITY_TYPE_CODES,
|
|
26
|
+
ForbiddenError: () => ForbiddenError,
|
|
27
|
+
NetworkError: () => NetworkError,
|
|
28
|
+
ParseError: () => ParseError,
|
|
29
|
+
RateLimitError: () => RateLimitError,
|
|
30
|
+
SIGNAL_TYPE_CODES: () => SIGNAL_TYPE_CODES,
|
|
31
|
+
StatsWidgetClient: () => StatsWidgetClient,
|
|
32
|
+
UpstreamError: () => UpstreamError,
|
|
33
|
+
WidgetSdkError: () => WidgetSdkError
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/errors.ts
|
|
38
|
+
var WidgetSdkError = class extends Error {
|
|
39
|
+
constructor(message, code, status) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = new.target.name;
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.status = status;
|
|
44
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var AuthError = class extends WidgetSdkError {
|
|
48
|
+
constructor(message = "Invalid or missing public key") {
|
|
49
|
+
super(message, "unauthorized", 401);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var ForbiddenError = class extends WidgetSdkError {
|
|
53
|
+
constructor(message = "Origin not allowed or widget disabled") {
|
|
54
|
+
super(message, "forbidden", 403);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var RateLimitError = class extends WidgetSdkError {
|
|
58
|
+
constructor(retryAfter, message = "Rate limited") {
|
|
59
|
+
super(message, "rate_limited", 429);
|
|
60
|
+
this.retryAfter = retryAfter;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var UpstreamError = class extends WidgetSdkError {
|
|
64
|
+
constructor(status, message = "Upstream error") {
|
|
65
|
+
super(message, "upstream_error", status);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var NetworkError = class extends WidgetSdkError {
|
|
69
|
+
constructor(message = "Network request failed", cause) {
|
|
70
|
+
super(message, "network_error");
|
|
71
|
+
this.cause = cause;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var ParseError = class extends WidgetSdkError {
|
|
75
|
+
constructor(message = "Malformed NDJSON line", line) {
|
|
76
|
+
super(message, "parse_error");
|
|
77
|
+
this.line = line;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/http.ts
|
|
82
|
+
function endpoint(cfg, path) {
|
|
83
|
+
return `${cfg.baseUrl.replace(/\/+$/, "")}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`;
|
|
84
|
+
}
|
|
85
|
+
function toWidgetError(status, retryAfterHeader) {
|
|
86
|
+
switch (status) {
|
|
87
|
+
case 401:
|
|
88
|
+
return new AuthError();
|
|
89
|
+
case 403:
|
|
90
|
+
return new ForbiddenError();
|
|
91
|
+
case 429: {
|
|
92
|
+
const n = retryAfterHeader != null ? Number(retryAfterHeader) : void 0;
|
|
93
|
+
return new RateLimitError(Number.isFinite(n) ? n : void 0);
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
return new UpstreamError(status);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function isAbort(error) {
|
|
100
|
+
return error instanceof Error && error.name === "AbortError";
|
|
101
|
+
}
|
|
102
|
+
async function send(cfg, path, body, signal) {
|
|
103
|
+
try {
|
|
104
|
+
return await cfg.fetch(endpoint(cfg, path), {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: { "Content-Type": "application/json", "X-SS-Public-Key": cfg.publicKey },
|
|
107
|
+
body: JSON.stringify(body),
|
|
108
|
+
signal
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (isAbort(error)) throw error;
|
|
112
|
+
throw new NetworkError("Network request failed", error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function postChat(cfg, input, signal) {
|
|
116
|
+
const res = await send(cfg, "chat", input, signal);
|
|
117
|
+
if (!res.ok || res.body == null) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
118
|
+
return res;
|
|
119
|
+
}
|
|
120
|
+
async function postSignal(cfg, wireBody, signal) {
|
|
121
|
+
const res = await send(cfg, "signals", wireBody, signal);
|
|
122
|
+
if (!res.ok) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/ndjson.ts
|
|
126
|
+
function parseLine(line) {
|
|
127
|
+
const trimmed = line.trim();
|
|
128
|
+
if (trimmed === "") return void 0;
|
|
129
|
+
try {
|
|
130
|
+
return JSON.parse(trimmed);
|
|
131
|
+
} catch {
|
|
132
|
+
throw new ParseError("Malformed NDJSON line", line);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function createNdjsonParser() {
|
|
136
|
+
let buffer = "";
|
|
137
|
+
return {
|
|
138
|
+
push(text) {
|
|
139
|
+
buffer += text;
|
|
140
|
+
const out = [];
|
|
141
|
+
let idx;
|
|
142
|
+
while ((idx = buffer.indexOf("\n")) >= 0) {
|
|
143
|
+
const line = buffer.slice(0, idx);
|
|
144
|
+
buffer = buffer.slice(idx + 1);
|
|
145
|
+
const parsed = parseLine(line);
|
|
146
|
+
if (parsed !== void 0) out.push(parsed);
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
},
|
|
150
|
+
flush() {
|
|
151
|
+
const rest = buffer;
|
|
152
|
+
buffer = "";
|
|
153
|
+
const parsed = parseLine(rest);
|
|
154
|
+
return parsed === void 0 ? [] : [parsed];
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/chat.ts
|
|
160
|
+
function dispatch(ev, cb) {
|
|
161
|
+
switch (ev.type) {
|
|
162
|
+
case "progress":
|
|
163
|
+
cb.onProgress?.(ev.data);
|
|
164
|
+
break;
|
|
165
|
+
case "answer":
|
|
166
|
+
cb.onAnswer?.(ev.data);
|
|
167
|
+
break;
|
|
168
|
+
case "entity_card":
|
|
169
|
+
cb.onEntityCard?.(ev.data);
|
|
170
|
+
break;
|
|
171
|
+
case "action_button":
|
|
172
|
+
cb.onActionButton?.(ev.data);
|
|
173
|
+
break;
|
|
174
|
+
case "intent_chip":
|
|
175
|
+
cb.onIntentChip?.(ev.data);
|
|
176
|
+
break;
|
|
177
|
+
case "actions_loading":
|
|
178
|
+
cb.onActionsLoading?.(ev.data);
|
|
179
|
+
break;
|
|
180
|
+
case "turn_complete":
|
|
181
|
+
cb.onComplete?.(ev.data);
|
|
182
|
+
break;
|
|
183
|
+
case "error":
|
|
184
|
+
cb.onError?.(ev.data);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function* streamEvents(cfg, input, signal) {
|
|
189
|
+
const res = await postChat(cfg, input, signal);
|
|
190
|
+
const reader = res.body.getReader();
|
|
191
|
+
const decoder = new TextDecoder();
|
|
192
|
+
const parser = createNdjsonParser();
|
|
193
|
+
try {
|
|
194
|
+
for (; ; ) {
|
|
195
|
+
const { done, value } = await reader.read();
|
|
196
|
+
if (done) break;
|
|
197
|
+
for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj;
|
|
198
|
+
}
|
|
199
|
+
for (const obj of parser.flush()) yield obj;
|
|
200
|
+
} finally {
|
|
201
|
+
await reader.cancel().catch(() => {
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function runChat(cfg, input, callbacks, opts) {
|
|
206
|
+
const controller = new AbortController();
|
|
207
|
+
const external = opts?.signal;
|
|
208
|
+
if (external) {
|
|
209
|
+
if (external.aborted) controller.abort();
|
|
210
|
+
else external.addEventListener("abort", () => controller.abort(), { once: true });
|
|
211
|
+
}
|
|
212
|
+
async function* source() {
|
|
213
|
+
for await (const ev of streamEvents(cfg, input, controller.signal)) {
|
|
214
|
+
opts?.tap?.(ev);
|
|
215
|
+
yield ev;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const iterator = source();
|
|
219
|
+
let consumed = false;
|
|
220
|
+
async function drive() {
|
|
221
|
+
try {
|
|
222
|
+
for await (const ev of iterator) {
|
|
223
|
+
if (callbacks) dispatch(ev, callbacks);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (callbacks?.onError && error instanceof WidgetSdkError) {
|
|
227
|
+
callbacks.onError(error);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
[Symbol.asyncIterator]() {
|
|
235
|
+
if (consumed) throw new Error("chat stream already consumed");
|
|
236
|
+
consumed = true;
|
|
237
|
+
return iterator;
|
|
238
|
+
},
|
|
239
|
+
then(onfulfilled, onrejected) {
|
|
240
|
+
if (consumed) return Promise.resolve().then(onfulfilled, onrejected);
|
|
241
|
+
consumed = true;
|
|
242
|
+
return drive().then(onfulfilled, onrejected);
|
|
243
|
+
},
|
|
244
|
+
cancel() {
|
|
245
|
+
controller.abort();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/signals.ts
|
|
251
|
+
var SIGNAL_TYPE_CODES = {
|
|
252
|
+
MatchPageView: 1,
|
|
253
|
+
PlayerPageView: 2,
|
|
254
|
+
TeamPageView: 3,
|
|
255
|
+
MarketView: 4,
|
|
256
|
+
SearchQuery: 5,
|
|
257
|
+
SessionDepth: 6,
|
|
258
|
+
TimeOnPage: 7,
|
|
259
|
+
InsightViewed: 8,
|
|
260
|
+
InsightMarketClicked: 9,
|
|
261
|
+
BetPlacedFromInsight: 10,
|
|
262
|
+
InsightScrollDepth: 11,
|
|
263
|
+
ToolCall: 12,
|
|
264
|
+
EntityMention: 13,
|
|
265
|
+
Handoff: 14,
|
|
266
|
+
FollowUpQuery: 15,
|
|
267
|
+
RecommendationDismissed: 16
|
|
268
|
+
};
|
|
269
|
+
var ENTITY_TYPE_CODES = {
|
|
270
|
+
Match: 1,
|
|
271
|
+
Team: 2,
|
|
272
|
+
Player: 3,
|
|
273
|
+
Competition: 4,
|
|
274
|
+
Market: 5,
|
|
275
|
+
Article: 6,
|
|
276
|
+
Session: 7,
|
|
277
|
+
Query: 8,
|
|
278
|
+
Conversation: 9
|
|
279
|
+
};
|
|
280
|
+
function toSignalWireBody(input) {
|
|
281
|
+
const signalType = SIGNAL_TYPE_CODES[input.signalType];
|
|
282
|
+
const entityType = ENTITY_TYPE_CODES[input.entityType];
|
|
283
|
+
if (signalType === void 0) throw new Error(`Unknown signalType: ${String(input.signalType)}`);
|
|
284
|
+
if (entityType === void 0) throw new Error(`Unknown entityType: ${String(input.entityType)}`);
|
|
285
|
+
return { signalType, entityType, entityName: input.entityName, operatorUserId: input.operatorUserId };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/conversation.ts
|
|
289
|
+
var Conversation = class {
|
|
290
|
+
constructor(cfg, context) {
|
|
291
|
+
this.cfg = cfg;
|
|
292
|
+
this.context = context;
|
|
293
|
+
}
|
|
294
|
+
send(input, callbacks) {
|
|
295
|
+
const mergedContext = { ...this.context, ...input.userContext };
|
|
296
|
+
const full = {
|
|
297
|
+
...input,
|
|
298
|
+
conversationId: input.conversationId ?? this.conversationId,
|
|
299
|
+
userContext: Object.keys(mergedContext).length > 0 ? mergedContext : void 0
|
|
300
|
+
};
|
|
301
|
+
return runChat(this.cfg, full, callbacks, {
|
|
302
|
+
tap: (ev) => {
|
|
303
|
+
if (ev.type === "turn_complete") this.conversationId = ev.data.conversationId;
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
sendSignal(input) {
|
|
308
|
+
const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId;
|
|
309
|
+
if (!operatorUserId) throw new Error("operatorUserId is required (set it on conversation() or pass it to sendSignal)");
|
|
310
|
+
return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId }));
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// src/client.ts
|
|
315
|
+
var DEFAULT_BASE_URL = "https://widget.sensiblestats.com";
|
|
316
|
+
var StatsWidgetClient = class {
|
|
317
|
+
constructor(options) {
|
|
318
|
+
if (!options.operatorId) throw new Error("operatorId is required");
|
|
319
|
+
if (!options.publicKey) throw new Error("publicKey is required");
|
|
320
|
+
const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
321
|
+
if (!fetchImpl) throw new Error("No fetch implementation available; pass options.fetch");
|
|
322
|
+
this.cfg = {
|
|
323
|
+
operatorId: options.operatorId,
|
|
324
|
+
publicKey: options.publicKey,
|
|
325
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
326
|
+
fetch: fetchImpl
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
chat(input, callbacks) {
|
|
330
|
+
return runChat(this.cfg, input, callbacks);
|
|
331
|
+
}
|
|
332
|
+
async sendSignal(input) {
|
|
333
|
+
await postSignal(this.cfg, toSignalWireBody(input));
|
|
334
|
+
}
|
|
335
|
+
conversation(context) {
|
|
336
|
+
return new Conversation(this.cfg, context);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
340
|
+
0 && (module.exports = {
|
|
341
|
+
AuthError,
|
|
342
|
+
Conversation,
|
|
343
|
+
ENTITY_TYPE_CODES,
|
|
344
|
+
ForbiddenError,
|
|
345
|
+
NetworkError,
|
|
346
|
+
ParseError,
|
|
347
|
+
RateLimitError,
|
|
348
|
+
SIGNAL_TYPE_CODES,
|
|
349
|
+
StatsWidgetClient,
|
|
350
|
+
UpstreamError,
|
|
351
|
+
WidgetSdkError
|
|
352
|
+
});
|
|
353
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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/client.ts"],"sourcesContent":["export { StatsWidgetClient } from './client'\nexport { Conversation } from './conversation'\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} from './errors'\nexport type {\n StatsWidgetClientOptions, FetchLike, UserContext, ChatInput,\n SignalType, SignalEntityType, SignalInput,\n} from './types'\nexport type {\n ChatEvent, ProgressEventData, AnswerEventData, EntityCard, EntityCardEventData,\n ActionButtonEventData, IntentChipEventData, ActionsLoadingEventData,\n TurnCompleteEventData, StreamErrorEventData,\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}\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, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\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\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: { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey },\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 toWidgetError(res.status, res.headers.get('Retry-After'))\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","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; operatorUserId: 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 { signalType, entityType, entityName: input.entityName, operatorUserId: input.operatorUserId }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: Omit<SignalInput, 'operatorUserId'> & { operatorUserId?: string }): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n if (!operatorUserId) throw new Error('operatorUserId is required (set it on conversation() or pass it to sendSignal)')\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId }))\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { 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 }\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAGxC,YAAY,SAAiB,MAAc,QAAiB;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AACO,IAAM,YAAN,cAAwB,eAAe;AAAA,EAC5C,YAAY,UAAU,iCAAiC;AAAE,UAAM,SAAS,gBAAgB,GAAG;AAAA,EAAE;AAC/F;AACO,IAAM,iBAAN,cAA6B,eAAe;AAAA,EACjD,YAAY,UAAU,yCAAyC;AAAE,UAAM,SAAS,aAAa,GAAG;AAAA,EAAE;AACpG;AACO,IAAM,iBAAN,cAA6B,eAAe;AAAA,EAEjD,YAAY,YAAqB,UAAU,gBAAgB;AAAE,UAAM,SAAS,gBAAgB,GAAG;AAAG,SAAK,aAAa;AAAA,EAAW;AACjI;AACO,IAAM,gBAAN,cAA4B,eAAe;AAAA,EAChD,YAAY,QAAgB,UAAU,kBAAkB;AAAE,UAAM,SAAS,kBAAkB,MAAM;AAAA,EAAE;AACrG;AACO,IAAM,eAAN,cAA2B,eAAe;AAAA,EAE/C,YAAY,UAAU,0BAA0B,OAAiB;AAAE,UAAM,SAAS,eAAe;AAAG,SAAK,QAAQ;AAAA,EAAM;AACzH;AACO,IAAM,aAAN,cAAyB,eAAe;AAAA,EAE7C,YAAY,UAAU,yBAAyB,MAAe;AAAE,UAAM,SAAS,aAAa;AAAG,SAAK,OAAO;AAAA,EAAK;AAClH;;;ACrBA,SAAS,SAAS,KAAqB,MAAsB;AAC3D,SAAO,GAAG,IAAI,QAAQ,QAAQ,QAAQ,EAAE,CAAC,OAAO,mBAAmB,IAAI,UAAU,CAAC,IAAI,IAAI;AAC5F;AAEO,SAAS,cAAc,QAAgB,kBAAiD;AAC7F,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAK,aAAO,IAAI,UAAU;AAAA,IAC/B,KAAK;AAAK,aAAO,IAAI,eAAe;AAAA,IACpC,KAAK,KAAK;AACR,YAAM,IAAI,oBAAoB,OAAO,OAAO,gBAAgB,IAAI;AAChE,aAAO,IAAI,eAAe,OAAO,SAAS,CAAC,IAAK,IAAe,MAAS;AAAA,IAC1E;AAAA,IACA;AAAS,aAAO,IAAI,cAAc,MAAM;AAAA,EAC1C;AACF;AAEA,SAAS,QAAQ,OAAyB;AACxC,SAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAEA,eAAe,KAAK,KAAqB,MAAc,MAAc,QAAyC;AAC5G,MAAI;AACF,WAAO,MAAM,IAAI,MAAM,SAAS,KAAK,IAAI,GAAG;AAAA,MAC1C,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oBAAoB,mBAAmB,IAAI,UAAU;AAAA,MAChF,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,QAAQ,KAAK,EAAG,OAAM;AAC1B,UAAM,IAAI,aAAa,0BAA0B,KAAK;AAAA,EACxD;AACF;AAEA,eAAsB,SAAS,KAAqB,OAAkB,QAAwC;AAC5G,QAAM,MAAM,MAAM,KAAK,KAAK,QAAQ,OAAO,MAAM;AACjD,MAAI,CAAC,IAAI,MAAM,IAAI,QAAQ,KAAM,OAAM,cAAc,IAAI,QAAQ,IAAI,QAAQ,IAAI,aAAa,CAAC;AAC/F,SAAO;AACT;AAEA,eAAsB,WAAW,KAAqB,UAAkB,QAAqC;AAC3G,QAAM,MAAM,MAAM,KAAK,KAAK,WAAW,UAAU,MAAM;AACvD,MAAI,CAAC,IAAI,GAAI,OAAM,cAAc,IAAI,QAAQ,IAAI,QAAQ,IAAI,aAAa,CAAC;AAC7E;;;AC9CA,SAAS,UAAU,MAAmC;AACpD,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,YAAY,GAAI,QAAO;AAC3B,MAAI;AACF,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,UAAM,IAAI,WAAW,yBAAyB,IAAI;AAAA,EACpD;AACF;AAEO,SAAS,qBAAmC;AACjD,MAAI,SAAS;AACb,SAAO;AAAA,IACL,KAAK,MAAyB;AAC5B,gBAAU;AACV,YAAM,MAAiB,CAAC;AACxB,UAAI;AACJ,cAAQ,MAAM,OAAO,QAAQ,IAAI,MAAM,GAAG;AACxC,cAAM,OAAO,OAAO,MAAM,GAAG,GAAG;AAChC,iBAAS,OAAO,MAAM,MAAM,CAAC;AAC7B,cAAM,SAAS,UAAU,IAAI;AAC7B,YAAI,WAAW,OAAW,KAAI,KAAK,MAAM;AAAA,MAC3C;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAmB;AACjB,YAAM,OAAO;AACb,eAAS;AACT,YAAM,SAAS,UAAU,IAAI;AAC7B,aAAO,WAAW,SAAY,CAAC,IAAI,CAAC,MAAM;AAAA,IAC5C;AAAA,EACF;AACF;;;ACfA,SAAS,SAAS,IAAe,IAAyB;AACxD,UAAQ,GAAG,MAAM;AAAA,IACf,KAAK;AAAY,SAAG,aAAa,GAAG,IAAI;AAAG;AAAA,IAC3C,KAAK;AAAU,SAAG,WAAW,GAAG,IAAI;AAAG;AAAA,IACvC,KAAK;AAAe,SAAG,eAAe,GAAG,IAAI;AAAG;AAAA,IAChD,KAAK;AAAiB,SAAG,iBAAiB,GAAG,IAAI;AAAG;AAAA,IACpD,KAAK;AAAe,SAAG,eAAe,GAAG,IAAI;AAAG;AAAA,IAChD,KAAK;AAAmB,SAAG,mBAAmB,GAAG,IAAI;AAAG;AAAA,IACxD,KAAK;AAAiB,SAAG,aAAa,GAAG,IAAI;AAAG;AAAA,IAChD,KAAK;AAAS,SAAG,UAAU,GAAG,IAAI;AAAG;AAAA,EACvC;AACF;AAEA,gBAAgB,aAAa,KAAqB,OAAkB,QAAgD;AAClH,QAAM,MAAM,MAAM,SAAS,KAAK,OAAO,MAAM;AAC7C,QAAM,SAAS,IAAI,KAAM,UAAU;AACnC,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,SAAS,mBAAmB;AAClC,MAAI;AACF,eAAS;AACP,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,iBAAW,OAAO,OAAO,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,EAAG,OAAM;AAAA,IAChF;AACA,eAAW,OAAO,OAAO,MAAM,EAAG,OAAM;AAAA,EAC1C,UAAE;AACA,UAAM,OAAO,OAAO,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACtC;AACF;AAEO,SAAS,QACd,KACA,OACA,WACA,MACY;AACZ,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,WAAW,MAAM;AACvB,MAAI,UAAU;AACZ,QAAI,SAAS,QAAS,YAAW,MAAM;AAAA,QAClC,UAAS,iBAAiB,SAAS,MAAM,WAAW,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,EAClF;AAEA,kBAAgB,SAAoC;AAClD,qBAAiB,MAAM,aAAa,KAAK,OAAO,WAAW,MAAM,GAAG;AAClE,YAAM,MAAM,EAAE;AACd,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,WAAW,OAAO;AACxB,MAAI,WAAW;AAEf,iBAAe,QAAuB;AACpC,QAAI;AACF,uBAAiB,MAAM,UAAU;AAAE,YAAI,UAAW,UAAS,IAAI,SAAS;AAAA,MAAE;AAAA,IAC5E,SAAS,OAAO;AACd,UAAI,WAAW,WAAW,iBAAiB,gBAAgB;AAAE,kBAAU,QAAQ,KAAK;AAAG;AAAA,MAAO;AAC9F,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AAAA,IACL,CAAC,OAAO,aAAa,IAA8B;AACjD,UAAI,SAAU,OAAM,IAAI,MAAM,8BAA8B;AAC5D,iBAAW;AACX,aAAO;AAAA,IACT;AAAA,IACA,KACE,aACA,YACkC;AAClC,UAAI,SAAU,QAAO,QAAQ,QAAQ,EAAE,KAAK,aAAa,UAAU;AACnE,iBAAW;AACX,aAAO,MAAM,EAAE,KAAK,aAAa,UAAU;AAAA,IAC7C;AAAA,IACA,SAAe;AAAE,iBAAW,MAAM;AAAA,IAAE;AAAA,EACtC;AACF;;;ACpGO,IAAM,oBAAgD;AAAA,EAC3D,eAAe;AAAA,EAAG,gBAAgB;AAAA,EAAG,cAAc;AAAA,EAAG,YAAY;AAAA,EAClE,aAAa;AAAA,EAAG,cAAc;AAAA,EAAG,YAAY;AAAA,EAAG,eAAe;AAAA,EAC/D,sBAAsB;AAAA,EAAG,sBAAsB;AAAA,EAAI,oBAAoB;AAAA,EACvE,UAAU;AAAA,EAAI,eAAe;AAAA,EAAI,SAAS;AAAA,EAAI,eAAe;AAAA,EAAI,yBAAyB;AAC5F;AAEO,IAAM,oBAAsD;AAAA,EACjE,OAAO;AAAA,EAAG,MAAM;AAAA,EAAG,QAAQ;AAAA,EAAG,aAAa;AAAA,EAAG,QAAQ;AAAA,EACtD,SAAS;AAAA,EAAG,SAAS;AAAA,EAAG,OAAO;AAAA,EAAG,cAAc;AAClD;AAEO,SAAS,iBAAiB,OAE/B;AACA,QAAM,aAAa,kBAAkB,MAAM,UAAU;AACrD,QAAM,aAAa,kBAAkB,MAAM,UAAU;AACrD,MAAI,eAAe,OAAW,OAAM,IAAI,MAAM,uBAAuB,OAAO,MAAM,UAAU,CAAC,EAAE;AAC/F,MAAI,eAAe,OAAW,OAAM,IAAI,MAAM,uBAAuB,OAAO,MAAM,UAAU,CAAC,EAAE;AAC/F,SAAO,EAAE,YAAY,YAAY,YAAY,MAAM,YAAY,gBAAgB,MAAM,eAAe;AACtG;;;ACjBO,IAAM,eAAN,MAAmB;AAAA,EAGxB,YAA6B,KAAsC,SAAuB;AAA7D;AAAsC;AAAA,EAAwB;AAAA,EAE3F,KAAK,OAAkB,WAAuC;AAC5D,UAAM,gBAA6B,EAAE,GAAG,KAAK,SAAS,GAAG,MAAM,YAAY;AAC3E,UAAM,OAAkB;AAAA,MACtB,GAAG;AAAA,MACH,gBAAgB,MAAM,kBAAkB,KAAK;AAAA,MAC7C,aAAa,OAAO,KAAK,aAAa,EAAE,SAAS,IAAI,gBAAgB;AAAA,IACvE;AACA,WAAO,QAAQ,KAAK,KAAK,MAAM,WAAW;AAAA,MACxC,KAAK,CAAC,OAAO;AAAE,YAAI,GAAG,SAAS,gBAAiB,MAAK,iBAAiB,GAAG,KAAK;AAAA,MAAe;AAAA,IAC/F,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,OAAyF;AAClG,UAAM,iBAAiB,MAAM,kBAAkB,KAAK,SAAS;AAC7D,QAAI,CAAC,eAAgB,OAAM,IAAI,MAAM,gFAAgF;AACrH,WAAO,WAAW,KAAK,KAAK,iBAAiB,EAAE,GAAG,OAAO,eAAe,CAAC,CAAC;AAAA,EAC5E;AACF;;;ACrBA,IAAM,mBAAmB;AAElB,IAAM,oBAAN,MAAwB;AAAA,EAG7B,YAAY,SAAmC;AAC7C,QAAI,CAAC,QAAQ,WAAY,OAAM,IAAI,MAAM,wBAAwB;AACjE,QAAI,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,uBAAuB;AAC/D,UAAM,YAAY,QAAQ,UAAU,WAAW,QAAQ,WAAW,MAAM,KAAK,UAAU,IAAI;AAC3F,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,uDAAuD;AACvF,SAAK,MAAM;AAAA,MACT,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,MACnB,SAAS,QAAQ,WAAW;AAAA,MAC5B,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,KAAK,OAAkB,WAAuC;AAC5D,WAAO,QAAQ,KAAK,KAAK,OAAO,SAAS;AAAA,EAC3C;AAAA,EAEA,MAAM,WAAW,OAAmC;AAClD,UAAM,WAAW,KAAK,KAAK,iBAAiB,KAAK,CAAC;AAAA,EACpD;AAAA,EAEA,aAAa,SAAqC;AAChD,WAAO,IAAI,aAAa,KAAK,KAAK,OAAO;AAAA,EAC3C;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
declare class WidgetSdkError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly status?: number;
|
|
4
|
+
constructor(message: string, code: string, status?: number);
|
|
5
|
+
}
|
|
6
|
+
declare class AuthError extends WidgetSdkError {
|
|
7
|
+
constructor(message?: string);
|
|
8
|
+
}
|
|
9
|
+
declare class ForbiddenError extends WidgetSdkError {
|
|
10
|
+
constructor(message?: string);
|
|
11
|
+
}
|
|
12
|
+
declare class RateLimitError extends WidgetSdkError {
|
|
13
|
+
readonly retryAfter?: number;
|
|
14
|
+
constructor(retryAfter?: number, message?: string);
|
|
15
|
+
}
|
|
16
|
+
declare class UpstreamError extends WidgetSdkError {
|
|
17
|
+
constructor(status: number, message?: string);
|
|
18
|
+
}
|
|
19
|
+
declare class NetworkError extends WidgetSdkError {
|
|
20
|
+
readonly cause?: unknown;
|
|
21
|
+
constructor(message?: string, cause?: unknown);
|
|
22
|
+
}
|
|
23
|
+
declare class ParseError extends WidgetSdkError {
|
|
24
|
+
readonly line?: string;
|
|
25
|
+
constructor(message?: string, line?: string);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ProgressEventData {
|
|
29
|
+
phase: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}
|
|
32
|
+
interface AnswerEventData {
|
|
33
|
+
text: string;
|
|
34
|
+
}
|
|
35
|
+
interface EntityCard {
|
|
36
|
+
entityId: number;
|
|
37
|
+
entityType: string;
|
|
38
|
+
mentionText: string;
|
|
39
|
+
canonicalName: string;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
interface EntityCardEventData {
|
|
43
|
+
card: EntityCard;
|
|
44
|
+
}
|
|
45
|
+
interface ActionButtonEventData {
|
|
46
|
+
action: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
interface IntentChipEventData {
|
|
49
|
+
intent: Record<string, unknown>;
|
|
50
|
+
}
|
|
51
|
+
interface ActionsLoadingEventData {
|
|
52
|
+
message: string;
|
|
53
|
+
}
|
|
54
|
+
interface TurnCompleteEventData {
|
|
55
|
+
conversationId: string;
|
|
56
|
+
agentId?: string;
|
|
57
|
+
routeDecision: string;
|
|
58
|
+
isAgentRouted: boolean;
|
|
59
|
+
totalLatencyMs: number;
|
|
60
|
+
}
|
|
61
|
+
interface StreamErrorEventData {
|
|
62
|
+
code: string;
|
|
63
|
+
message: string;
|
|
64
|
+
terminal: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface EventEnvelope<TType extends string, TData> {
|
|
67
|
+
type: TType;
|
|
68
|
+
requestId: string;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
data: TData;
|
|
71
|
+
}
|
|
72
|
+
type ChatEvent = EventEnvelope<'progress', ProgressEventData> | EventEnvelope<'answer', AnswerEventData> | EventEnvelope<'entity_card', EntityCardEventData> | EventEnvelope<'action_button', ActionButtonEventData> | EventEnvelope<'intent_chip', IntentChipEventData> | EventEnvelope<'actions_loading', ActionsLoadingEventData> | EventEnvelope<'turn_complete', TurnCompleteEventData> | EventEnvelope<'error', StreamErrorEventData>;
|
|
73
|
+
|
|
74
|
+
type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
|
|
75
|
+
interface StatsWidgetClientOptions {
|
|
76
|
+
operatorId: string;
|
|
77
|
+
publicKey: string;
|
|
78
|
+
baseUrl?: string;
|
|
79
|
+
/** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */
|
|
80
|
+
fetch?: FetchLike;
|
|
81
|
+
}
|
|
82
|
+
interface UserContext {
|
|
83
|
+
operatorUserId?: string;
|
|
84
|
+
defaultLanguage?: string;
|
|
85
|
+
}
|
|
86
|
+
interface ChatInput {
|
|
87
|
+
message: string;
|
|
88
|
+
conversationId?: string;
|
|
89
|
+
actionId?: string;
|
|
90
|
+
userContext?: UserContext;
|
|
91
|
+
}
|
|
92
|
+
type SignalType = 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView' | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed' | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth' | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed';
|
|
93
|
+
type SignalEntityType = 'Match' | 'Team' | 'Player' | 'Competition' | 'Market' | 'Article' | 'Session' | 'Query' | 'Conversation';
|
|
94
|
+
interface SignalInput {
|
|
95
|
+
signalType: SignalType;
|
|
96
|
+
entityType: SignalEntityType;
|
|
97
|
+
entityName: string;
|
|
98
|
+
operatorUserId: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface ResolvedConfig {
|
|
102
|
+
operatorId: string;
|
|
103
|
+
publicKey: string;
|
|
104
|
+
baseUrl: string;
|
|
105
|
+
fetch: FetchLike;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface ChatCallbacks {
|
|
109
|
+
onProgress?(data: ProgressEventData): void;
|
|
110
|
+
onAnswer?(data: AnswerEventData): void;
|
|
111
|
+
onEntityCard?(data: EntityCardEventData): void;
|
|
112
|
+
onActionButton?(data: ActionButtonEventData): void;
|
|
113
|
+
onIntentChip?(data: IntentChipEventData): void;
|
|
114
|
+
onActionsLoading?(data: ActionsLoadingEventData): void;
|
|
115
|
+
onError?(error: StreamErrorEventData | WidgetSdkError): void;
|
|
116
|
+
onComplete?(data: TurnCompleteEventData): void;
|
|
117
|
+
}
|
|
118
|
+
interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {
|
|
119
|
+
cancel(): void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
declare class Conversation {
|
|
123
|
+
private readonly cfg;
|
|
124
|
+
private readonly context?;
|
|
125
|
+
conversationId?: string;
|
|
126
|
+
constructor(cfg: ResolvedConfig, context?: UserContext | undefined);
|
|
127
|
+
send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle;
|
|
128
|
+
sendSignal(input: Omit<SignalInput, 'operatorUserId'> & {
|
|
129
|
+
operatorUserId?: string;
|
|
130
|
+
}): Promise<void>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare class StatsWidgetClient {
|
|
134
|
+
private readonly cfg;
|
|
135
|
+
constructor(options: StatsWidgetClientOptions);
|
|
136
|
+
chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle;
|
|
137
|
+
sendSignal(input: SignalInput): Promise<void>;
|
|
138
|
+
conversation(context?: UserContext): Conversation;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare const SIGNAL_TYPE_CODES: Record<SignalType, number>;
|
|
142
|
+
declare const ENTITY_TYPE_CODES: Record<SignalEntityType, number>;
|
|
143
|
+
|
|
144
|
+
export { type ActionButtonEventData, type ActionsLoadingEventData, type AnswerEventData, AuthError, type ChatCallbacks, type ChatEvent, type ChatHandle, type ChatInput, Conversation, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type FetchLike, ForbiddenError, type IntentChipEventData, NetworkError, ParseError, type ProgressEventData, RateLimitError, SIGNAL_TYPE_CODES, type SignalEntityType, type SignalInput, type SignalType, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type TurnCompleteEventData, UpstreamError, type UserContext, WidgetSdkError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
declare class WidgetSdkError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly status?: number;
|
|
4
|
+
constructor(message: string, code: string, status?: number);
|
|
5
|
+
}
|
|
6
|
+
declare class AuthError extends WidgetSdkError {
|
|
7
|
+
constructor(message?: string);
|
|
8
|
+
}
|
|
9
|
+
declare class ForbiddenError extends WidgetSdkError {
|
|
10
|
+
constructor(message?: string);
|
|
11
|
+
}
|
|
12
|
+
declare class RateLimitError extends WidgetSdkError {
|
|
13
|
+
readonly retryAfter?: number;
|
|
14
|
+
constructor(retryAfter?: number, message?: string);
|
|
15
|
+
}
|
|
16
|
+
declare class UpstreamError extends WidgetSdkError {
|
|
17
|
+
constructor(status: number, message?: string);
|
|
18
|
+
}
|
|
19
|
+
declare class NetworkError extends WidgetSdkError {
|
|
20
|
+
readonly cause?: unknown;
|
|
21
|
+
constructor(message?: string, cause?: unknown);
|
|
22
|
+
}
|
|
23
|
+
declare class ParseError extends WidgetSdkError {
|
|
24
|
+
readonly line?: string;
|
|
25
|
+
constructor(message?: string, line?: string);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ProgressEventData {
|
|
29
|
+
phase: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}
|
|
32
|
+
interface AnswerEventData {
|
|
33
|
+
text: string;
|
|
34
|
+
}
|
|
35
|
+
interface EntityCard {
|
|
36
|
+
entityId: number;
|
|
37
|
+
entityType: string;
|
|
38
|
+
mentionText: string;
|
|
39
|
+
canonicalName: string;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
interface EntityCardEventData {
|
|
43
|
+
card: EntityCard;
|
|
44
|
+
}
|
|
45
|
+
interface ActionButtonEventData {
|
|
46
|
+
action: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
interface IntentChipEventData {
|
|
49
|
+
intent: Record<string, unknown>;
|
|
50
|
+
}
|
|
51
|
+
interface ActionsLoadingEventData {
|
|
52
|
+
message: string;
|
|
53
|
+
}
|
|
54
|
+
interface TurnCompleteEventData {
|
|
55
|
+
conversationId: string;
|
|
56
|
+
agentId?: string;
|
|
57
|
+
routeDecision: string;
|
|
58
|
+
isAgentRouted: boolean;
|
|
59
|
+
totalLatencyMs: number;
|
|
60
|
+
}
|
|
61
|
+
interface StreamErrorEventData {
|
|
62
|
+
code: string;
|
|
63
|
+
message: string;
|
|
64
|
+
terminal: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface EventEnvelope<TType extends string, TData> {
|
|
67
|
+
type: TType;
|
|
68
|
+
requestId: string;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
data: TData;
|
|
71
|
+
}
|
|
72
|
+
type ChatEvent = EventEnvelope<'progress', ProgressEventData> | EventEnvelope<'answer', AnswerEventData> | EventEnvelope<'entity_card', EntityCardEventData> | EventEnvelope<'action_button', ActionButtonEventData> | EventEnvelope<'intent_chip', IntentChipEventData> | EventEnvelope<'actions_loading', ActionsLoadingEventData> | EventEnvelope<'turn_complete', TurnCompleteEventData> | EventEnvelope<'error', StreamErrorEventData>;
|
|
73
|
+
|
|
74
|
+
type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
|
|
75
|
+
interface StatsWidgetClientOptions {
|
|
76
|
+
operatorId: string;
|
|
77
|
+
publicKey: string;
|
|
78
|
+
baseUrl?: string;
|
|
79
|
+
/** Advanced/testing: inject a fetch implementation. Defaults to globalThis.fetch. */
|
|
80
|
+
fetch?: FetchLike;
|
|
81
|
+
}
|
|
82
|
+
interface UserContext {
|
|
83
|
+
operatorUserId?: string;
|
|
84
|
+
defaultLanguage?: string;
|
|
85
|
+
}
|
|
86
|
+
interface ChatInput {
|
|
87
|
+
message: string;
|
|
88
|
+
conversationId?: string;
|
|
89
|
+
actionId?: string;
|
|
90
|
+
userContext?: UserContext;
|
|
91
|
+
}
|
|
92
|
+
type SignalType = 'MatchPageView' | 'PlayerPageView' | 'TeamPageView' | 'MarketView' | 'SearchQuery' | 'SessionDepth' | 'TimeOnPage' | 'InsightViewed' | 'InsightMarketClicked' | 'BetPlacedFromInsight' | 'InsightScrollDepth' | 'ToolCall' | 'EntityMention' | 'Handoff' | 'FollowUpQuery' | 'RecommendationDismissed';
|
|
93
|
+
type SignalEntityType = 'Match' | 'Team' | 'Player' | 'Competition' | 'Market' | 'Article' | 'Session' | 'Query' | 'Conversation';
|
|
94
|
+
interface SignalInput {
|
|
95
|
+
signalType: SignalType;
|
|
96
|
+
entityType: SignalEntityType;
|
|
97
|
+
entityName: string;
|
|
98
|
+
operatorUserId: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface ResolvedConfig {
|
|
102
|
+
operatorId: string;
|
|
103
|
+
publicKey: string;
|
|
104
|
+
baseUrl: string;
|
|
105
|
+
fetch: FetchLike;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface ChatCallbacks {
|
|
109
|
+
onProgress?(data: ProgressEventData): void;
|
|
110
|
+
onAnswer?(data: AnswerEventData): void;
|
|
111
|
+
onEntityCard?(data: EntityCardEventData): void;
|
|
112
|
+
onActionButton?(data: ActionButtonEventData): void;
|
|
113
|
+
onIntentChip?(data: IntentChipEventData): void;
|
|
114
|
+
onActionsLoading?(data: ActionsLoadingEventData): void;
|
|
115
|
+
onError?(error: StreamErrorEventData | WidgetSdkError): void;
|
|
116
|
+
onComplete?(data: TurnCompleteEventData): void;
|
|
117
|
+
}
|
|
118
|
+
interface ChatHandle extends AsyncIterable<ChatEvent>, PromiseLike<void> {
|
|
119
|
+
cancel(): void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
declare class Conversation {
|
|
123
|
+
private readonly cfg;
|
|
124
|
+
private readonly context?;
|
|
125
|
+
conversationId?: string;
|
|
126
|
+
constructor(cfg: ResolvedConfig, context?: UserContext | undefined);
|
|
127
|
+
send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle;
|
|
128
|
+
sendSignal(input: Omit<SignalInput, 'operatorUserId'> & {
|
|
129
|
+
operatorUserId?: string;
|
|
130
|
+
}): Promise<void>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare class StatsWidgetClient {
|
|
134
|
+
private readonly cfg;
|
|
135
|
+
constructor(options: StatsWidgetClientOptions);
|
|
136
|
+
chat(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle;
|
|
137
|
+
sendSignal(input: SignalInput): Promise<void>;
|
|
138
|
+
conversation(context?: UserContext): Conversation;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare const SIGNAL_TYPE_CODES: Record<SignalType, number>;
|
|
142
|
+
declare const ENTITY_TYPE_CODES: Record<SignalEntityType, number>;
|
|
143
|
+
|
|
144
|
+
export { type ActionButtonEventData, type ActionsLoadingEventData, type AnswerEventData, AuthError, type ChatCallbacks, type ChatEvent, type ChatHandle, type ChatInput, Conversation, ENTITY_TYPE_CODES, type EntityCard, type EntityCardEventData, type FetchLike, ForbiddenError, type IntentChipEventData, NetworkError, ParseError, type ProgressEventData, RateLimitError, SIGNAL_TYPE_CODES, type SignalEntityType, type SignalInput, type SignalType, StatsWidgetClient, type StatsWidgetClientOptions, type StreamErrorEventData, type TurnCompleteEventData, UpstreamError, type UserContext, WidgetSdkError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var WidgetSdkError = class extends Error {
|
|
3
|
+
constructor(message, code, status) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.status = status;
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var AuthError = class extends WidgetSdkError {
|
|
12
|
+
constructor(message = "Invalid or missing public key") {
|
|
13
|
+
super(message, "unauthorized", 401);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var ForbiddenError = class extends WidgetSdkError {
|
|
17
|
+
constructor(message = "Origin not allowed or widget disabled") {
|
|
18
|
+
super(message, "forbidden", 403);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var RateLimitError = class extends WidgetSdkError {
|
|
22
|
+
constructor(retryAfter, message = "Rate limited") {
|
|
23
|
+
super(message, "rate_limited", 429);
|
|
24
|
+
this.retryAfter = retryAfter;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var UpstreamError = class extends WidgetSdkError {
|
|
28
|
+
constructor(status, message = "Upstream error") {
|
|
29
|
+
super(message, "upstream_error", status);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var NetworkError = class extends WidgetSdkError {
|
|
33
|
+
constructor(message = "Network request failed", cause) {
|
|
34
|
+
super(message, "network_error");
|
|
35
|
+
this.cause = cause;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var ParseError = class extends WidgetSdkError {
|
|
39
|
+
constructor(message = "Malformed NDJSON line", line) {
|
|
40
|
+
super(message, "parse_error");
|
|
41
|
+
this.line = line;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/http.ts
|
|
46
|
+
function endpoint(cfg, path) {
|
|
47
|
+
return `${cfg.baseUrl.replace(/\/+$/, "")}/v1/${encodeURIComponent(cfg.operatorId)}/${path}`;
|
|
48
|
+
}
|
|
49
|
+
function toWidgetError(status, retryAfterHeader) {
|
|
50
|
+
switch (status) {
|
|
51
|
+
case 401:
|
|
52
|
+
return new AuthError();
|
|
53
|
+
case 403:
|
|
54
|
+
return new ForbiddenError();
|
|
55
|
+
case 429: {
|
|
56
|
+
const n = retryAfterHeader != null ? Number(retryAfterHeader) : void 0;
|
|
57
|
+
return new RateLimitError(Number.isFinite(n) ? n : void 0);
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
return new UpstreamError(status);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function isAbort(error) {
|
|
64
|
+
return error instanceof Error && error.name === "AbortError";
|
|
65
|
+
}
|
|
66
|
+
async function send(cfg, path, body, signal) {
|
|
67
|
+
try {
|
|
68
|
+
return await cfg.fetch(endpoint(cfg, path), {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "Content-Type": "application/json", "X-SS-Public-Key": cfg.publicKey },
|
|
71
|
+
body: JSON.stringify(body),
|
|
72
|
+
signal
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (isAbort(error)) throw error;
|
|
76
|
+
throw new NetworkError("Network request failed", error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function postChat(cfg, input, signal) {
|
|
80
|
+
const res = await send(cfg, "chat", input, signal);
|
|
81
|
+
if (!res.ok || res.body == null) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
82
|
+
return res;
|
|
83
|
+
}
|
|
84
|
+
async function postSignal(cfg, wireBody, signal) {
|
|
85
|
+
const res = await send(cfg, "signals", wireBody, signal);
|
|
86
|
+
if (!res.ok) throw toWidgetError(res.status, res.headers.get("Retry-After"));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/ndjson.ts
|
|
90
|
+
function parseLine(line) {
|
|
91
|
+
const trimmed = line.trim();
|
|
92
|
+
if (trimmed === "") return void 0;
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(trimmed);
|
|
95
|
+
} catch {
|
|
96
|
+
throw new ParseError("Malformed NDJSON line", line);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function createNdjsonParser() {
|
|
100
|
+
let buffer = "";
|
|
101
|
+
return {
|
|
102
|
+
push(text) {
|
|
103
|
+
buffer += text;
|
|
104
|
+
const out = [];
|
|
105
|
+
let idx;
|
|
106
|
+
while ((idx = buffer.indexOf("\n")) >= 0) {
|
|
107
|
+
const line = buffer.slice(0, idx);
|
|
108
|
+
buffer = buffer.slice(idx + 1);
|
|
109
|
+
const parsed = parseLine(line);
|
|
110
|
+
if (parsed !== void 0) out.push(parsed);
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
},
|
|
114
|
+
flush() {
|
|
115
|
+
const rest = buffer;
|
|
116
|
+
buffer = "";
|
|
117
|
+
const parsed = parseLine(rest);
|
|
118
|
+
return parsed === void 0 ? [] : [parsed];
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/chat.ts
|
|
124
|
+
function dispatch(ev, cb) {
|
|
125
|
+
switch (ev.type) {
|
|
126
|
+
case "progress":
|
|
127
|
+
cb.onProgress?.(ev.data);
|
|
128
|
+
break;
|
|
129
|
+
case "answer":
|
|
130
|
+
cb.onAnswer?.(ev.data);
|
|
131
|
+
break;
|
|
132
|
+
case "entity_card":
|
|
133
|
+
cb.onEntityCard?.(ev.data);
|
|
134
|
+
break;
|
|
135
|
+
case "action_button":
|
|
136
|
+
cb.onActionButton?.(ev.data);
|
|
137
|
+
break;
|
|
138
|
+
case "intent_chip":
|
|
139
|
+
cb.onIntentChip?.(ev.data);
|
|
140
|
+
break;
|
|
141
|
+
case "actions_loading":
|
|
142
|
+
cb.onActionsLoading?.(ev.data);
|
|
143
|
+
break;
|
|
144
|
+
case "turn_complete":
|
|
145
|
+
cb.onComplete?.(ev.data);
|
|
146
|
+
break;
|
|
147
|
+
case "error":
|
|
148
|
+
cb.onError?.(ev.data);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function* streamEvents(cfg, input, signal) {
|
|
153
|
+
const res = await postChat(cfg, input, signal);
|
|
154
|
+
const reader = res.body.getReader();
|
|
155
|
+
const decoder = new TextDecoder();
|
|
156
|
+
const parser = createNdjsonParser();
|
|
157
|
+
try {
|
|
158
|
+
for (; ; ) {
|
|
159
|
+
const { done, value } = await reader.read();
|
|
160
|
+
if (done) break;
|
|
161
|
+
for (const obj of parser.push(decoder.decode(value, { stream: true }))) yield obj;
|
|
162
|
+
}
|
|
163
|
+
for (const obj of parser.flush()) yield obj;
|
|
164
|
+
} finally {
|
|
165
|
+
await reader.cancel().catch(() => {
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function runChat(cfg, input, callbacks, opts) {
|
|
170
|
+
const controller = new AbortController();
|
|
171
|
+
const external = opts?.signal;
|
|
172
|
+
if (external) {
|
|
173
|
+
if (external.aborted) controller.abort();
|
|
174
|
+
else external.addEventListener("abort", () => controller.abort(), { once: true });
|
|
175
|
+
}
|
|
176
|
+
async function* source() {
|
|
177
|
+
for await (const ev of streamEvents(cfg, input, controller.signal)) {
|
|
178
|
+
opts?.tap?.(ev);
|
|
179
|
+
yield ev;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const iterator = source();
|
|
183
|
+
let consumed = false;
|
|
184
|
+
async function drive() {
|
|
185
|
+
try {
|
|
186
|
+
for await (const ev of iterator) {
|
|
187
|
+
if (callbacks) dispatch(ev, callbacks);
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (callbacks?.onError && error instanceof WidgetSdkError) {
|
|
191
|
+
callbacks.onError(error);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
[Symbol.asyncIterator]() {
|
|
199
|
+
if (consumed) throw new Error("chat stream already consumed");
|
|
200
|
+
consumed = true;
|
|
201
|
+
return iterator;
|
|
202
|
+
},
|
|
203
|
+
then(onfulfilled, onrejected) {
|
|
204
|
+
if (consumed) return Promise.resolve().then(onfulfilled, onrejected);
|
|
205
|
+
consumed = true;
|
|
206
|
+
return drive().then(onfulfilled, onrejected);
|
|
207
|
+
},
|
|
208
|
+
cancel() {
|
|
209
|
+
controller.abort();
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/signals.ts
|
|
215
|
+
var SIGNAL_TYPE_CODES = {
|
|
216
|
+
MatchPageView: 1,
|
|
217
|
+
PlayerPageView: 2,
|
|
218
|
+
TeamPageView: 3,
|
|
219
|
+
MarketView: 4,
|
|
220
|
+
SearchQuery: 5,
|
|
221
|
+
SessionDepth: 6,
|
|
222
|
+
TimeOnPage: 7,
|
|
223
|
+
InsightViewed: 8,
|
|
224
|
+
InsightMarketClicked: 9,
|
|
225
|
+
BetPlacedFromInsight: 10,
|
|
226
|
+
InsightScrollDepth: 11,
|
|
227
|
+
ToolCall: 12,
|
|
228
|
+
EntityMention: 13,
|
|
229
|
+
Handoff: 14,
|
|
230
|
+
FollowUpQuery: 15,
|
|
231
|
+
RecommendationDismissed: 16
|
|
232
|
+
};
|
|
233
|
+
var ENTITY_TYPE_CODES = {
|
|
234
|
+
Match: 1,
|
|
235
|
+
Team: 2,
|
|
236
|
+
Player: 3,
|
|
237
|
+
Competition: 4,
|
|
238
|
+
Market: 5,
|
|
239
|
+
Article: 6,
|
|
240
|
+
Session: 7,
|
|
241
|
+
Query: 8,
|
|
242
|
+
Conversation: 9
|
|
243
|
+
};
|
|
244
|
+
function toSignalWireBody(input) {
|
|
245
|
+
const signalType = SIGNAL_TYPE_CODES[input.signalType];
|
|
246
|
+
const entityType = ENTITY_TYPE_CODES[input.entityType];
|
|
247
|
+
if (signalType === void 0) throw new Error(`Unknown signalType: ${String(input.signalType)}`);
|
|
248
|
+
if (entityType === void 0) throw new Error(`Unknown entityType: ${String(input.entityType)}`);
|
|
249
|
+
return { signalType, entityType, entityName: input.entityName, operatorUserId: input.operatorUserId };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/conversation.ts
|
|
253
|
+
var Conversation = class {
|
|
254
|
+
constructor(cfg, context) {
|
|
255
|
+
this.cfg = cfg;
|
|
256
|
+
this.context = context;
|
|
257
|
+
}
|
|
258
|
+
send(input, callbacks) {
|
|
259
|
+
const mergedContext = { ...this.context, ...input.userContext };
|
|
260
|
+
const full = {
|
|
261
|
+
...input,
|
|
262
|
+
conversationId: input.conversationId ?? this.conversationId,
|
|
263
|
+
userContext: Object.keys(mergedContext).length > 0 ? mergedContext : void 0
|
|
264
|
+
};
|
|
265
|
+
return runChat(this.cfg, full, callbacks, {
|
|
266
|
+
tap: (ev) => {
|
|
267
|
+
if (ev.type === "turn_complete") this.conversationId = ev.data.conversationId;
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
sendSignal(input) {
|
|
272
|
+
const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId;
|
|
273
|
+
if (!operatorUserId) throw new Error("operatorUserId is required (set it on conversation() or pass it to sendSignal)");
|
|
274
|
+
return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId }));
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// src/client.ts
|
|
279
|
+
var DEFAULT_BASE_URL = "https://widget.sensiblestats.com";
|
|
280
|
+
var StatsWidgetClient = class {
|
|
281
|
+
constructor(options) {
|
|
282
|
+
if (!options.operatorId) throw new Error("operatorId is required");
|
|
283
|
+
if (!options.publicKey) throw new Error("publicKey is required");
|
|
284
|
+
const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
285
|
+
if (!fetchImpl) throw new Error("No fetch implementation available; pass options.fetch");
|
|
286
|
+
this.cfg = {
|
|
287
|
+
operatorId: options.operatorId,
|
|
288
|
+
publicKey: options.publicKey,
|
|
289
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
290
|
+
fetch: fetchImpl
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
chat(input, callbacks) {
|
|
294
|
+
return runChat(this.cfg, input, callbacks);
|
|
295
|
+
}
|
|
296
|
+
async sendSignal(input) {
|
|
297
|
+
await postSignal(this.cfg, toSignalWireBody(input));
|
|
298
|
+
}
|
|
299
|
+
conversation(context) {
|
|
300
|
+
return new Conversation(this.cfg, context);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
export {
|
|
304
|
+
AuthError,
|
|
305
|
+
Conversation,
|
|
306
|
+
ENTITY_TYPE_CODES,
|
|
307
|
+
ForbiddenError,
|
|
308
|
+
NetworkError,
|
|
309
|
+
ParseError,
|
|
310
|
+
RateLimitError,
|
|
311
|
+
SIGNAL_TYPE_CODES,
|
|
312
|
+
StatsWidgetClient,
|
|
313
|
+
UpstreamError,
|
|
314
|
+
WidgetSdkError
|
|
315
|
+
};
|
|
316
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/ndjson.ts","../src/chat.ts","../src/signals.ts","../src/conversation.ts","../src/client.ts"],"sourcesContent":["export class WidgetSdkError extends Error {\n readonly code: string\n readonly status?: number\n constructor(message: string, code: string, status?: number) {\n super(message)\n this.name = new.target.name\n this.code = code\n this.status = status\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\nexport class AuthError extends WidgetSdkError {\n constructor(message = 'Invalid or missing public key') { super(message, 'unauthorized', 401) }\n}\nexport class ForbiddenError extends WidgetSdkError {\n constructor(message = 'Origin not allowed or widget disabled') { super(message, 'forbidden', 403) }\n}\nexport class RateLimitError extends WidgetSdkError {\n readonly retryAfter?: number\n constructor(retryAfter?: number, message = 'Rate limited') { super(message, 'rate_limited', 429); this.retryAfter = retryAfter }\n}\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, NetworkError, RateLimitError, UpstreamError, WidgetSdkError } from './errors'\nimport type { ChatInput, FetchLike } from './types'\n\nexport interface ResolvedConfig {\n operatorId: string\n publicKey: string\n baseUrl: string\n fetch: FetchLike\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\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: { 'Content-Type': 'application/json', 'X-SS-Public-Key': cfg.publicKey },\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 toWidgetError(res.status, res.headers.get('Retry-After'))\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","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; operatorUserId: 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 { signalType, entityType, entityName: input.entityName, operatorUserId: input.operatorUserId }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { postSignal, type ResolvedConfig } from './http'\nimport { toSignalWireBody } from './signals'\nimport type { ChatInput, SignalInput, UserContext } from './types'\n\nexport class Conversation {\n conversationId?: string\n\n constructor(private readonly cfg: ResolvedConfig, private readonly context?: UserContext) {}\n\n send(input: ChatInput, callbacks?: ChatCallbacks): ChatHandle {\n const mergedContext: UserContext = { ...this.context, ...input.userContext }\n const full: ChatInput = {\n ...input,\n conversationId: input.conversationId ?? this.conversationId,\n userContext: Object.keys(mergedContext).length > 0 ? mergedContext : undefined,\n }\n return runChat(this.cfg, full, callbacks, {\n tap: (ev) => { if (ev.type === 'turn_complete') this.conversationId = ev.data.conversationId },\n })\n }\n\n sendSignal(input: Omit<SignalInput, 'operatorUserId'> & { operatorUserId?: string }): Promise<void> {\n const operatorUserId = input.operatorUserId ?? this.context?.operatorUserId\n if (!operatorUserId) throw new Error('operatorUserId is required (set it on conversation() or pass it to sendSignal)')\n return postSignal(this.cfg, toSignalWireBody({ ...input, operatorUserId }))\n }\n}\n","import { runChat, type ChatCallbacks, type ChatHandle } from './chat'\nimport { Conversation } from './conversation'\nimport { 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 }\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"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sensiblestats/widget-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Headless browser SDK for the SensibleStats chat widget gateway.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/cebirci/sensible-stats.git",
|
|
29
|
+
"directory": "SensibleStats.Widget/packages/widget-sdk"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://widget.sensiblestats.com",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"prepublishOnly": "yarn build"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.3.0",
|
|
43
|
+
"typescript": "^5.6.0",
|
|
44
|
+
"vitest": "^2.1.0"
|
|
45
|
+
}
|
|
46
|
+
}
|