@agg-build/sdk 4.24.0 → 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agg-websocket-Cm_8f8hA.d.mts → agg-websocket-x_U4-orL.d.mts} +163 -14
- package/dist/{agg-websocket-Cm_8f8hA.d.ts → agg-websocket-x_U4-orL.d.ts} +163 -14
- package/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +129 -3
- package/dist/browser.mjs +1 -1
- package/dist/{chunk-QXBVA5TW.mjs → chunk-CPMSVNBO.mjs} +129 -3
- package/dist/index.d.mts +12 -5
- package/dist/index.d.ts +12 -5
- package/dist/index.js +191 -14
- package/dist/index.mjs +62 -12
- package/dist/market-data.d.mts +2 -2
- package/dist/market-data.d.ts +2 -2
- package/dist/market-data.js +129 -3
- package/dist/market-data.mjs +1 -1
- package/package.json +1 -1
package/dist/market-data.js
CHANGED
|
@@ -488,6 +488,10 @@ var RECONNECT_BASE_MS = 1e3;
|
|
|
488
488
|
var RECONNECT_MAX_MS = 3e4;
|
|
489
489
|
var STALE_TIMEOUT_MS = 45e3;
|
|
490
490
|
var ORDERBOOK_DEBUG_TOP_LEVELS = 5;
|
|
491
|
+
var WATCHDOG_SILENCE_MS = 5 * 6e4;
|
|
492
|
+
var WATCHDOG_CHECK_INTERVAL_MS = 6e4;
|
|
493
|
+
var WATCHDOG_BATCH_MAX = 100;
|
|
494
|
+
var WATCHDOG_REQUEST_TIMEOUT_MS = 15e3;
|
|
491
495
|
var AggWebSocket = class {
|
|
492
496
|
constructor(options) {
|
|
493
497
|
this.ws = null;
|
|
@@ -513,6 +517,18 @@ var AggWebSocket = class {
|
|
|
513
517
|
this.books = /* @__PURE__ */ new Map();
|
|
514
518
|
/** Markets currently resyncing (awaiting snapshot after seq gap / checksum mismatch). */
|
|
515
519
|
this.resyncing = /* @__PURE__ */ new Set();
|
|
520
|
+
/**
|
|
521
|
+
* Per subscribed orderbook outcome: last time it made progress (subscribe,
|
|
522
|
+
* snapshot, applied delta) or was checked against REST (ms). Tracked from
|
|
523
|
+
* subscribe, not from the first snapshot, so a book that never arrives or
|
|
524
|
+
* is stuck resyncing is still found by the watchdog.
|
|
525
|
+
*/
|
|
526
|
+
this.bookCheckedAt = /* @__PURE__ */ new Map();
|
|
527
|
+
/** Outcomes the watchdog already resnapshotted; a repeat mismatch resubscribes. */
|
|
528
|
+
this.watchdogResnapshotted = /* @__PURE__ */ new Set();
|
|
529
|
+
this.watchdogTimer = null;
|
|
530
|
+
this.watchdogAbort = null;
|
|
531
|
+
this.watchdogPausedUntil = 0;
|
|
516
532
|
// ── Connection state ──
|
|
517
533
|
this.connecting = false;
|
|
518
534
|
this._connected = false;
|
|
@@ -528,6 +544,7 @@ var AggWebSocket = class {
|
|
|
528
544
|
this.callbacks = (_b = options.callbacks) != null ? _b : {};
|
|
529
545
|
this.initialToken = options.initialToken;
|
|
530
546
|
this.enableLogs = (_c = options.enableLogs) != null ? _c : false;
|
|
547
|
+
this.bookWatchdog = options.bookWatchdog;
|
|
531
548
|
}
|
|
532
549
|
// ── Public API ──
|
|
533
550
|
get connected() {
|
|
@@ -673,6 +690,7 @@ var AggWebSocket = class {
|
|
|
673
690
|
this.subs.set(outcomeId, sub);
|
|
674
691
|
}
|
|
675
692
|
if (sub.refCount === 0) {
|
|
693
|
+
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
676
694
|
this.pendingSubs.add(outcomeId);
|
|
677
695
|
this.ensureConnected();
|
|
678
696
|
if (this._connected) {
|
|
@@ -697,6 +715,8 @@ var AggWebSocket = class {
|
|
|
697
715
|
this.books.delete(outcomeId);
|
|
698
716
|
}
|
|
699
717
|
this.resyncing.delete(outcomeId);
|
|
718
|
+
this.bookCheckedAt.delete(outcomeId);
|
|
719
|
+
this.watchdogResnapshotted.delete(outcomeId);
|
|
700
720
|
if (this._connected) {
|
|
701
721
|
if (this.pendingFlushSubs.has(outcomeId)) {
|
|
702
722
|
this.pendingFlushSubs.delete(outcomeId);
|
|
@@ -764,6 +784,7 @@ var AggWebSocket = class {
|
|
|
764
784
|
}
|
|
765
785
|
/** Send a JWT to authenticate (or re-authenticate) the connection. */
|
|
766
786
|
authenticate(token) {
|
|
787
|
+
this.initialToken = token;
|
|
767
788
|
if (this._connected) {
|
|
768
789
|
this.send({ action: "authenticate", token });
|
|
769
790
|
}
|
|
@@ -795,6 +816,7 @@ var AggWebSocket = class {
|
|
|
795
816
|
}
|
|
796
817
|
/** Permanently destroy. Cannot reconnect after this. */
|
|
797
818
|
destroy() {
|
|
819
|
+
var _a;
|
|
798
820
|
this.destroyed = true;
|
|
799
821
|
for (const controller of this.historyControllers)
|
|
800
822
|
controller.abort(new Error("Market-data client disposed"));
|
|
@@ -805,6 +827,12 @@ var AggWebSocket = class {
|
|
|
805
827
|
this.subs.clear();
|
|
806
828
|
this.books.clear();
|
|
807
829
|
this.resyncing.clear();
|
|
830
|
+
if (this.watchdogTimer) clearInterval(this.watchdogTimer);
|
|
831
|
+
this.watchdogTimer = null;
|
|
832
|
+
(_a = this.watchdogAbort) == null ? void 0 : _a.abort();
|
|
833
|
+
this.watchdogAbort = null;
|
|
834
|
+
this.bookCheckedAt.clear();
|
|
835
|
+
this.watchdogResnapshotted.clear();
|
|
808
836
|
this.pendingSubs.clear();
|
|
809
837
|
this.pendingTradeSubs.clear();
|
|
810
838
|
this.pendingResnapshots.clear();
|
|
@@ -988,11 +1016,21 @@ var AggWebSocket = class {
|
|
|
988
1016
|
* ready to accept subscriptions. Now flush all pending subs.
|
|
989
1017
|
*/
|
|
990
1018
|
handleConnected(msg) {
|
|
991
|
-
var _a, _b, _c, _d;
|
|
1019
|
+
var _a, _b, _c, _d, _e;
|
|
992
1020
|
this._connected = true;
|
|
993
|
-
|
|
994
|
-
|
|
1021
|
+
if (this.bookWatchdog && !this.watchdogTimer && !this.destroyed) {
|
|
1022
|
+
this.watchdogTimer = setInterval(
|
|
1023
|
+
() => void this.checkSilentBooks(),
|
|
1024
|
+
(_a = this.bookWatchdog.checkIntervalMs) != null ? _a : WATCHDOG_CHECK_INTERVAL_MS
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
(_c = (_b = this.callbacks).onConnectionStateChange) == null ? void 0 : _c.call(_b, true);
|
|
1028
|
+
(_e = (_d = this.callbacks).onConnected) == null ? void 0 : _e.call(_d, msg);
|
|
995
1029
|
const orderbookSet = new Set(this.activeOrderbookMarkets());
|
|
1030
|
+
const reconnectedAt = Date.now();
|
|
1031
|
+
for (const id of orderbookSet) {
|
|
1032
|
+
if (this.bookCheckedAt.has(id)) this.bookCheckedAt.set(id, reconnectedAt);
|
|
1033
|
+
}
|
|
996
1034
|
this.pendingSubs.forEach((id) => orderbookSet.add(id));
|
|
997
1035
|
this.pendingFlushSubs.forEach((id) => orderbookSet.add(id));
|
|
998
1036
|
const orderbookIds = Array.from(orderbookSet);
|
|
@@ -1035,6 +1073,7 @@ var AggWebSocket = class {
|
|
|
1035
1073
|
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1036
1074
|
const book = snapshotToOrderbook(msg);
|
|
1037
1075
|
this.books.set(msg.outcomeId, new IndexedOrderbook(book));
|
|
1076
|
+
this.bookCheckedAt.set(msg.outcomeId, Date.now());
|
|
1038
1077
|
this.resyncing.delete(msg.outcomeId);
|
|
1039
1078
|
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1040
1079
|
this.debugOrderbook("snapshot_applied", {
|
|
@@ -1104,6 +1143,8 @@ var AggWebSocket = class {
|
|
|
1104
1143
|
this.requestResnapshot(outcomeId);
|
|
1105
1144
|
return;
|
|
1106
1145
|
}
|
|
1146
|
+
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1147
|
+
this.watchdogResnapshotted.delete(outcomeId);
|
|
1107
1148
|
(_b = (_a = this.callbacks).onBookTick) == null ? void 0 : _b.call(_a, outcomeId, {
|
|
1108
1149
|
midpoint: msg.midpoint,
|
|
1109
1150
|
timestamp: msg.timestamp,
|
|
@@ -1126,6 +1167,8 @@ var AggWebSocket = class {
|
|
|
1126
1167
|
var _a, _b;
|
|
1127
1168
|
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1128
1169
|
this.books.delete(msg.outcomeId);
|
|
1170
|
+
this.bookCheckedAt.delete(msg.outcomeId);
|
|
1171
|
+
this.watchdogResnapshotted.delete(msg.outcomeId);
|
|
1129
1172
|
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1130
1173
|
this.resyncing.delete(msg.outcomeId);
|
|
1131
1174
|
(_b = (_a = this.callbacks).onMarketResolved) == null ? void 0 : _b.call(_a, msg);
|
|
@@ -1145,6 +1188,89 @@ var AggWebSocket = class {
|
|
|
1145
1188
|
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1146
1189
|
(_b = (_a = this.callbacks).onRedeemEvent) == null ? void 0 : _b.call(_a, msg);
|
|
1147
1190
|
}
|
|
1191
|
+
// ── Book watchdog ──
|
|
1192
|
+
/**
|
|
1193
|
+
* Heartbeats prove the socket, not each stream. Every subscribed outcome
|
|
1194
|
+
* with no progress for `silenceMs` is checked against the REST `seq`:
|
|
1195
|
+
*
|
|
1196
|
+
* - book present, not resyncing, same `seq` → the market is just quiet;
|
|
1197
|
+
* - different `seq`, no book (snapshot never arrived, or a resubscribe's
|
|
1198
|
+
* snapshot was lost), or stuck resyncing (any recovery whose snapshot
|
|
1199
|
+
* was lost) → resnapshot, then resubscribe on the next overdue check;
|
|
1200
|
+
* - REST can't serve it (`null`) → counted as an attempt, so the next
|
|
1201
|
+
* batch moves on to other outcomes instead of retrying the same 100.
|
|
1202
|
+
*/
|
|
1203
|
+
checkSilentBooks() {
|
|
1204
|
+
return __async(this, null, function* () {
|
|
1205
|
+
var _a;
|
|
1206
|
+
const opts = this.bookWatchdog;
|
|
1207
|
+
if (!opts || !this._connected || this.watchdogAbort) return;
|
|
1208
|
+
const now = Date.now();
|
|
1209
|
+
if (now < this.watchdogPausedUntil) return;
|
|
1210
|
+
const silenceMs = (_a = opts.silenceMs) != null ? _a : WATCHDOG_SILENCE_MS;
|
|
1211
|
+
const silent = this.activeOrderbookMarkets().filter((id) => this.bookCheckedAt.has(id)).filter((id) => now - this.bookCheckedAt.get(id) >= silenceMs).sort((a, b) => this.bookCheckedAt.get(a) - this.bookCheckedAt.get(b)).slice(0, WATCHDOG_BATCH_MAX);
|
|
1212
|
+
if (silent.length === 0) return;
|
|
1213
|
+
const checkedAt = new Map(silent.map((id) => [id, this.bookCheckedAt.get(id)]));
|
|
1214
|
+
const abort = new AbortController();
|
|
1215
|
+
this.watchdogAbort = abort;
|
|
1216
|
+
const timeout = setTimeout(() => abort.abort(), WATCHDOG_REQUEST_TIMEOUT_MS);
|
|
1217
|
+
try {
|
|
1218
|
+
const url = new URL(`${opts.baseUrl.replace(/\/$/, "")}/orderbooks/outcomes`);
|
|
1219
|
+
url.searchParams.set("venueMarketOutcomeIds", silent.join(","));
|
|
1220
|
+
url.searchParams.set("depth", "1");
|
|
1221
|
+
const response = yield fetch(url, { headers: opts.headers, signal: abort.signal });
|
|
1222
|
+
if (!response.ok) {
|
|
1223
|
+
const retryAfterS = Number(response.headers.get("retry-after"));
|
|
1224
|
+
if (response.status === 429 && retryAfterS > 0) {
|
|
1225
|
+
this.watchdogPausedUntil = Date.now() + retryAfterS * 1e3;
|
|
1226
|
+
}
|
|
1227
|
+
this.emitDiagnostic({ type: "book_watchdog_error", status: response.status });
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
const body = yield response.json();
|
|
1231
|
+
if (this.destroyed) return;
|
|
1232
|
+
silent.forEach((outcomeId, i) => {
|
|
1233
|
+
var _a2, _b;
|
|
1234
|
+
if (this.bookCheckedAt.get(outcomeId) !== checkedAt.get(outcomeId)) return;
|
|
1235
|
+
const server = (_a2 = body.data) == null ? void 0 : _a2[i];
|
|
1236
|
+
if (!server) {
|
|
1237
|
+
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
const book = this.books.get(outcomeId);
|
|
1241
|
+
if (book && !this.resyncing.has(outcomeId) && server.seq === book.seq) {
|
|
1242
|
+
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1243
|
+
this.watchdogResnapshotted.delete(outcomeId);
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
const action = this.watchdogResnapshotted.has(outcomeId) ? "resubscribe" : "resnapshot";
|
|
1247
|
+
this.emitDiagnostic({
|
|
1248
|
+
type: "book_watchdog_resync",
|
|
1249
|
+
outcomeId,
|
|
1250
|
+
localSeq: (_b = book == null ? void 0 : book.seq) != null ? _b : null,
|
|
1251
|
+
serverSeq: server.seq,
|
|
1252
|
+
action
|
|
1253
|
+
});
|
|
1254
|
+
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1255
|
+
if (action === "resubscribe") {
|
|
1256
|
+
this.watchdogResnapshotted.delete(outcomeId);
|
|
1257
|
+
this.books.delete(outcomeId);
|
|
1258
|
+
this.resyncing.add(outcomeId);
|
|
1259
|
+
this.send({ action: "unsubscribe", channel: "orderbook", outcomeIds: [outcomeId] });
|
|
1260
|
+
this.sendSubscribe([outcomeId]);
|
|
1261
|
+
} else {
|
|
1262
|
+
this.watchdogResnapshotted.add(outcomeId);
|
|
1263
|
+
this.requestResnapshot(outcomeId, true);
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
} catch (e) {
|
|
1267
|
+
if (!this.destroyed) this.emitDiagnostic({ type: "book_watchdog_error", status: null });
|
|
1268
|
+
} finally {
|
|
1269
|
+
clearTimeout(timeout);
|
|
1270
|
+
if (this.watchdogAbort === abort) this.watchdogAbort = null;
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1148
1274
|
// ── Resnapshot ──
|
|
1149
1275
|
requestResnapshot(outcomeId, force = false) {
|
|
1150
1276
|
if (this.resyncing.has(outcomeId) && !force) return;
|
package/dist/market-data.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agg-build/sdk",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.26.0",
|
|
4
4
|
"description": "Vanilla TypeScript client for the AGG prediction market aggregator (auth, markets, orderbooks, charts, trading, managed execution, WebSockets). Works in browsers, Node.js, and React Native.",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|