@agg-build/sdk 4.17.4 → 4.18.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.
@@ -0,0 +1,2073 @@
1
+ import {
2
+ __async,
3
+ __objRest,
4
+ __spreadProps,
5
+ __spreadValues
6
+ } from "./chunk-WNQUEZJF.mjs";
7
+
8
+ // src/market-data/history-decoder.ts
9
+ function decodeChartHistory(payload) {
10
+ if (payload.length > 1048576) throw new Error("Chart history exceeds decode budget");
11
+ const body = JSON.parse(payload);
12
+ if (!body || !Array.isArray(body.data) || body.data.length > 5e3 || typeof body.venueMarketOutcomeId !== "string" || typeof body.venue !== "string" || !["1m", "5m", "1h", "1d"].includes(body.resolution) || !body.meta)
13
+ throw new Error("Invalid chart history response");
14
+ const price = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
15
+ for (const bar of body.data) {
16
+ if (!Number.isSafeInteger(bar.t) || bar.t < 0 || ![bar.o, bar.h, bar.l, bar.c].every(price) || bar.l > Math.min(bar.o, bar.c) || bar.h < Math.max(bar.o, bar.c) || bar.v !== null && (!Number.isFinite(bar.v) || bar.v < 0) || bar.mean !== void 0 && !price(bar.mean))
17
+ throw new Error("Invalid chart history candle");
18
+ }
19
+ const data = [...body.data].sort((a, b) => a.t - b.t);
20
+ if (data.some((bar, index) => index > 0 && data[index - 1].t === bar.t))
21
+ throw new Error("Duplicate chart history timestamp");
22
+ return __spreadProps(__spreadValues({}, body), { data });
23
+ }
24
+ function readChartHistoryText(response) {
25
+ return __async(this, null, function* () {
26
+ var _a, _b;
27
+ const maxBytes = 1048576;
28
+ if (Number(response.headers.get("content-length")) > maxBytes) {
29
+ yield (_a = response.body) == null ? void 0 : _a.cancel();
30
+ throw new Error("Chart history exceeds decode budget");
31
+ }
32
+ if (!((_b = response.body) == null ? void 0 : _b.getReader)) {
33
+ const text2 = yield response.text();
34
+ if (new TextEncoder().encode(text2).byteLength > maxBytes)
35
+ throw new Error("Chart history exceeds decode budget");
36
+ return text2;
37
+ }
38
+ const reader = response.body.getReader();
39
+ const decoder = new TextDecoder();
40
+ let size = 0;
41
+ let text = "";
42
+ try {
43
+ while (true) {
44
+ const { value, done } = yield reader.read();
45
+ if (done) return text + decoder.decode();
46
+ size += value.byteLength;
47
+ if (size > maxBytes) {
48
+ yield reader.cancel();
49
+ throw new Error("Chart history exceeds decode budget");
50
+ }
51
+ text += decoder.decode(value, { stream: true });
52
+ }
53
+ } finally {
54
+ reader.releaseLock();
55
+ }
56
+ });
57
+ }
58
+
59
+ // src/market-history.ts
60
+ function readBoundedBody(response, signal) {
61
+ return __async(this, null, function* () {
62
+ var _a, _b;
63
+ if (!response.body) throw new Error("Missing history body");
64
+ const reader = response.body.getReader();
65
+ const chunks = [];
66
+ let size = 0;
67
+ const abort = () => {
68
+ void reader.cancel(signal.reason).catch(() => void 0);
69
+ };
70
+ signal.addEventListener("abort", abort, { once: true });
71
+ try {
72
+ while (true) {
73
+ if (signal.aborted) throw (_a = signal.reason) != null ? _a : new Error("History request aborted");
74
+ const { done, value } = yield reader.read();
75
+ if (signal.aborted) throw (_b = signal.reason) != null ? _b : new Error("History request aborted");
76
+ if (done) break;
77
+ size += value.byteLength;
78
+ if (size > 262144) {
79
+ yield reader.cancel();
80
+ throw new Error("Oversized history object");
81
+ }
82
+ chunks.push(value);
83
+ }
84
+ const bytes = new Uint8Array(size);
85
+ let offset = 0;
86
+ for (const chunk of chunks) {
87
+ bytes.set(chunk, offset);
88
+ offset += chunk.byteLength;
89
+ }
90
+ return bytes;
91
+ } finally {
92
+ signal.removeEventListener("abort", abort);
93
+ reader.releaseLock();
94
+ }
95
+ });
96
+ }
97
+ function loadImmutableHistory(_0) {
98
+ return __async(this, arguments, function* ({
99
+ manifest,
100
+ fetch: fetcher = globalThis.fetch,
101
+ signal,
102
+ digest
103
+ }) {
104
+ if (manifest.version !== 1 || !["venue-ohlcv-v1", "polymarket-price-samples-v1", "kalshi-ohlcv-quote-fallback-v2"].includes(
105
+ manifest.semantics
106
+ ) || manifest.chunks.length > 8 || manifest.chunks.reduce((n, c) => n + c.points, 0) > 4096 || !manifest.meta.complete) {
107
+ throw new Error("History manifest is incomplete or unsupported");
108
+ }
109
+ const hash = digest != null ? digest : ((bytes) => __async(null, null, function* () {
110
+ var _a;
111
+ if (!((_a = globalThis.crypto) == null ? void 0 : _a.subtle))
112
+ throw new Error(
113
+ "History integrity requires WebCrypto or an injected SHA-256 implementation"
114
+ );
115
+ const value = yield globalThis.crypto.subtle.digest("SHA-256", bytes);
116
+ return Array.from(new Uint8Array(value), (b) => b.toString(16).padStart(2, "0")).join("");
117
+ }));
118
+ const results = new Array(manifest.chunks.length);
119
+ let next = 0;
120
+ const controller = new AbortController();
121
+ const deadline = setTimeout(
122
+ () => controller.abort(new Error("History download budget exhausted")),
123
+ 2e3
124
+ );
125
+ const abort = () => controller.abort(signal == null ? void 0 : signal.reason);
126
+ signal == null ? void 0 : signal.addEventListener("abort", abort, { once: true });
127
+ if (signal == null ? void 0 : signal.aborted) abort();
128
+ try {
129
+ yield Promise.all(
130
+ Array.from({ length: Math.min(2, manifest.chunks.length) }, () => __async(null, null, function* () {
131
+ var _a;
132
+ while (next < manifest.chunks.length) {
133
+ if (controller.signal.aborted)
134
+ throw (_a = controller.signal.reason) != null ? _a : new Error("History request aborted");
135
+ const index = next++;
136
+ const chunk = manifest.chunks[index];
137
+ if (chunk.points < 0 || chunk.points > 512 || chunk.from >= chunk.to || new URL(chunk.url).protocol !== "https:")
138
+ throw new Error("Invalid history reference");
139
+ const response = yield fetcher(chunk.url, {
140
+ signal: controller.signal,
141
+ credentials: "omit"
142
+ });
143
+ if (!response.ok) throw new Error(`History download failed (${response.status})`);
144
+ if (Number(response.headers.get("content-length")) > 262144)
145
+ throw new Error("Oversized history object");
146
+ const bytes = yield readBoundedBody(response, controller.signal);
147
+ if (bytes.byteLength > 262144 || (yield hash(bytes)) !== chunk.sha256)
148
+ throw new Error("History integrity mismatch");
149
+ const object2 = JSON.parse(new TextDecoder().decode(bytes));
150
+ if (object2.version !== 1 || object2.venueMarketOutcomeId !== manifest.venueMarketOutcomeId || object2.venue !== manifest.venue || object2.resolution !== manifest.resolution || object2.semantics !== manifest.semantics || object2.from !== chunk.from || object2.to !== chunk.to || !Array.isArray(object2.data) || object2.data.length !== chunk.points) {
151
+ throw new Error("History identity mismatch");
152
+ }
153
+ let previous = -Infinity;
154
+ for (const bar of object2.data) {
155
+ if (!Number.isSafeInteger(bar.t) || bar.t <= previous || bar.t < chunk.from || bar.t >= chunk.to || ![bar.o, bar.h, bar.l, bar.c].every((v) => Number.isFinite(v) && v >= 0 && v <= 1) || bar.l > Math.min(bar.o, bar.c) || bar.h < Math.max(bar.o, bar.c) || bar.v !== null && (!Number.isFinite(bar.v) || bar.v < 0) || bar.mean !== void 0 && (!Number.isFinite(bar.mean) || bar.mean < 0 || bar.mean > 1))
156
+ throw new Error("Invalid history candle");
157
+ previous = bar.t;
158
+ }
159
+ results[index] = object2.data;
160
+ }
161
+ }))
162
+ );
163
+ const bars = results.flat().filter((b) => b.t >= manifest.from && b.t < manifest.to).sort((a, b) => a.t - b.t);
164
+ if (bars.some((b, i) => i > 0 && bars[i - 1].t === b.t))
165
+ throw new Error("Overlapping history chunks");
166
+ return bars;
167
+ } catch (error) {
168
+ controller.abort(error);
169
+ throw error;
170
+ } finally {
171
+ clearTimeout(deadline);
172
+ signal == null ? void 0 : signal.removeEventListener("abort", abort);
173
+ }
174
+ });
175
+ }
176
+
177
+ // ../common/src/enums/venue.ts
178
+ var Venue = /* @__PURE__ */ ((Venue2) => {
179
+ Venue2["kalshi"] = "kalshi";
180
+ Venue2["polymarket"] = "polymarket";
181
+ Venue2["limitless"] = "limitless";
182
+ Venue2["opinion"] = "opinion";
183
+ Venue2["predict"] = "predict";
184
+ Venue2["pred"] = "pred";
185
+ Venue2["tiprun"] = "tiprun";
186
+ Venue2["probable"] = "probable";
187
+ Venue2["myriad"] = "myriad";
188
+ Venue2["hyperliquid"] = "hyperliquid";
189
+ Venue2["novig"] = "novig";
190
+ Venue2["prophetx"] = "prophetx";
191
+ Venue2["betdex"] = "betdex";
192
+ return Venue2;
193
+ })(Venue || {});
194
+ var VENUES = [
195
+ "kalshi" /* kalshi */,
196
+ "polymarket" /* polymarket */,
197
+ "limitless" /* limitless */,
198
+ "opinion" /* opinion */,
199
+ "predict" /* predict */,
200
+ "pred" /* pred */,
201
+ "tiprun" /* tiprun */,
202
+ "probable" /* probable */,
203
+ "myriad" /* myriad */,
204
+ "hyperliquid" /* hyperliquid */,
205
+ "novig" /* novig */,
206
+ "prophetx" /* prophetx */,
207
+ "betdex" /* betdex */
208
+ ];
209
+ var VENUE_CHAIN_IDS = {
210
+ ["kalshi" /* kalshi */]: 792703809,
211
+ ["polymarket" /* polymarket */]: 137,
212
+ ["limitless" /* limitless */]: 8453,
213
+ ["predict" /* predict */]: 56,
214
+ ["pred" /* pred */]: 8453,
215
+ ["tiprun" /* tiprun */]: 42161,
216
+ ["myriad" /* myriad */]: 56,
217
+ ["hyperliquid" /* hyperliquid */]: 1337,
218
+ ["novig" /* novig */]: 792703809,
219
+ ["prophetx" /* prophetx */]: 792703809
220
+ };
221
+ var ACTIVE_VENUES = [
222
+ "kalshi" /* kalshi */,
223
+ "polymarket" /* polymarket */,
224
+ "limitless" /* limitless */,
225
+ "opinion" /* opinion */,
226
+ "predict" /* predict */,
227
+ "pred" /* pred */,
228
+ "tiprun" /* tiprun */,
229
+ "probable" /* probable */,
230
+ "myriad" /* myriad */,
231
+ "hyperliquid" /* hyperliquid */,
232
+ "novig" /* novig */,
233
+ "prophetx" /* prophetx */,
234
+ "betdex" /* betdex */
235
+ ];
236
+ var INACTIVE_VENUES = [];
237
+ var DEFAULT_DISABLED_VENUES = [
238
+ "pred" /* pred */,
239
+ "tiprun" /* tiprun */,
240
+ "novig" /* novig */,
241
+ "prophetx" /* prophetx */,
242
+ "betdex" /* betdex */
243
+ ];
244
+ var ACTIVE_VENUE_SET = new Set(ACTIVE_VENUES);
245
+ var INACTIVE_VENUE_SET = new Set(INACTIVE_VENUES);
246
+ function normalizeVenue(venue) {
247
+ return venue.trim().toLowerCase();
248
+ }
249
+ function isVenueActive(venue) {
250
+ if (ACTIVE_VENUE_SET.has(venue)) return true;
251
+ if (INACTIVE_VENUE_SET.has(venue)) return false;
252
+ return ACTIVE_VENUE_SET.has(normalizeVenue(venue));
253
+ }
254
+ function isVenueInactive(venue) {
255
+ if (INACTIVE_VENUE_SET.has(venue)) return true;
256
+ if (ACTIVE_VENUE_SET.has(venue)) return false;
257
+ return INACTIVE_VENUE_SET.has(normalizeVenue(venue));
258
+ }
259
+ function isVenueDataVisible(venue, dataVisibleOverride = []) {
260
+ if (isVenueActive(venue)) return true;
261
+ const n = normalizeVenue(venue);
262
+ return dataVisibleOverride.some((v) => normalizeVenue(v) === n);
263
+ }
264
+ function getEffectiveDisabledVenues(disabledVenues, dataVisibleVenues = []) {
265
+ if (disabledVenues === void 0) {
266
+ const disabled2 = new Set(DEFAULT_DISABLED_VENUES);
267
+ for (const venue of dataVisibleVenues) disabled2.delete(normalizeVenue(venue));
268
+ return VENUES.filter((venue) => disabled2.has(venue));
269
+ }
270
+ const disabled = new Set(disabledVenues.map(normalizeVenue));
271
+ return VENUES.filter((venue) => disabled.has(venue));
272
+ }
273
+
274
+ // ../common/src/enums/image-size.ts
275
+ var ImageSize = /* @__PURE__ */ ((ImageSize2) => {
276
+ ImageSize2[ImageSize2["sm"] = 44] = "sm";
277
+ ImageSize2[ImageSize2["md"] = 48] = "md";
278
+ ImageSize2[ImageSize2["lg"] = 60] = "lg";
279
+ ImageSize2[ImageSize2["xl"] = 80] = "xl";
280
+ ImageSize2[ImageSize2["xxl"] = 96] = "xxl";
281
+ ImageSize2[ImageSize2["xxxl"] = 120] = "xxxl";
282
+ ImageSize2[ImageSize2["original"] = 0] = "original";
283
+ return ImageSize2;
284
+ })(ImageSize || {});
285
+ var IMAGE_SIZES = [
286
+ 44 /* sm */,
287
+ 48 /* md */,
288
+ 60 /* lg */,
289
+ 80 /* xl */,
290
+ 96 /* xxl */,
291
+ 120 /* xxxl */
292
+ ];
293
+ var RETINA_IMAGE_SIZES = [80 /* xl */, 96 /* xxl */, 120 /* xxxl */];
294
+
295
+ // ../common/src/enums/account.ts
296
+ var AccountType = /* @__PURE__ */ ((AccountType2) => {
297
+ AccountType2["oauth"] = "oauth";
298
+ AccountType2["siwe"] = "siwe";
299
+ AccountType2["siws"] = "siws";
300
+ AccountType2["email"] = "email";
301
+ return AccountType2;
302
+ })(AccountType || {});
303
+ var AccountProvider = /* @__PURE__ */ ((AccountProvider2) => {
304
+ AccountProvider2["wallet"] = "wallet";
305
+ AccountProvider2["solana_wallet"] = "solana_wallet";
306
+ AccountProvider2["google"] = "google";
307
+ AccountProvider2["twitter"] = "twitter";
308
+ AccountProvider2["apple"] = "apple";
309
+ AccountProvider2["email"] = "email";
310
+ return AccountProvider2;
311
+ })(AccountProvider || {});
312
+
313
+ // ../common/src/enums/chain.ts
314
+ var Chain = /* @__PURE__ */ ((Chain2) => {
315
+ Chain2["evm"] = "evm";
316
+ Chain2["svm"] = "svm";
317
+ return Chain2;
318
+ })(Chain || {});
319
+
320
+ // ../common/src/enums/market-status.ts
321
+ var MatchStatus = /* @__PURE__ */ ((MatchStatus2) => {
322
+ MatchStatus2["pending"] = "pending";
323
+ MatchStatus2["unmatched"] = "unmatched";
324
+ MatchStatus2["review"] = "review";
325
+ MatchStatus2["matched"] = "matched";
326
+ MatchStatus2["verified"] = "verified";
327
+ MatchStatus2["rejected"] = "rejected";
328
+ return MatchStatus2;
329
+ })(MatchStatus || {});
330
+ var MatchType = /* @__PURE__ */ ((MatchType2) => {
331
+ MatchType2["manual"] = "manual";
332
+ MatchType2["llm"] = "llm";
333
+ return MatchType2;
334
+ })(MatchType || {});
335
+ var CONFIRMED_MATCH_STATUSES = ["matched" /* matched */, "verified" /* verified */];
336
+ var MarketStatus = /* @__PURE__ */ ((MarketStatus2) => {
337
+ MarketStatus2["open"] = "open";
338
+ MarketStatus2["closed"] = "closed";
339
+ MarketStatus2["resolved"] = "resolved";
340
+ MarketStatus2["unopened"] = "unopened";
341
+ MarketStatus2["paused"] = "paused";
342
+ return MarketStatus2;
343
+ })(MarketStatus || {});
344
+
345
+ // ../common/src/enums/trading.ts
346
+ var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
347
+ OrderStatus2["pending"] = "pending";
348
+ OrderStatus2["signing"] = "signing";
349
+ OrderStatus2["pending_bridge"] = "pending_bridge";
350
+ OrderStatus2["submitting"] = "submitting";
351
+ OrderStatus2["submitted"] = "submitted";
352
+ OrderStatus2["open"] = "open";
353
+ OrderStatus2["partially_filled_open"] = "partially_filled_open";
354
+ OrderStatus2["cancel_pending"] = "cancel_pending";
355
+ OrderStatus2["filled"] = "filled";
356
+ OrderStatus2["partial_fill"] = "partial_fill";
357
+ OrderStatus2["failed"] = "failed";
358
+ OrderStatus2["expired"] = "expired";
359
+ OrderStatus2["cancelled"] = "cancelled";
360
+ return OrderStatus2;
361
+ })(OrderStatus || {});
362
+ var TradeSide = /* @__PURE__ */ ((TradeSide2) => {
363
+ TradeSide2["Buy"] = "buy";
364
+ TradeSide2["Sell"] = "sell";
365
+ return TradeSide2;
366
+ })(TradeSide || {});
367
+ var OrderType = /* @__PURE__ */ ((OrderType2) => {
368
+ OrderType2["Market"] = "market";
369
+ OrderType2["Limit"] = "limit";
370
+ return OrderType2;
371
+ })(OrderType || {});
372
+ var TimeInForce = /* @__PURE__ */ ((TimeInForce2) => {
373
+ TimeInForce2["GTC"] = "GTC";
374
+ TimeInForce2["GTD"] = "GTD";
375
+ TimeInForce2["FOK"] = "FOK";
376
+ TimeInForce2["FAK"] = "FAK";
377
+ TimeInForce2["IOC"] = "IOC";
378
+ TimeInForce2["ALO"] = "ALO";
379
+ return TimeInForce2;
380
+ })(TimeInForce || {});
381
+
382
+ // ../common/src/utils/format-market-display.ts
383
+ function formatOutcomeLabel(venue, outcome, _market) {
384
+ return outcome.label;
385
+ }
386
+ function formatMarketQuestion(venue, market) {
387
+ var _a, _b, _c, _d;
388
+ if ((_a = market.shortTitle) == null ? void 0 : _a.trim()) return market.shortTitle.trim();
389
+ if (venue === "kalshi" /* kalshi */) {
390
+ const firstTitle = (_d = (_c = (_b = market.venueMarketOutcomes) == null ? void 0 : _b[0]) == null ? void 0 : _c.title) == null ? void 0 : _d.trim();
391
+ if (firstTitle) return firstTitle;
392
+ }
393
+ return market.question.trim();
394
+ }
395
+ function formatOutcomeTitle(_venue, outcome, market) {
396
+ var _a, _b;
397
+ const outcomes = (_a = market.venueMarketOutcomes) != null ? _a : [];
398
+ if (outcomes.length >= 2) {
399
+ const normalized = outcomes.map((o) => {
400
+ var _a2, _b2;
401
+ return (_b2 = (_a2 = o.title) == null ? void 0 : _a2.trim()) != null ? _b2 : "";
402
+ });
403
+ const hasAnyTitle = normalized.some((t) => t.length > 0);
404
+ if (hasAnyTitle && normalized.every((t) => t === normalized[0])) return null;
405
+ }
406
+ const title = (_b = outcome.title) == null ? void 0 : _b.trim();
407
+ if (title) return title;
408
+ return deriveOverUnderTitle(outcome.label, market.question);
409
+ }
410
+ var OVER_UNDER_QUESTION = /\bO\/U\s+\d/i;
411
+ function deriveOverUnderTitle(label, question) {
412
+ if (!question || !OVER_UNDER_QUESTION.test(question)) return null;
413
+ const normalized = label.trim().toLowerCase();
414
+ if (normalized === "yes") return "Over";
415
+ if (normalized === "no") return "Under";
416
+ return null;
417
+ }
418
+
419
+ // ../common/src/utils/auth.ts
420
+ function getWalletAddressFromUserProfile(user) {
421
+ var _a, _b, _c, _d, _e;
422
+ const oauthWallet = (_b = (_a = user == null ? void 0 : user.accounts) == null ? void 0 : _a.find(
423
+ (a) => a.type === "oauth" /* oauth */ && String(a.provider).toLowerCase() === "wallet"
424
+ )) != null ? _b : null;
425
+ if (oauthWallet == null ? void 0 : oauthWallet.providerAccountId) return oauthWallet.providerAccountId;
426
+ const siweAccount = (_d = (_c = user == null ? void 0 : user.accounts) == null ? void 0 : _c.find((a) => a.type === "siwe" /* siwe */)) != null ? _d : null;
427
+ return (_e = siweAccount == null ? void 0 : siweAccount.providerAccountId) != null ? _e : void 0;
428
+ }
429
+
430
+ // ../common/src/utils/validate.ts
431
+ function safeParse(value, guard) {
432
+ if (guard(value)) return { success: true, data: value };
433
+ return { success: false };
434
+ }
435
+ function parse(value, guard, message = "Validation failed") {
436
+ if (guard(value)) return value;
437
+ const err = new Error(message);
438
+ err.issues = [{ message }];
439
+ throw err;
440
+ }
441
+ function isEnum(values) {
442
+ return (v) => typeof v === "string" && values.has(v);
443
+ }
444
+ function enumGuard(source) {
445
+ const values = new Set(Array.isArray(source) ? source : Object.values(source));
446
+ return isEnum(values);
447
+ }
448
+ function isFiniteNonNeg(v) {
449
+ return typeof v === "number" && Number.isFinite(v) && v >= 0;
450
+ }
451
+ function isNonEmptyString(v) {
452
+ return typeof v === "string" && v.length > 0;
453
+ }
454
+ function hasShape(v, checks) {
455
+ if (typeof v !== "object" || v === null) return false;
456
+ const obj = v;
457
+ for (const [key, check] of Object.entries(checks)) {
458
+ if (!(key in obj) || !check(obj[key])) return false;
459
+ }
460
+ return true;
461
+ }
462
+ var EMAIL_MSG = "Enter a valid email address.";
463
+ var EMAIL_MAX_LEN = 254;
464
+ function isEmail(v) {
465
+ const n = v.length;
466
+ if (n === 0 || n > EMAIL_MAX_LEN) return false;
467
+ let atIdx = -1;
468
+ for (let i = 0; i < n; i++) {
469
+ const c = v.charCodeAt(i);
470
+ if (c === 32 || c >= 9 && c <= 13) return false;
471
+ if (c === 64) {
472
+ if (atIdx !== -1) return false;
473
+ atIdx = i;
474
+ }
475
+ }
476
+ if (atIdx <= 0 || atIdx === n - 1) return false;
477
+ for (let i = atIdx + 2; i < n - 1; i++) {
478
+ if (v.charCodeAt(i) === 46) return true;
479
+ }
480
+ return false;
481
+ }
482
+ function parseEmail(raw) {
483
+ const email = raw.trim();
484
+ if (!isEmail(email)) {
485
+ return { success: false, error: { issues: [{ message: EMAIL_MSG }] } };
486
+ }
487
+ return { success: true, data: { email } };
488
+ }
489
+ function parseEmailStrict(raw) {
490
+ var _a;
491
+ const result = parseEmail(raw);
492
+ if (!result.success) {
493
+ const err = new Error(EMAIL_MSG);
494
+ err.issues = (_a = result.error) == null ? void 0 : _a.issues;
495
+ throw err;
496
+ }
497
+ return result.data;
498
+ }
499
+
500
+ // ../common/src/utils/image-url.ts
501
+ function pickVariant(px) {
502
+ if (px <= 44 /* sm */) return 44 /* sm */;
503
+ if (px <= 48 /* md */) return 48 /* md */;
504
+ if (px <= 60 /* lg */) return 60 /* lg */;
505
+ return 0 /* original */;
506
+ }
507
+ var VARIANT_RE = /\/(original|raw|\d+)\.webp$/;
508
+ function optimizedImageUrl(url, maxPx) {
509
+ if (!url) return void 0;
510
+ if (!VARIANT_RE.test(url)) return url;
511
+ const variant = pickVariant(maxPx);
512
+ const filename = variant === 0 /* original */ ? "original.webp" : `${variant}.webp`;
513
+ return url.replace(VARIANT_RE, `/${filename}`);
514
+ }
515
+ function retinaImageUrl(url, maxPx) {
516
+ if (!url) return void 0;
517
+ if (!VARIANT_RE.test(url)) return void 0;
518
+ const variant = RETINA_IMAGE_SIZES.find((size) => size >= maxPx * 2);
519
+ if (variant == null) return void 0;
520
+ return url.replace(VARIANT_RE, `/${variant}.webp`);
521
+ }
522
+
523
+ // ../common/src/utils/venue-market-cluster.ts
524
+ var toNonEmptyString = (value) => {
525
+ if (typeof value !== "string") return void 0;
526
+ const trimmedValue = value.trim();
527
+ return trimmedValue ? trimmedValue : void 0;
528
+ };
529
+ var addGraphEdge = (adjacencyById, fromMarketId, toMarketId) => {
530
+ var _a, _b;
531
+ if (fromMarketId === toMarketId) return;
532
+ const fromNeighbors = (_a = adjacencyById.get(fromMarketId)) != null ? _a : /* @__PURE__ */ new Set();
533
+ fromNeighbors.add(toMarketId);
534
+ adjacencyById.set(fromMarketId, fromNeighbors);
535
+ const toNeighbors = (_b = adjacencyById.get(toMarketId)) != null ? _b : /* @__PURE__ */ new Set();
536
+ toNeighbors.add(fromMarketId);
537
+ adjacencyById.set(toMarketId, toNeighbors);
538
+ };
539
+ var collectDirectRelationMarkets = (market) => {
540
+ var _a, _b, _c;
541
+ const relationMarkets = [];
542
+ const seenRelationIds = /* @__PURE__ */ new Set();
543
+ const addRelationMarket = (relationMarket) => {
544
+ if (!relationMarket) return;
545
+ if (seenRelationIds.has(relationMarket.id)) return;
546
+ seenRelationIds.add(relationMarket.id);
547
+ relationMarkets.push(relationMarket);
548
+ };
549
+ for (const matchedVenueMarket of (_a = market.matchedVenueMarkets) != null ? _a : []) {
550
+ addRelationMarket(matchedVenueMarket);
551
+ }
552
+ addRelationMarket((_c = (_b = market.matchEntry) == null ? void 0 : _b.targetVenueMarket) != null ? _c : void 0);
553
+ return relationMarkets;
554
+ };
555
+ var dedupeSourceMarketsById = (markets) => {
556
+ const seenMarketIds = /* @__PURE__ */ new Set();
557
+ return markets.filter((market) => {
558
+ if (seenMarketIds.has(market.id)) {
559
+ return false;
560
+ }
561
+ seenMarketIds.add(market.id);
562
+ return true;
563
+ });
564
+ };
565
+ var collectUniqueRelatedMarkets = (markets, sourceMarketsById) => {
566
+ const relatedMarketsById = /* @__PURE__ */ new Map();
567
+ for (const market of markets) {
568
+ for (const relatedMarket of collectDirectRelationMarkets(market)) {
569
+ if (sourceMarketsById.has(relatedMarket.id) || relatedMarketsById.has(relatedMarket.id)) {
570
+ continue;
571
+ }
572
+ relatedMarketsById.set(relatedMarket.id, relatedMarket);
573
+ }
574
+ }
575
+ return Array.from(relatedMarketsById.values());
576
+ };
577
+ var normalizeVenueMarketCluster = (markets, selectedMarketId) => {
578
+ var _a, _b;
579
+ if (markets.length === 0) return [];
580
+ const orderedSourceMarkets = dedupeSourceMarketsById(markets);
581
+ const sourceMarketsById = new Map(orderedSourceMarkets.map((market) => [market.id, market]));
582
+ const orderedRelatedMarkets = collectUniqueRelatedMarkets(
583
+ orderedSourceMarkets,
584
+ sourceMarketsById
585
+ );
586
+ const relatedMarketsById = new Map(orderedRelatedMarkets.map((market) => [market.id, market]));
587
+ const resolvedSelectedMarketId = toNonEmptyString(selectedMarketId);
588
+ if (!resolvedSelectedMarketId) {
589
+ return [...orderedSourceMarkets, ...orderedRelatedMarkets];
590
+ }
591
+ const adjacencyById = /* @__PURE__ */ new Map();
592
+ for (const market of orderedSourceMarkets) {
593
+ for (const relatedMarket of collectDirectRelationMarkets(market)) {
594
+ addGraphEdge(adjacencyById, market.id, relatedMarket.id);
595
+ }
596
+ const targetVenueMarketId = toNonEmptyString((_a = market.matchEntry) == null ? void 0 : _a.targetVenueMarketId);
597
+ if (targetVenueMarketId) {
598
+ addGraphEdge(adjacencyById, market.id, targetVenueMarketId);
599
+ }
600
+ }
601
+ if (!sourceMarketsById.has(resolvedSelectedMarketId) && !relatedMarketsById.has(resolvedSelectedMarketId)) {
602
+ return [];
603
+ }
604
+ const visitedMarketIds = /* @__PURE__ */ new Set();
605
+ const queue = [resolvedSelectedMarketId];
606
+ while (queue.length > 0) {
607
+ const currentMarketId = queue.shift();
608
+ if (!currentMarketId || visitedMarketIds.has(currentMarketId)) {
609
+ continue;
610
+ }
611
+ visitedMarketIds.add(currentMarketId);
612
+ const neighborMarketIds = adjacencyById.get(currentMarketId);
613
+ for (const neighborMarketId of Array.from(neighborMarketIds != null ? neighborMarketIds : /* @__PURE__ */ new Set())) {
614
+ if (!visitedMarketIds.has(neighborMarketId)) {
615
+ queue.push(neighborMarketId);
616
+ }
617
+ }
618
+ }
619
+ const orderedClusterMarkets = [];
620
+ const appendedMarketIds = /* @__PURE__ */ new Set();
621
+ const appendMarket = (market) => {
622
+ if (!market) return;
623
+ if (!visitedMarketIds.has(market.id)) return;
624
+ if (appendedMarketIds.has(market.id)) return;
625
+ appendedMarketIds.add(market.id);
626
+ orderedClusterMarkets.push(market);
627
+ };
628
+ appendMarket(
629
+ (_b = sourceMarketsById.get(resolvedSelectedMarketId)) != null ? _b : relatedMarketsById.get(resolvedSelectedMarketId)
630
+ );
631
+ for (const market of orderedSourceMarkets) {
632
+ appendMarket(market);
633
+ }
634
+ for (const market of orderedRelatedMarkets) {
635
+ appendMarket(market);
636
+ }
637
+ return orderedClusterMarkets;
638
+ };
639
+
640
+ // ../common/src/utils/sort-venues.ts
641
+ var VENUE_SORT_ORDER = [
642
+ "polymarket" /* polymarket */,
643
+ "hyperliquid" /* hyperliquid */,
644
+ "predict" /* predict */,
645
+ "prophetx" /* prophetx */,
646
+ "betdex" /* betdex */,
647
+ "kalshi" /* kalshi */,
648
+ "limitless" /* limitless */,
649
+ "myriad" /* myriad */,
650
+ "pred" /* pred */,
651
+ "tiprun" /* tiprun */,
652
+ "probable" /* probable */,
653
+ "novig" /* novig */,
654
+ "opinion" /* opinion */
655
+ ];
656
+ var venueOrderIndex = new Map(VENUE_SORT_ORDER.map((v, i) => [v, i]));
657
+ var getVenueOrder = (venue) => {
658
+ var _a;
659
+ return (_a = venueOrderIndex.get(venue)) != null ? _a : VENUE_SORT_ORDER.length;
660
+ };
661
+ var sortVenues = (venues) => [...venues].sort((a, b) => getVenueOrder(a) - getVenueOrder(b));
662
+
663
+ // ../common/src/utils/venue-url.ts
664
+ function buildVenueUrl(venue, opts) {
665
+ switch (venue) {
666
+ case "kalshi": {
667
+ const series = opts.seriesExternalId;
668
+ const event = opts.eventExternalId;
669
+ if (series && event) {
670
+ return `https://kalshi.com/markets/${series.toLowerCase()}/${event.toLowerCase()}`;
671
+ }
672
+ return null;
673
+ }
674
+ case "polymarket": {
675
+ if (opts.eventSlug) return `https://polymarket.com/event/${opts.eventSlug}`;
676
+ if (opts.conditionId) return `https://polymarket.com/market/${opts.conditionId}`;
677
+ return null;
678
+ }
679
+ case "predict": {
680
+ if (opts.eventSlug) return `https://predict.fun/market/${opts.eventSlug}`;
681
+ return null;
682
+ }
683
+ case "pred": {
684
+ if (opts.eventSlug) return `https://www.pred.app/trade/${opts.eventSlug}`;
685
+ return null;
686
+ }
687
+ case "limitless": {
688
+ if (opts.eventSlug) return `https://limitless.exchange/markets/${opts.eventSlug}`;
689
+ return null;
690
+ }
691
+ case "opinion": {
692
+ if (opts.eventSlug) return `https://www.opinion.trade/market/${opts.eventSlug}`;
693
+ return null;
694
+ }
695
+ case "myriad": {
696
+ if (opts.eventSlug) return `https://myriad.markets/markets/${opts.eventSlug}`;
697
+ return null;
698
+ }
699
+ case "hyperliquid": {
700
+ if (opts.eventSlug) return `https://app.hyperliquid.xyz/trade/${opts.eventSlug}`;
701
+ return null;
702
+ }
703
+ case "probable": {
704
+ if (opts.eventSlug) return `https://probable.markets/event/${opts.eventSlug}`;
705
+ return null;
706
+ }
707
+ case "novig": {
708
+ if (opts.outcomeExternalId && opts.partnerId) {
709
+ return opts.platform === "native" ? `novigapp://events/${opts.outcomeExternalId}/${opts.partnerId}` : `https://novig.com/events/${opts.outcomeExternalId}/${opts.partnerId}`;
710
+ }
711
+ return null;
712
+ }
713
+ default:
714
+ return null;
715
+ }
716
+ }
717
+
718
+ // ../common/src/utils/limit-price-ticks.ts
719
+ var LIMIT_PRICE_RAW_SCALE = BigInt(1e6);
720
+ var resolveTickSizeRaw = (tickSize) => {
721
+ const scaledTick = tickSize * Number(LIMIT_PRICE_RAW_SCALE);
722
+ const roundedTick = Math.round(scaledTick);
723
+ if (!Number.isFinite(scaledTick) || roundedTick <= 0 || Math.abs(scaledTick - roundedTick) > 1e-6) {
724
+ throw new RangeError(`Unsupported limit-order tick size: ${tickSize}`);
725
+ }
726
+ return BigInt(roundedTick);
727
+ };
728
+ var adjustLimitPriceRawToTick = ({
729
+ limitPriceRaw,
730
+ side,
731
+ tickSize
732
+ }) => {
733
+ const originalPrice = BigInt(limitPriceRaw);
734
+ const originalPriceRaw = originalPrice.toString();
735
+ if (tickSize == null) {
736
+ return {
737
+ adjusted: false,
738
+ adjustedPriceRaw: originalPriceRaw,
739
+ originalPriceRaw,
740
+ tickSizeRaw: null
741
+ };
742
+ }
743
+ const tickSizeRaw = resolveTickSizeRaw(tickSize);
744
+ const remainder = originalPrice % tickSizeRaw;
745
+ if (remainder === BigInt(0)) {
746
+ return {
747
+ adjusted: false,
748
+ adjustedPriceRaw: originalPriceRaw,
749
+ originalPriceRaw,
750
+ tickSizeRaw: tickSizeRaw.toString()
751
+ };
752
+ }
753
+ const adjustedPrice = side === "buy" ? originalPrice - remainder : originalPrice + (tickSizeRaw - remainder);
754
+ return {
755
+ adjusted: true,
756
+ adjustedPriceRaw: adjustedPrice.toString(),
757
+ originalPriceRaw,
758
+ tickSizeRaw: tickSizeRaw.toString()
759
+ };
760
+ };
761
+
762
+ // ../common/src/utils/balance-refill.ts
763
+ var DEFAULT_BALANCE_REFILL_DAILY_CAP_RAW = "1002000000";
764
+ var DEFAULT_BALANCE_REFILL_MAX_FEE_RAW = "2000000";
765
+ var getBalanceRefillMaximumRaw = (dailyCapRaw, maxFeeRaw) => {
766
+ const dailyCap = BigInt(dailyCapRaw);
767
+ const maximumFee = BigInt(maxFeeRaw);
768
+ if (dailyCap <= maximumFee) return "0";
769
+ return (dailyCap - maximumFee).toString();
770
+ };
771
+ var isBalanceRefillWithinDailyCap = (minimumRaw, refillAmountRaw, dailyCapRaw, maxFeeRaw) => {
772
+ const maximum = BigInt(getBalanceRefillMaximumRaw(dailyCapRaw, maxFeeRaw));
773
+ return BigInt(minimumRaw) <= maximum && BigInt(refillAmountRaw) <= maximum;
774
+ };
775
+
776
+ // ../common/src/utils/trading-splits.ts
777
+ function computeBestSplitsByAmount(selections, side, maxDollarAmount) {
778
+ var _a;
779
+ if (selections.length === 0 || maxDollarAmount <= 0) {
780
+ return { splits: [], totalSize: 0, totalCost: 0 };
781
+ }
782
+ const levels2 = [];
783
+ for (const o of selections) {
784
+ const venue = o.market.venue;
785
+ const venueMarketOutcomeId = o.outcome.id;
786
+ const outcomeExternalIdentifier = (_a = o.outcome.externalIdentifier) != null ? _a : void 0;
787
+ if (side === "buy" /* Buy */) {
788
+ [...o.orderbook.asks].sort((a, b) => a.price - b.price).forEach(
789
+ (l) => {
790
+ var _a2;
791
+ return levels2.push({
792
+ venue,
793
+ venueMarketOutcomeId,
794
+ outcomeExternalIdentifier,
795
+ price: l.price,
796
+ size: l.size,
797
+ negRisk: (_a2 = o.orderbook.negRisk) != null ? _a2 : false
798
+ });
799
+ }
800
+ );
801
+ } else {
802
+ [...o.orderbook.bids].sort((a, b) => b.price - a.price).forEach(
803
+ (l) => {
804
+ var _a2;
805
+ return levels2.push({
806
+ venue,
807
+ venueMarketOutcomeId,
808
+ outcomeExternalIdentifier,
809
+ price: 1 - l.price,
810
+ size: l.size,
811
+ negRisk: (_a2 = o.orderbook.negRisk) != null ? _a2 : false
812
+ });
813
+ }
814
+ );
815
+ }
816
+ }
817
+ levels2.sort((a, b) => a.price - b.price);
818
+ let totalCost = 0;
819
+ const fills = [];
820
+ for (const l of levels2) {
821
+ if (totalCost >= maxDollarAmount) break;
822
+ const remainingBudget = maxDollarAmount - totalCost;
823
+ const maxSizeAtLevel = Math.min(l.size, remainingBudget / l.price);
824
+ if (maxSizeAtLevel <= 0) continue;
825
+ const take = maxSizeAtLevel;
826
+ fills.push({
827
+ venue: l.venue,
828
+ venueMarketOutcomeId: l.venueMarketOutcomeId,
829
+ outcomeExternalIdentifier: l.outcomeExternalIdentifier,
830
+ price: l.price,
831
+ size: take,
832
+ negRisk: l.negRisk
833
+ });
834
+ totalCost += l.price * take;
835
+ }
836
+ if (fills.length === 0) {
837
+ return { splits: [], totalSize: 0, totalCost: 0 };
838
+ }
839
+ const byOutcome = {};
840
+ for (const f of fills) {
841
+ const key = `${f.venue}:${f.venueMarketOutcomeId}`;
842
+ const existing = byOutcome[key];
843
+ if (!existing) {
844
+ byOutcome[key] = {
845
+ size: f.size,
846
+ venue: f.venue,
847
+ venueMarketOutcomeId: f.venueMarketOutcomeId,
848
+ outcomeExternalIdentifier: f.outcomeExternalIdentifier,
849
+ negRisk: f.negRisk
850
+ };
851
+ } else {
852
+ existing.size += f.size;
853
+ }
854
+ }
855
+ const splits = [];
856
+ let totalSize = 0;
857
+ for (const key in byOutcome) {
858
+ const { size, venue, venueMarketOutcomeId, outcomeExternalIdentifier, negRisk } = byOutcome[key];
859
+ totalSize += size;
860
+ let price = 0;
861
+ if (size > 0) {
862
+ const outcomeFills = fills.filter(
863
+ (f) => f.venue === venue && f.venueMarketOutcomeId === venueMarketOutcomeId
864
+ );
865
+ if (side === "buy" /* Buy */) {
866
+ const rawPrice = Math.max(...outcomeFills.map((f) => f.price));
867
+ price = Math.ceil(rawPrice * 100) / 100;
868
+ } else {
869
+ const rawPrice = Math.min(...outcomeFills.map((f) => 1 - f.price));
870
+ price = Math.floor(rawPrice * 100) / 100;
871
+ }
872
+ }
873
+ splits.push({
874
+ venue,
875
+ venueMarketOutcomeId,
876
+ side,
877
+ price,
878
+ size,
879
+ negRisk,
880
+ outcomeExternalIdentifier
881
+ });
882
+ }
883
+ return {
884
+ splits,
885
+ totalSize,
886
+ totalCost
887
+ };
888
+ }
889
+
890
+ // ../common/src/orderbook-checksum.ts
891
+ function orderbookCrc32(value) {
892
+ let crc = 4294967295;
893
+ for (let i = 0; i < value.length; i++) {
894
+ crc ^= value.charCodeAt(i);
895
+ for (let bit = 0; bit < 8; bit++) crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
896
+ }
897
+ return (crc ^ 4294967295) >>> 0;
898
+ }
899
+ function projectedOrderbookChecksum(book) {
900
+ let result = 0;
901
+ for (const level of book.bids) result ^= orderbookCrc32(`B${level.price}:${level.size}`);
902
+ for (const level of book.asks) result ^= orderbookCrc32(`A${level.price}:${level.size}`);
903
+ return result >>> 0;
904
+ }
905
+
906
+ // src/orderbook-utils.ts
907
+ var PRICE_KEY_SCALE = 1e9;
908
+ function computeChecksum(book) {
909
+ return projectedOrderbookChecksum(book);
910
+ }
911
+ function attributedToLevel(wire) {
912
+ return { price: wire[0], size: wire[1], venues: __spreadValues({}, wire[2]) };
913
+ }
914
+ function venueLevelToLevel(wire) {
915
+ return { price: wire[0], size: wire[1] };
916
+ }
917
+ function convertVenueBooks(raw) {
918
+ const result = {};
919
+ for (const [venue, book] of Object.entries(raw)) {
920
+ result[venue] = {
921
+ bids: book.bids.map(venueLevelToLevel),
922
+ asks: book.asks.map(venueLevelToLevel)
923
+ };
924
+ }
925
+ return result;
926
+ }
927
+ function snapshotToOrderbook(snapshot) {
928
+ return {
929
+ marketId: snapshot.outcomeId,
930
+ outcomeId: snapshot.outcomeId,
931
+ bids: snapshot.bids.map(attributedToLevel),
932
+ asks: snapshot.asks.map(attributedToLevel),
933
+ venueOrderbooks: convertVenueBooks(snapshot.venueOrderbooks),
934
+ venues: __spreadValues({}, snapshot.venues),
935
+ midpoint: snapshot.midpoint,
936
+ spread: snapshot.spread,
937
+ seq: snapshot.seq,
938
+ checksum: snapshot.checksum,
939
+ timestamp: snapshot.timestamp
940
+ };
941
+ }
942
+ function applyOrderbookDelta(state, delta) {
943
+ var _a, _b;
944
+ const bids = applyChanges([...state.bids], delta.bidChanges, "desc");
945
+ const asks = applyChanges([...state.asks], delta.askChanges, "asc");
946
+ const impliedBidChangesByVenue = deriveVenueChangesFromAttributedChanges(
947
+ state.bids,
948
+ delta.bidChanges
949
+ );
950
+ const impliedAskChangesByVenue = deriveVenueChangesFromAttributedChanges(
951
+ state.asks,
952
+ delta.askChanges
953
+ );
954
+ const venueOrderbooks = __spreadValues({}, state.venueOrderbooks);
955
+ const venuesWithDelta = /* @__PURE__ */ new Set([
956
+ ...Object.keys(delta.venueDeltaBooks),
957
+ ...Object.keys(impliedBidChangesByVenue),
958
+ ...Object.keys(impliedAskChangesByVenue)
959
+ ]);
960
+ for (const venue of venuesWithDelta) {
961
+ const explicitChanges = delta.venueDeltaBooks[venue];
962
+ const bidChanges = mergeVenueLevelChanges(
963
+ explicitChanges == null ? void 0 : explicitChanges.bidChanges,
964
+ impliedBidChangesByVenue[venue]
965
+ );
966
+ const askChanges = mergeVenueLevelChanges(
967
+ explicitChanges == null ? void 0 : explicitChanges.askChanges,
968
+ impliedAskChangesByVenue[venue]
969
+ );
970
+ if (bidChanges.length === 0 && askChanges.length === 0) continue;
971
+ const existing = (_a = venueOrderbooks[venue]) != null ? _a : { bids: [], asks: [] };
972
+ venueOrderbooks[venue] = {
973
+ bids: applyVenueChanges([...existing.bids], bidChanges, "desc"),
974
+ asks: applyVenueChanges([...existing.asks], askChanges, "asc")
975
+ };
976
+ }
977
+ return {
978
+ marketId: state.marketId,
979
+ outcomeId: (_b = state.outcomeId) != null ? _b : delta.outcomeId,
980
+ bids,
981
+ asks,
982
+ venueOrderbooks,
983
+ venues: __spreadValues(__spreadValues({}, state.venues), delta.venues),
984
+ midpoint: delta.midpoint,
985
+ spread: delta.spread,
986
+ seq: delta.seq,
987
+ checksum: delta.checksum,
988
+ timestamp: delta.timestamp
989
+ };
990
+ }
991
+ function toPriceKey(price) {
992
+ return String(Math.round(price * PRICE_KEY_SCALE));
993
+ }
994
+ function applyChanges(levels2, changes, sort) {
995
+ const levelsByPrice = new Map(levels2.map((level) => [toPriceKey(level.price), level]));
996
+ for (const [price, size, venues] of changes) {
997
+ const key = toPriceKey(price);
998
+ if (size === 0) {
999
+ levelsByPrice.delete(key);
1000
+ continue;
1001
+ }
1002
+ levelsByPrice.set(key, {
1003
+ price,
1004
+ size,
1005
+ venues: __spreadValues({}, venues != null ? venues : {})
1006
+ });
1007
+ }
1008
+ levels2 = [...levelsByPrice.values()];
1009
+ levels2.sort(sort === "desc" ? (a, b) => b.price - a.price : (a, b) => a.price - b.price);
1010
+ return levels2;
1011
+ }
1012
+ function applyVenueChanges(levels2, changes, sort) {
1013
+ const levelsByPrice = new Map(levels2.map((level) => [toPriceKey(level.price), level]));
1014
+ for (const [price, size] of changes) {
1015
+ const key = toPriceKey(price);
1016
+ if (size === 0) {
1017
+ levelsByPrice.delete(key);
1018
+ continue;
1019
+ }
1020
+ levelsByPrice.set(key, { price, size });
1021
+ }
1022
+ levels2 = [...levelsByPrice.values()];
1023
+ levels2.sort(sort === "desc" ? (a, b) => b.price - a.price : (a, b) => a.price - b.price);
1024
+ return levels2;
1025
+ }
1026
+ function mergeVenueLevelChanges(primary, fallback) {
1027
+ if (!(primary == null ? void 0 : primary.length)) return fallback ? [...fallback] : [];
1028
+ if (!(fallback == null ? void 0 : fallback.length)) return [...primary];
1029
+ const changesByPrice = /* @__PURE__ */ new Map();
1030
+ for (const change of fallback) {
1031
+ changesByPrice.set(toPriceKey(change[0]), change);
1032
+ }
1033
+ for (const change of primary) {
1034
+ changesByPrice.set(toPriceKey(change[0]), change);
1035
+ }
1036
+ return [...changesByPrice.values()];
1037
+ }
1038
+ function deriveVenueChangesFromAttributedChanges(previousLevels, changes) {
1039
+ var _a, _b;
1040
+ const previousLevelsByPrice = new Map(
1041
+ previousLevels.map((level) => [toPriceKey(level.price), level])
1042
+ );
1043
+ const venueChanges = {};
1044
+ for (const [price, size, nextVenuesRaw] of changes) {
1045
+ const key = toPriceKey(price);
1046
+ const previousLevel = previousLevelsByPrice.get(key);
1047
+ const previousVenues = (_a = previousLevel == null ? void 0 : previousLevel.venues) != null ? _a : {};
1048
+ const nextVenues = nextVenuesRaw != null ? nextVenuesRaw : {};
1049
+ const affectedVenues = /* @__PURE__ */ new Set([...Object.keys(previousVenues), ...Object.keys(nextVenues)]);
1050
+ for (const venue of affectedVenues) {
1051
+ const nextSize = Number((_b = nextVenues[venue]) != null ? _b : 0);
1052
+ if (!Number.isFinite(nextSize)) continue;
1053
+ if (!venueChanges[venue]) {
1054
+ venueChanges[venue] = [];
1055
+ }
1056
+ venueChanges[venue].push([price, nextSize]);
1057
+ }
1058
+ if (size === 0) {
1059
+ previousLevelsByPrice.delete(key);
1060
+ continue;
1061
+ }
1062
+ previousLevelsByPrice.set(key, {
1063
+ price,
1064
+ size,
1065
+ venues: __spreadValues({}, nextVenues)
1066
+ });
1067
+ }
1068
+ return venueChanges;
1069
+ }
1070
+ var IndexedOrderbook = class {
1071
+ constructor(state) {
1072
+ this.venueBooks = /* @__PURE__ */ new Map();
1073
+ this.bids = new Map(state.bids.map((level) => [toPriceKey(level.price), level]));
1074
+ this.asks = new Map(state.asks.map((level) => [toPriceKey(level.price), level]));
1075
+ for (const [venue, book] of Object.entries(state.venueOrderbooks)) {
1076
+ this.venueBooks.set(venue, {
1077
+ bids: new Map(book.bids.map((level) => [toPriceKey(level.price), level])),
1078
+ asks: new Map(book.asks.map((level) => [toPriceKey(level.price), level]))
1079
+ });
1080
+ }
1081
+ const _a = state, { bids: _bids, asks: _asks, venueOrderbooks: _venueBooks } = _a, metadata = __objRest(_a, ["bids", "asks", "venueOrderbooks"]);
1082
+ this.metadata = metadata;
1083
+ this.cached = state;
1084
+ this.checksumValue = computeChecksum(state);
1085
+ }
1086
+ get seq() {
1087
+ return this.metadata.seq;
1088
+ }
1089
+ get checksum() {
1090
+ return this.checksumValue;
1091
+ }
1092
+ /** Verify before committing, including duplicate-price changes within a frame. */
1093
+ apply(delta) {
1094
+ var _a;
1095
+ let checksum = this.checksumValue;
1096
+ for (const [levels2, changes, side] of [
1097
+ [this.bids, delta.bidChanges, "B"],
1098
+ [this.asks, delta.askChanges, "A"]
1099
+ ]) {
1100
+ const changed = /* @__PURE__ */ new Map();
1101
+ for (const [price, size, venues] of changes) {
1102
+ const key = toPriceKey(price);
1103
+ const previous = changed.has(key) ? changed.get(key) : levels2.get(key);
1104
+ if (previous) checksum ^= orderbookCrc32(`${side}${previous.price}:${previous.size}`);
1105
+ if (size !== 0) checksum ^= orderbookCrc32(`${side}${price}:${size}`);
1106
+ changed.set(key, size === 0 ? void 0 : { price, size, venues: __spreadValues({}, venues) });
1107
+ }
1108
+ }
1109
+ checksum >>>= 0;
1110
+ if (checksum !== delta.checksum) return checksum;
1111
+ const previousBids = delta.bidChanges.flatMap(
1112
+ ([price]) => {
1113
+ var _a2;
1114
+ return (_a2 = this.bids.get(toPriceKey(price))) != null ? _a2 : [];
1115
+ }
1116
+ );
1117
+ const previousAsks = delta.askChanges.flatMap(
1118
+ ([price]) => {
1119
+ var _a2;
1120
+ return (_a2 = this.asks.get(toPriceKey(price))) != null ? _a2 : [];
1121
+ }
1122
+ );
1123
+ const impliedBids = deriveVenueChangesFromAttributedChanges(previousBids, delta.bidChanges);
1124
+ const impliedAsks = deriveVenueChangesFromAttributedChanges(previousAsks, delta.askChanges);
1125
+ for (const venue of /* @__PURE__ */ new Set([
1126
+ ...Object.keys(delta.venueDeltaBooks),
1127
+ ...Object.keys(impliedBids),
1128
+ ...Object.keys(impliedAsks)
1129
+ ])) {
1130
+ let book = this.venueBooks.get(venue);
1131
+ if (!book) {
1132
+ book = { bids: /* @__PURE__ */ new Map(), asks: /* @__PURE__ */ new Map() };
1133
+ this.venueBooks.set(venue, book);
1134
+ }
1135
+ const explicit = delta.venueDeltaBooks[venue];
1136
+ for (const [levels2, changes] of [
1137
+ [book.bids, mergeVenueLevelChanges(explicit == null ? void 0 : explicit.bidChanges, impliedBids[venue])],
1138
+ [book.asks, mergeVenueLevelChanges(explicit == null ? void 0 : explicit.askChanges, impliedAsks[venue])]
1139
+ ]) {
1140
+ for (const [price, size] of changes) {
1141
+ if (size === 0) levels2.delete(toPriceKey(price));
1142
+ else levels2.set(toPriceKey(price), { price, size });
1143
+ }
1144
+ }
1145
+ }
1146
+ for (const [levels2, changes] of [
1147
+ [this.bids, delta.bidChanges],
1148
+ [this.asks, delta.askChanges]
1149
+ ]) {
1150
+ for (const [price, size, venues] of changes) {
1151
+ if (size === 0) levels2.delete(toPriceKey(price));
1152
+ else levels2.set(toPriceKey(price), { price, size, venues: __spreadValues({}, venues) });
1153
+ }
1154
+ }
1155
+ this.metadata = __spreadProps(__spreadValues({}, this.metadata), {
1156
+ outcomeId: (_a = this.metadata.outcomeId) != null ? _a : delta.outcomeId,
1157
+ venues: __spreadValues(__spreadValues({}, this.metadata.venues), delta.venues),
1158
+ midpoint: delta.midpoint,
1159
+ spread: delta.spread,
1160
+ seq: delta.seq,
1161
+ checksum: delta.checksum,
1162
+ timestamp: delta.timestamp
1163
+ });
1164
+ this.checksumValue = checksum;
1165
+ this.cached = null;
1166
+ return checksum;
1167
+ }
1168
+ view() {
1169
+ if (this.cached) return this.cached;
1170
+ const bids = (levels2) => [...levels2.values()].sort((a, b) => b.price - a.price);
1171
+ const asks = (levels2) => [...levels2.values()].sort((a, b) => a.price - b.price);
1172
+ this.cached = __spreadProps(__spreadValues({}, this.metadata), {
1173
+ bids: bids(this.bids),
1174
+ asks: asks(this.asks),
1175
+ venueOrderbooks: Object.fromEntries(
1176
+ [...this.venueBooks].map(([venue, book]) => [
1177
+ venue,
1178
+ { bids: bids(book.bids), asks: asks(book.asks) }
1179
+ ])
1180
+ )
1181
+ });
1182
+ return this.cached;
1183
+ }
1184
+ };
1185
+
1186
+ // src/market-data/validate.ts
1187
+ var object = (value) => !!value && typeof value === "object" && !Array.isArray(value);
1188
+ var finite = (value) => typeof value === "number" && Number.isFinite(value);
1189
+ var nullable = (value) => value === null || finite(value);
1190
+ var levels = (value, attributed) => Array.isArray(value) && value.length <= 1e4 && value.every(
1191
+ (level) => Array.isArray(level) && finite(level[0]) && level[0] >= 0 && finite(level[1]) && level[1] >= 0 && (!attributed || object(level[2]) && Object.values(level[2]).every((size) => finite(size) && size >= 0))
1192
+ );
1193
+ function validMarketFrame(frame) {
1194
+ if (typeof frame.outcomeId !== "string" || !frame.outcomeId || !finite(frame.timestamp) || frame.timestamp < 0)
1195
+ return false;
1196
+ if (frame.type === "trade")
1197
+ return finite(frame.price) && frame.price >= 0 && finite(frame.size) && frame.size >= 0 && typeof frame.venue === "string" && (frame.side === "buy" || frame.side === "sell");
1198
+ if (!Number.isSafeInteger(frame.seq) || frame.seq < 0 || !Number.isInteger(frame.checksum) || frame.checksum < 0 || frame.checksum > 4294967295 || !nullable(frame.midpoint) || !nullable(frame.spread) || !object(frame.venues))
1199
+ return false;
1200
+ for (const info of Object.values(frame.venues))
1201
+ if (!object(info) || !nullable(info.bestBid) || !nullable(info.bestAsk)) return false;
1202
+ const snapshot = frame.type === "orderbook_snapshot";
1203
+ if (!levels(frame[snapshot ? "bids" : "bidChanges"], true) || !levels(frame[snapshot ? "asks" : "askChanges"], true))
1204
+ return false;
1205
+ const books = frame[snapshot ? "venueOrderbooks" : "venueDeltaBooks"];
1206
+ return object(books) && Object.values(books).every(
1207
+ (book) => object(book) && levels(book[snapshot ? "bids" : "bidChanges"], false) && levels(book[snapshot ? "asks" : "askChanges"], false)
1208
+ );
1209
+ }
1210
+
1211
+ // src/agg-websocket.ts
1212
+ var RECONNECT_BASE_MS = 1e3;
1213
+ var RECONNECT_MAX_MS = 3e4;
1214
+ var STALE_TIMEOUT_MS = 45e3;
1215
+ var ORDERBOOK_DEBUG_TOP_LEVELS = 5;
1216
+ var AggWebSocket = class {
1217
+ constructor(options) {
1218
+ this.ws = null;
1219
+ // ── Subscription tracking ──
1220
+ this.subs = /* @__PURE__ */ new Map();
1221
+ this.pendingSubs = /* @__PURE__ */ new Set();
1222
+ this.pendingTradeSubs = /* @__PURE__ */ new Set();
1223
+ this.pendingResnapshots = /* @__PURE__ */ new Set();
1224
+ // ── Post-connect batching (coalesces same-tick sub/unsub calls into one frame) ──
1225
+ this.pendingFlushSubs = /* @__PURE__ */ new Set();
1226
+ this.pendingFlushUnsubs = /* @__PURE__ */ new Set();
1227
+ this.pendingFlushTradeSubs = /* @__PURE__ */ new Set();
1228
+ this.pendingFlushTradeUnsubs = /* @__PURE__ */ new Set();
1229
+ this.pendingFlushArbSubs = /* @__PURE__ */ new Set();
1230
+ this.pendingFlushArbUnsubs = /* @__PURE__ */ new Set();
1231
+ this.flushScheduled = false;
1232
+ // ── Arb subscriptions ──
1233
+ this.arbSubs = /* @__PURE__ */ new Map();
1234
+ this.arbFeedCbs = /* @__PURE__ */ new Set();
1235
+ /** Latest arb market update per marketId (last-value-wins, loss-tolerant). */
1236
+ this.latestArb = /* @__PURE__ */ new Map();
1237
+ // ── Orderbook state per market ──
1238
+ this.books = /* @__PURE__ */ new Map();
1239
+ /** Markets currently resyncing (awaiting snapshot after seq gap / checksum mismatch). */
1240
+ this.resyncing = /* @__PURE__ */ new Set();
1241
+ // ── Connection state ──
1242
+ this.connecting = false;
1243
+ this._connected = false;
1244
+ this.reconnectAttempts = 0;
1245
+ this.reconnectTimer = null;
1246
+ this.staleTimer = null;
1247
+ this.lastMessageTime = 0;
1248
+ this.destroyed = false;
1249
+ this.historyControllers = /* @__PURE__ */ new Set();
1250
+ var _a, _b, _c;
1251
+ this.deferBookViews = (_a = options.deferBookViews) != null ? _a : false;
1252
+ this.url = options.url;
1253
+ this.callbacks = (_b = options.callbacks) != null ? _b : {};
1254
+ this.initialToken = options.initialToken;
1255
+ this.enableLogs = (_c = options.enableLogs) != null ? _c : false;
1256
+ }
1257
+ // ── Public API ──
1258
+ get connected() {
1259
+ return this._connected;
1260
+ }
1261
+ /** Decode dynamic authenticated REST bytes in the same processing environment as live data. */
1262
+ decodeHistory(payload) {
1263
+ return __async(this, null, function* () {
1264
+ return decodeChartHistory(payload);
1265
+ });
1266
+ }
1267
+ /** Immutable history decoder. Browser adapters execute this inside their Worker. */
1268
+ loadHistory(manifest, options) {
1269
+ return __async(this, null, function* () {
1270
+ var _a, _b, _c;
1271
+ if (this.destroyed) throw new Error("Market-data client disposed");
1272
+ const controller = new AbortController();
1273
+ const abort = () => {
1274
+ var _a2;
1275
+ return controller.abort((_a2 = options == null ? void 0 : options.signal) == null ? void 0 : _a2.reason);
1276
+ };
1277
+ (_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.addEventListener("abort", abort, { once: true });
1278
+ if ((_b = options == null ? void 0 : options.signal) == null ? void 0 : _b.aborted) abort();
1279
+ this.historyControllers.add(controller);
1280
+ try {
1281
+ controller.signal.throwIfAborted();
1282
+ const result = yield loadImmutableHistory({ manifest, signal: controller.signal });
1283
+ controller.signal.throwIfAborted();
1284
+ return result;
1285
+ } finally {
1286
+ this.historyControllers.delete(controller);
1287
+ (_c = options == null ? void 0 : options.signal) == null ? void 0 : _c.removeEventListener("abort", abort);
1288
+ }
1289
+ });
1290
+ }
1291
+ /** Optional framework-independent host diagnostics, cleared on disposal. */
1292
+ setHostDiagnostics(provider) {
1293
+ this.hostDiagnostics = provider;
1294
+ }
1295
+ /** On-demand ownership diagnostics; contains no credentials or user/account data. */
1296
+ getDiagnostics() {
1297
+ var _a;
1298
+ return {
1299
+ connected: this.connected,
1300
+ host: (_a = this.hostDiagnostics) == null ? void 0 : _a.call(this),
1301
+ transport: this.destroyed ? "disposed" : "direct",
1302
+ orderbookOutcomeIds: this.activeOrderbookMarkets(),
1303
+ tradeOutcomeIds: this.activeTradeMarkets(),
1304
+ arbMarketIds: this.activeArbMarkets(),
1305
+ arbFeedSubscribers: this.arbFeedCbs.size,
1306
+ cachedBooks: this.books.size,
1307
+ cachedArb: this.latestArb.size,
1308
+ resyncingBooks: this.resyncing.size,
1309
+ pendingResnapshots: this.pendingResnapshots.size,
1310
+ pendingHistoryRequests: this.historyControllers.size
1311
+ };
1312
+ }
1313
+ /** Get the current orderbook state for an outcome (or null if no snapshot received yet). */
1314
+ getBook(outcomeId) {
1315
+ var _a, _b;
1316
+ return (_b = (_a = this.books.get(outcomeId)) == null ? void 0 : _a.view()) != null ? _b : null;
1317
+ }
1318
+ /** Whether an outcome is currently resyncing (waiting for fresh snapshot). */
1319
+ isResyncing(outcomeId) {
1320
+ return this.resyncing.has(outcomeId);
1321
+ }
1322
+ /** Get the latest arb update for a market (or null if none received yet). */
1323
+ getArb(marketId) {
1324
+ var _a;
1325
+ return (_a = this.latestArb.get(marketId)) != null ? _a : null;
1326
+ }
1327
+ /**
1328
+ * Subscribe to per-market arb updates for a given marketId.
1329
+ * Ref-counted: multiple callers for the same marketId share one server subscription.
1330
+ * Returns an unsubscribe function.
1331
+ */
1332
+ subscribeArb(marketId, cb) {
1333
+ let entry = this.arbSubs.get(marketId);
1334
+ if (!entry) {
1335
+ entry = { refCount: 0, cbs: /* @__PURE__ */ new Set() };
1336
+ this.arbSubs.set(marketId, entry);
1337
+ this.ensureConnected();
1338
+ if (this._connected) {
1339
+ this.pendingFlushArbUnsubs.delete(marketId);
1340
+ this.pendingFlushArbSubs.add(marketId);
1341
+ this.scheduleFlush();
1342
+ }
1343
+ }
1344
+ entry.cbs.add(cb);
1345
+ entry.refCount++;
1346
+ return () => {
1347
+ const e = this.arbSubs.get(marketId);
1348
+ if (!e) return;
1349
+ e.cbs.delete(cb);
1350
+ e.refCount--;
1351
+ if (e.refCount <= 0) {
1352
+ this.arbSubs.delete(marketId);
1353
+ if (this._connected) {
1354
+ if (this.pendingFlushArbSubs.has(marketId)) {
1355
+ this.pendingFlushArbSubs.delete(marketId);
1356
+ } else {
1357
+ this.pendingFlushArbUnsubs.add(marketId);
1358
+ this.scheduleFlush();
1359
+ }
1360
+ }
1361
+ }
1362
+ };
1363
+ }
1364
+ /**
1365
+ * Subscribe to the global arb-feed batches.
1366
+ * Only one server subscription is maintained regardless of how many callers.
1367
+ * Returns an unsubscribe function.
1368
+ */
1369
+ subscribeArbFeed(cb) {
1370
+ const wasEmpty = this.arbFeedCbs.size === 0;
1371
+ this.arbFeedCbs.add(cb);
1372
+ if (wasEmpty) {
1373
+ this.ensureConnected();
1374
+ if (this._connected) {
1375
+ this.send({ action: "subscribe", channel: "arb-feed" });
1376
+ }
1377
+ }
1378
+ return () => {
1379
+ this.arbFeedCbs.delete(cb);
1380
+ if (this.arbFeedCbs.size === 0 && this._connected) {
1381
+ this.send({ action: "unsubscribe", channel: "arb-feed" });
1382
+ }
1383
+ };
1384
+ }
1385
+ /**
1386
+ * Subscribe to a feed by outcome ID.
1387
+ * @param outcomeId The venueMarketOutcomeId to subscribe to.
1388
+ * @param channel "orderbook" (default) or "trades".
1389
+ * Returns an unsubscribe function (ref-counted).
1390
+ */
1391
+ subscribe(outcomeId, channel = "orderbook") {
1392
+ if (channel === "trades") {
1393
+ return this._subscribeTrades(outcomeId);
1394
+ }
1395
+ let sub = this.subs.get(outcomeId);
1396
+ if (!sub) {
1397
+ sub = { refCount: 0, tradeRefs: 0 };
1398
+ this.subs.set(outcomeId, sub);
1399
+ }
1400
+ if (sub.refCount === 0) {
1401
+ this.pendingSubs.add(outcomeId);
1402
+ this.ensureConnected();
1403
+ if (this._connected) {
1404
+ this.pendingFlushUnsubs.delete(outcomeId);
1405
+ this.pendingFlushSubs.add(outcomeId);
1406
+ this.pendingSubs.delete(outcomeId);
1407
+ this.scheduleFlush();
1408
+ }
1409
+ }
1410
+ sub.refCount++;
1411
+ let released = false;
1412
+ return () => {
1413
+ if (released) return;
1414
+ released = true;
1415
+ const s = this.subs.get(outcomeId);
1416
+ if (!s) return;
1417
+ s.refCount--;
1418
+ if (s.refCount <= 0) {
1419
+ s.refCount = 0;
1420
+ if (s.tradeRefs <= 0) {
1421
+ this.subs.delete(outcomeId);
1422
+ this.books.delete(outcomeId);
1423
+ }
1424
+ this.resyncing.delete(outcomeId);
1425
+ if (this._connected) {
1426
+ if (this.pendingFlushSubs.has(outcomeId)) {
1427
+ this.pendingFlushSubs.delete(outcomeId);
1428
+ } else {
1429
+ this.pendingFlushUnsubs.add(outcomeId);
1430
+ this.scheduleFlush();
1431
+ }
1432
+ }
1433
+ this.pendingSubs.delete(outcomeId);
1434
+ this.pendingResnapshots.delete(outcomeId);
1435
+ }
1436
+ };
1437
+ }
1438
+ /**
1439
+ * Subscribe to an outcome's trade feed.
1440
+ * @deprecated Use `subscribe(outcomeId, "trades")` instead.
1441
+ * Returns an unsubscribe function.
1442
+ */
1443
+ subscribeTrades(outcomeId) {
1444
+ return this._subscribeTrades(outcomeId);
1445
+ }
1446
+ _subscribeTrades(outcomeId) {
1447
+ let sub = this.subs.get(outcomeId);
1448
+ if (!sub) {
1449
+ sub = { refCount: 0, tradeRefs: 0 };
1450
+ this.subs.set(outcomeId, sub);
1451
+ }
1452
+ if (sub.tradeRefs === 0) {
1453
+ this.pendingTradeSubs.add(outcomeId);
1454
+ this.ensureConnected();
1455
+ if (this._connected) {
1456
+ this.pendingFlushTradeUnsubs.delete(outcomeId);
1457
+ this.pendingFlushTradeSubs.add(outcomeId);
1458
+ this.pendingTradeSubs.delete(outcomeId);
1459
+ this.scheduleFlush();
1460
+ }
1461
+ }
1462
+ sub.tradeRefs++;
1463
+ let released = false;
1464
+ return () => {
1465
+ if (released) return;
1466
+ released = true;
1467
+ const s = this.subs.get(outcomeId);
1468
+ if (!s) return;
1469
+ s.tradeRefs--;
1470
+ if (s.tradeRefs <= 0) {
1471
+ s.tradeRefs = 0;
1472
+ if (this._connected) {
1473
+ if (this.pendingFlushTradeSubs.has(outcomeId)) {
1474
+ this.pendingFlushTradeSubs.delete(outcomeId);
1475
+ } else {
1476
+ this.pendingFlushTradeUnsubs.add(outcomeId);
1477
+ this.scheduleFlush();
1478
+ }
1479
+ }
1480
+ this.pendingTradeSubs.delete(outcomeId);
1481
+ this.pendingResnapshots.delete(outcomeId);
1482
+ if (s.refCount <= 0) {
1483
+ this.subs.delete(outcomeId);
1484
+ this.books.delete(outcomeId);
1485
+ this.resyncing.delete(outcomeId);
1486
+ }
1487
+ }
1488
+ };
1489
+ }
1490
+ /** Send a JWT to authenticate (or re-authenticate) the connection. */
1491
+ authenticate(token) {
1492
+ if (this._connected) {
1493
+ this.send({ action: "authenticate", token });
1494
+ }
1495
+ }
1496
+ /** Request a fresh snapshot for one or more subscribed outcomes. */
1497
+ resnapshot(outcomeIdOrIds) {
1498
+ const outcomeIds = Array.isArray(outcomeIdOrIds) ? outcomeIdOrIds : [outcomeIdOrIds];
1499
+ outcomeIds.forEach((outcomeId) => {
1500
+ this.requestResnapshot(outcomeId, true);
1501
+ });
1502
+ }
1503
+ /** Connect (idempotent). Called automatically on first subscribe. */
1504
+ connect() {
1505
+ this.ensureConnected();
1506
+ }
1507
+ /** Disconnect and clean up. Reusable — call connect() to reconnect. */
1508
+ disconnect() {
1509
+ var _a, _b;
1510
+ this.cancelReconnect();
1511
+ this.cancelStaleTimer();
1512
+ this._connected = false;
1513
+ this.connecting = false;
1514
+ if (this.ws) {
1515
+ this.ws.onclose = null;
1516
+ this.ws.close();
1517
+ this.ws = null;
1518
+ }
1519
+ (_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
1520
+ }
1521
+ /** Permanently destroy. Cannot reconnect after this. */
1522
+ destroy() {
1523
+ this.destroyed = true;
1524
+ for (const controller of this.historyControllers)
1525
+ controller.abort(new Error("Market-data client disposed"));
1526
+ this.historyControllers.clear();
1527
+ this.disconnect();
1528
+ this.hostDiagnostics = void 0;
1529
+ this.callbacks = {};
1530
+ this.subs.clear();
1531
+ this.books.clear();
1532
+ this.resyncing.clear();
1533
+ this.pendingSubs.clear();
1534
+ this.pendingTradeSubs.clear();
1535
+ this.pendingResnapshots.clear();
1536
+ this.pendingFlushSubs.clear();
1537
+ this.pendingFlushUnsubs.clear();
1538
+ this.pendingFlushTradeSubs.clear();
1539
+ this.pendingFlushTradeUnsubs.clear();
1540
+ this.arbSubs.clear();
1541
+ this.arbFeedCbs.clear();
1542
+ this.latestArb.clear();
1543
+ this.pendingFlushArbSubs.clear();
1544
+ this.pendingFlushArbUnsubs.clear();
1545
+ this.flushScheduled = false;
1546
+ }
1547
+ /** Update callbacks (e.g., after React re-render). */
1548
+ setCallbacks(callbacks) {
1549
+ this.callbacks = callbacks;
1550
+ }
1551
+ // ── Connection management ──
1552
+ ensureConnected() {
1553
+ var _a;
1554
+ if (this.destroyed) return;
1555
+ if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN || this.connecting) return;
1556
+ this.doConnect();
1557
+ }
1558
+ doConnect() {
1559
+ if (this.destroyed) return;
1560
+ this.connecting = true;
1561
+ const ws = new WebSocket(this.url);
1562
+ this.ws = ws;
1563
+ ws.onopen = () => {
1564
+ if (this.destroyed || this.ws !== ws) return;
1565
+ this.connecting = false;
1566
+ this.reconnectAttempts = 0;
1567
+ this.resetStaleTimer();
1568
+ if (this.initialToken) {
1569
+ this.send({ action: "authenticate", token: this.initialToken });
1570
+ }
1571
+ };
1572
+ ws.onmessage = (event) => {
1573
+ var _a, _b;
1574
+ if (this.destroyed || this.ws !== ws) return;
1575
+ this.lastMessageTime = Date.now();
1576
+ (_b = (_a = this.callbacks).onFrameReceived) == null ? void 0 : _b.call(_a, this.lastMessageTime);
1577
+ this.resetStaleTimer();
1578
+ try {
1579
+ const raw = JSON.parse(event.data);
1580
+ this.handleMessage(raw);
1581
+ } catch (e) {
1582
+ }
1583
+ };
1584
+ ws.onclose = () => {
1585
+ var _a, _b;
1586
+ this.ws = null;
1587
+ this.connecting = false;
1588
+ const wasConnected = this._connected;
1589
+ this._connected = false;
1590
+ this.cancelStaleTimer();
1591
+ if (wasConnected) {
1592
+ (_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
1593
+ }
1594
+ if (!this.destroyed && (this.subs.size > 0 || this.arbSubs.size > 0 || this.arbFeedCbs.size > 0)) {
1595
+ this.scheduleReconnect();
1596
+ }
1597
+ };
1598
+ ws.onerror = () => {
1599
+ };
1600
+ }
1601
+ scheduleReconnect() {
1602
+ this.cancelReconnect();
1603
+ const delay = Math.min(
1604
+ RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts),
1605
+ RECONNECT_MAX_MS
1606
+ );
1607
+ this.reconnectAttempts++;
1608
+ this.emitDiagnostic({ type: "reconnect", attempt: this.reconnectAttempts, delayMs: delay });
1609
+ this.reconnectTimer = setTimeout(() => {
1610
+ this.reconnectTimer = null;
1611
+ this.doConnect();
1612
+ }, delay);
1613
+ }
1614
+ cancelReconnect() {
1615
+ if (this.reconnectTimer) {
1616
+ clearTimeout(this.reconnectTimer);
1617
+ this.reconnectTimer = null;
1618
+ }
1619
+ }
1620
+ // ── Staleness detection ──
1621
+ resetStaleTimer() {
1622
+ this.cancelStaleTimer();
1623
+ this.staleTimer = setTimeout(() => {
1624
+ const age = Date.now() - this.lastMessageTime;
1625
+ this.emitDiagnostic({ type: "stale_connection", lastMessageAge: age });
1626
+ if (this.ws) {
1627
+ this.ws.close();
1628
+ }
1629
+ }, STALE_TIMEOUT_MS);
1630
+ }
1631
+ cancelStaleTimer() {
1632
+ if (this.staleTimer) {
1633
+ clearTimeout(this.staleTimer);
1634
+ this.staleTimer = null;
1635
+ }
1636
+ }
1637
+ // ── Message handling ──
1638
+ handleMessage(raw) {
1639
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
1640
+ const type = raw.type;
1641
+ if (["orderbook_snapshot", "orderbook_delta", "trade"].includes(type) && !validMarketFrame(raw)) {
1642
+ (_b = (_a = this.callbacks).onError) == null ? void 0 : _b.call(_a, { type: "error", message: "Invalid market-data frame" });
1643
+ if (typeof raw.outcomeId === "string" && this.subs.has(raw.outcomeId))
1644
+ this.requestResnapshot(raw.outcomeId);
1645
+ return;
1646
+ }
1647
+ switch (type) {
1648
+ case "orderbook_snapshot":
1649
+ this.handleSnapshot(raw);
1650
+ break;
1651
+ case "orderbook_delta":
1652
+ this.handleDelta(raw);
1653
+ break;
1654
+ case "trade":
1655
+ this.handleTrade(raw);
1656
+ break;
1657
+ case "heartbeat":
1658
+ this.handleHeartbeat(raw);
1659
+ break;
1660
+ case "subscribed":
1661
+ (_d = (_c = this.callbacks).onSubscribed) == null ? void 0 : _d.call(_c, raw);
1662
+ break;
1663
+ case "unsubscribed":
1664
+ (_f = (_e = this.callbacks).onUnsubscribed) == null ? void 0 : _f.call(_e, raw);
1665
+ break;
1666
+ case "connected":
1667
+ this.handleConnected(raw);
1668
+ break;
1669
+ case "authenticated":
1670
+ (_h = (_g = this.callbacks).onAuthenticated) == null ? void 0 : _h.call(_g, raw);
1671
+ break;
1672
+ case "market_resolved":
1673
+ this.handleMarketResolved(raw);
1674
+ break;
1675
+ case "error":
1676
+ (_j = (_i = this.callbacks).onError) == null ? void 0 : _j.call(_i, raw);
1677
+ break;
1678
+ case "order_submitted":
1679
+ this.handleOrderSubmitted(raw);
1680
+ break;
1681
+ case "balance_update":
1682
+ this.handleBalanceUpdate(raw);
1683
+ break;
1684
+ case "order_event":
1685
+ (_l = (_k = this.callbacks).onOrderEvent) == null ? void 0 : _l.call(_k, raw);
1686
+ break;
1687
+ case "redeem_event":
1688
+ this.handleRedeemEvent(raw);
1689
+ break;
1690
+ case "withdrawal_lifecycle":
1691
+ (_n = (_m = this.callbacks).onWithdrawalLifecycle) == null ? void 0 : _n.call(_m, raw);
1692
+ break;
1693
+ case "arb_market_update": {
1694
+ const arbMsg = raw;
1695
+ this.latestArb.set(arbMsg.marketId, arbMsg);
1696
+ const arbEntry = this.arbSubs.get(arbMsg.marketId);
1697
+ if (arbEntry) {
1698
+ for (const cb of arbEntry.cbs) cb(arbMsg);
1699
+ }
1700
+ (_p = (_o = this.callbacks).onArbMarket) == null ? void 0 : _p.call(_o, arbMsg);
1701
+ break;
1702
+ }
1703
+ case "arb_feed_batch": {
1704
+ const feedMsg = raw;
1705
+ for (const cb of this.arbFeedCbs) cb(feedMsg);
1706
+ (_r = (_q = this.callbacks).onArbFeed) == null ? void 0 : _r.call(_q, feedMsg);
1707
+ break;
1708
+ }
1709
+ }
1710
+ }
1711
+ /**
1712
+ * Server confirmed the connection — gateway has validated our appId and is
1713
+ * ready to accept subscriptions. Now flush all pending subs.
1714
+ */
1715
+ handleConnected(msg) {
1716
+ var _a, _b, _c, _d;
1717
+ this._connected = true;
1718
+ (_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, true);
1719
+ (_d = (_c = this.callbacks).onConnected) == null ? void 0 : _d.call(_c, msg);
1720
+ const orderbookSet = new Set(this.activeOrderbookMarkets());
1721
+ this.pendingSubs.forEach((id) => orderbookSet.add(id));
1722
+ this.pendingFlushSubs.forEach((id) => orderbookSet.add(id));
1723
+ const orderbookIds = Array.from(orderbookSet);
1724
+ if (orderbookIds.length > 0) {
1725
+ this.sendSubscribe(orderbookIds);
1726
+ }
1727
+ this.pendingSubs.clear();
1728
+ this.pendingFlushSubs.clear();
1729
+ this.pendingFlushUnsubs.clear();
1730
+ const tradeSet = new Set(this.activeTradeMarkets());
1731
+ this.pendingTradeSubs.forEach((id) => tradeSet.add(id));
1732
+ this.pendingFlushTradeSubs.forEach((id) => tradeSet.add(id));
1733
+ const tradeIds = Array.from(tradeSet);
1734
+ if (tradeIds.length > 0) {
1735
+ this.send({ action: "subscribe", channel: "trades", outcomeIds: tradeIds });
1736
+ }
1737
+ this.pendingTradeSubs.clear();
1738
+ this.pendingFlushTradeSubs.clear();
1739
+ this.pendingFlushTradeUnsubs.clear();
1740
+ const resnapshotIds = Array.from(this.pendingResnapshots);
1741
+ if (resnapshotIds.length > 0) {
1742
+ this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: resnapshotIds });
1743
+ }
1744
+ this.pendingResnapshots.clear();
1745
+ const arbSet = new Set(this.activeArbMarkets());
1746
+ this.pendingFlushArbSubs.forEach((id) => arbSet.add(id));
1747
+ const arbIds = Array.from(arbSet);
1748
+ if (arbIds.length > 0) {
1749
+ this.send({ action: "subscribe", channel: "arb", marketIds: arbIds });
1750
+ }
1751
+ this.pendingFlushArbSubs.clear();
1752
+ this.pendingFlushArbUnsubs.clear();
1753
+ if (this.arbFeedCbs.size > 0) {
1754
+ this.send({ action: "subscribe", channel: "arb-feed" });
1755
+ }
1756
+ }
1757
+ handleSnapshot(raw) {
1758
+ var _a, _b, _c, _d;
1759
+ if (!this.subs.has(raw.outcomeId)) return;
1760
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1761
+ const book = snapshotToOrderbook(msg);
1762
+ this.books.set(msg.outcomeId, new IndexedOrderbook(book));
1763
+ this.resyncing.delete(msg.outcomeId);
1764
+ this.pendingResnapshots.delete(msg.outcomeId);
1765
+ this.debugOrderbook("snapshot_applied", {
1766
+ outcomeId: msg.outcomeId,
1767
+ seq: msg.seq,
1768
+ checksum: msg.checksum,
1769
+ bidsTop: this.summarizeTopLevels(book.bids),
1770
+ asksTop: this.summarizeTopLevels(book.asks)
1771
+ });
1772
+ (_b = (_a = this.callbacks).onBookTick) == null ? void 0 : _b.call(_a, msg.outcomeId, {
1773
+ midpoint: msg.midpoint,
1774
+ timestamp: msg.timestamp,
1775
+ source: "snapshot"
1776
+ });
1777
+ if (!this.deferBookViews) (_d = (_c = this.callbacks).onSnapshot) == null ? void 0 : _d.call(_c, msg.outcomeId, book);
1778
+ }
1779
+ handleDelta(raw) {
1780
+ var _a, _b, _c, _d;
1781
+ if (!this.subs.has(raw.outcomeId)) return;
1782
+ const outcomeId = raw.outcomeId;
1783
+ const current = this.books.get(outcomeId);
1784
+ if (!current) {
1785
+ this.debugOrderbook("delta_missing_snapshot", { outcomeId, seq: raw.seq });
1786
+ this.requestResnapshot(outcomeId);
1787
+ return;
1788
+ }
1789
+ if (raw.seq <= current.seq) {
1790
+ this.debugOrderbook("delta_stale_ignored", {
1791
+ outcomeId,
1792
+ currentSeq: current.seq,
1793
+ receivedSeq: raw.seq
1794
+ });
1795
+ return;
1796
+ }
1797
+ if (raw.seq > current.seq + 1) {
1798
+ this.debugOrderbook("delta_seq_gap", {
1799
+ outcomeId,
1800
+ expectedSeq: current.seq + 1,
1801
+ receivedSeq: raw.seq
1802
+ });
1803
+ this.emitDiagnostic({
1804
+ type: "seq_gap",
1805
+ marketId: outcomeId,
1806
+ outcomeId,
1807
+ expected: current.seq + 1,
1808
+ received: raw.seq
1809
+ });
1810
+ this.requestResnapshot(outcomeId);
1811
+ return;
1812
+ }
1813
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1814
+ const computed = current.apply(msg);
1815
+ if (computed !== msg.checksum) {
1816
+ this.debugOrderbook("delta_checksum_mismatch", {
1817
+ outcomeId,
1818
+ seq: msg.seq,
1819
+ expected: msg.checksum,
1820
+ computed
1821
+ });
1822
+ this.emitDiagnostic({
1823
+ type: "checksum_mismatch",
1824
+ marketId: outcomeId,
1825
+ outcomeId,
1826
+ expected: msg.checksum,
1827
+ computed
1828
+ });
1829
+ this.requestResnapshot(outcomeId);
1830
+ return;
1831
+ }
1832
+ (_b = (_a = this.callbacks).onBookTick) == null ? void 0 : _b.call(_a, outcomeId, {
1833
+ midpoint: msg.midpoint,
1834
+ timestamp: msg.timestamp,
1835
+ source: "delta"
1836
+ });
1837
+ if (!this.deferBookViews) (_d = (_c = this.callbacks).onDelta) == null ? void 0 : _d.call(_c, outcomeId, current.view());
1838
+ }
1839
+ handleTrade(raw) {
1840
+ var _a, _b;
1841
+ if (!this.subs.has(raw.outcomeId)) return;
1842
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1843
+ (_b = (_a = this.callbacks).onTrade) == null ? void 0 : _b.call(_a, msg);
1844
+ }
1845
+ handleHeartbeat(raw) {
1846
+ var _a, _b;
1847
+ const msg = __spreadProps(__spreadValues({}, raw), { ts: raw.ts / 1e3 });
1848
+ (_b = (_a = this.callbacks).onHeartbeat) == null ? void 0 : _b.call(_a, msg);
1849
+ }
1850
+ handleMarketResolved(raw) {
1851
+ var _a, _b;
1852
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1853
+ this.books.delete(msg.outcomeId);
1854
+ this.pendingResnapshots.delete(msg.outcomeId);
1855
+ this.resyncing.delete(msg.outcomeId);
1856
+ (_b = (_a = this.callbacks).onMarketResolved) == null ? void 0 : _b.call(_a, msg);
1857
+ }
1858
+ handleOrderSubmitted(raw) {
1859
+ var _a, _b;
1860
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1861
+ (_b = (_a = this.callbacks).onOrderSubmitted) == null ? void 0 : _b.call(_a, msg);
1862
+ }
1863
+ handleBalanceUpdate(raw) {
1864
+ var _a, _b;
1865
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1866
+ (_b = (_a = this.callbacks).onBalanceUpdate) == null ? void 0 : _b.call(_a, msg);
1867
+ }
1868
+ handleRedeemEvent(raw) {
1869
+ var _a, _b;
1870
+ const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
1871
+ (_b = (_a = this.callbacks).onRedeemEvent) == null ? void 0 : _b.call(_a, msg);
1872
+ }
1873
+ // ── Resnapshot ──
1874
+ requestResnapshot(outcomeId, force = false) {
1875
+ if (this.resyncing.has(outcomeId) && !force) return;
1876
+ this.resyncing.add(outcomeId);
1877
+ if (this._connected) {
1878
+ this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: [outcomeId] });
1879
+ this.pendingResnapshots.delete(outcomeId);
1880
+ return;
1881
+ }
1882
+ this.pendingResnapshots.add(outcomeId);
1883
+ this.ensureConnected();
1884
+ }
1885
+ // ── Helpers ──
1886
+ /**
1887
+ * Schedule a microtask that flushes queued subscribe/unsubscribe frames.
1888
+ * Coalesces multiple same-tick sub/unsub calls into at most one frame per
1889
+ * channel+action pair.
1890
+ */
1891
+ scheduleFlush() {
1892
+ if (this.flushScheduled) return;
1893
+ this.flushScheduled = true;
1894
+ queueMicrotask(() => {
1895
+ this.flushScheduled = false;
1896
+ if (!this._connected) {
1897
+ this.pendingFlushSubs.clear();
1898
+ this.pendingFlushUnsubs.clear();
1899
+ this.pendingFlushTradeSubs.clear();
1900
+ this.pendingFlushTradeUnsubs.clear();
1901
+ this.pendingFlushArbSubs.clear();
1902
+ this.pendingFlushArbUnsubs.clear();
1903
+ return;
1904
+ }
1905
+ this.flushPending();
1906
+ });
1907
+ }
1908
+ flushPending() {
1909
+ for (const id of [...this.pendingFlushSubs]) {
1910
+ if (this.pendingFlushUnsubs.has(id)) {
1911
+ this.pendingFlushSubs.delete(id);
1912
+ this.pendingFlushUnsubs.delete(id);
1913
+ }
1914
+ }
1915
+ if (this.pendingFlushSubs.size > 0) {
1916
+ this.sendSubscribe(Array.from(this.pendingFlushSubs));
1917
+ this.pendingFlushSubs.clear();
1918
+ }
1919
+ if (this.pendingFlushUnsubs.size > 0) {
1920
+ this.send({
1921
+ action: "unsubscribe",
1922
+ channel: "orderbook",
1923
+ outcomeIds: Array.from(this.pendingFlushUnsubs)
1924
+ });
1925
+ this.pendingFlushUnsubs.clear();
1926
+ }
1927
+ for (const id of [...this.pendingFlushTradeSubs]) {
1928
+ if (this.pendingFlushTradeUnsubs.has(id)) {
1929
+ this.pendingFlushTradeSubs.delete(id);
1930
+ this.pendingFlushTradeUnsubs.delete(id);
1931
+ }
1932
+ }
1933
+ if (this.pendingFlushTradeSubs.size > 0) {
1934
+ this.send({
1935
+ action: "subscribe",
1936
+ channel: "trades",
1937
+ outcomeIds: Array.from(this.pendingFlushTradeSubs)
1938
+ });
1939
+ this.pendingFlushTradeSubs.clear();
1940
+ }
1941
+ if (this.pendingFlushTradeUnsubs.size > 0) {
1942
+ this.send({
1943
+ action: "unsubscribe",
1944
+ channel: "trades",
1945
+ outcomeIds: Array.from(this.pendingFlushTradeUnsubs)
1946
+ });
1947
+ this.pendingFlushTradeUnsubs.clear();
1948
+ }
1949
+ for (const id of [...this.pendingFlushArbSubs]) {
1950
+ if (this.pendingFlushArbUnsubs.has(id)) {
1951
+ this.pendingFlushArbSubs.delete(id);
1952
+ this.pendingFlushArbUnsubs.delete(id);
1953
+ }
1954
+ }
1955
+ if (this.pendingFlushArbSubs.size > 0) {
1956
+ this.send({
1957
+ action: "subscribe",
1958
+ channel: "arb",
1959
+ marketIds: Array.from(this.pendingFlushArbSubs)
1960
+ });
1961
+ this.pendingFlushArbSubs.clear();
1962
+ }
1963
+ if (this.pendingFlushArbUnsubs.size > 0) {
1964
+ this.send({
1965
+ action: "unsubscribe",
1966
+ channel: "arb",
1967
+ marketIds: Array.from(this.pendingFlushArbUnsubs)
1968
+ });
1969
+ this.pendingFlushArbUnsubs.clear();
1970
+ }
1971
+ }
1972
+ sendSubscribe(outcomeIds) {
1973
+ this.send({ action: "subscribe", channel: "orderbook", outcomeIds });
1974
+ }
1975
+ send(msg) {
1976
+ var _a;
1977
+ if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN) {
1978
+ this.ws.send(JSON.stringify(msg));
1979
+ }
1980
+ }
1981
+ activeOrderbookMarkets() {
1982
+ const markets = [];
1983
+ this.subs.forEach((sub, id) => {
1984
+ if (sub.refCount > 0) markets.push(id);
1985
+ });
1986
+ return markets;
1987
+ }
1988
+ activeTradeMarkets() {
1989
+ const markets = [];
1990
+ this.subs.forEach((sub, id) => {
1991
+ if (sub.tradeRefs > 0) markets.push(id);
1992
+ });
1993
+ return markets;
1994
+ }
1995
+ activeArbMarkets() {
1996
+ return Array.from(this.arbSubs.keys());
1997
+ }
1998
+ emitDiagnostic(event) {
1999
+ var _a, _b;
2000
+ (_b = (_a = this.callbacks).onDiagnostics) == null ? void 0 : _b.call(_a, event);
2001
+ }
2002
+ summarizeTopLevels(levels2) {
2003
+ return levels2.slice(0, ORDERBOOK_DEBUG_TOP_LEVELS).map((level) => ({ price: level.price, size: level.size }));
2004
+ }
2005
+ debugOrderbook(event, payload) {
2006
+ if (!this.isOrderbookDebugEnabled()) return;
2007
+ console.debug(`[AggWebSocket][orderbook] ${event}`, payload);
2008
+ }
2009
+ isOrderbookDebugEnabled() {
2010
+ return this.enableLogs;
2011
+ }
2012
+ };
2013
+
2014
+ export {
2015
+ decodeChartHistory,
2016
+ readChartHistoryText,
2017
+ loadImmutableHistory,
2018
+ Venue,
2019
+ VENUES,
2020
+ VENUE_CHAIN_IDS,
2021
+ ACTIVE_VENUES,
2022
+ INACTIVE_VENUES,
2023
+ isVenueActive,
2024
+ isVenueInactive,
2025
+ isVenueDataVisible,
2026
+ getEffectiveDisabledVenues,
2027
+ ImageSize,
2028
+ IMAGE_SIZES,
2029
+ RETINA_IMAGE_SIZES,
2030
+ AccountType,
2031
+ AccountProvider,
2032
+ Chain,
2033
+ MatchStatus,
2034
+ MatchType,
2035
+ CONFIRMED_MATCH_STATUSES,
2036
+ MarketStatus,
2037
+ OrderStatus,
2038
+ TradeSide,
2039
+ OrderType,
2040
+ TimeInForce,
2041
+ formatOutcomeLabel,
2042
+ formatMarketQuestion,
2043
+ formatOutcomeTitle,
2044
+ getWalletAddressFromUserProfile,
2045
+ safeParse,
2046
+ parse,
2047
+ isEnum,
2048
+ enumGuard,
2049
+ isFiniteNonNeg,
2050
+ isNonEmptyString,
2051
+ hasShape,
2052
+ isEmail,
2053
+ parseEmail,
2054
+ parseEmailStrict,
2055
+ computeBestSplitsByAmount,
2056
+ optimizedImageUrl,
2057
+ retinaImageUrl,
2058
+ normalizeVenueMarketCluster,
2059
+ sortVenues,
2060
+ buildVenueUrl,
2061
+ LIMIT_PRICE_RAW_SCALE,
2062
+ adjustLimitPriceRawToTick,
2063
+ DEFAULT_BALANCE_REFILL_DAILY_CAP_RAW,
2064
+ DEFAULT_BALANCE_REFILL_MAX_FEE_RAW,
2065
+ getBalanceRefillMaximumRaw,
2066
+ isBalanceRefillWithinDailyCap,
2067
+ orderbookCrc32,
2068
+ projectedOrderbookChecksum,
2069
+ computeChecksum,
2070
+ snapshotToOrderbook,
2071
+ applyOrderbookDelta,
2072
+ AggWebSocket
2073
+ };