@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.
- package/dist/agg-websocket-BatL1Zrt.d.mts +4320 -0
- package/dist/agg-websocket-BatL1Zrt.d.ts +4320 -0
- package/dist/browser.d.mts +69 -0
- package/dist/browser.d.ts +69 -0
- package/dist/browser.js +2049 -0
- package/dist/browser.mjs +804 -0
- package/dist/chunk-QXBVA5TW.mjs +2073 -0
- package/dist/chunk-VD5UTAVD.mjs +158 -0
- package/dist/index.d.mts +431 -4249
- package/dist/index.d.ts +431 -4249
- package/dist/index.js +705 -114
- package/dist/index.mjs +244 -1752
- package/dist/market-data.d.mts +7 -0
- package/dist/market-data.d.ts +7 -0
- package/dist/market-data.js +1776 -0
- package/dist/market-data.mjs +352 -0
- package/package.json +27 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CandleBuilder
|
|
3
|
+
} from "./chunk-VD5UTAVD.mjs";
|
|
4
|
+
import {
|
|
5
|
+
ACTIVE_VENUES,
|
|
6
|
+
AccountProvider,
|
|
7
|
+
AccountType,
|
|
8
|
+
AggWebSocket,
|
|
9
|
+
CONFIRMED_MATCH_STATUSES,
|
|
10
|
+
Chain,
|
|
11
|
+
DEFAULT_BALANCE_REFILL_DAILY_CAP_RAW,
|
|
12
|
+
DEFAULT_BALANCE_REFILL_MAX_FEE_RAW,
|
|
13
|
+
IMAGE_SIZES,
|
|
14
|
+
INACTIVE_VENUES,
|
|
15
|
+
ImageSize,
|
|
16
|
+
LIMIT_PRICE_RAW_SCALE,
|
|
17
|
+
MarketStatus,
|
|
18
|
+
MatchStatus,
|
|
19
|
+
MatchType,
|
|
20
|
+
OrderStatus,
|
|
21
|
+
OrderType,
|
|
22
|
+
RETINA_IMAGE_SIZES,
|
|
23
|
+
TimeInForce,
|
|
24
|
+
TradeSide,
|
|
25
|
+
VENUES,
|
|
26
|
+
VENUE_CHAIN_IDS,
|
|
27
|
+
Venue,
|
|
28
|
+
adjustLimitPriceRawToTick,
|
|
29
|
+
applyOrderbookDelta,
|
|
30
|
+
buildVenueUrl,
|
|
31
|
+
computeBestSplitsByAmount,
|
|
32
|
+
computeChecksum,
|
|
33
|
+
enumGuard,
|
|
34
|
+
formatMarketQuestion,
|
|
35
|
+
formatOutcomeLabel,
|
|
36
|
+
formatOutcomeTitle,
|
|
37
|
+
getBalanceRefillMaximumRaw,
|
|
38
|
+
getEffectiveDisabledVenues,
|
|
39
|
+
getWalletAddressFromUserProfile,
|
|
40
|
+
hasShape,
|
|
41
|
+
isBalanceRefillWithinDailyCap,
|
|
42
|
+
isEmail,
|
|
43
|
+
isEnum,
|
|
44
|
+
isFiniteNonNeg,
|
|
45
|
+
isNonEmptyString,
|
|
46
|
+
isVenueActive,
|
|
47
|
+
isVenueDataVisible,
|
|
48
|
+
isVenueInactive,
|
|
49
|
+
loadImmutableHistory,
|
|
50
|
+
normalizeVenueMarketCluster,
|
|
51
|
+
optimizedImageUrl,
|
|
52
|
+
orderbookCrc32,
|
|
53
|
+
parse,
|
|
54
|
+
parseEmail,
|
|
55
|
+
parseEmailStrict,
|
|
56
|
+
projectedOrderbookChecksum,
|
|
57
|
+
readChartHistoryText,
|
|
58
|
+
retinaImageUrl,
|
|
59
|
+
safeParse,
|
|
60
|
+
snapshotToOrderbook,
|
|
61
|
+
sortVenues
|
|
62
|
+
} from "./chunk-QXBVA5TW.mjs";
|
|
1
63
|
import {
|
|
2
64
|
__async,
|
|
3
65
|
__objRest,
|
|
@@ -5,686 +67,26 @@ import {
|
|
|
5
67
|
__spreadValues
|
|
6
68
|
} from "./chunk-WNQUEZJF.mjs";
|
|
7
69
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Venue3["opinion"] = "opinion";
|
|
14
|
-
Venue3["predict"] = "predict";
|
|
15
|
-
Venue3["pred"] = "pred";
|
|
16
|
-
Venue3["probable"] = "probable";
|
|
17
|
-
Venue3["myriad"] = "myriad";
|
|
18
|
-
Venue3["hyperliquid"] = "hyperliquid";
|
|
19
|
-
Venue3["novig"] = "novig";
|
|
20
|
-
Venue3["prophetx"] = "prophetx";
|
|
21
|
-
return Venue3;
|
|
22
|
-
})(Venue || {});
|
|
23
|
-
var VENUES = [
|
|
24
|
-
"kalshi" /* kalshi */,
|
|
25
|
-
"polymarket" /* polymarket */,
|
|
26
|
-
"limitless" /* limitless */,
|
|
27
|
-
"opinion" /* opinion */,
|
|
28
|
-
"predict" /* predict */,
|
|
29
|
-
"pred" /* pred */,
|
|
30
|
-
"probable" /* probable */,
|
|
31
|
-
"myriad" /* myriad */,
|
|
32
|
-
"hyperliquid" /* hyperliquid */,
|
|
33
|
-
"novig" /* novig */,
|
|
34
|
-
"prophetx" /* prophetx */
|
|
35
|
-
];
|
|
36
|
-
var VENUE_CHAIN_IDS = {
|
|
37
|
-
["kalshi" /* kalshi */]: 792703809,
|
|
38
|
-
["polymarket" /* polymarket */]: 137,
|
|
39
|
-
["limitless" /* limitless */]: 8453,
|
|
40
|
-
["predict" /* predict */]: 56,
|
|
41
|
-
["pred" /* pred */]: 8453,
|
|
42
|
-
["myriad" /* myriad */]: 56,
|
|
43
|
-
["hyperliquid" /* hyperliquid */]: 1337,
|
|
44
|
-
["novig" /* novig */]: 792703809,
|
|
45
|
-
["prophetx" /* prophetx */]: 792703809
|
|
46
|
-
};
|
|
47
|
-
var ACTIVE_VENUES = [
|
|
48
|
-
"kalshi" /* kalshi */,
|
|
49
|
-
"polymarket" /* polymarket */,
|
|
50
|
-
"limitless" /* limitless */,
|
|
51
|
-
"opinion" /* opinion */,
|
|
52
|
-
"predict" /* predict */,
|
|
53
|
-
"pred" /* pred */,
|
|
54
|
-
"probable" /* probable */,
|
|
55
|
-
"myriad" /* myriad */,
|
|
56
|
-
"hyperliquid" /* hyperliquid */,
|
|
57
|
-
"novig" /* novig */,
|
|
58
|
-
"prophetx" /* prophetx */
|
|
59
|
-
];
|
|
60
|
-
var INACTIVE_VENUES = [];
|
|
61
|
-
var DEFAULT_DISABLED_VENUES = ["pred" /* pred */, "novig" /* novig */, "prophetx" /* prophetx */];
|
|
62
|
-
var ACTIVE_VENUE_SET = new Set(ACTIVE_VENUES);
|
|
63
|
-
var INACTIVE_VENUE_SET = new Set(INACTIVE_VENUES);
|
|
64
|
-
function normalizeVenue(venue) {
|
|
65
|
-
return venue.trim().toLowerCase();
|
|
66
|
-
}
|
|
67
|
-
function isVenueActive(venue) {
|
|
68
|
-
if (ACTIVE_VENUE_SET.has(venue)) return true;
|
|
69
|
-
if (INACTIVE_VENUE_SET.has(venue)) return false;
|
|
70
|
-
return ACTIVE_VENUE_SET.has(normalizeVenue(venue));
|
|
71
|
-
}
|
|
72
|
-
function isVenueInactive(venue) {
|
|
73
|
-
if (INACTIVE_VENUE_SET.has(venue)) return true;
|
|
74
|
-
if (ACTIVE_VENUE_SET.has(venue)) return false;
|
|
75
|
-
return INACTIVE_VENUE_SET.has(normalizeVenue(venue));
|
|
76
|
-
}
|
|
77
|
-
function isVenueDataVisible(venue, dataVisibleOverride = []) {
|
|
78
|
-
if (isVenueActive(venue)) return true;
|
|
79
|
-
const n = normalizeVenue(venue);
|
|
80
|
-
return dataVisibleOverride.some((v) => normalizeVenue(v) === n);
|
|
70
|
+
// src/retry-after.ts
|
|
71
|
+
function parseRetryAfterSeconds(value) {
|
|
72
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
73
|
+
const milliseconds = value * 1e3;
|
|
74
|
+
return Number.isSafeInteger(milliseconds) ? milliseconds : void 0;
|
|
81
75
|
}
|
|
82
|
-
function
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
76
|
+
function parseRetryAfterHeader(value, now = Date.now()) {
|
|
77
|
+
if (!value) return void 0;
|
|
78
|
+
const text = value.trim();
|
|
79
|
+
if (/^\d+$/.test(text)) return parseRetryAfterSeconds(Number(text));
|
|
80
|
+
if (!/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(
|
|
81
|
+
text
|
|
82
|
+
))
|
|
83
|
+
return void 0;
|
|
84
|
+
const timestamp = Date.parse(text);
|
|
85
|
+
if (!Number.isFinite(timestamp) || new Date(timestamp).toUTCString() !== text) return void 0;
|
|
86
|
+
const milliseconds = timestamp - now;
|
|
87
|
+
return Number.isSafeInteger(milliseconds) && milliseconds >= 0 ? milliseconds : void 0;
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
// ../common/src/enums/image-size.ts
|
|
93
|
-
var ImageSize = /* @__PURE__ */ ((ImageSize2) => {
|
|
94
|
-
ImageSize2[ImageSize2["sm"] = 44] = "sm";
|
|
95
|
-
ImageSize2[ImageSize2["md"] = 48] = "md";
|
|
96
|
-
ImageSize2[ImageSize2["lg"] = 60] = "lg";
|
|
97
|
-
ImageSize2[ImageSize2["original"] = 0] = "original";
|
|
98
|
-
return ImageSize2;
|
|
99
|
-
})(ImageSize || {});
|
|
100
|
-
var IMAGE_SIZES = [44 /* sm */, 48 /* md */, 60 /* lg */];
|
|
101
|
-
|
|
102
|
-
// ../common/src/enums/account.ts
|
|
103
|
-
var AccountType = /* @__PURE__ */ ((AccountType2) => {
|
|
104
|
-
AccountType2["oauth"] = "oauth";
|
|
105
|
-
AccountType2["siwe"] = "siwe";
|
|
106
|
-
AccountType2["siws"] = "siws";
|
|
107
|
-
AccountType2["email"] = "email";
|
|
108
|
-
return AccountType2;
|
|
109
|
-
})(AccountType || {});
|
|
110
|
-
var AccountProvider = /* @__PURE__ */ ((AccountProvider2) => {
|
|
111
|
-
AccountProvider2["wallet"] = "wallet";
|
|
112
|
-
AccountProvider2["solana_wallet"] = "solana_wallet";
|
|
113
|
-
AccountProvider2["google"] = "google";
|
|
114
|
-
AccountProvider2["twitter"] = "twitter";
|
|
115
|
-
AccountProvider2["apple"] = "apple";
|
|
116
|
-
AccountProvider2["email"] = "email";
|
|
117
|
-
return AccountProvider2;
|
|
118
|
-
})(AccountProvider || {});
|
|
119
|
-
|
|
120
|
-
// ../common/src/enums/chain.ts
|
|
121
|
-
var Chain = /* @__PURE__ */ ((Chain2) => {
|
|
122
|
-
Chain2["evm"] = "evm";
|
|
123
|
-
Chain2["svm"] = "svm";
|
|
124
|
-
return Chain2;
|
|
125
|
-
})(Chain || {});
|
|
126
|
-
|
|
127
|
-
// ../common/src/enums/market-status.ts
|
|
128
|
-
var MatchStatus = /* @__PURE__ */ ((MatchStatus3) => {
|
|
129
|
-
MatchStatus3["pending"] = "pending";
|
|
130
|
-
MatchStatus3["unmatched"] = "unmatched";
|
|
131
|
-
MatchStatus3["review"] = "review";
|
|
132
|
-
MatchStatus3["matched"] = "matched";
|
|
133
|
-
MatchStatus3["verified"] = "verified";
|
|
134
|
-
MatchStatus3["rejected"] = "rejected";
|
|
135
|
-
return MatchStatus3;
|
|
136
|
-
})(MatchStatus || {});
|
|
137
|
-
var MatchType = /* @__PURE__ */ ((MatchType2) => {
|
|
138
|
-
MatchType2["manual"] = "manual";
|
|
139
|
-
MatchType2["llm"] = "llm";
|
|
140
|
-
return MatchType2;
|
|
141
|
-
})(MatchType || {});
|
|
142
|
-
var CONFIRMED_MATCH_STATUSES = ["matched" /* matched */, "verified" /* verified */];
|
|
143
|
-
var MarketStatus = /* @__PURE__ */ ((MarketStatus3) => {
|
|
144
|
-
MarketStatus3["open"] = "open";
|
|
145
|
-
MarketStatus3["closed"] = "closed";
|
|
146
|
-
MarketStatus3["resolved"] = "resolved";
|
|
147
|
-
MarketStatus3["unopened"] = "unopened";
|
|
148
|
-
MarketStatus3["paused"] = "paused";
|
|
149
|
-
return MarketStatus3;
|
|
150
|
-
})(MarketStatus || {});
|
|
151
|
-
|
|
152
|
-
// ../common/src/enums/trading.ts
|
|
153
|
-
var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
|
|
154
|
-
OrderStatus2["pending"] = "pending";
|
|
155
|
-
OrderStatus2["signing"] = "signing";
|
|
156
|
-
OrderStatus2["pending_bridge"] = "pending_bridge";
|
|
157
|
-
OrderStatus2["submitting"] = "submitting";
|
|
158
|
-
OrderStatus2["submitted"] = "submitted";
|
|
159
|
-
OrderStatus2["open"] = "open";
|
|
160
|
-
OrderStatus2["partially_filled_open"] = "partially_filled_open";
|
|
161
|
-
OrderStatus2["cancel_pending"] = "cancel_pending";
|
|
162
|
-
OrderStatus2["filled"] = "filled";
|
|
163
|
-
OrderStatus2["partial_fill"] = "partial_fill";
|
|
164
|
-
OrderStatus2["failed"] = "failed";
|
|
165
|
-
OrderStatus2["expired"] = "expired";
|
|
166
|
-
OrderStatus2["cancelled"] = "cancelled";
|
|
167
|
-
return OrderStatus2;
|
|
168
|
-
})(OrderStatus || {});
|
|
169
|
-
var TradeSide = /* @__PURE__ */ ((TradeSide2) => {
|
|
170
|
-
TradeSide2["Buy"] = "buy";
|
|
171
|
-
TradeSide2["Sell"] = "sell";
|
|
172
|
-
return TradeSide2;
|
|
173
|
-
})(TradeSide || {});
|
|
174
|
-
var OrderType = /* @__PURE__ */ ((OrderType2) => {
|
|
175
|
-
OrderType2["Market"] = "market";
|
|
176
|
-
OrderType2["Limit"] = "limit";
|
|
177
|
-
return OrderType2;
|
|
178
|
-
})(OrderType || {});
|
|
179
|
-
var TimeInForce = /* @__PURE__ */ ((TimeInForce2) => {
|
|
180
|
-
TimeInForce2["GTC"] = "GTC";
|
|
181
|
-
TimeInForce2["GTD"] = "GTD";
|
|
182
|
-
TimeInForce2["FOK"] = "FOK";
|
|
183
|
-
TimeInForce2["FAK"] = "FAK";
|
|
184
|
-
TimeInForce2["IOC"] = "IOC";
|
|
185
|
-
TimeInForce2["ALO"] = "ALO";
|
|
186
|
-
return TimeInForce2;
|
|
187
|
-
})(TimeInForce || {});
|
|
188
|
-
|
|
189
|
-
// ../common/src/utils/format-market-display.ts
|
|
190
|
-
function formatOutcomeLabel(venue, outcome, _market) {
|
|
191
|
-
return outcome.label;
|
|
192
|
-
}
|
|
193
|
-
function formatMarketQuestion(venue, market) {
|
|
194
|
-
var _a, _b, _c, _d;
|
|
195
|
-
if ((_a = market.shortTitle) == null ? void 0 : _a.trim()) return market.shortTitle.trim();
|
|
196
|
-
if (venue === "kalshi" /* kalshi */) {
|
|
197
|
-
const firstTitle = (_d = (_c = (_b = market.venueMarketOutcomes) == null ? void 0 : _b[0]) == null ? void 0 : _c.title) == null ? void 0 : _d.trim();
|
|
198
|
-
if (firstTitle) return firstTitle;
|
|
199
|
-
}
|
|
200
|
-
return market.question.trim();
|
|
201
|
-
}
|
|
202
|
-
function formatOutcomeTitle(_venue, outcome, market) {
|
|
203
|
-
var _a, _b;
|
|
204
|
-
const outcomes = (_a = market.venueMarketOutcomes) != null ? _a : [];
|
|
205
|
-
if (outcomes.length >= 2) {
|
|
206
|
-
const normalized = outcomes.map((o) => {
|
|
207
|
-
var _a2, _b2;
|
|
208
|
-
return (_b2 = (_a2 = o.title) == null ? void 0 : _a2.trim()) != null ? _b2 : "";
|
|
209
|
-
});
|
|
210
|
-
const hasAnyTitle = normalized.some((t) => t.length > 0);
|
|
211
|
-
if (hasAnyTitle && normalized.every((t) => t === normalized[0])) return null;
|
|
212
|
-
}
|
|
213
|
-
const title = (_b = outcome.title) == null ? void 0 : _b.trim();
|
|
214
|
-
if (title) return title;
|
|
215
|
-
return deriveOverUnderTitle(outcome.label, market.question);
|
|
216
|
-
}
|
|
217
|
-
var OVER_UNDER_QUESTION = /\bO\/U\s+\d/i;
|
|
218
|
-
function deriveOverUnderTitle(label, question) {
|
|
219
|
-
if (!question || !OVER_UNDER_QUESTION.test(question)) return null;
|
|
220
|
-
const normalized = label.trim().toLowerCase();
|
|
221
|
-
if (normalized === "yes") return "Over";
|
|
222
|
-
if (normalized === "no") return "Under";
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ../common/src/utils/auth.ts
|
|
227
|
-
function getWalletAddressFromUserProfile(user) {
|
|
228
|
-
var _a, _b, _c, _d, _e;
|
|
229
|
-
const oauthWallet = (_b = (_a = user == null ? void 0 : user.accounts) == null ? void 0 : _a.find(
|
|
230
|
-
(a) => a.type === "oauth" /* oauth */ && String(a.provider).toLowerCase() === "wallet"
|
|
231
|
-
)) != null ? _b : null;
|
|
232
|
-
if (oauthWallet == null ? void 0 : oauthWallet.providerAccountId) return oauthWallet.providerAccountId;
|
|
233
|
-
const siweAccount = (_d = (_c = user == null ? void 0 : user.accounts) == null ? void 0 : _c.find((a) => a.type === "siwe" /* siwe */)) != null ? _d : null;
|
|
234
|
-
return (_e = siweAccount == null ? void 0 : siweAccount.providerAccountId) != null ? _e : void 0;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// ../common/src/utils/validate.ts
|
|
238
|
-
function safeParse(value, guard) {
|
|
239
|
-
if (guard(value)) return { success: true, data: value };
|
|
240
|
-
return { success: false };
|
|
241
|
-
}
|
|
242
|
-
function parse(value, guard, message = "Validation failed") {
|
|
243
|
-
if (guard(value)) return value;
|
|
244
|
-
const err = new Error(message);
|
|
245
|
-
err.issues = [{ message }];
|
|
246
|
-
throw err;
|
|
247
|
-
}
|
|
248
|
-
function isEnum(values) {
|
|
249
|
-
return (v) => typeof v === "string" && values.has(v);
|
|
250
|
-
}
|
|
251
|
-
function enumGuard(source) {
|
|
252
|
-
const values = new Set(Array.isArray(source) ? source : Object.values(source));
|
|
253
|
-
return isEnum(values);
|
|
254
|
-
}
|
|
255
|
-
function isFiniteNonNeg(v) {
|
|
256
|
-
return typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
257
|
-
}
|
|
258
|
-
function isNonEmptyString(v) {
|
|
259
|
-
return typeof v === "string" && v.length > 0;
|
|
260
|
-
}
|
|
261
|
-
function hasShape(v, checks) {
|
|
262
|
-
if (typeof v !== "object" || v === null) return false;
|
|
263
|
-
const obj = v;
|
|
264
|
-
for (const [key, check] of Object.entries(checks)) {
|
|
265
|
-
if (!(key in obj) || !check(obj[key])) return false;
|
|
266
|
-
}
|
|
267
|
-
return true;
|
|
268
|
-
}
|
|
269
|
-
var EMAIL_MSG = "Enter a valid email address.";
|
|
270
|
-
var EMAIL_MAX_LEN = 254;
|
|
271
|
-
function isEmail(v) {
|
|
272
|
-
const n = v.length;
|
|
273
|
-
if (n === 0 || n > EMAIL_MAX_LEN) return false;
|
|
274
|
-
let atIdx = -1;
|
|
275
|
-
for (let i = 0; i < n; i++) {
|
|
276
|
-
const c = v.charCodeAt(i);
|
|
277
|
-
if (c === 32 || c >= 9 && c <= 13) return false;
|
|
278
|
-
if (c === 64) {
|
|
279
|
-
if (atIdx !== -1) return false;
|
|
280
|
-
atIdx = i;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (atIdx <= 0 || atIdx === n - 1) return false;
|
|
284
|
-
for (let i = atIdx + 2; i < n - 1; i++) {
|
|
285
|
-
if (v.charCodeAt(i) === 46) return true;
|
|
286
|
-
}
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
289
|
-
function parseEmail(raw) {
|
|
290
|
-
const email = raw.trim();
|
|
291
|
-
if (!isEmail(email)) {
|
|
292
|
-
return { success: false, error: { issues: [{ message: EMAIL_MSG }] } };
|
|
293
|
-
}
|
|
294
|
-
return { success: true, data: { email } };
|
|
295
|
-
}
|
|
296
|
-
function parseEmailStrict(raw) {
|
|
297
|
-
var _a;
|
|
298
|
-
const result = parseEmail(raw);
|
|
299
|
-
if (!result.success) {
|
|
300
|
-
const err = new Error(EMAIL_MSG);
|
|
301
|
-
err.issues = (_a = result.error) == null ? void 0 : _a.issues;
|
|
302
|
-
throw err;
|
|
303
|
-
}
|
|
304
|
-
return result.data;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ../common/src/utils/trading-splits.ts
|
|
308
|
-
function computeBestSplitsByAmount(selections, side, maxDollarAmount) {
|
|
309
|
-
var _a;
|
|
310
|
-
if (selections.length === 0 || maxDollarAmount <= 0) {
|
|
311
|
-
return { splits: [], totalSize: 0, totalCost: 0 };
|
|
312
|
-
}
|
|
313
|
-
const levels = [];
|
|
314
|
-
for (const o of selections) {
|
|
315
|
-
const venue = o.market.venue;
|
|
316
|
-
const venueMarketOutcomeId = o.outcome.id;
|
|
317
|
-
const outcomeExternalIdentifier = (_a = o.outcome.externalIdentifier) != null ? _a : void 0;
|
|
318
|
-
if (side === "buy" /* Buy */) {
|
|
319
|
-
[...o.orderbook.asks].sort((a, b) => a.price - b.price).forEach(
|
|
320
|
-
(l) => {
|
|
321
|
-
var _a2;
|
|
322
|
-
return levels.push({
|
|
323
|
-
venue,
|
|
324
|
-
venueMarketOutcomeId,
|
|
325
|
-
outcomeExternalIdentifier,
|
|
326
|
-
price: l.price,
|
|
327
|
-
size: l.size,
|
|
328
|
-
negRisk: (_a2 = o.orderbook.negRisk) != null ? _a2 : false
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
);
|
|
332
|
-
} else {
|
|
333
|
-
[...o.orderbook.bids].sort((a, b) => b.price - a.price).forEach(
|
|
334
|
-
(l) => {
|
|
335
|
-
var _a2;
|
|
336
|
-
return levels.push({
|
|
337
|
-
venue,
|
|
338
|
-
venueMarketOutcomeId,
|
|
339
|
-
outcomeExternalIdentifier,
|
|
340
|
-
price: 1 - l.price,
|
|
341
|
-
size: l.size,
|
|
342
|
-
negRisk: (_a2 = o.orderbook.negRisk) != null ? _a2 : false
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
levels.sort((a, b) => a.price - b.price);
|
|
349
|
-
let totalCost = 0;
|
|
350
|
-
const fills = [];
|
|
351
|
-
for (const l of levels) {
|
|
352
|
-
if (totalCost >= maxDollarAmount) break;
|
|
353
|
-
const remainingBudget = maxDollarAmount - totalCost;
|
|
354
|
-
const maxSizeAtLevel = Math.min(l.size, remainingBudget / l.price);
|
|
355
|
-
if (maxSizeAtLevel <= 0) continue;
|
|
356
|
-
const take = maxSizeAtLevel;
|
|
357
|
-
fills.push({
|
|
358
|
-
venue: l.venue,
|
|
359
|
-
venueMarketOutcomeId: l.venueMarketOutcomeId,
|
|
360
|
-
outcomeExternalIdentifier: l.outcomeExternalIdentifier,
|
|
361
|
-
price: l.price,
|
|
362
|
-
size: take,
|
|
363
|
-
negRisk: l.negRisk
|
|
364
|
-
});
|
|
365
|
-
totalCost += l.price * take;
|
|
366
|
-
}
|
|
367
|
-
if (fills.length === 0) {
|
|
368
|
-
return { splits: [], totalSize: 0, totalCost: 0 };
|
|
369
|
-
}
|
|
370
|
-
const byOutcome = {};
|
|
371
|
-
for (const f of fills) {
|
|
372
|
-
const key = `${f.venue}:${f.venueMarketOutcomeId}`;
|
|
373
|
-
const existing = byOutcome[key];
|
|
374
|
-
if (!existing) {
|
|
375
|
-
byOutcome[key] = {
|
|
376
|
-
size: f.size,
|
|
377
|
-
venue: f.venue,
|
|
378
|
-
venueMarketOutcomeId: f.venueMarketOutcomeId,
|
|
379
|
-
outcomeExternalIdentifier: f.outcomeExternalIdentifier,
|
|
380
|
-
negRisk: f.negRisk
|
|
381
|
-
};
|
|
382
|
-
} else {
|
|
383
|
-
existing.size += f.size;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
const splits = [];
|
|
387
|
-
let totalSize = 0;
|
|
388
|
-
for (const key in byOutcome) {
|
|
389
|
-
const { size, venue, venueMarketOutcomeId, outcomeExternalIdentifier, negRisk } = byOutcome[key];
|
|
390
|
-
totalSize += size;
|
|
391
|
-
let price = 0;
|
|
392
|
-
if (size > 0) {
|
|
393
|
-
const outcomeFills = fills.filter(
|
|
394
|
-
(f) => f.venue === venue && f.venueMarketOutcomeId === venueMarketOutcomeId
|
|
395
|
-
);
|
|
396
|
-
if (side === "buy" /* Buy */) {
|
|
397
|
-
const rawPrice = Math.max(...outcomeFills.map((f) => f.price));
|
|
398
|
-
price = Math.ceil(rawPrice * 100) / 100;
|
|
399
|
-
} else {
|
|
400
|
-
const rawPrice = Math.min(...outcomeFills.map((f) => 1 - f.price));
|
|
401
|
-
price = Math.floor(rawPrice * 100) / 100;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
splits.push({
|
|
405
|
-
venue,
|
|
406
|
-
venueMarketOutcomeId,
|
|
407
|
-
side,
|
|
408
|
-
price,
|
|
409
|
-
size,
|
|
410
|
-
negRisk,
|
|
411
|
-
outcomeExternalIdentifier
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
return {
|
|
415
|
-
splits,
|
|
416
|
-
totalSize,
|
|
417
|
-
totalCost
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// ../common/src/utils/image-url.ts
|
|
422
|
-
function pickVariant(px) {
|
|
423
|
-
if (px <= 44 /* sm */) return 44 /* sm */;
|
|
424
|
-
if (px <= 48 /* md */) return 48 /* md */;
|
|
425
|
-
if (px <= 60 /* lg */) return 60 /* lg */;
|
|
426
|
-
return 0 /* original */;
|
|
427
|
-
}
|
|
428
|
-
var VARIANT_RE = /\/(original|raw|\d+)\.webp$/;
|
|
429
|
-
function optimizedImageUrl(url, maxPx) {
|
|
430
|
-
if (!url) return void 0;
|
|
431
|
-
if (!VARIANT_RE.test(url)) return url;
|
|
432
|
-
const variant = pickVariant(maxPx);
|
|
433
|
-
const filename = variant === 0 /* original */ ? "original.webp" : `${variant}.webp`;
|
|
434
|
-
return url.replace(VARIANT_RE, `/${filename}`);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// ../common/src/utils/venue-market-cluster.ts
|
|
438
|
-
var toNonEmptyString = (value) => {
|
|
439
|
-
if (typeof value !== "string") return void 0;
|
|
440
|
-
const trimmedValue = value.trim();
|
|
441
|
-
return trimmedValue ? trimmedValue : void 0;
|
|
442
|
-
};
|
|
443
|
-
var addGraphEdge = (adjacencyById, fromMarketId, toMarketId) => {
|
|
444
|
-
var _a, _b;
|
|
445
|
-
if (fromMarketId === toMarketId) return;
|
|
446
|
-
const fromNeighbors = (_a = adjacencyById.get(fromMarketId)) != null ? _a : /* @__PURE__ */ new Set();
|
|
447
|
-
fromNeighbors.add(toMarketId);
|
|
448
|
-
adjacencyById.set(fromMarketId, fromNeighbors);
|
|
449
|
-
const toNeighbors = (_b = adjacencyById.get(toMarketId)) != null ? _b : /* @__PURE__ */ new Set();
|
|
450
|
-
toNeighbors.add(fromMarketId);
|
|
451
|
-
adjacencyById.set(toMarketId, toNeighbors);
|
|
452
|
-
};
|
|
453
|
-
var collectDirectRelationMarkets = (market) => {
|
|
454
|
-
var _a, _b, _c;
|
|
455
|
-
const relationMarkets = [];
|
|
456
|
-
const seenRelationIds = /* @__PURE__ */ new Set();
|
|
457
|
-
const addRelationMarket = (relationMarket) => {
|
|
458
|
-
if (!relationMarket) return;
|
|
459
|
-
if (seenRelationIds.has(relationMarket.id)) return;
|
|
460
|
-
seenRelationIds.add(relationMarket.id);
|
|
461
|
-
relationMarkets.push(relationMarket);
|
|
462
|
-
};
|
|
463
|
-
for (const matchedVenueMarket of (_a = market.matchedVenueMarkets) != null ? _a : []) {
|
|
464
|
-
addRelationMarket(matchedVenueMarket);
|
|
465
|
-
}
|
|
466
|
-
addRelationMarket((_c = (_b = market.matchEntry) == null ? void 0 : _b.targetVenueMarket) != null ? _c : void 0);
|
|
467
|
-
return relationMarkets;
|
|
468
|
-
};
|
|
469
|
-
var dedupeSourceMarketsById = (markets) => {
|
|
470
|
-
const seenMarketIds = /* @__PURE__ */ new Set();
|
|
471
|
-
return markets.filter((market) => {
|
|
472
|
-
if (seenMarketIds.has(market.id)) {
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
seenMarketIds.add(market.id);
|
|
476
|
-
return true;
|
|
477
|
-
});
|
|
478
|
-
};
|
|
479
|
-
var collectUniqueRelatedMarkets = (markets, sourceMarketsById) => {
|
|
480
|
-
const relatedMarketsById = /* @__PURE__ */ new Map();
|
|
481
|
-
for (const market of markets) {
|
|
482
|
-
for (const relatedMarket of collectDirectRelationMarkets(market)) {
|
|
483
|
-
if (sourceMarketsById.has(relatedMarket.id) || relatedMarketsById.has(relatedMarket.id)) {
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
relatedMarketsById.set(relatedMarket.id, relatedMarket);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
return Array.from(relatedMarketsById.values());
|
|
490
|
-
};
|
|
491
|
-
var normalizeVenueMarketCluster = (markets, selectedMarketId) => {
|
|
492
|
-
var _a, _b;
|
|
493
|
-
if (markets.length === 0) return [];
|
|
494
|
-
const orderedSourceMarkets = dedupeSourceMarketsById(markets);
|
|
495
|
-
const sourceMarketsById = new Map(orderedSourceMarkets.map((market) => [market.id, market]));
|
|
496
|
-
const orderedRelatedMarkets = collectUniqueRelatedMarkets(
|
|
497
|
-
orderedSourceMarkets,
|
|
498
|
-
sourceMarketsById
|
|
499
|
-
);
|
|
500
|
-
const relatedMarketsById = new Map(orderedRelatedMarkets.map((market) => [market.id, market]));
|
|
501
|
-
const resolvedSelectedMarketId = toNonEmptyString(selectedMarketId);
|
|
502
|
-
if (!resolvedSelectedMarketId) {
|
|
503
|
-
return [...orderedSourceMarkets, ...orderedRelatedMarkets];
|
|
504
|
-
}
|
|
505
|
-
const adjacencyById = /* @__PURE__ */ new Map();
|
|
506
|
-
for (const market of orderedSourceMarkets) {
|
|
507
|
-
for (const relatedMarket of collectDirectRelationMarkets(market)) {
|
|
508
|
-
addGraphEdge(adjacencyById, market.id, relatedMarket.id);
|
|
509
|
-
}
|
|
510
|
-
const targetVenueMarketId = toNonEmptyString((_a = market.matchEntry) == null ? void 0 : _a.targetVenueMarketId);
|
|
511
|
-
if (targetVenueMarketId) {
|
|
512
|
-
addGraphEdge(adjacencyById, market.id, targetVenueMarketId);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
if (!sourceMarketsById.has(resolvedSelectedMarketId) && !relatedMarketsById.has(resolvedSelectedMarketId)) {
|
|
516
|
-
return [];
|
|
517
|
-
}
|
|
518
|
-
const visitedMarketIds = /* @__PURE__ */ new Set();
|
|
519
|
-
const queue = [resolvedSelectedMarketId];
|
|
520
|
-
while (queue.length > 0) {
|
|
521
|
-
const currentMarketId = queue.shift();
|
|
522
|
-
if (!currentMarketId || visitedMarketIds.has(currentMarketId)) {
|
|
523
|
-
continue;
|
|
524
|
-
}
|
|
525
|
-
visitedMarketIds.add(currentMarketId);
|
|
526
|
-
const neighborMarketIds = adjacencyById.get(currentMarketId);
|
|
527
|
-
for (const neighborMarketId of Array.from(neighborMarketIds != null ? neighborMarketIds : /* @__PURE__ */ new Set())) {
|
|
528
|
-
if (!visitedMarketIds.has(neighborMarketId)) {
|
|
529
|
-
queue.push(neighborMarketId);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
const orderedClusterMarkets = [];
|
|
534
|
-
const appendedMarketIds = /* @__PURE__ */ new Set();
|
|
535
|
-
const appendMarket = (market) => {
|
|
536
|
-
if (!market) return;
|
|
537
|
-
if (!visitedMarketIds.has(market.id)) return;
|
|
538
|
-
if (appendedMarketIds.has(market.id)) return;
|
|
539
|
-
appendedMarketIds.add(market.id);
|
|
540
|
-
orderedClusterMarkets.push(market);
|
|
541
|
-
};
|
|
542
|
-
appendMarket(
|
|
543
|
-
(_b = sourceMarketsById.get(resolvedSelectedMarketId)) != null ? _b : relatedMarketsById.get(resolvedSelectedMarketId)
|
|
544
|
-
);
|
|
545
|
-
for (const market of orderedSourceMarkets) {
|
|
546
|
-
appendMarket(market);
|
|
547
|
-
}
|
|
548
|
-
for (const market of orderedRelatedMarkets) {
|
|
549
|
-
appendMarket(market);
|
|
550
|
-
}
|
|
551
|
-
return orderedClusterMarkets;
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
// ../common/src/utils/sort-venues.ts
|
|
555
|
-
var VENUE_SORT_ORDER = [
|
|
556
|
-
"polymarket" /* polymarket */,
|
|
557
|
-
"hyperliquid" /* hyperliquid */,
|
|
558
|
-
"predict" /* predict */,
|
|
559
|
-
"prophetx" /* prophetx */,
|
|
560
|
-
"kalshi" /* kalshi */,
|
|
561
|
-
"limitless" /* limitless */,
|
|
562
|
-
"myriad" /* myriad */,
|
|
563
|
-
"pred" /* pred */,
|
|
564
|
-
"probable" /* probable */,
|
|
565
|
-
"novig" /* novig */,
|
|
566
|
-
"opinion" /* opinion */
|
|
567
|
-
];
|
|
568
|
-
var venueOrderIndex = new Map(VENUE_SORT_ORDER.map((v, i) => [v, i]));
|
|
569
|
-
var getVenueOrder = (venue) => {
|
|
570
|
-
var _a;
|
|
571
|
-
return (_a = venueOrderIndex.get(venue)) != null ? _a : VENUE_SORT_ORDER.length;
|
|
572
|
-
};
|
|
573
|
-
var sortVenues = (venues) => [...venues].sort((a, b) => getVenueOrder(a) - getVenueOrder(b));
|
|
574
|
-
|
|
575
|
-
// ../common/src/utils/venue-url.ts
|
|
576
|
-
function buildVenueUrl(venue, opts) {
|
|
577
|
-
switch (venue) {
|
|
578
|
-
case "kalshi": {
|
|
579
|
-
const series = opts.seriesExternalId;
|
|
580
|
-
const event = opts.eventExternalId;
|
|
581
|
-
if (series && event) {
|
|
582
|
-
return `https://kalshi.com/markets/${series.toLowerCase()}/${event.toLowerCase()}`;
|
|
583
|
-
}
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
case "polymarket": {
|
|
587
|
-
if (opts.eventSlug) return `https://polymarket.com/event/${opts.eventSlug}`;
|
|
588
|
-
if (opts.conditionId) return `https://polymarket.com/market/${opts.conditionId}`;
|
|
589
|
-
return null;
|
|
590
|
-
}
|
|
591
|
-
case "predict": {
|
|
592
|
-
if (opts.eventSlug) return `https://predict.fun/market/${opts.eventSlug}`;
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
case "pred": {
|
|
596
|
-
if (opts.eventSlug) return `https://www.pred.app/trade/${opts.eventSlug}`;
|
|
597
|
-
return null;
|
|
598
|
-
}
|
|
599
|
-
case "limitless": {
|
|
600
|
-
if (opts.eventSlug) return `https://limitless.exchange/markets/${opts.eventSlug}`;
|
|
601
|
-
return null;
|
|
602
|
-
}
|
|
603
|
-
case "opinion": {
|
|
604
|
-
if (opts.eventSlug) return `https://www.opinion.trade/market/${opts.eventSlug}`;
|
|
605
|
-
return null;
|
|
606
|
-
}
|
|
607
|
-
case "myriad": {
|
|
608
|
-
if (opts.eventSlug) return `https://myriad.markets/markets/${opts.eventSlug}`;
|
|
609
|
-
return null;
|
|
610
|
-
}
|
|
611
|
-
case "hyperliquid": {
|
|
612
|
-
if (opts.eventSlug) return `https://app.hyperliquid.xyz/trade/${opts.eventSlug}`;
|
|
613
|
-
return null;
|
|
614
|
-
}
|
|
615
|
-
case "probable": {
|
|
616
|
-
if (opts.eventSlug) return `https://probable.markets/event/${opts.eventSlug}`;
|
|
617
|
-
return null;
|
|
618
|
-
}
|
|
619
|
-
case "novig": {
|
|
620
|
-
if (opts.outcomeExternalId && opts.partnerId) {
|
|
621
|
-
return opts.platform === "native" ? `novigapp://events/${opts.outcomeExternalId}/${opts.partnerId}` : `https://novig.com/events/${opts.outcomeExternalId}/${opts.partnerId}`;
|
|
622
|
-
}
|
|
623
|
-
return null;
|
|
624
|
-
}
|
|
625
|
-
default:
|
|
626
|
-
return null;
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// ../common/src/utils/limit-price-ticks.ts
|
|
631
|
-
var LIMIT_PRICE_RAW_SCALE = BigInt(1e6);
|
|
632
|
-
var resolveTickSizeRaw = (tickSize) => {
|
|
633
|
-
const scaledTick = tickSize * Number(LIMIT_PRICE_RAW_SCALE);
|
|
634
|
-
const roundedTick = Math.round(scaledTick);
|
|
635
|
-
if (!Number.isFinite(scaledTick) || roundedTick <= 0 || Math.abs(scaledTick - roundedTick) > 1e-6) {
|
|
636
|
-
throw new RangeError(`Unsupported limit-order tick size: ${tickSize}`);
|
|
637
|
-
}
|
|
638
|
-
return BigInt(roundedTick);
|
|
639
|
-
};
|
|
640
|
-
var adjustLimitPriceRawToTick = ({
|
|
641
|
-
limitPriceRaw,
|
|
642
|
-
side,
|
|
643
|
-
tickSize
|
|
644
|
-
}) => {
|
|
645
|
-
const originalPrice = BigInt(limitPriceRaw);
|
|
646
|
-
const originalPriceRaw = originalPrice.toString();
|
|
647
|
-
if (tickSize == null) {
|
|
648
|
-
return {
|
|
649
|
-
adjusted: false,
|
|
650
|
-
adjustedPriceRaw: originalPriceRaw,
|
|
651
|
-
originalPriceRaw,
|
|
652
|
-
tickSizeRaw: null
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
const tickSizeRaw = resolveTickSizeRaw(tickSize);
|
|
656
|
-
const remainder = originalPrice % tickSizeRaw;
|
|
657
|
-
if (remainder === BigInt(0)) {
|
|
658
|
-
return {
|
|
659
|
-
adjusted: false,
|
|
660
|
-
adjustedPriceRaw: originalPriceRaw,
|
|
661
|
-
originalPriceRaw,
|
|
662
|
-
tickSizeRaw: tickSizeRaw.toString()
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
const adjustedPrice = side === "buy" ? originalPrice - remainder : originalPrice + (tickSizeRaw - remainder);
|
|
666
|
-
return {
|
|
667
|
-
adjusted: true,
|
|
668
|
-
adjustedPriceRaw: adjustedPrice.toString(),
|
|
669
|
-
originalPriceRaw,
|
|
670
|
-
tickSizeRaw: tickSizeRaw.toString()
|
|
671
|
-
};
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
// ../common/src/utils/balance-refill.ts
|
|
675
|
-
var DEFAULT_BALANCE_REFILL_DAILY_CAP_RAW = "1002000000";
|
|
676
|
-
var DEFAULT_BALANCE_REFILL_MAX_FEE_RAW = "2000000";
|
|
677
|
-
var getBalanceRefillMaximumRaw = (dailyCapRaw, maxFeeRaw) => {
|
|
678
|
-
const dailyCap = BigInt(dailyCapRaw);
|
|
679
|
-
const maximumFee = BigInt(maxFeeRaw);
|
|
680
|
-
if (dailyCap <= maximumFee) return "0";
|
|
681
|
-
return (dailyCap - maximumFee).toString();
|
|
682
|
-
};
|
|
683
|
-
var isBalanceRefillWithinDailyCap = (minimumRaw, refillAmountRaw, dailyCapRaw, maxFeeRaw) => {
|
|
684
|
-
const maximum = BigInt(getBalanceRefillMaximumRaw(dailyCapRaw, maxFeeRaw));
|
|
685
|
-
return BigInt(minimumRaw) <= maximum && BigInt(refillAmountRaw) <= maximum;
|
|
686
|
-
};
|
|
687
|
-
|
|
688
90
|
// src/errors.ts
|
|
689
91
|
var TurnstileChallengeError = class extends Error {
|
|
690
92
|
constructor(siteKey) {
|
|
@@ -700,6 +102,7 @@ var AggApiError = class _AggApiError extends Error {
|
|
|
700
102
|
this.status = status;
|
|
701
103
|
if (init.code !== void 0) this.code = init.code;
|
|
702
104
|
if (init.retryable !== void 0) this.retryable = init.retryable;
|
|
105
|
+
if (init.retryAfterMs !== void 0) this.retryAfterMs = init.retryAfterMs;
|
|
703
106
|
if (init.errors !== void 0) this.errors = init.errors;
|
|
704
107
|
Object.setPrototypeOf(this, _AggApiError.prototype);
|
|
705
108
|
}
|
|
@@ -855,931 +258,6 @@ var RECURRENCE_CADENCES = [
|
|
|
855
258
|
"P1Y"
|
|
856
259
|
];
|
|
857
260
|
|
|
858
|
-
// src/orderbook-utils.ts
|
|
859
|
-
var PRICE_KEY_SCALE = 1e9;
|
|
860
|
-
function crc32(str) {
|
|
861
|
-
let crc = 4294967295;
|
|
862
|
-
for (let i = 0; i < str.length; i++) {
|
|
863
|
-
crc ^= str.charCodeAt(i);
|
|
864
|
-
for (let j = 0; j < 8; j++) {
|
|
865
|
-
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
return (crc ^ 4294967295) >>> 0;
|
|
869
|
-
}
|
|
870
|
-
function computeChecksum(book) {
|
|
871
|
-
let checksum = 0;
|
|
872
|
-
for (const b of book.bids) checksum ^= crc32(`B${b.price}:${b.size}`);
|
|
873
|
-
for (const a of book.asks) checksum ^= crc32(`A${a.price}:${a.size}`);
|
|
874
|
-
return checksum >>> 0;
|
|
875
|
-
}
|
|
876
|
-
function attributedToLevel(wire) {
|
|
877
|
-
return { price: wire[0], size: wire[1], venues: __spreadValues({}, wire[2]) };
|
|
878
|
-
}
|
|
879
|
-
function venueLevelToLevel(wire) {
|
|
880
|
-
return { price: wire[0], size: wire[1] };
|
|
881
|
-
}
|
|
882
|
-
function convertVenueBooks(raw) {
|
|
883
|
-
const result = {};
|
|
884
|
-
for (const [venue, book] of Object.entries(raw)) {
|
|
885
|
-
result[venue] = {
|
|
886
|
-
bids: book.bids.map(venueLevelToLevel),
|
|
887
|
-
asks: book.asks.map(venueLevelToLevel)
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
return result;
|
|
891
|
-
}
|
|
892
|
-
function snapshotToOrderbook(snapshot) {
|
|
893
|
-
return {
|
|
894
|
-
marketId: snapshot.outcomeId,
|
|
895
|
-
outcomeId: snapshot.outcomeId,
|
|
896
|
-
bids: snapshot.bids.map(attributedToLevel),
|
|
897
|
-
asks: snapshot.asks.map(attributedToLevel),
|
|
898
|
-
venueOrderbooks: convertVenueBooks(snapshot.venueOrderbooks),
|
|
899
|
-
venues: __spreadValues({}, snapshot.venues),
|
|
900
|
-
midpoint: snapshot.midpoint,
|
|
901
|
-
spread: snapshot.spread,
|
|
902
|
-
seq: snapshot.seq,
|
|
903
|
-
checksum: snapshot.checksum,
|
|
904
|
-
timestamp: snapshot.timestamp
|
|
905
|
-
};
|
|
906
|
-
}
|
|
907
|
-
function applyOrderbookDelta(state, delta) {
|
|
908
|
-
var _a, _b;
|
|
909
|
-
const bids = applyChanges([...state.bids], delta.bidChanges, "desc");
|
|
910
|
-
const asks = applyChanges([...state.asks], delta.askChanges, "asc");
|
|
911
|
-
const impliedBidChangesByVenue = deriveVenueChangesFromAttributedChanges(
|
|
912
|
-
state.bids,
|
|
913
|
-
delta.bidChanges
|
|
914
|
-
);
|
|
915
|
-
const impliedAskChangesByVenue = deriveVenueChangesFromAttributedChanges(
|
|
916
|
-
state.asks,
|
|
917
|
-
delta.askChanges
|
|
918
|
-
);
|
|
919
|
-
const venueOrderbooks = __spreadValues({}, state.venueOrderbooks);
|
|
920
|
-
const venuesWithDelta = /* @__PURE__ */ new Set([
|
|
921
|
-
...Object.keys(delta.venueDeltaBooks),
|
|
922
|
-
...Object.keys(impliedBidChangesByVenue),
|
|
923
|
-
...Object.keys(impliedAskChangesByVenue)
|
|
924
|
-
]);
|
|
925
|
-
for (const venue of venuesWithDelta) {
|
|
926
|
-
const explicitChanges = delta.venueDeltaBooks[venue];
|
|
927
|
-
const bidChanges = mergeVenueLevelChanges(
|
|
928
|
-
explicitChanges == null ? void 0 : explicitChanges.bidChanges,
|
|
929
|
-
impliedBidChangesByVenue[venue]
|
|
930
|
-
);
|
|
931
|
-
const askChanges = mergeVenueLevelChanges(
|
|
932
|
-
explicitChanges == null ? void 0 : explicitChanges.askChanges,
|
|
933
|
-
impliedAskChangesByVenue[venue]
|
|
934
|
-
);
|
|
935
|
-
if (bidChanges.length === 0 && askChanges.length === 0) continue;
|
|
936
|
-
const existing = (_a = venueOrderbooks[venue]) != null ? _a : { bids: [], asks: [] };
|
|
937
|
-
venueOrderbooks[venue] = {
|
|
938
|
-
bids: applyVenueChanges([...existing.bids], bidChanges, "desc"),
|
|
939
|
-
asks: applyVenueChanges([...existing.asks], askChanges, "asc")
|
|
940
|
-
};
|
|
941
|
-
}
|
|
942
|
-
return {
|
|
943
|
-
marketId: state.marketId,
|
|
944
|
-
outcomeId: (_b = state.outcomeId) != null ? _b : delta.outcomeId,
|
|
945
|
-
bids,
|
|
946
|
-
asks,
|
|
947
|
-
venueOrderbooks,
|
|
948
|
-
venues: __spreadValues(__spreadValues({}, state.venues), delta.venues),
|
|
949
|
-
midpoint: delta.midpoint,
|
|
950
|
-
spread: delta.spread,
|
|
951
|
-
seq: delta.seq,
|
|
952
|
-
checksum: delta.checksum,
|
|
953
|
-
timestamp: delta.timestamp
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
function toPriceKey(price) {
|
|
957
|
-
return String(Math.round(price * PRICE_KEY_SCALE));
|
|
958
|
-
}
|
|
959
|
-
function applyChanges(levels, changes, sort) {
|
|
960
|
-
const levelsByPrice = new Map(levels.map((level) => [toPriceKey(level.price), level]));
|
|
961
|
-
for (const [price, size, venues] of changes) {
|
|
962
|
-
const key = toPriceKey(price);
|
|
963
|
-
if (size === 0) {
|
|
964
|
-
levelsByPrice.delete(key);
|
|
965
|
-
continue;
|
|
966
|
-
}
|
|
967
|
-
levelsByPrice.set(key, {
|
|
968
|
-
price,
|
|
969
|
-
size,
|
|
970
|
-
venues: __spreadValues({}, venues != null ? venues : {})
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
levels = [...levelsByPrice.values()];
|
|
974
|
-
levels.sort(sort === "desc" ? (a, b) => b.price - a.price : (a, b) => a.price - b.price);
|
|
975
|
-
return levels;
|
|
976
|
-
}
|
|
977
|
-
function applyVenueChanges(levels, changes, sort) {
|
|
978
|
-
const levelsByPrice = new Map(levels.map((level) => [toPriceKey(level.price), level]));
|
|
979
|
-
for (const [price, size] of changes) {
|
|
980
|
-
const key = toPriceKey(price);
|
|
981
|
-
if (size === 0) {
|
|
982
|
-
levelsByPrice.delete(key);
|
|
983
|
-
continue;
|
|
984
|
-
}
|
|
985
|
-
levelsByPrice.set(key, { price, size });
|
|
986
|
-
}
|
|
987
|
-
levels = [...levelsByPrice.values()];
|
|
988
|
-
levels.sort(sort === "desc" ? (a, b) => b.price - a.price : (a, b) => a.price - b.price);
|
|
989
|
-
return levels;
|
|
990
|
-
}
|
|
991
|
-
function mergeVenueLevelChanges(primary, fallback) {
|
|
992
|
-
if (!(primary == null ? void 0 : primary.length)) return fallback ? [...fallback] : [];
|
|
993
|
-
if (!(fallback == null ? void 0 : fallback.length)) return [...primary];
|
|
994
|
-
const changesByPrice = /* @__PURE__ */ new Map();
|
|
995
|
-
for (const change of fallback) {
|
|
996
|
-
changesByPrice.set(toPriceKey(change[0]), change);
|
|
997
|
-
}
|
|
998
|
-
for (const change of primary) {
|
|
999
|
-
changesByPrice.set(toPriceKey(change[0]), change);
|
|
1000
|
-
}
|
|
1001
|
-
return [...changesByPrice.values()];
|
|
1002
|
-
}
|
|
1003
|
-
function deriveVenueChangesFromAttributedChanges(previousLevels, changes) {
|
|
1004
|
-
var _a, _b;
|
|
1005
|
-
const previousLevelsByPrice = new Map(
|
|
1006
|
-
previousLevels.map((level) => [toPriceKey(level.price), level])
|
|
1007
|
-
);
|
|
1008
|
-
const venueChanges = {};
|
|
1009
|
-
for (const [price, size, nextVenuesRaw] of changes) {
|
|
1010
|
-
const key = toPriceKey(price);
|
|
1011
|
-
const previousLevel = previousLevelsByPrice.get(key);
|
|
1012
|
-
const previousVenues = (_a = previousLevel == null ? void 0 : previousLevel.venues) != null ? _a : {};
|
|
1013
|
-
const nextVenues = nextVenuesRaw != null ? nextVenuesRaw : {};
|
|
1014
|
-
const affectedVenues = /* @__PURE__ */ new Set([...Object.keys(previousVenues), ...Object.keys(nextVenues)]);
|
|
1015
|
-
for (const venue of affectedVenues) {
|
|
1016
|
-
const nextSize = Number((_b = nextVenues[venue]) != null ? _b : 0);
|
|
1017
|
-
if (!Number.isFinite(nextSize)) continue;
|
|
1018
|
-
if (!venueChanges[venue]) {
|
|
1019
|
-
venueChanges[venue] = [];
|
|
1020
|
-
}
|
|
1021
|
-
venueChanges[venue].push([price, nextSize]);
|
|
1022
|
-
}
|
|
1023
|
-
if (size === 0) {
|
|
1024
|
-
previousLevelsByPrice.delete(key);
|
|
1025
|
-
continue;
|
|
1026
|
-
}
|
|
1027
|
-
previousLevelsByPrice.set(key, {
|
|
1028
|
-
price,
|
|
1029
|
-
size,
|
|
1030
|
-
venues: __spreadValues({}, nextVenues)
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
return venueChanges;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
// src/agg-websocket.ts
|
|
1037
|
-
var RECONNECT_BASE_MS = 1e3;
|
|
1038
|
-
var RECONNECT_MAX_MS = 3e4;
|
|
1039
|
-
var STALE_TIMEOUT_MS = 45e3;
|
|
1040
|
-
var ORDERBOOK_DEBUG_TOP_LEVELS = 5;
|
|
1041
|
-
var AggWebSocket = class {
|
|
1042
|
-
constructor(options) {
|
|
1043
|
-
this.ws = null;
|
|
1044
|
-
// ── Subscription tracking ──
|
|
1045
|
-
this.subs = /* @__PURE__ */ new Map();
|
|
1046
|
-
this.pendingSubs = /* @__PURE__ */ new Set();
|
|
1047
|
-
this.pendingTradeSubs = /* @__PURE__ */ new Set();
|
|
1048
|
-
this.pendingResnapshots = /* @__PURE__ */ new Set();
|
|
1049
|
-
// ── Post-connect batching (coalesces same-tick sub/unsub calls into one frame) ──
|
|
1050
|
-
this.pendingFlushSubs = /* @__PURE__ */ new Set();
|
|
1051
|
-
this.pendingFlushUnsubs = /* @__PURE__ */ new Set();
|
|
1052
|
-
this.pendingFlushTradeSubs = /* @__PURE__ */ new Set();
|
|
1053
|
-
this.pendingFlushTradeUnsubs = /* @__PURE__ */ new Set();
|
|
1054
|
-
this.pendingFlushArbSubs = /* @__PURE__ */ new Set();
|
|
1055
|
-
this.pendingFlushArbUnsubs = /* @__PURE__ */ new Set();
|
|
1056
|
-
this.flushScheduled = false;
|
|
1057
|
-
// ── Arb subscriptions ──
|
|
1058
|
-
this.arbSubs = /* @__PURE__ */ new Map();
|
|
1059
|
-
this.arbFeedCbs = /* @__PURE__ */ new Set();
|
|
1060
|
-
/** Latest arb market update per marketId (last-value-wins, loss-tolerant). */
|
|
1061
|
-
this.latestArb = /* @__PURE__ */ new Map();
|
|
1062
|
-
// ── Orderbook state per market ──
|
|
1063
|
-
this.books = /* @__PURE__ */ new Map();
|
|
1064
|
-
/** Markets currently resyncing (awaiting snapshot after seq gap / checksum mismatch). */
|
|
1065
|
-
this.resyncing = /* @__PURE__ */ new Set();
|
|
1066
|
-
// ── Connection state ──
|
|
1067
|
-
this.connecting = false;
|
|
1068
|
-
this._connected = false;
|
|
1069
|
-
this.reconnectAttempts = 0;
|
|
1070
|
-
this.reconnectTimer = null;
|
|
1071
|
-
this.staleTimer = null;
|
|
1072
|
-
this.lastMessageTime = 0;
|
|
1073
|
-
this.destroyed = false;
|
|
1074
|
-
var _a, _b;
|
|
1075
|
-
this.url = options.url;
|
|
1076
|
-
this.callbacks = (_a = options.callbacks) != null ? _a : {};
|
|
1077
|
-
this.initialToken = options.initialToken;
|
|
1078
|
-
this.enableLogs = (_b = options.enableLogs) != null ? _b : false;
|
|
1079
|
-
}
|
|
1080
|
-
// ── Public API ──
|
|
1081
|
-
get connected() {
|
|
1082
|
-
return this._connected;
|
|
1083
|
-
}
|
|
1084
|
-
/** Get the current orderbook state for an outcome (or null if no snapshot received yet). */
|
|
1085
|
-
getBook(outcomeId) {
|
|
1086
|
-
var _a;
|
|
1087
|
-
return (_a = this.books.get(outcomeId)) != null ? _a : null;
|
|
1088
|
-
}
|
|
1089
|
-
/** Whether an outcome is currently resyncing (waiting for fresh snapshot). */
|
|
1090
|
-
isResyncing(outcomeId) {
|
|
1091
|
-
return this.resyncing.has(outcomeId);
|
|
1092
|
-
}
|
|
1093
|
-
/** Get the latest arb update for a market (or null if none received yet). */
|
|
1094
|
-
getArb(marketId) {
|
|
1095
|
-
var _a;
|
|
1096
|
-
return (_a = this.latestArb.get(marketId)) != null ? _a : null;
|
|
1097
|
-
}
|
|
1098
|
-
/**
|
|
1099
|
-
* Subscribe to per-market arb updates for a given marketId.
|
|
1100
|
-
* Ref-counted: multiple callers for the same marketId share one server subscription.
|
|
1101
|
-
* Returns an unsubscribe function.
|
|
1102
|
-
*/
|
|
1103
|
-
subscribeArb(marketId, cb) {
|
|
1104
|
-
let entry = this.arbSubs.get(marketId);
|
|
1105
|
-
if (!entry) {
|
|
1106
|
-
entry = { refCount: 0, cbs: /* @__PURE__ */ new Set() };
|
|
1107
|
-
this.arbSubs.set(marketId, entry);
|
|
1108
|
-
this.ensureConnected();
|
|
1109
|
-
if (this._connected) {
|
|
1110
|
-
this.pendingFlushArbUnsubs.delete(marketId);
|
|
1111
|
-
this.pendingFlushArbSubs.add(marketId);
|
|
1112
|
-
this.scheduleFlush();
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
entry.cbs.add(cb);
|
|
1116
|
-
entry.refCount++;
|
|
1117
|
-
return () => {
|
|
1118
|
-
const e = this.arbSubs.get(marketId);
|
|
1119
|
-
if (!e) return;
|
|
1120
|
-
e.cbs.delete(cb);
|
|
1121
|
-
e.refCount--;
|
|
1122
|
-
if (e.refCount <= 0) {
|
|
1123
|
-
this.arbSubs.delete(marketId);
|
|
1124
|
-
if (this._connected) {
|
|
1125
|
-
if (this.pendingFlushArbSubs.has(marketId)) {
|
|
1126
|
-
this.pendingFlushArbSubs.delete(marketId);
|
|
1127
|
-
} else {
|
|
1128
|
-
this.pendingFlushArbUnsubs.add(marketId);
|
|
1129
|
-
this.scheduleFlush();
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
};
|
|
1134
|
-
}
|
|
1135
|
-
/**
|
|
1136
|
-
* Subscribe to the global arb-feed batches.
|
|
1137
|
-
* Only one server subscription is maintained regardless of how many callers.
|
|
1138
|
-
* Returns an unsubscribe function.
|
|
1139
|
-
*/
|
|
1140
|
-
subscribeArbFeed(cb) {
|
|
1141
|
-
const wasEmpty = this.arbFeedCbs.size === 0;
|
|
1142
|
-
this.arbFeedCbs.add(cb);
|
|
1143
|
-
if (wasEmpty) {
|
|
1144
|
-
this.ensureConnected();
|
|
1145
|
-
if (this._connected) {
|
|
1146
|
-
this.send({ action: "subscribe", channel: "arb-feed" });
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
return () => {
|
|
1150
|
-
this.arbFeedCbs.delete(cb);
|
|
1151
|
-
if (this.arbFeedCbs.size === 0 && this._connected) {
|
|
1152
|
-
this.send({ action: "unsubscribe", channel: "arb-feed" });
|
|
1153
|
-
}
|
|
1154
|
-
};
|
|
1155
|
-
}
|
|
1156
|
-
/**
|
|
1157
|
-
* Subscribe to a feed by outcome ID.
|
|
1158
|
-
* @param outcomeId The venueMarketOutcomeId to subscribe to.
|
|
1159
|
-
* @param channel "orderbook" (default) or "trades".
|
|
1160
|
-
* Returns an unsubscribe function (ref-counted).
|
|
1161
|
-
*/
|
|
1162
|
-
subscribe(outcomeId, channel = "orderbook") {
|
|
1163
|
-
if (channel === "trades") {
|
|
1164
|
-
return this._subscribeTrades(outcomeId);
|
|
1165
|
-
}
|
|
1166
|
-
let sub = this.subs.get(outcomeId);
|
|
1167
|
-
if (!sub) {
|
|
1168
|
-
sub = { refCount: 0, tradeRefs: 0 };
|
|
1169
|
-
this.subs.set(outcomeId, sub);
|
|
1170
|
-
this.pendingSubs.add(outcomeId);
|
|
1171
|
-
this.ensureConnected();
|
|
1172
|
-
if (this._connected) {
|
|
1173
|
-
this.pendingFlushUnsubs.delete(outcomeId);
|
|
1174
|
-
this.pendingFlushSubs.add(outcomeId);
|
|
1175
|
-
this.pendingSubs.delete(outcomeId);
|
|
1176
|
-
this.scheduleFlush();
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
sub.refCount++;
|
|
1180
|
-
return () => {
|
|
1181
|
-
const s = this.subs.get(outcomeId);
|
|
1182
|
-
if (!s) return;
|
|
1183
|
-
s.refCount--;
|
|
1184
|
-
if (s.refCount <= 0 && s.tradeRefs <= 0) {
|
|
1185
|
-
this.subs.delete(outcomeId);
|
|
1186
|
-
this.books.delete(outcomeId);
|
|
1187
|
-
this.resyncing.delete(outcomeId);
|
|
1188
|
-
if (this._connected) {
|
|
1189
|
-
if (this.pendingFlushSubs.has(outcomeId)) {
|
|
1190
|
-
this.pendingFlushSubs.delete(outcomeId);
|
|
1191
|
-
} else {
|
|
1192
|
-
this.pendingFlushUnsubs.add(outcomeId);
|
|
1193
|
-
this.scheduleFlush();
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
this.pendingSubs.delete(outcomeId);
|
|
1197
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1198
|
-
}
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
/**
|
|
1202
|
-
* Subscribe to an outcome's trade feed.
|
|
1203
|
-
* @deprecated Use `subscribe(outcomeId, "trades")` instead.
|
|
1204
|
-
* Returns an unsubscribe function.
|
|
1205
|
-
*/
|
|
1206
|
-
subscribeTrades(outcomeId) {
|
|
1207
|
-
return this._subscribeTrades(outcomeId);
|
|
1208
|
-
}
|
|
1209
|
-
_subscribeTrades(outcomeId) {
|
|
1210
|
-
let sub = this.subs.get(outcomeId);
|
|
1211
|
-
if (!sub) {
|
|
1212
|
-
sub = { refCount: 0, tradeRefs: 0 };
|
|
1213
|
-
this.subs.set(outcomeId, sub);
|
|
1214
|
-
}
|
|
1215
|
-
if (sub.tradeRefs === 0) {
|
|
1216
|
-
this.pendingTradeSubs.add(outcomeId);
|
|
1217
|
-
this.ensureConnected();
|
|
1218
|
-
if (this._connected) {
|
|
1219
|
-
this.pendingFlushTradeUnsubs.delete(outcomeId);
|
|
1220
|
-
this.pendingFlushTradeSubs.add(outcomeId);
|
|
1221
|
-
this.pendingTradeSubs.delete(outcomeId);
|
|
1222
|
-
this.scheduleFlush();
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
sub.tradeRefs++;
|
|
1226
|
-
return () => {
|
|
1227
|
-
const s = this.subs.get(outcomeId);
|
|
1228
|
-
if (!s) return;
|
|
1229
|
-
s.tradeRefs--;
|
|
1230
|
-
if (s.tradeRefs <= 0) {
|
|
1231
|
-
s.tradeRefs = 0;
|
|
1232
|
-
if (this._connected) {
|
|
1233
|
-
if (this.pendingFlushTradeSubs.has(outcomeId)) {
|
|
1234
|
-
this.pendingFlushTradeSubs.delete(outcomeId);
|
|
1235
|
-
} else {
|
|
1236
|
-
this.pendingFlushTradeUnsubs.add(outcomeId);
|
|
1237
|
-
this.scheduleFlush();
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
this.pendingTradeSubs.delete(outcomeId);
|
|
1241
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1242
|
-
if (s.refCount <= 0) {
|
|
1243
|
-
this.subs.delete(outcomeId);
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
/** Send a JWT to authenticate (or re-authenticate) the connection. */
|
|
1249
|
-
authenticate(token) {
|
|
1250
|
-
if (this._connected) {
|
|
1251
|
-
this.send({ action: "authenticate", token });
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
/** Request a fresh snapshot for one or more subscribed outcomes. */
|
|
1255
|
-
resnapshot(outcomeIdOrIds) {
|
|
1256
|
-
const outcomeIds = Array.isArray(outcomeIdOrIds) ? outcomeIdOrIds : [outcomeIdOrIds];
|
|
1257
|
-
outcomeIds.forEach((outcomeId) => {
|
|
1258
|
-
this.requestResnapshot(outcomeId, true);
|
|
1259
|
-
});
|
|
1260
|
-
}
|
|
1261
|
-
/** Connect (idempotent). Called automatically on first subscribe. */
|
|
1262
|
-
connect() {
|
|
1263
|
-
this.ensureConnected();
|
|
1264
|
-
}
|
|
1265
|
-
/** Disconnect and clean up. Reusable — call connect() to reconnect. */
|
|
1266
|
-
disconnect() {
|
|
1267
|
-
var _a, _b;
|
|
1268
|
-
this.cancelReconnect();
|
|
1269
|
-
this.cancelStaleTimer();
|
|
1270
|
-
this._connected = false;
|
|
1271
|
-
this.connecting = false;
|
|
1272
|
-
if (this.ws) {
|
|
1273
|
-
this.ws.onclose = null;
|
|
1274
|
-
this.ws.close();
|
|
1275
|
-
this.ws = null;
|
|
1276
|
-
}
|
|
1277
|
-
(_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
|
|
1278
|
-
}
|
|
1279
|
-
/** Permanently destroy. Cannot reconnect after this. */
|
|
1280
|
-
destroy() {
|
|
1281
|
-
this.destroyed = true;
|
|
1282
|
-
this.disconnect();
|
|
1283
|
-
this.subs.clear();
|
|
1284
|
-
this.books.clear();
|
|
1285
|
-
this.resyncing.clear();
|
|
1286
|
-
this.pendingSubs.clear();
|
|
1287
|
-
this.pendingTradeSubs.clear();
|
|
1288
|
-
this.pendingResnapshots.clear();
|
|
1289
|
-
this.pendingFlushSubs.clear();
|
|
1290
|
-
this.pendingFlushUnsubs.clear();
|
|
1291
|
-
this.pendingFlushTradeSubs.clear();
|
|
1292
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1293
|
-
this.arbSubs.clear();
|
|
1294
|
-
this.arbFeedCbs.clear();
|
|
1295
|
-
this.latestArb.clear();
|
|
1296
|
-
this.pendingFlushArbSubs.clear();
|
|
1297
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1298
|
-
this.flushScheduled = false;
|
|
1299
|
-
}
|
|
1300
|
-
/** Update callbacks (e.g., after React re-render). */
|
|
1301
|
-
setCallbacks(callbacks) {
|
|
1302
|
-
this.callbacks = callbacks;
|
|
1303
|
-
}
|
|
1304
|
-
// ── Connection management ──
|
|
1305
|
-
ensureConnected() {
|
|
1306
|
-
var _a;
|
|
1307
|
-
if (this.destroyed) return;
|
|
1308
|
-
if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN || this.connecting) return;
|
|
1309
|
-
this.doConnect();
|
|
1310
|
-
}
|
|
1311
|
-
doConnect() {
|
|
1312
|
-
if (this.destroyed) return;
|
|
1313
|
-
this.connecting = true;
|
|
1314
|
-
const ws = new WebSocket(this.url);
|
|
1315
|
-
this.ws = ws;
|
|
1316
|
-
ws.onopen = () => {
|
|
1317
|
-
this.connecting = false;
|
|
1318
|
-
this.reconnectAttempts = 0;
|
|
1319
|
-
this.resetStaleTimer();
|
|
1320
|
-
if (this.initialToken) {
|
|
1321
|
-
this.send({ action: "authenticate", token: this.initialToken });
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
ws.onmessage = (event) => {
|
|
1325
|
-
this.lastMessageTime = Date.now();
|
|
1326
|
-
this.resetStaleTimer();
|
|
1327
|
-
try {
|
|
1328
|
-
const raw = JSON.parse(event.data);
|
|
1329
|
-
this.handleMessage(raw);
|
|
1330
|
-
} catch (e) {
|
|
1331
|
-
}
|
|
1332
|
-
};
|
|
1333
|
-
ws.onclose = () => {
|
|
1334
|
-
var _a, _b;
|
|
1335
|
-
this.ws = null;
|
|
1336
|
-
this.connecting = false;
|
|
1337
|
-
const wasConnected = this._connected;
|
|
1338
|
-
this._connected = false;
|
|
1339
|
-
this.cancelStaleTimer();
|
|
1340
|
-
if (wasConnected) {
|
|
1341
|
-
(_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
|
|
1342
|
-
}
|
|
1343
|
-
if (!this.destroyed && (this.subs.size > 0 || this.arbSubs.size > 0 || this.arbFeedCbs.size > 0)) {
|
|
1344
|
-
this.scheduleReconnect();
|
|
1345
|
-
}
|
|
1346
|
-
};
|
|
1347
|
-
ws.onerror = () => {
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
scheduleReconnect() {
|
|
1351
|
-
this.cancelReconnect();
|
|
1352
|
-
const delay = Math.min(
|
|
1353
|
-
RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts),
|
|
1354
|
-
RECONNECT_MAX_MS
|
|
1355
|
-
);
|
|
1356
|
-
this.reconnectAttempts++;
|
|
1357
|
-
this.emitDiagnostic({ type: "reconnect", attempt: this.reconnectAttempts, delayMs: delay });
|
|
1358
|
-
this.reconnectTimer = setTimeout(() => {
|
|
1359
|
-
this.reconnectTimer = null;
|
|
1360
|
-
this.doConnect();
|
|
1361
|
-
}, delay);
|
|
1362
|
-
}
|
|
1363
|
-
cancelReconnect() {
|
|
1364
|
-
if (this.reconnectTimer) {
|
|
1365
|
-
clearTimeout(this.reconnectTimer);
|
|
1366
|
-
this.reconnectTimer = null;
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
// ── Staleness detection ──
|
|
1370
|
-
resetStaleTimer() {
|
|
1371
|
-
this.cancelStaleTimer();
|
|
1372
|
-
this.staleTimer = setTimeout(() => {
|
|
1373
|
-
const age = Date.now() - this.lastMessageTime;
|
|
1374
|
-
this.emitDiagnostic({ type: "stale_connection", lastMessageAge: age });
|
|
1375
|
-
if (this.ws) {
|
|
1376
|
-
this.ws.close();
|
|
1377
|
-
}
|
|
1378
|
-
}, STALE_TIMEOUT_MS);
|
|
1379
|
-
}
|
|
1380
|
-
cancelStaleTimer() {
|
|
1381
|
-
if (this.staleTimer) {
|
|
1382
|
-
clearTimeout(this.staleTimer);
|
|
1383
|
-
this.staleTimer = null;
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
// ── Message handling ──
|
|
1387
|
-
handleMessage(raw) {
|
|
1388
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
1389
|
-
const type = raw.type;
|
|
1390
|
-
switch (type) {
|
|
1391
|
-
case "orderbook_snapshot":
|
|
1392
|
-
this.handleSnapshot(raw);
|
|
1393
|
-
break;
|
|
1394
|
-
case "orderbook_delta":
|
|
1395
|
-
this.handleDelta(raw);
|
|
1396
|
-
break;
|
|
1397
|
-
case "trade":
|
|
1398
|
-
this.handleTrade(raw);
|
|
1399
|
-
break;
|
|
1400
|
-
case "heartbeat":
|
|
1401
|
-
this.handleHeartbeat(raw);
|
|
1402
|
-
break;
|
|
1403
|
-
case "subscribed":
|
|
1404
|
-
(_b = (_a = this.callbacks).onSubscribed) == null ? void 0 : _b.call(_a, raw);
|
|
1405
|
-
break;
|
|
1406
|
-
case "unsubscribed":
|
|
1407
|
-
(_d = (_c = this.callbacks).onUnsubscribed) == null ? void 0 : _d.call(_c, raw);
|
|
1408
|
-
break;
|
|
1409
|
-
case "connected":
|
|
1410
|
-
this.handleConnected(raw);
|
|
1411
|
-
break;
|
|
1412
|
-
case "authenticated":
|
|
1413
|
-
(_f = (_e = this.callbacks).onAuthenticated) == null ? void 0 : _f.call(_e, raw);
|
|
1414
|
-
break;
|
|
1415
|
-
case "market_resolved":
|
|
1416
|
-
this.handleMarketResolved(raw);
|
|
1417
|
-
break;
|
|
1418
|
-
case "error":
|
|
1419
|
-
(_h = (_g = this.callbacks).onError) == null ? void 0 : _h.call(_g, raw);
|
|
1420
|
-
break;
|
|
1421
|
-
case "order_submitted":
|
|
1422
|
-
this.handleOrderSubmitted(raw);
|
|
1423
|
-
break;
|
|
1424
|
-
case "balance_update":
|
|
1425
|
-
this.handleBalanceUpdate(raw);
|
|
1426
|
-
break;
|
|
1427
|
-
case "order_event":
|
|
1428
|
-
(_j = (_i = this.callbacks).onOrderEvent) == null ? void 0 : _j.call(_i, raw);
|
|
1429
|
-
break;
|
|
1430
|
-
case "redeem_event":
|
|
1431
|
-
this.handleRedeemEvent(raw);
|
|
1432
|
-
break;
|
|
1433
|
-
case "withdrawal_lifecycle":
|
|
1434
|
-
(_l = (_k = this.callbacks).onWithdrawalLifecycle) == null ? void 0 : _l.call(_k, raw);
|
|
1435
|
-
break;
|
|
1436
|
-
case "arb_market_update": {
|
|
1437
|
-
const arbMsg = raw;
|
|
1438
|
-
this.latestArb.set(arbMsg.marketId, arbMsg);
|
|
1439
|
-
const arbEntry = this.arbSubs.get(arbMsg.marketId);
|
|
1440
|
-
if (arbEntry) {
|
|
1441
|
-
for (const cb of arbEntry.cbs) cb(arbMsg);
|
|
1442
|
-
}
|
|
1443
|
-
(_n = (_m = this.callbacks).onArbMarket) == null ? void 0 : _n.call(_m, arbMsg);
|
|
1444
|
-
break;
|
|
1445
|
-
}
|
|
1446
|
-
case "arb_feed_batch": {
|
|
1447
|
-
const feedMsg = raw;
|
|
1448
|
-
for (const cb of this.arbFeedCbs) cb(feedMsg);
|
|
1449
|
-
(_p = (_o = this.callbacks).onArbFeed) == null ? void 0 : _p.call(_o, feedMsg);
|
|
1450
|
-
break;
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
/**
|
|
1455
|
-
* Server confirmed the connection — gateway has validated our appId and is
|
|
1456
|
-
* ready to accept subscriptions. Now flush all pending subs.
|
|
1457
|
-
*/
|
|
1458
|
-
handleConnected(msg) {
|
|
1459
|
-
var _a, _b, _c, _d;
|
|
1460
|
-
this._connected = true;
|
|
1461
|
-
(_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, true);
|
|
1462
|
-
(_d = (_c = this.callbacks).onConnected) == null ? void 0 : _d.call(_c, msg);
|
|
1463
|
-
const orderbookSet = new Set(this.activeOrderbookMarkets());
|
|
1464
|
-
this.pendingSubs.forEach((id) => orderbookSet.add(id));
|
|
1465
|
-
this.pendingFlushSubs.forEach((id) => orderbookSet.add(id));
|
|
1466
|
-
const orderbookIds = Array.from(orderbookSet);
|
|
1467
|
-
if (orderbookIds.length > 0) {
|
|
1468
|
-
this.sendSubscribe(orderbookIds);
|
|
1469
|
-
}
|
|
1470
|
-
this.pendingSubs.clear();
|
|
1471
|
-
this.pendingFlushSubs.clear();
|
|
1472
|
-
this.pendingFlushUnsubs.clear();
|
|
1473
|
-
const tradeSet = new Set(this.activeTradeMarkets());
|
|
1474
|
-
this.pendingTradeSubs.forEach((id) => tradeSet.add(id));
|
|
1475
|
-
this.pendingFlushTradeSubs.forEach((id) => tradeSet.add(id));
|
|
1476
|
-
const tradeIds = Array.from(tradeSet);
|
|
1477
|
-
if (tradeIds.length > 0) {
|
|
1478
|
-
this.send({ action: "subscribe", channel: "trades", outcomeIds: tradeIds });
|
|
1479
|
-
}
|
|
1480
|
-
this.pendingTradeSubs.clear();
|
|
1481
|
-
this.pendingFlushTradeSubs.clear();
|
|
1482
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1483
|
-
const resnapshotIds = Array.from(this.pendingResnapshots);
|
|
1484
|
-
if (resnapshotIds.length > 0) {
|
|
1485
|
-
this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: resnapshotIds });
|
|
1486
|
-
}
|
|
1487
|
-
this.pendingResnapshots.clear();
|
|
1488
|
-
const arbSet = new Set(this.activeArbMarkets());
|
|
1489
|
-
this.pendingFlushArbSubs.forEach((id) => arbSet.add(id));
|
|
1490
|
-
const arbIds = Array.from(arbSet);
|
|
1491
|
-
if (arbIds.length > 0) {
|
|
1492
|
-
this.send({ action: "subscribe", channel: "arb", marketIds: arbIds });
|
|
1493
|
-
}
|
|
1494
|
-
this.pendingFlushArbSubs.clear();
|
|
1495
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1496
|
-
if (this.arbFeedCbs.size > 0) {
|
|
1497
|
-
this.send({ action: "subscribe", channel: "arb-feed" });
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
handleSnapshot(raw) {
|
|
1501
|
-
var _a, _b;
|
|
1502
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1503
|
-
const book = snapshotToOrderbook(msg);
|
|
1504
|
-
this.books.set(msg.outcomeId, book);
|
|
1505
|
-
this.resyncing.delete(msg.outcomeId);
|
|
1506
|
-
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1507
|
-
this.debugOrderbook("snapshot_applied", {
|
|
1508
|
-
outcomeId: msg.outcomeId,
|
|
1509
|
-
seq: msg.seq,
|
|
1510
|
-
checksum: msg.checksum,
|
|
1511
|
-
bidsTop: this.summarizeTopLevels(book.bids),
|
|
1512
|
-
asksTop: this.summarizeTopLevels(book.asks)
|
|
1513
|
-
});
|
|
1514
|
-
(_b = (_a = this.callbacks).onSnapshot) == null ? void 0 : _b.call(_a, msg.outcomeId, book);
|
|
1515
|
-
}
|
|
1516
|
-
handleDelta(raw) {
|
|
1517
|
-
var _a, _b;
|
|
1518
|
-
const outcomeId = raw.outcomeId;
|
|
1519
|
-
const current = this.books.get(outcomeId);
|
|
1520
|
-
const deltaTop = {
|
|
1521
|
-
bids: raw.bidChanges.slice(0, ORDERBOOK_DEBUG_TOP_LEVELS).map(([price, size]) => ({
|
|
1522
|
-
price,
|
|
1523
|
-
size
|
|
1524
|
-
})),
|
|
1525
|
-
asks: raw.askChanges.slice(0, ORDERBOOK_DEBUG_TOP_LEVELS).map(([price, size]) => ({
|
|
1526
|
-
price,
|
|
1527
|
-
size
|
|
1528
|
-
}))
|
|
1529
|
-
};
|
|
1530
|
-
this.debugOrderbook("delta_received", {
|
|
1531
|
-
outcomeId,
|
|
1532
|
-
seq: raw.seq,
|
|
1533
|
-
checksum: raw.checksum,
|
|
1534
|
-
hasCurrentBook: Boolean(current),
|
|
1535
|
-
deltaTop
|
|
1536
|
-
});
|
|
1537
|
-
if (!current) {
|
|
1538
|
-
this.debugOrderbook("delta_missing_snapshot", { outcomeId, seq: raw.seq });
|
|
1539
|
-
this.requestResnapshot(outcomeId);
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
if (raw.seq <= current.seq) {
|
|
1543
|
-
this.debugOrderbook("delta_stale_ignored", {
|
|
1544
|
-
outcomeId,
|
|
1545
|
-
currentSeq: current.seq,
|
|
1546
|
-
receivedSeq: raw.seq
|
|
1547
|
-
});
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
if (raw.seq > current.seq + 1) {
|
|
1551
|
-
this.debugOrderbook("delta_seq_gap", {
|
|
1552
|
-
outcomeId,
|
|
1553
|
-
expectedSeq: current.seq + 1,
|
|
1554
|
-
receivedSeq: raw.seq
|
|
1555
|
-
});
|
|
1556
|
-
this.emitDiagnostic({
|
|
1557
|
-
type: "seq_gap",
|
|
1558
|
-
marketId: outcomeId,
|
|
1559
|
-
outcomeId,
|
|
1560
|
-
expected: current.seq + 1,
|
|
1561
|
-
received: raw.seq
|
|
1562
|
-
});
|
|
1563
|
-
this.requestResnapshot(outcomeId);
|
|
1564
|
-
return;
|
|
1565
|
-
}
|
|
1566
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1567
|
-
const newBook = applyOrderbookDelta(current, msg);
|
|
1568
|
-
this.debugOrderbook("delta_applied_locally", {
|
|
1569
|
-
outcomeId,
|
|
1570
|
-
fromSeq: current.seq,
|
|
1571
|
-
toSeq: newBook.seq,
|
|
1572
|
-
beforeTop: {
|
|
1573
|
-
bids: this.summarizeTopLevels(current.bids),
|
|
1574
|
-
asks: this.summarizeTopLevels(current.asks)
|
|
1575
|
-
},
|
|
1576
|
-
afterTop: {
|
|
1577
|
-
bids: this.summarizeTopLevels(newBook.bids),
|
|
1578
|
-
asks: this.summarizeTopLevels(newBook.asks)
|
|
1579
|
-
}
|
|
1580
|
-
});
|
|
1581
|
-
const computed = computeChecksum(newBook);
|
|
1582
|
-
if (computed !== msg.checksum) {
|
|
1583
|
-
this.debugOrderbook("delta_checksum_mismatch", {
|
|
1584
|
-
outcomeId,
|
|
1585
|
-
seq: msg.seq,
|
|
1586
|
-
expected: msg.checksum,
|
|
1587
|
-
computed
|
|
1588
|
-
});
|
|
1589
|
-
this.emitDiagnostic({
|
|
1590
|
-
type: "checksum_mismatch",
|
|
1591
|
-
marketId: outcomeId,
|
|
1592
|
-
outcomeId,
|
|
1593
|
-
expected: msg.checksum,
|
|
1594
|
-
computed
|
|
1595
|
-
});
|
|
1596
|
-
this.requestResnapshot(outcomeId);
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
this.books.set(outcomeId, newBook);
|
|
1600
|
-
this.debugOrderbook("delta_committed", {
|
|
1601
|
-
outcomeId,
|
|
1602
|
-
seq: newBook.seq,
|
|
1603
|
-
checksum: newBook.checksum,
|
|
1604
|
-
bidsTop: this.summarizeTopLevels(newBook.bids),
|
|
1605
|
-
asksTop: this.summarizeTopLevels(newBook.asks)
|
|
1606
|
-
});
|
|
1607
|
-
(_b = (_a = this.callbacks).onDelta) == null ? void 0 : _b.call(_a, outcomeId, newBook);
|
|
1608
|
-
}
|
|
1609
|
-
handleTrade(raw) {
|
|
1610
|
-
var _a, _b;
|
|
1611
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1612
|
-
(_b = (_a = this.callbacks).onTrade) == null ? void 0 : _b.call(_a, msg);
|
|
1613
|
-
}
|
|
1614
|
-
handleHeartbeat(raw) {
|
|
1615
|
-
var _a, _b;
|
|
1616
|
-
const msg = __spreadProps(__spreadValues({}, raw), { ts: raw.ts / 1e3 });
|
|
1617
|
-
(_b = (_a = this.callbacks).onHeartbeat) == null ? void 0 : _b.call(_a, msg);
|
|
1618
|
-
}
|
|
1619
|
-
handleMarketResolved(raw) {
|
|
1620
|
-
var _a, _b;
|
|
1621
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1622
|
-
this.books.delete(msg.outcomeId);
|
|
1623
|
-
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1624
|
-
this.resyncing.delete(msg.outcomeId);
|
|
1625
|
-
(_b = (_a = this.callbacks).onMarketResolved) == null ? void 0 : _b.call(_a, msg);
|
|
1626
|
-
}
|
|
1627
|
-
handleOrderSubmitted(raw) {
|
|
1628
|
-
var _a, _b;
|
|
1629
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1630
|
-
(_b = (_a = this.callbacks).onOrderSubmitted) == null ? void 0 : _b.call(_a, msg);
|
|
1631
|
-
}
|
|
1632
|
-
handleBalanceUpdate(raw) {
|
|
1633
|
-
var _a, _b;
|
|
1634
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1635
|
-
(_b = (_a = this.callbacks).onBalanceUpdate) == null ? void 0 : _b.call(_a, msg);
|
|
1636
|
-
}
|
|
1637
|
-
handleRedeemEvent(raw) {
|
|
1638
|
-
var _a, _b;
|
|
1639
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1640
|
-
(_b = (_a = this.callbacks).onRedeemEvent) == null ? void 0 : _b.call(_a, msg);
|
|
1641
|
-
}
|
|
1642
|
-
// ── Resnapshot ──
|
|
1643
|
-
requestResnapshot(outcomeId, force = false) {
|
|
1644
|
-
if (this.resyncing.has(outcomeId) && !force) return;
|
|
1645
|
-
this.resyncing.add(outcomeId);
|
|
1646
|
-
if (this._connected) {
|
|
1647
|
-
this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: [outcomeId] });
|
|
1648
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1649
|
-
return;
|
|
1650
|
-
}
|
|
1651
|
-
this.pendingResnapshots.add(outcomeId);
|
|
1652
|
-
this.ensureConnected();
|
|
1653
|
-
}
|
|
1654
|
-
// ── Helpers ──
|
|
1655
|
-
/**
|
|
1656
|
-
* Schedule a microtask that flushes queued subscribe/unsubscribe frames.
|
|
1657
|
-
* Coalesces multiple same-tick sub/unsub calls into at most one frame per
|
|
1658
|
-
* channel+action pair.
|
|
1659
|
-
*/
|
|
1660
|
-
scheduleFlush() {
|
|
1661
|
-
if (this.flushScheduled) return;
|
|
1662
|
-
this.flushScheduled = true;
|
|
1663
|
-
queueMicrotask(() => {
|
|
1664
|
-
this.flushScheduled = false;
|
|
1665
|
-
if (!this._connected) {
|
|
1666
|
-
this.pendingFlushSubs.clear();
|
|
1667
|
-
this.pendingFlushUnsubs.clear();
|
|
1668
|
-
this.pendingFlushTradeSubs.clear();
|
|
1669
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1670
|
-
this.pendingFlushArbSubs.clear();
|
|
1671
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1672
|
-
return;
|
|
1673
|
-
}
|
|
1674
|
-
this.flushPending();
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1677
|
-
flushPending() {
|
|
1678
|
-
for (const id of [...this.pendingFlushSubs]) {
|
|
1679
|
-
if (this.pendingFlushUnsubs.has(id)) {
|
|
1680
|
-
this.pendingFlushSubs.delete(id);
|
|
1681
|
-
this.pendingFlushUnsubs.delete(id);
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
if (this.pendingFlushSubs.size > 0) {
|
|
1685
|
-
this.sendSubscribe(Array.from(this.pendingFlushSubs));
|
|
1686
|
-
this.pendingFlushSubs.clear();
|
|
1687
|
-
}
|
|
1688
|
-
if (this.pendingFlushUnsubs.size > 0) {
|
|
1689
|
-
this.send({
|
|
1690
|
-
action: "unsubscribe",
|
|
1691
|
-
channel: "orderbook",
|
|
1692
|
-
outcomeIds: Array.from(this.pendingFlushUnsubs)
|
|
1693
|
-
});
|
|
1694
|
-
this.pendingFlushUnsubs.clear();
|
|
1695
|
-
}
|
|
1696
|
-
for (const id of [...this.pendingFlushTradeSubs]) {
|
|
1697
|
-
if (this.pendingFlushTradeUnsubs.has(id)) {
|
|
1698
|
-
this.pendingFlushTradeSubs.delete(id);
|
|
1699
|
-
this.pendingFlushTradeUnsubs.delete(id);
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
if (this.pendingFlushTradeSubs.size > 0) {
|
|
1703
|
-
this.send({
|
|
1704
|
-
action: "subscribe",
|
|
1705
|
-
channel: "trades",
|
|
1706
|
-
outcomeIds: Array.from(this.pendingFlushTradeSubs)
|
|
1707
|
-
});
|
|
1708
|
-
this.pendingFlushTradeSubs.clear();
|
|
1709
|
-
}
|
|
1710
|
-
if (this.pendingFlushTradeUnsubs.size > 0) {
|
|
1711
|
-
this.send({
|
|
1712
|
-
action: "unsubscribe",
|
|
1713
|
-
channel: "trades",
|
|
1714
|
-
outcomeIds: Array.from(this.pendingFlushTradeUnsubs)
|
|
1715
|
-
});
|
|
1716
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1717
|
-
}
|
|
1718
|
-
for (const id of [...this.pendingFlushArbSubs]) {
|
|
1719
|
-
if (this.pendingFlushArbUnsubs.has(id)) {
|
|
1720
|
-
this.pendingFlushArbSubs.delete(id);
|
|
1721
|
-
this.pendingFlushArbUnsubs.delete(id);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
if (this.pendingFlushArbSubs.size > 0) {
|
|
1725
|
-
this.send({
|
|
1726
|
-
action: "subscribe",
|
|
1727
|
-
channel: "arb",
|
|
1728
|
-
marketIds: Array.from(this.pendingFlushArbSubs)
|
|
1729
|
-
});
|
|
1730
|
-
this.pendingFlushArbSubs.clear();
|
|
1731
|
-
}
|
|
1732
|
-
if (this.pendingFlushArbUnsubs.size > 0) {
|
|
1733
|
-
this.send({
|
|
1734
|
-
action: "unsubscribe",
|
|
1735
|
-
channel: "arb",
|
|
1736
|
-
marketIds: Array.from(this.pendingFlushArbUnsubs)
|
|
1737
|
-
});
|
|
1738
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
sendSubscribe(outcomeIds) {
|
|
1742
|
-
this.send({ action: "subscribe", channel: "orderbook", outcomeIds });
|
|
1743
|
-
}
|
|
1744
|
-
send(msg) {
|
|
1745
|
-
var _a;
|
|
1746
|
-
if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN) {
|
|
1747
|
-
this.ws.send(JSON.stringify(msg));
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
activeOrderbookMarkets() {
|
|
1751
|
-
const markets = [];
|
|
1752
|
-
this.subs.forEach((sub, id) => {
|
|
1753
|
-
if (sub.refCount > 0) markets.push(id);
|
|
1754
|
-
});
|
|
1755
|
-
return markets;
|
|
1756
|
-
}
|
|
1757
|
-
activeTradeMarkets() {
|
|
1758
|
-
const markets = [];
|
|
1759
|
-
this.subs.forEach((sub, id) => {
|
|
1760
|
-
if (sub.tradeRefs > 0) markets.push(id);
|
|
1761
|
-
});
|
|
1762
|
-
return markets;
|
|
1763
|
-
}
|
|
1764
|
-
activeArbMarkets() {
|
|
1765
|
-
return Array.from(this.arbSubs.keys());
|
|
1766
|
-
}
|
|
1767
|
-
emitDiagnostic(event) {
|
|
1768
|
-
var _a, _b;
|
|
1769
|
-
(_b = (_a = this.callbacks).onDiagnostics) == null ? void 0 : _b.call(_a, event);
|
|
1770
|
-
}
|
|
1771
|
-
summarizeTopLevels(levels) {
|
|
1772
|
-
return levels.slice(0, ORDERBOOK_DEBUG_TOP_LEVELS).map((level) => ({ price: level.price, size: level.size }));
|
|
1773
|
-
}
|
|
1774
|
-
debugOrderbook(event, payload) {
|
|
1775
|
-
if (!this.isOrderbookDebugEnabled()) return;
|
|
1776
|
-
console.debug(`[AggWebSocket][orderbook] ${event}`, payload);
|
|
1777
|
-
}
|
|
1778
|
-
isOrderbookDebugEnabled() {
|
|
1779
|
-
return this.enableLogs;
|
|
1780
|
-
}
|
|
1781
|
-
};
|
|
1782
|
-
|
|
1783
261
|
// src/client.ts
|
|
1784
262
|
var COOKIE_REFRESH_DELIVERY = "cookie-refresh";
|
|
1785
263
|
var DEFAULT_MIDPOINT_IDS_PER_REQUEST = 75;
|
|
@@ -1870,7 +348,7 @@ var AggClient = class {
|
|
|
1870
348
|
this.authChannel = null;
|
|
1871
349
|
/** In-flight refresh promise — serializes concurrent 401 retries so only one refresh runs. */
|
|
1872
350
|
this.pendingRefresh = null;
|
|
1873
|
-
var _a, _b;
|
|
351
|
+
var _a, _b, _c;
|
|
1874
352
|
if (!options.appId && !options.adminKey) {
|
|
1875
353
|
throw new Error("AggClient requires at least one of appId or adminKey");
|
|
1876
354
|
}
|
|
@@ -1880,9 +358,11 @@ var AggClient = class {
|
|
|
1880
358
|
this.signer = options.signer;
|
|
1881
359
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
1882
360
|
this.wsUrl = options.wsUrl;
|
|
361
|
+
this.preferImmutableHistory = (_a = options.preferImmutableHistory) != null ? _a : false;
|
|
362
|
+
this.webSocketFactory = options.webSocketFactory;
|
|
1883
363
|
this.authOptions = options.auth;
|
|
1884
|
-
this.storageKey = `agg_auth_${(
|
|
1885
|
-
this.authDelivery = (
|
|
364
|
+
this.storageKey = `agg_auth_${(_b = this._appId) != null ? _b : "default"}`;
|
|
365
|
+
this.authDelivery = (_c = options.authDelivery) != null ? _c : "body";
|
|
1886
366
|
this.shouldPersistSession = options.persistSession !== false;
|
|
1887
367
|
this.restoreSession();
|
|
1888
368
|
this.initAuthChannel();
|
|
@@ -2010,7 +490,7 @@ var AggClient = class {
|
|
|
2010
490
|
* @param path - API path (e.g. `/venue-events`)
|
|
2011
491
|
* @param init - Fetch init options, plus optional `query` object for URL search params
|
|
2012
492
|
*/
|
|
2013
|
-
request(path, init) {
|
|
493
|
+
request(path, init, decode) {
|
|
2014
494
|
return __async(this, null, function* () {
|
|
2015
495
|
const response = yield this.rawFetch(path, init);
|
|
2016
496
|
if (response.status === 401 && this.accessToken && !AUTH_PATHS.has(path)) {
|
|
@@ -2021,7 +501,7 @@ var AggClient = class {
|
|
|
2021
501
|
return this.throwResponseError(retryResponse);
|
|
2022
502
|
}
|
|
2023
503
|
if (retryResponse.status === 204) return void 0;
|
|
2024
|
-
return retryResponse.json();
|
|
504
|
+
return decode ? decode(retryResponse) : retryResponse.json();
|
|
2025
505
|
} catch (e) {
|
|
2026
506
|
this.clearAccessToken();
|
|
2027
507
|
return this.throwResponseError(response);
|
|
@@ -2031,7 +511,7 @@ var AggClient = class {
|
|
|
2031
511
|
return this.throwResponseError(response);
|
|
2032
512
|
}
|
|
2033
513
|
if (response.status === 204) return void 0;
|
|
2034
|
-
return response.json();
|
|
514
|
+
return decode ? decode(response) : response.json();
|
|
2035
515
|
});
|
|
2036
516
|
}
|
|
2037
517
|
rawFetch(path, init) {
|
|
@@ -2068,12 +548,15 @@ var AggClient = class {
|
|
|
2068
548
|
}
|
|
2069
549
|
throwResponseError(response) {
|
|
2070
550
|
return __async(this, null, function* () {
|
|
551
|
+
var _a;
|
|
2071
552
|
let message = response.status === 404 ? "Market not found" : `AGG API error: ${response.status} ${response.statusText}`;
|
|
2072
553
|
let code;
|
|
2073
554
|
let retryable;
|
|
555
|
+
let retryAfterMs = parseRetryAfterHeader((_a = response.headers) == null ? void 0 : _a.get("Retry-After"));
|
|
2074
556
|
let errors;
|
|
2075
557
|
try {
|
|
2076
558
|
const body = yield response.json();
|
|
559
|
+
retryAfterMs != null ? retryAfterMs : retryAfterMs = parseRetryAfterSeconds(body == null ? void 0 : body.retryAfter);
|
|
2077
560
|
if (typeof body.message === "string" && body.message.length > 0) {
|
|
2078
561
|
message = body.message;
|
|
2079
562
|
}
|
|
@@ -2092,7 +575,7 @@ var AggClient = class {
|
|
|
2092
575
|
}
|
|
2093
576
|
} catch (e) {
|
|
2094
577
|
}
|
|
2095
|
-
throw new AggApiError(message, response.status, { code, retryable, errors });
|
|
578
|
+
throw new AggApiError(message, response.status, { code, retryable, retryAfterMs, errors });
|
|
2096
579
|
});
|
|
2097
580
|
}
|
|
2098
581
|
/**
|
|
@@ -2519,14 +1002,19 @@ Issued At: ${issuedAt}`;
|
|
|
2519
1002
|
*
|
|
2520
1003
|
* Pass `quoteId` to fetch every leg of a multi-venue split route in
|
|
2521
1004
|
* one call — `useQuoteSummary(quoteId)` reduces the list into a
|
|
2522
|
-
* rollup (total cost, share-weighted avg price, to-win).
|
|
1005
|
+
* rollup (total cost, share-weighted avg price, to-win). Pass
|
|
1006
|
+
* `venueMarketIds` to narrow to the orders on those markets. Sent as
|
|
1007
|
+
* repeated params in one request; batch long lists yourself (or use
|
|
1008
|
+
* `useExecutionOrdersForMarkets`) to keep the URL short.
|
|
2523
1009
|
*/
|
|
2524
1010
|
getExecutionOrders() {
|
|
2525
1011
|
return __async(this, arguments, function* (params = {}) {
|
|
1012
|
+
var _a;
|
|
2526
1013
|
const query = {};
|
|
2527
1014
|
if (params.orderId) query.orderId = params.orderId;
|
|
2528
1015
|
if (params.quoteId) query.quoteId = params.quoteId;
|
|
2529
1016
|
if (params.externalId) query.externalId = params.externalId;
|
|
1017
|
+
if ((_a = params.venueMarketIds) == null ? void 0 : _a.length) query.venueMarketIds = params.venueMarketIds;
|
|
2530
1018
|
if (params.status) query.status = params.status;
|
|
2531
1019
|
if (params.orderType) query.orderType = params.orderType;
|
|
2532
1020
|
if (params.mode) query.mode = params.mode;
|
|
@@ -2576,16 +1064,92 @@ Issued At: ${issuedAt}`;
|
|
|
2576
1064
|
});
|
|
2577
1065
|
});
|
|
2578
1066
|
}
|
|
2579
|
-
/**
|
|
1067
|
+
/**
|
|
1068
|
+
* Get cash balances and per-venue position balances.
|
|
1069
|
+
*
|
|
1070
|
+
* `custody: "self"` returns the wallets linked to this account — plus their
|
|
1071
|
+
* Polymarket deposit and legacy wallets — instead of the managed wallet. Each
|
|
1072
|
+
* chain row then carries `address` and `custodyKind`; `positions` is
|
|
1073
|
+
* account-wide either way.
|
|
1074
|
+
*
|
|
1075
|
+
* Caveat on the headline number: a chain row with `custodyKind:
|
|
1076
|
+
* "POLYMARKET_LEGACY"` and `legacyKind: "proxy"` holds funds that can only
|
|
1077
|
+
* be spent on Polymarket, but it still counts towards its token's
|
|
1078
|
+
* `totalRaw`/`availableRaw` (a token's totals are always the sum of its
|
|
1079
|
+
* chain rows). If you show "spendable anywhere", subtract those rows.
|
|
1080
|
+
*/
|
|
2580
1081
|
getManagedBalances() {
|
|
2581
1082
|
return __async(this, arguments, function* (params = {}) {
|
|
2582
1083
|
const query = {};
|
|
2583
1084
|
if (params.mode) query.mode = params.mode;
|
|
1085
|
+
if (params.custody) query.custody = params.custody;
|
|
2584
1086
|
return this.request("/execution/balances", {
|
|
2585
1087
|
query: Object.keys(query).length ? query : void 0
|
|
2586
1088
|
});
|
|
2587
1089
|
});
|
|
2588
1090
|
}
|
|
1091
|
+
/** Read hosted custody status without creating a signing wallet or account. */
|
|
1092
|
+
getHostedVenueAccount(_0) {
|
|
1093
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1094
|
+
return this.request(
|
|
1095
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}`,
|
|
1096
|
+
{
|
|
1097
|
+
query: params.mode ? { mode: params.mode } : void 0
|
|
1098
|
+
}
|
|
1099
|
+
);
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
/** Owned exact ledger entries; not balances, fill fees or withdrawal finality. */
|
|
1103
|
+
getHostedVenueActivity(_0) {
|
|
1104
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1105
|
+
return this.request(
|
|
1106
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/activity`,
|
|
1107
|
+
{
|
|
1108
|
+
query: __spreadValues(__spreadValues({}, params.mode ? { mode: params.mode } : {}), params.page !== void 0 ? { page: String(params.page) } : {})
|
|
1109
|
+
}
|
|
1110
|
+
);
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
/** Explicit hosted-account creation; no signing wallet or credential upload. */
|
|
1114
|
+
provisionHostedVenueAccount(venue, body) {
|
|
1115
|
+
return __async(this, null, function* () {
|
|
1116
|
+
return this.request(
|
|
1117
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}`,
|
|
1118
|
+
{
|
|
1119
|
+
method: "POST",
|
|
1120
|
+
body: JSON.stringify(body)
|
|
1121
|
+
}
|
|
1122
|
+
);
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
/** Fetch the owned hosted account's verified Solana USDC deposit address. */
|
|
1126
|
+
getHostedVenueDepositAddress(_0) {
|
|
1127
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1128
|
+
return this.request(
|
|
1129
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/deposit-address`,
|
|
1130
|
+
{ query: params.mode ? { mode: params.mode } : void 0 }
|
|
1131
|
+
);
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
/** Submit exactly one explicit hosted withdrawal under a caller idempotency key. */
|
|
1135
|
+
withdrawHostedVenue(venue, body) {
|
|
1136
|
+
return __async(this, null, function* () {
|
|
1137
|
+
return this.request(
|
|
1138
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/withdrawals`,
|
|
1139
|
+
{ method: "POST", body: JSON.stringify(body) }
|
|
1140
|
+
);
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
/** Read only Agg's persisted withdrawal state; this never replays a native request. */
|
|
1144
|
+
getHostedVenueWithdrawal(_0, _1) {
|
|
1145
|
+
return __async(this, arguments, function* (venue, withdrawalId, params = {}) {
|
|
1146
|
+
if (!withdrawalId) throw new Error("withdrawalId is required");
|
|
1147
|
+
return this.request(
|
|
1148
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/withdrawals/${encodeURIComponent(withdrawalId)}`,
|
|
1149
|
+
{ query: params.mode ? { mode: params.mode } : void 0 }
|
|
1150
|
+
);
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
2589
1153
|
/** Store or replace encrypted credentials for a venue. Secrets are never returned. */
|
|
2590
1154
|
upsertVenueKey(body) {
|
|
2591
1155
|
return __async(this, null, function* () {
|
|
@@ -2755,6 +1319,17 @@ Issued At: ${issuedAt}`;
|
|
|
2755
1319
|
});
|
|
2756
1320
|
}
|
|
2757
1321
|
/** Get a single venue event by ID. Requires appId or admin auth. */
|
|
1322
|
+
getEventBootstrap(eventId, options) {
|
|
1323
|
+
return __async(this, null, function* () {
|
|
1324
|
+
return this.request(
|
|
1325
|
+
`/venue-events/${encodeURIComponent(eventId)}/bootstrap`,
|
|
1326
|
+
{
|
|
1327
|
+
query: (options == null ? void 0 : options.limit) ? { limit: String(options.limit) } : void 0,
|
|
1328
|
+
signal: options == null ? void 0 : options.signal
|
|
1329
|
+
}
|
|
1330
|
+
);
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
2758
1333
|
getVenueEventById(id, options) {
|
|
2759
1334
|
return __async(this, null, function* () {
|
|
2760
1335
|
return this.request(`/venue-events/${encodeURIComponent(id)}`, {
|
|
@@ -2883,14 +1458,15 @@ Issued At: ${issuedAt}`;
|
|
|
2883
1458
|
});
|
|
2884
1459
|
}
|
|
2885
1460
|
/** List venue markets with optional filters. Requires appId or admin auth. Supports cursor-based pagination. */
|
|
2886
|
-
getVenueMarkets(options) {
|
|
1461
|
+
getVenueMarkets(options, requestOptions) {
|
|
2887
1462
|
return __async(this, null, function* () {
|
|
2888
|
-
var _a;
|
|
1463
|
+
var _a, _b;
|
|
2889
1464
|
const query = {};
|
|
2890
1465
|
if (options == null ? void 0 : options.venue) query.venue = options.venue;
|
|
1466
|
+
if ((_a = options == null ? void 0 : options.externalIdentifier) == null ? void 0 : _a.length) query.externalIdentifier = options.externalIdentifier;
|
|
2891
1467
|
if (options == null ? void 0 : options.venueEventId) query.venueEventId = options.venueEventId;
|
|
2892
1468
|
if ((options == null ? void 0 : options.cluster) === false) query.cluster = "false";
|
|
2893
|
-
if ((
|
|
1469
|
+
if ((_b = options == null ? void 0 : options.search) == null ? void 0 : _b.trim()) query.search = options.search.trim();
|
|
2894
1470
|
if (options == null ? void 0 : options.matchStatus) query.matchStatus = options.matchStatus;
|
|
2895
1471
|
if (options == null ? void 0 : options.status) query.status = options.status;
|
|
2896
1472
|
if ((options == null ? void 0 : options.aggKey) && options.aggKey.length > 0) query.aggKey = options.aggKey;
|
|
@@ -2910,7 +1486,8 @@ Issued At: ${issuedAt}`;
|
|
|
2910
1486
|
if (options == null ? void 0 : options.sortDir) query.sortDir = options.sortDir;
|
|
2911
1487
|
if (options == null ? void 0 : options.context) query.context = options.context;
|
|
2912
1488
|
return this.request("/venue-markets", {
|
|
2913
|
-
query: Object.keys(query).length > 0 ? query : void 0
|
|
1489
|
+
query: Object.keys(query).length > 0 ? query : void 0,
|
|
1490
|
+
signal: requestOptions == null ? void 0 : requestOptions.signal
|
|
2914
1491
|
});
|
|
2915
1492
|
});
|
|
2916
1493
|
}
|
|
@@ -3012,7 +1589,7 @@ Issued At: ${issuedAt}`;
|
|
|
3012
1589
|
* format intentionally omits the param so the server hits the cheaper
|
|
3013
1590
|
* (and longer-TTL) light cache slot.
|
|
3014
1591
|
*/
|
|
3015
|
-
search(params) {
|
|
1592
|
+
search(params, options) {
|
|
3016
1593
|
return __async(this, null, function* () {
|
|
3017
1594
|
const query = {
|
|
3018
1595
|
q: params.q,
|
|
@@ -3023,8 +1600,10 @@ Issued At: ${issuedAt}`;
|
|
|
3023
1600
|
if (params.limit != null) query.limit = String(params.limit);
|
|
3024
1601
|
if (params.cursor) query.cursor = params.cursor;
|
|
3025
1602
|
if (params.deep) query.deepSearch = "true";
|
|
1603
|
+
if (params.mode) query.mode = params.mode;
|
|
3026
1604
|
return this.request("/search", {
|
|
3027
|
-
query
|
|
1605
|
+
query,
|
|
1606
|
+
signal: options == null ? void 0 : options.signal
|
|
3028
1607
|
});
|
|
3029
1608
|
});
|
|
3030
1609
|
}
|
|
@@ -3086,6 +1665,7 @@ Issued At: ${issuedAt}`;
|
|
|
3086
1665
|
/** Get the canonical TradingView-style bar series for a single venue market outcome. */
|
|
3087
1666
|
getChartBars(params, options) {
|
|
3088
1667
|
return __async(this, null, function* () {
|
|
1668
|
+
var _a, _b;
|
|
3089
1669
|
const resolution = mapChartResolution(params.resolution);
|
|
3090
1670
|
const query = {
|
|
3091
1671
|
venueMarketOutcomeId: params.venueMarketOutcomeId,
|
|
@@ -3094,12 +1674,39 @@ Issued At: ${issuedAt}`;
|
|
|
3094
1674
|
if (resolution) query.resolution = resolution;
|
|
3095
1675
|
if (params.from != null) query.from = String(params.from);
|
|
3096
1676
|
if (params.countBack != null) query.countBack = String(params.countBack);
|
|
1677
|
+
if (options == null ? void 0 : options.decode) {
|
|
1678
|
+
const text = yield this.request(
|
|
1679
|
+
"/charts/bars",
|
|
1680
|
+
{ query, signal: options.signal },
|
|
1681
|
+
(response) => readChartHistoryText(response)
|
|
1682
|
+
);
|
|
1683
|
+
(_a = options.signal) == null ? void 0 : _a.throwIfAborted();
|
|
1684
|
+
const decoded = yield options.decode(text);
|
|
1685
|
+
(_b = options.signal) == null ? void 0 : _b.throwIfAborted();
|
|
1686
|
+
return decoded;
|
|
1687
|
+
}
|
|
3097
1688
|
return this.request("/charts/bars", {
|
|
3098
1689
|
query,
|
|
3099
1690
|
signal: options == null ? void 0 : options.signal
|
|
3100
1691
|
});
|
|
3101
1692
|
});
|
|
3102
1693
|
}
|
|
1694
|
+
getChartHistoryManifest(params, options) {
|
|
1695
|
+
return __async(this, null, function* () {
|
|
1696
|
+
const query = {
|
|
1697
|
+
venueMarketOutcomeId: params.venueMarketOutcomeId,
|
|
1698
|
+
to: String(params.to)
|
|
1699
|
+
};
|
|
1700
|
+
const resolution = mapChartResolution(params.resolution);
|
|
1701
|
+
if (resolution) query.resolution = resolution;
|
|
1702
|
+
if (params.from != null) query.from = String(params.from);
|
|
1703
|
+
if (params.countBack != null) query.countBack = String(params.countBack);
|
|
1704
|
+
return this.request("/charts/history/manifest", {
|
|
1705
|
+
query,
|
|
1706
|
+
signal: options == null ? void 0 : options.signal
|
|
1707
|
+
});
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
3103
1710
|
// --- Batch orderbooks ---
|
|
3104
1711
|
/** Get live per-venue orderbooks for the explicit venueMarketIds requested. */
|
|
3105
1712
|
getOrderbooks(params, options) {
|
|
@@ -3194,22 +1801,34 @@ Issued At: ${issuedAt}`;
|
|
|
3194
1801
|
return params.side ? __spreadProps(__spreadValues({}, response), { side: params.side }) : response;
|
|
3195
1802
|
});
|
|
3196
1803
|
}
|
|
1804
|
+
/** Seed subscribed outcomes with one bounded batch of compatible snapshots. */
|
|
1805
|
+
getOutcomeOrderbooks(params, options) {
|
|
1806
|
+
return __async(this, null, function* () {
|
|
1807
|
+
return this.request("/orderbooks/outcomes", {
|
|
1808
|
+
query: __spreadValues({
|
|
1809
|
+
venueMarketOutcomeIds: params.venueMarketOutcomeIds.join(",")
|
|
1810
|
+
}, params.depth == null ? {} : { depth: String(params.depth) }),
|
|
1811
|
+
signal: options == null ? void 0 : options.signal
|
|
1812
|
+
});
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
3197
1815
|
/**
|
|
3198
1816
|
* Create an AggWebSocket instance configured with this client's appId and optional auth token.
|
|
3199
1817
|
* Requires `wsUrl` to be set in the client options.
|
|
3200
1818
|
*/
|
|
3201
1819
|
createWebSocket(callbacks, options) {
|
|
3202
|
-
var _a;
|
|
1820
|
+
var _a, _b;
|
|
3203
1821
|
if (!this.wsUrl) {
|
|
3204
1822
|
throw new Error("AggClient.createWebSocket() requires wsUrl to be set in client options");
|
|
3205
1823
|
}
|
|
3206
1824
|
const url = new URL(this.wsUrl);
|
|
3207
1825
|
if (this._appId) url.searchParams.set("appId", this._appId);
|
|
3208
|
-
|
|
1826
|
+
const createSocket = (_a = this.webSocketFactory) != null ? _a : ((socketOptions) => new AggWebSocket(socketOptions));
|
|
1827
|
+
return createSocket({
|
|
3209
1828
|
url: url.toString(),
|
|
3210
1829
|
callbacks,
|
|
3211
1830
|
initialToken: this.accessToken,
|
|
3212
|
-
enableLogs: (
|
|
1831
|
+
enableLogs: (_b = options == null ? void 0 : options.enableLogs) != null ? _b : false
|
|
3213
1832
|
});
|
|
3214
1833
|
}
|
|
3215
1834
|
/** Execute a previously quoted managed trade. Returns pending order IDs. */
|
|
@@ -3505,138 +2124,6 @@ Issued At: ${issuedAt}`;
|
|
|
3505
2124
|
// src/best-split.ts
|
|
3506
2125
|
var computeBestSplitsByAmount2 = computeBestSplitsByAmount;
|
|
3507
2126
|
|
|
3508
|
-
// src/candle-builder.ts
|
|
3509
|
-
var INTERVAL_SECS = {
|
|
3510
|
-
"1m": 60,
|
|
3511
|
-
"5m": 300,
|
|
3512
|
-
"1h": 3600,
|
|
3513
|
-
"1d": 86400
|
|
3514
|
-
};
|
|
3515
|
-
var ALL_INTERVALS = ["1m", "5m", "1h", "1d"];
|
|
3516
|
-
var MAX_CLOSED = 500;
|
|
3517
|
-
var CandleBuilder = class {
|
|
3518
|
-
constructor() {
|
|
3519
|
-
this.forming = /* @__PURE__ */ new Map();
|
|
3520
|
-
this.closedMap = /* @__PURE__ */ new Map();
|
|
3521
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
3522
|
-
this._midpoint = null;
|
|
3523
|
-
this.dirty = false;
|
|
3524
|
-
this.scheduled = false;
|
|
3525
|
-
for (const interval of ALL_INTERVALS) {
|
|
3526
|
-
this.closedMap.set(interval, []);
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
/** Feed a midpoint (from orderbook delta). Updates O/H/L/C for all intervals. */
|
|
3530
|
-
addMidpoint(midpoint, timestampSecs) {
|
|
3531
|
-
if (!Number.isFinite(midpoint) || !Number.isFinite(timestampSecs)) return;
|
|
3532
|
-
this._midpoint = midpoint;
|
|
3533
|
-
for (const interval of ALL_INTERVALS) {
|
|
3534
|
-
this.updateCandle(interval, midpoint, timestampSecs);
|
|
3535
|
-
}
|
|
3536
|
-
this.markDirty();
|
|
3537
|
-
}
|
|
3538
|
-
/** Feed a trade. Updates volume + refines H/L/C from trade price. */
|
|
3539
|
-
addTrade(price, size, timestampSecs) {
|
|
3540
|
-
if (!Number.isFinite(price) || !Number.isFinite(size) || !Number.isFinite(timestampSecs))
|
|
3541
|
-
return;
|
|
3542
|
-
for (const interval of ALL_INTERVALS) {
|
|
3543
|
-
this.updateCandle(interval, price, timestampSecs, size);
|
|
3544
|
-
}
|
|
3545
|
-
this.markDirty();
|
|
3546
|
-
}
|
|
3547
|
-
/** Current forming candle for an interval. */
|
|
3548
|
-
getForming(interval) {
|
|
3549
|
-
var _a;
|
|
3550
|
-
return (_a = this.forming.get(interval)) != null ? _a : null;
|
|
3551
|
-
}
|
|
3552
|
-
/** Closed candles for an interval (ring buffer, max 500, newest last). */
|
|
3553
|
-
getClosed(interval) {
|
|
3554
|
-
var _a;
|
|
3555
|
-
return (_a = this.closedMap.get(interval)) != null ? _a : [];
|
|
3556
|
-
}
|
|
3557
|
-
/** Current midpoint (latest value fed). */
|
|
3558
|
-
get midpoint() {
|
|
3559
|
-
return this._midpoint;
|
|
3560
|
-
}
|
|
3561
|
-
/**
|
|
3562
|
-
* Subscribe to state changes. Returns unsubscribe function.
|
|
3563
|
-
* BATCHED: callbacks fire at most once per rAF frame (~16ms).
|
|
3564
|
-
* In non-browser environments, falls back to 16ms setTimeout.
|
|
3565
|
-
*/
|
|
3566
|
-
onChange(listener) {
|
|
3567
|
-
this.listeners.add(listener);
|
|
3568
|
-
return () => {
|
|
3569
|
-
this.listeners.delete(listener);
|
|
3570
|
-
};
|
|
3571
|
-
}
|
|
3572
|
-
/** Clear all state (on reconnect). */
|
|
3573
|
-
reset() {
|
|
3574
|
-
this.forming.clear();
|
|
3575
|
-
for (const interval of ALL_INTERVALS) {
|
|
3576
|
-
this.closedMap.set(interval, []);
|
|
3577
|
-
}
|
|
3578
|
-
this._midpoint = null;
|
|
3579
|
-
this.dirty = false;
|
|
3580
|
-
}
|
|
3581
|
-
/** Clear all state AND unsubscribe all listeners. Called on store eviction. */
|
|
3582
|
-
dispose() {
|
|
3583
|
-
this.reset();
|
|
3584
|
-
this.listeners.clear();
|
|
3585
|
-
}
|
|
3586
|
-
updateCandle(interval, price, timestampSecs, tradeSize) {
|
|
3587
|
-
const secs = INTERVAL_SECS[interval];
|
|
3588
|
-
const openTime = Math.floor(timestampSecs / secs) * secs;
|
|
3589
|
-
const current = this.forming.get(interval);
|
|
3590
|
-
if (current && current.openTime !== openTime) {
|
|
3591
|
-
const closed = this.closedMap.get(interval);
|
|
3592
|
-
closed.push(__spreadProps(__spreadValues({}, current), { isFinal: true }));
|
|
3593
|
-
if (closed.length > MAX_CLOSED) closed.shift();
|
|
3594
|
-
this.forming.set(interval, {
|
|
3595
|
-
openTime,
|
|
3596
|
-
o: price,
|
|
3597
|
-
h: price,
|
|
3598
|
-
l: price,
|
|
3599
|
-
c: price,
|
|
3600
|
-
v: tradeSize != null ? tradeSize : 0,
|
|
3601
|
-
tradeCount: tradeSize != null ? 1 : 0,
|
|
3602
|
-
isFinal: false
|
|
3603
|
-
});
|
|
3604
|
-
} else if (!current) {
|
|
3605
|
-
this.forming.set(interval, {
|
|
3606
|
-
openTime,
|
|
3607
|
-
o: price,
|
|
3608
|
-
h: price,
|
|
3609
|
-
l: price,
|
|
3610
|
-
c: price,
|
|
3611
|
-
v: tradeSize != null ? tradeSize : 0,
|
|
3612
|
-
tradeCount: tradeSize != null ? 1 : 0,
|
|
3613
|
-
isFinal: false
|
|
3614
|
-
});
|
|
3615
|
-
} else {
|
|
3616
|
-
current.h = Math.max(current.h, price);
|
|
3617
|
-
current.l = Math.min(current.l, price);
|
|
3618
|
-
current.c = price;
|
|
3619
|
-
if (tradeSize != null) {
|
|
3620
|
-
current.v += tradeSize;
|
|
3621
|
-
current.tradeCount += 1;
|
|
3622
|
-
}
|
|
3623
|
-
}
|
|
3624
|
-
}
|
|
3625
|
-
markDirty() {
|
|
3626
|
-
this.dirty = true;
|
|
3627
|
-
if (this.scheduled) return;
|
|
3628
|
-
this.scheduled = true;
|
|
3629
|
-
const tick = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 16);
|
|
3630
|
-
tick(() => {
|
|
3631
|
-
this.scheduled = false;
|
|
3632
|
-
if (this.dirty) {
|
|
3633
|
-
this.dirty = false;
|
|
3634
|
-
this.listeners.forEach((l) => l());
|
|
3635
|
-
}
|
|
3636
|
-
});
|
|
3637
|
-
}
|
|
3638
|
-
};
|
|
3639
|
-
|
|
3640
2127
|
// src/market-aggregator.ts
|
|
3641
2128
|
function mergeCandles(candles) {
|
|
3642
2129
|
const valid = candles.filter((c2) => c2 != null);
|
|
@@ -3715,6 +2202,7 @@ export {
|
|
|
3715
2202
|
OrderStatus,
|
|
3716
2203
|
OrderType,
|
|
3717
2204
|
RECURRENCE_CADENCES,
|
|
2205
|
+
RETINA_IMAGE_SIZES,
|
|
3718
2206
|
SELF_CUSTODY_FILL_TIMEOUT_MS,
|
|
3719
2207
|
SELF_CUSTODY_POLL_INTERVAL_MS,
|
|
3720
2208
|
TERMINAL_EXECUTION_STATES,
|
|
@@ -3748,13 +2236,17 @@ export {
|
|
|
3748
2236
|
isVenueActive,
|
|
3749
2237
|
isVenueDataVisible,
|
|
3750
2238
|
isVenueInactive,
|
|
2239
|
+
loadImmutableHistory,
|
|
3751
2240
|
mergeCandles,
|
|
3752
2241
|
mergeClosedCandles,
|
|
3753
2242
|
normalizeVenueMarketCluster,
|
|
3754
2243
|
optimizedImageUrl,
|
|
2244
|
+
orderbookCrc32,
|
|
3755
2245
|
parse,
|
|
3756
2246
|
parseEmail,
|
|
3757
2247
|
parseEmailStrict,
|
|
2248
|
+
projectedOrderbookChecksum,
|
|
2249
|
+
retinaImageUrl,
|
|
3758
2250
|
safeParse,
|
|
3759
2251
|
snapshotToOrderbook,
|
|
3760
2252
|
sortVenues,
|