@agg-build/sdk 4.17.4 → 4.19.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/README.md +6 -0
- package/dist/agg-websocket-CE7v1_-O.d.mts +4358 -0
- package/dist/agg-websocket-CE7v1_-O.d.ts +4358 -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 +439 -4244
- package/dist/index.d.ts +439 -4244
- package/dist/index.js +744 -125
- package/dist/index.mjs +283 -1763
- 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/dist/server.d.mts +16 -2
- package/dist/server.d.ts +16 -2
- 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);
|
|
81
|
-
}
|
|
82
|
-
function getEffectiveDisabledVenues(disabledVenues, dataVisibleVenues = []) {
|
|
83
|
-
if (disabledVenues === void 0) {
|
|
84
|
-
const disabled2 = new Set(DEFAULT_DISABLED_VENUES);
|
|
85
|
-
for (const venue of dataVisibleVenues) disabled2.delete(normalizeVenue(venue));
|
|
86
|
-
return VENUES.filter((venue) => disabled2.has(venue));
|
|
87
|
-
}
|
|
88
|
-
const disabled = new Set(disabledVenues.map(normalizeVenue));
|
|
89
|
-
return VENUES.filter((venue) => disabled.has(venue));
|
|
90
|
-
}
|
|
91
|
-
|
|
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;
|
|
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;
|
|
268
75
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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;
|
|
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;
|
|
305
88
|
}
|
|
306
89
|
|
|
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;
|
|
@@ -2563,6 +1051,23 @@ Issued At: ${issuedAt}`;
|
|
|
2563
1051
|
});
|
|
2564
1052
|
});
|
|
2565
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Per-app trader leaderboard ranked by realized P&L or volume over an
|
|
1056
|
+
* inclusive UTC day range. `rank` is exact within the top 100.
|
|
1057
|
+
*/
|
|
1058
|
+
getLeaderboard() {
|
|
1059
|
+
return __async(this, arguments, function* (params = {}) {
|
|
1060
|
+
const query = {};
|
|
1061
|
+
if (params.from) query.from = params.from;
|
|
1062
|
+
if (params.to) query.to = params.to;
|
|
1063
|
+
if (params.metric) query.metric = params.metric;
|
|
1064
|
+
if (params.limit != null) query.limit = String(params.limit);
|
|
1065
|
+
if (params.cursor) query.cursor = params.cursor;
|
|
1066
|
+
return this.request("/leaderboard", {
|
|
1067
|
+
query: Object.keys(query).length ? query : void 0
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
2566
1071
|
/** List execution positions for the authenticated user (cursor pagination). */
|
|
2567
1072
|
getExecutionPositions() {
|
|
2568
1073
|
return __async(this, arguments, function* (params = {}) {
|
|
@@ -2576,16 +1081,92 @@ Issued At: ${issuedAt}`;
|
|
|
2576
1081
|
});
|
|
2577
1082
|
});
|
|
2578
1083
|
}
|
|
2579
|
-
/**
|
|
1084
|
+
/**
|
|
1085
|
+
* Get cash balances and per-venue position balances.
|
|
1086
|
+
*
|
|
1087
|
+
* `custody: "self"` returns the wallets linked to this account — plus their
|
|
1088
|
+
* Polymarket deposit and legacy wallets — instead of the managed wallet. Each
|
|
1089
|
+
* chain row then carries `address` and `custodyKind`; `positions` is
|
|
1090
|
+
* account-wide either way.
|
|
1091
|
+
*
|
|
1092
|
+
* Caveat on the headline number: a chain row with `custodyKind:
|
|
1093
|
+
* "POLYMARKET_LEGACY"` and `legacyKind: "proxy"` holds funds that can only
|
|
1094
|
+
* be spent on Polymarket, but it still counts towards its token's
|
|
1095
|
+
* `totalRaw`/`availableRaw` (a token's totals are always the sum of its
|
|
1096
|
+
* chain rows). If you show "spendable anywhere", subtract those rows.
|
|
1097
|
+
*/
|
|
2580
1098
|
getManagedBalances() {
|
|
2581
1099
|
return __async(this, arguments, function* (params = {}) {
|
|
2582
1100
|
const query = {};
|
|
2583
1101
|
if (params.mode) query.mode = params.mode;
|
|
1102
|
+
if (params.custody) query.custody = params.custody;
|
|
2584
1103
|
return this.request("/execution/balances", {
|
|
2585
1104
|
query: Object.keys(query).length ? query : void 0
|
|
2586
1105
|
});
|
|
2587
1106
|
});
|
|
2588
1107
|
}
|
|
1108
|
+
/** Read hosted custody status without creating a signing wallet or account. */
|
|
1109
|
+
getHostedVenueAccount(_0) {
|
|
1110
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1111
|
+
return this.request(
|
|
1112
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}`,
|
|
1113
|
+
{
|
|
1114
|
+
query: params.mode ? { mode: params.mode } : void 0
|
|
1115
|
+
}
|
|
1116
|
+
);
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
/** Owned exact ledger entries; not balances, fill fees or withdrawal finality. */
|
|
1120
|
+
getHostedVenueActivity(_0) {
|
|
1121
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1122
|
+
return this.request(
|
|
1123
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/activity`,
|
|
1124
|
+
{
|
|
1125
|
+
query: __spreadValues(__spreadValues({}, params.mode ? { mode: params.mode } : {}), params.page !== void 0 ? { page: String(params.page) } : {})
|
|
1126
|
+
}
|
|
1127
|
+
);
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
/** Explicit hosted-account creation; no signing wallet or credential upload. */
|
|
1131
|
+
provisionHostedVenueAccount(venue, body) {
|
|
1132
|
+
return __async(this, null, function* () {
|
|
1133
|
+
return this.request(
|
|
1134
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}`,
|
|
1135
|
+
{
|
|
1136
|
+
method: "POST",
|
|
1137
|
+
body: JSON.stringify(body)
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
/** Fetch the owned hosted account's verified Solana USDC deposit address. */
|
|
1143
|
+
getHostedVenueDepositAddress(_0) {
|
|
1144
|
+
return __async(this, arguments, function* (venue, params = {}) {
|
|
1145
|
+
return this.request(
|
|
1146
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/deposit-address`,
|
|
1147
|
+
{ query: params.mode ? { mode: params.mode } : void 0 }
|
|
1148
|
+
);
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
/** Submit exactly one explicit hosted withdrawal under a caller idempotency key. */
|
|
1152
|
+
withdrawHostedVenue(venue, body) {
|
|
1153
|
+
return __async(this, null, function* () {
|
|
1154
|
+
return this.request(
|
|
1155
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/withdrawals`,
|
|
1156
|
+
{ method: "POST", body: JSON.stringify(body) }
|
|
1157
|
+
);
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
/** Read only Agg's persisted withdrawal state; this never replays a native request. */
|
|
1161
|
+
getHostedVenueWithdrawal(_0, _1) {
|
|
1162
|
+
return __async(this, arguments, function* (venue, withdrawalId, params = {}) {
|
|
1163
|
+
if (!withdrawalId) throw new Error("withdrawalId is required");
|
|
1164
|
+
return this.request(
|
|
1165
|
+
`/users/me/venue-accounts/${encodeURIComponent(venue)}/withdrawals/${encodeURIComponent(withdrawalId)}`,
|
|
1166
|
+
{ query: params.mode ? { mode: params.mode } : void 0 }
|
|
1167
|
+
);
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
2589
1170
|
/** Store or replace encrypted credentials for a venue. Secrets are never returned. */
|
|
2590
1171
|
upsertVenueKey(body) {
|
|
2591
1172
|
return __async(this, null, function* () {
|
|
@@ -2708,21 +1289,32 @@ Issued At: ${issuedAt}`;
|
|
|
2708
1289
|
});
|
|
2709
1290
|
}
|
|
2710
1291
|
/**
|
|
2711
|
-
* Cancel an
|
|
1292
|
+
* Cancel an agg order by id. Self-custody needs Polymarket ClobAuth
|
|
2712
1293
|
* or a fresh Hyperliquid cancel action signed by the EOA/client-held agent.
|
|
2713
1294
|
*/
|
|
2714
1295
|
cancelManagedOrder(orderId, options) {
|
|
2715
1296
|
return __async(this, null, function* () {
|
|
2716
|
-
return this.request(
|
|
2717
|
-
|
|
2718
|
-
{
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
1297
|
+
return this.request("/execution/orders/cancel", {
|
|
1298
|
+
method: "POST",
|
|
1299
|
+
body: JSON.stringify(__spreadValues({
|
|
1300
|
+
orderId
|
|
1301
|
+
}, (options == null ? void 0 : options.cancelSignature) ? { cancelSignature: options.cancelSignature } : {})),
|
|
1302
|
+
signal: options == null ? void 0 : options.signal
|
|
1303
|
+
});
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Cancel a Polymarket or Hyperliquid limit order that one of the user's
|
|
1308
|
+
* linked self-custody wallets placed outside AGG. `signerAddress` must be
|
|
1309
|
+
* that wallet and must have produced `cancelSignature`.
|
|
1310
|
+
*/
|
|
1311
|
+
cancelVenueOrder(params, options) {
|
|
1312
|
+
return __async(this, null, function* () {
|
|
1313
|
+
return this.request("/execution/orders/cancel", {
|
|
1314
|
+
method: "POST",
|
|
1315
|
+
body: JSON.stringify(params),
|
|
1316
|
+
signal: options == null ? void 0 : options.signal
|
|
1317
|
+
});
|
|
2726
1318
|
});
|
|
2727
1319
|
}
|
|
2728
1320
|
// --- Venue events & venue markets (primary) ---
|
|
@@ -2755,6 +1347,17 @@ Issued At: ${issuedAt}`;
|
|
|
2755
1347
|
});
|
|
2756
1348
|
}
|
|
2757
1349
|
/** Get a single venue event by ID. Requires appId or admin auth. */
|
|
1350
|
+
getEventBootstrap(eventId, options) {
|
|
1351
|
+
return __async(this, null, function* () {
|
|
1352
|
+
return this.request(
|
|
1353
|
+
`/venue-events/${encodeURIComponent(eventId)}/bootstrap`,
|
|
1354
|
+
{
|
|
1355
|
+
query: (options == null ? void 0 : options.limit) ? { limit: String(options.limit) } : void 0,
|
|
1356
|
+
signal: options == null ? void 0 : options.signal
|
|
1357
|
+
}
|
|
1358
|
+
);
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
2758
1361
|
getVenueEventById(id, options) {
|
|
2759
1362
|
return __async(this, null, function* () {
|
|
2760
1363
|
return this.request(`/venue-events/${encodeURIComponent(id)}`, {
|
|
@@ -2883,14 +1486,15 @@ Issued At: ${issuedAt}`;
|
|
|
2883
1486
|
});
|
|
2884
1487
|
}
|
|
2885
1488
|
/** List venue markets with optional filters. Requires appId or admin auth. Supports cursor-based pagination. */
|
|
2886
|
-
getVenueMarkets(options) {
|
|
1489
|
+
getVenueMarkets(options, requestOptions) {
|
|
2887
1490
|
return __async(this, null, function* () {
|
|
2888
|
-
var _a;
|
|
1491
|
+
var _a, _b;
|
|
2889
1492
|
const query = {};
|
|
2890
1493
|
if (options == null ? void 0 : options.venue) query.venue = options.venue;
|
|
1494
|
+
if ((_a = options == null ? void 0 : options.externalIdentifier) == null ? void 0 : _a.length) query.externalIdentifier = options.externalIdentifier;
|
|
2891
1495
|
if (options == null ? void 0 : options.venueEventId) query.venueEventId = options.venueEventId;
|
|
2892
1496
|
if ((options == null ? void 0 : options.cluster) === false) query.cluster = "false";
|
|
2893
|
-
if ((
|
|
1497
|
+
if ((_b = options == null ? void 0 : options.search) == null ? void 0 : _b.trim()) query.search = options.search.trim();
|
|
2894
1498
|
if (options == null ? void 0 : options.matchStatus) query.matchStatus = options.matchStatus;
|
|
2895
1499
|
if (options == null ? void 0 : options.status) query.status = options.status;
|
|
2896
1500
|
if ((options == null ? void 0 : options.aggKey) && options.aggKey.length > 0) query.aggKey = options.aggKey;
|
|
@@ -2910,7 +1514,8 @@ Issued At: ${issuedAt}`;
|
|
|
2910
1514
|
if (options == null ? void 0 : options.sortDir) query.sortDir = options.sortDir;
|
|
2911
1515
|
if (options == null ? void 0 : options.context) query.context = options.context;
|
|
2912
1516
|
return this.request("/venue-markets", {
|
|
2913
|
-
query: Object.keys(query).length > 0 ? query : void 0
|
|
1517
|
+
query: Object.keys(query).length > 0 ? query : void 0,
|
|
1518
|
+
signal: requestOptions == null ? void 0 : requestOptions.signal
|
|
2914
1519
|
});
|
|
2915
1520
|
});
|
|
2916
1521
|
}
|
|
@@ -3012,7 +1617,7 @@ Issued At: ${issuedAt}`;
|
|
|
3012
1617
|
* format intentionally omits the param so the server hits the cheaper
|
|
3013
1618
|
* (and longer-TTL) light cache slot.
|
|
3014
1619
|
*/
|
|
3015
|
-
search(params) {
|
|
1620
|
+
search(params, options) {
|
|
3016
1621
|
return __async(this, null, function* () {
|
|
3017
1622
|
const query = {
|
|
3018
1623
|
q: params.q,
|
|
@@ -3023,8 +1628,10 @@ Issued At: ${issuedAt}`;
|
|
|
3023
1628
|
if (params.limit != null) query.limit = String(params.limit);
|
|
3024
1629
|
if (params.cursor) query.cursor = params.cursor;
|
|
3025
1630
|
if (params.deep) query.deepSearch = "true";
|
|
1631
|
+
if (params.mode) query.mode = params.mode;
|
|
3026
1632
|
return this.request("/search", {
|
|
3027
|
-
query
|
|
1633
|
+
query,
|
|
1634
|
+
signal: options == null ? void 0 : options.signal
|
|
3028
1635
|
});
|
|
3029
1636
|
});
|
|
3030
1637
|
}
|
|
@@ -3086,6 +1693,7 @@ Issued At: ${issuedAt}`;
|
|
|
3086
1693
|
/** Get the canonical TradingView-style bar series for a single venue market outcome. */
|
|
3087
1694
|
getChartBars(params, options) {
|
|
3088
1695
|
return __async(this, null, function* () {
|
|
1696
|
+
var _a, _b;
|
|
3089
1697
|
const resolution = mapChartResolution(params.resolution);
|
|
3090
1698
|
const query = {
|
|
3091
1699
|
venueMarketOutcomeId: params.venueMarketOutcomeId,
|
|
@@ -3094,12 +1702,39 @@ Issued At: ${issuedAt}`;
|
|
|
3094
1702
|
if (resolution) query.resolution = resolution;
|
|
3095
1703
|
if (params.from != null) query.from = String(params.from);
|
|
3096
1704
|
if (params.countBack != null) query.countBack = String(params.countBack);
|
|
1705
|
+
if (options == null ? void 0 : options.decode) {
|
|
1706
|
+
const text = yield this.request(
|
|
1707
|
+
"/charts/bars",
|
|
1708
|
+
{ query, signal: options.signal },
|
|
1709
|
+
(response) => readChartHistoryText(response)
|
|
1710
|
+
);
|
|
1711
|
+
(_a = options.signal) == null ? void 0 : _a.throwIfAborted();
|
|
1712
|
+
const decoded = yield options.decode(text);
|
|
1713
|
+
(_b = options.signal) == null ? void 0 : _b.throwIfAborted();
|
|
1714
|
+
return decoded;
|
|
1715
|
+
}
|
|
3097
1716
|
return this.request("/charts/bars", {
|
|
3098
1717
|
query,
|
|
3099
1718
|
signal: options == null ? void 0 : options.signal
|
|
3100
1719
|
});
|
|
3101
1720
|
});
|
|
3102
1721
|
}
|
|
1722
|
+
getChartHistoryManifest(params, options) {
|
|
1723
|
+
return __async(this, null, function* () {
|
|
1724
|
+
const query = {
|
|
1725
|
+
venueMarketOutcomeId: params.venueMarketOutcomeId,
|
|
1726
|
+
to: String(params.to)
|
|
1727
|
+
};
|
|
1728
|
+
const resolution = mapChartResolution(params.resolution);
|
|
1729
|
+
if (resolution) query.resolution = resolution;
|
|
1730
|
+
if (params.from != null) query.from = String(params.from);
|
|
1731
|
+
if (params.countBack != null) query.countBack = String(params.countBack);
|
|
1732
|
+
return this.request("/charts/history/manifest", {
|
|
1733
|
+
query,
|
|
1734
|
+
signal: options == null ? void 0 : options.signal
|
|
1735
|
+
});
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
3103
1738
|
// --- Batch orderbooks ---
|
|
3104
1739
|
/** Get live per-venue orderbooks for the explicit venueMarketIds requested. */
|
|
3105
1740
|
getOrderbooks(params, options) {
|
|
@@ -3194,22 +1829,34 @@ Issued At: ${issuedAt}`;
|
|
|
3194
1829
|
return params.side ? __spreadProps(__spreadValues({}, response), { side: params.side }) : response;
|
|
3195
1830
|
});
|
|
3196
1831
|
}
|
|
1832
|
+
/** Seed subscribed outcomes with one bounded batch of compatible snapshots. */
|
|
1833
|
+
getOutcomeOrderbooks(params, options) {
|
|
1834
|
+
return __async(this, null, function* () {
|
|
1835
|
+
return this.request("/orderbooks/outcomes", {
|
|
1836
|
+
query: __spreadValues({
|
|
1837
|
+
venueMarketOutcomeIds: params.venueMarketOutcomeIds.join(",")
|
|
1838
|
+
}, params.depth == null ? {} : { depth: String(params.depth) }),
|
|
1839
|
+
signal: options == null ? void 0 : options.signal
|
|
1840
|
+
});
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
3197
1843
|
/**
|
|
3198
1844
|
* Create an AggWebSocket instance configured with this client's appId and optional auth token.
|
|
3199
1845
|
* Requires `wsUrl` to be set in the client options.
|
|
3200
1846
|
*/
|
|
3201
1847
|
createWebSocket(callbacks, options) {
|
|
3202
|
-
var _a;
|
|
1848
|
+
var _a, _b;
|
|
3203
1849
|
if (!this.wsUrl) {
|
|
3204
1850
|
throw new Error("AggClient.createWebSocket() requires wsUrl to be set in client options");
|
|
3205
1851
|
}
|
|
3206
1852
|
const url = new URL(this.wsUrl);
|
|
3207
1853
|
if (this._appId) url.searchParams.set("appId", this._appId);
|
|
3208
|
-
|
|
1854
|
+
const createSocket = (_a = this.webSocketFactory) != null ? _a : ((socketOptions) => new AggWebSocket(socketOptions));
|
|
1855
|
+
return createSocket({
|
|
3209
1856
|
url: url.toString(),
|
|
3210
1857
|
callbacks,
|
|
3211
1858
|
initialToken: this.accessToken,
|
|
3212
|
-
enableLogs: (
|
|
1859
|
+
enableLogs: (_b = options == null ? void 0 : options.enableLogs) != null ? _b : false
|
|
3213
1860
|
});
|
|
3214
1861
|
}
|
|
3215
1862
|
/** Execute a previously quoted managed trade. Returns pending order IDs. */
|
|
@@ -3505,138 +2152,6 @@ Issued At: ${issuedAt}`;
|
|
|
3505
2152
|
// src/best-split.ts
|
|
3506
2153
|
var computeBestSplitsByAmount2 = computeBestSplitsByAmount;
|
|
3507
2154
|
|
|
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
2155
|
// src/market-aggregator.ts
|
|
3641
2156
|
function mergeCandles(candles) {
|
|
3642
2157
|
const valid = candles.filter((c2) => c2 != null);
|
|
@@ -3715,6 +2230,7 @@ export {
|
|
|
3715
2230
|
OrderStatus,
|
|
3716
2231
|
OrderType,
|
|
3717
2232
|
RECURRENCE_CADENCES,
|
|
2233
|
+
RETINA_IMAGE_SIZES,
|
|
3718
2234
|
SELF_CUSTODY_FILL_TIMEOUT_MS,
|
|
3719
2235
|
SELF_CUSTODY_POLL_INTERVAL_MS,
|
|
3720
2236
|
TERMINAL_EXECUTION_STATES,
|
|
@@ -3748,13 +2264,17 @@ export {
|
|
|
3748
2264
|
isVenueActive,
|
|
3749
2265
|
isVenueDataVisible,
|
|
3750
2266
|
isVenueInactive,
|
|
2267
|
+
loadImmutableHistory,
|
|
3751
2268
|
mergeCandles,
|
|
3752
2269
|
mergeClosedCandles,
|
|
3753
2270
|
normalizeVenueMarketCluster,
|
|
3754
2271
|
optimizedImageUrl,
|
|
2272
|
+
orderbookCrc32,
|
|
3755
2273
|
parse,
|
|
3756
2274
|
parseEmail,
|
|
3757
2275
|
parseEmailStrict,
|
|
2276
|
+
projectedOrderbookChecksum,
|
|
2277
|
+
retinaImageUrl,
|
|
3758
2278
|
safeParse,
|
|
3759
2279
|
snapshotToOrderbook,
|
|
3760
2280
|
sortVenues,
|