@agg-build/sdk 4.32.0 → 4.34.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 +15 -0
- package/dist/{agg-websocket-ClGhhROZ.mjs → agg-websocket-C2neMzGT.mjs} +117 -4
- package/dist/agg-websocket-C2neMzGT.mjs.map +1 -0
- package/dist/{agg-websocket-CVZ7laJ4.js → agg-websocket-MYZiMRXn.js} +116 -3
- package/dist/{agg-websocket-DsEtBkLk.d.ts → agg-websocket-yR0BZ4yb.d.mts} +3820 -3533
- package/dist/agg-websocket-yR0BZ4yb.d.mts.map +1 -0
- package/dist/{agg-websocket-DsEtBkLk.d.mts → agg-websocket-yR0BZ4yb.d.ts} +3820 -3533
- package/dist/agg-websocket-yR0BZ4yb.d.ts.map +1 -0
- package/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/browser.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +569 -100
- package/dist/index.mjs +568 -101
- package/dist/index.mjs.map +1 -1
- package/dist/market-data.d.mts +1 -1
- package/dist/market-data.d.ts +1 -1
- package/dist/market-data.js +1 -1
- package/dist/market-data.mjs +1 -1
- package/package.json +1 -1
- package/dist/agg-websocket-ClGhhROZ.mjs.map +0 -1
- package/dist/agg-websocket-DsEtBkLk.d.mts.map +0 -1
- package/dist/agg-websocket-DsEtBkLk.d.ts.map +0 -1
|
@@ -509,6 +509,7 @@ const WATCHDOG_CHECK_INTERVAL_MS = 6e4;
|
|
|
509
509
|
const WATCHDOG_BATCH_MAX = 100;
|
|
510
510
|
/** A watchdog REST check that takes longer than this is abandoned. */
|
|
511
511
|
const WATCHDOG_REQUEST_TIMEOUT_MS = 15e3;
|
|
512
|
+
const CATALOG_FRAME_ID_PREFIX = "catalog-";
|
|
512
513
|
/**
|
|
513
514
|
* Agg WebSocket client. Single WS connection with refcounted market subscriptions.
|
|
514
515
|
*/
|
|
@@ -548,6 +549,10 @@ var AggWebSocket = class {
|
|
|
548
549
|
this.seenEventIds = /* @__PURE__ */ new Set();
|
|
549
550
|
this.hasConnected = false;
|
|
550
551
|
this.appEventCbs = /* @__PURE__ */ new Set();
|
|
552
|
+
this.catalogSubs = /* @__PURE__ */ new Set();
|
|
553
|
+
this.catalogSentKey = null;
|
|
554
|
+
this.catalogFrameSeq = 0;
|
|
555
|
+
this.catalogAckedSeq = 0;
|
|
551
556
|
this.rejected = false;
|
|
552
557
|
this.deferBookViews = options.deferBookViews ?? false;
|
|
553
558
|
this.url = options.url;
|
|
@@ -601,6 +606,7 @@ var AggWebSocket = class {
|
|
|
601
606
|
tradeOutcomeIds: this.activeTradeMarkets(),
|
|
602
607
|
arbMarketIds: this.activeArbMarkets(),
|
|
603
608
|
arbFeedSubscribers: this.arbFeedCbs.size,
|
|
609
|
+
catalogSubscribers: this.catalogSubs.size,
|
|
604
610
|
cachedBooks: this.books.size,
|
|
605
611
|
cachedArb: this.latestArb.size,
|
|
606
612
|
resyncingBooks: this.resyncing.size,
|
|
@@ -683,6 +689,78 @@ var AggWebSocket = class {
|
|
|
683
689
|
};
|
|
684
690
|
}
|
|
685
691
|
/**
|
|
692
|
+
* Subscribe to the catalog feed: new, changed and deleted events and
|
|
693
|
+
* markets. Live only — pair it with `GET /catalog/changes` (or use
|
|
694
|
+
* `AggClient.watchCatalog`, which does both).
|
|
695
|
+
*
|
|
696
|
+
* One server subscription is shared by every caller. Its filter is the
|
|
697
|
+
* union of the callers' filters (no filter when any caller has none), and
|
|
698
|
+
* each caller only receives frames matching its own filter. The subscribe
|
|
699
|
+
* is re-sent on every reconnect; `onSubscribed` fires each time the server
|
|
700
|
+
* confirms it. Returns an unsubscribe function.
|
|
701
|
+
*/
|
|
702
|
+
subscribeCatalog(filter, cb, opts = {}) {
|
|
703
|
+
const sub = {
|
|
704
|
+
filter: {
|
|
705
|
+
...filter.venues?.length ? { venues: [...filter.venues] } : {},
|
|
706
|
+
...filter.entities?.length ? { entities: [...filter.entities] } : {}
|
|
707
|
+
},
|
|
708
|
+
cb,
|
|
709
|
+
opts
|
|
710
|
+
};
|
|
711
|
+
this.catalogSubs.add(sub);
|
|
712
|
+
this.ensureConnected();
|
|
713
|
+
if (this._connected) {
|
|
714
|
+
if (!this.sendCatalogSubscribe(sub)) {
|
|
715
|
+
if (this.catalogAckedSeq >= this.catalogFrameSeq) queueMicrotask(() => {
|
|
716
|
+
if (this.catalogSubs.has(sub)) sub.opts.onSubscribed?.();
|
|
717
|
+
});
|
|
718
|
+
else sub.awaitingAck = this.catalogFrameSeq;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return () => {
|
|
722
|
+
if (!this.catalogSubs.delete(sub) || !this._connected) return;
|
|
723
|
+
if (this.catalogSubs.size === 0) {
|
|
724
|
+
this.catalogSentKey = null;
|
|
725
|
+
this.send({
|
|
726
|
+
action: "unsubscribe",
|
|
727
|
+
channel: "catalog"
|
|
728
|
+
});
|
|
729
|
+
} else this.sendCatalogSubscribe();
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Send the union filter if it differs from what the server holds. Callers
|
|
734
|
+
* in `confirm` wait for this frame's ack. Returns whether a frame was sent.
|
|
735
|
+
*/
|
|
736
|
+
sendCatalogSubscribe(...confirm) {
|
|
737
|
+
const filter = unionCatalogFilter([...this.catalogSubs].map((s) => s.filter));
|
|
738
|
+
const key = JSON.stringify(filter);
|
|
739
|
+
if (key === this.catalogSentKey) return false;
|
|
740
|
+
this.catalogSentKey = key;
|
|
741
|
+
const seq = ++this.catalogFrameSeq;
|
|
742
|
+
for (const sub of confirm) sub.awaitingAck = seq;
|
|
743
|
+
this.send({
|
|
744
|
+
action: "subscribe",
|
|
745
|
+
channel: "catalog",
|
|
746
|
+
...filter,
|
|
747
|
+
id: `${CATALOG_FRAME_ID_PREFIX}${seq}`
|
|
748
|
+
});
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
handleCatalogAck(msg) {
|
|
752
|
+
const seq = catalogFrameSeq(msg.id) ?? this.catalogFrameSeq;
|
|
753
|
+
if (seq > this.catalogAckedSeq) this.catalogAckedSeq = seq;
|
|
754
|
+
for (const sub of [...this.catalogSubs]) {
|
|
755
|
+
if (sub.awaitingAck === void 0 || sub.awaitingAck > seq) continue;
|
|
756
|
+
sub.awaitingAck = void 0;
|
|
757
|
+
sub.opts.onSubscribed?.();
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
handleCatalogChange(msg) {
|
|
761
|
+
for (const sub of [...this.catalogSubs]) if (this.catalogSubs.has(sub) && matchesCatalogFilter(sub.filter, msg)) sub.cb(msg);
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
686
764
|
* Subscribe to a feed by outcome ID.
|
|
687
765
|
* @param outcomeId The venueMarketOutcomeId to subscribe to.
|
|
688
766
|
* @param channel "orderbook" (default) or "trades".
|
|
@@ -887,6 +965,8 @@ var AggWebSocket = class {
|
|
|
887
965
|
this.arbSubs.clear();
|
|
888
966
|
this.arbFeedCbs.clear();
|
|
889
967
|
this.appEventCbs.clear();
|
|
968
|
+
this.catalogSubs.clear();
|
|
969
|
+
this.catalogSentKey = null;
|
|
890
970
|
this.seenEventIds.clear();
|
|
891
971
|
this.latestArb.clear();
|
|
892
972
|
this.pendingFlushArbSubs.clear();
|
|
@@ -944,7 +1024,7 @@ var AggWebSocket = class {
|
|
|
944
1024
|
});
|
|
945
1025
|
return;
|
|
946
1026
|
}
|
|
947
|
-
if (!this.destroyed && (this.subs.size > 0 || this.arbSubs.size > 0 || this.arbFeedCbs.size > 0 || this.appEventCbs.size > 0 || !!this.initialToken)) this.scheduleReconnect();
|
|
1027
|
+
if (!this.destroyed && (this.subs.size > 0 || this.arbSubs.size > 0 || this.arbFeedCbs.size > 0 || this.appEventCbs.size > 0 || this.catalogSubs.size > 0 || !!this.initialToken)) this.scheduleReconnect();
|
|
948
1028
|
};
|
|
949
1029
|
ws.onerror = () => {};
|
|
950
1030
|
}
|
|
@@ -1015,6 +1095,7 @@ var AggWebSocket = class {
|
|
|
1015
1095
|
this.handleHeartbeat(raw);
|
|
1016
1096
|
break;
|
|
1017
1097
|
case "subscribed":
|
|
1098
|
+
if (raw.channel === "catalog") this.handleCatalogAck(raw);
|
|
1018
1099
|
this.callbacks.onSubscribed?.(raw);
|
|
1019
1100
|
break;
|
|
1020
1101
|
case "unsubscribed":
|
|
@@ -1046,13 +1127,24 @@ var AggWebSocket = class {
|
|
|
1046
1127
|
channels: msg.channels
|
|
1047
1128
|
});
|
|
1048
1129
|
this.callbacks.onStreamInterrupted?.(msg);
|
|
1130
|
+
if (msg.channels?.includes("catalog")) for (const sub of [...this.catalogSubs]) sub.opts.onInterrupted?.();
|
|
1049
1131
|
break;
|
|
1050
1132
|
}
|
|
1051
1133
|
case "market_resolved":
|
|
1052
1134
|
this.handleMarketResolved(raw);
|
|
1053
1135
|
break;
|
|
1054
|
-
case "error":
|
|
1055
|
-
|
|
1136
|
+
case "error": {
|
|
1137
|
+
const msg = raw;
|
|
1138
|
+
const seq = catalogFrameSeq(msg.id);
|
|
1139
|
+
if (seq !== void 0) {
|
|
1140
|
+
if (seq === this.catalogFrameSeq) this.catalogSentKey = null;
|
|
1141
|
+
for (const sub of [...this.catalogSubs]) if (sub.awaitingAck !== void 0 && sub.awaitingAck <= seq) sub.opts.onError?.(msg);
|
|
1142
|
+
}
|
|
1143
|
+
this.callbacks.onError?.(msg);
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
case "catalog_change":
|
|
1147
|
+
this.handleCatalogChange(raw);
|
|
1056
1148
|
break;
|
|
1057
1149
|
case "order_submitted":
|
|
1058
1150
|
this.handleOrderSubmitted(raw);
|
|
@@ -1152,6 +1244,9 @@ var AggWebSocket = class {
|
|
|
1152
1244
|
channel: "arb-feed"
|
|
1153
1245
|
});
|
|
1154
1246
|
if (this.appEventCbs.size > 0) this.sendAppEventsSubscribe();
|
|
1247
|
+
this.catalogSentKey = null;
|
|
1248
|
+
this.catalogAckedSeq = this.catalogFrameSeq;
|
|
1249
|
+
if (this.catalogSubs.size > 0) this.sendCatalogSubscribe(...this.catalogSubs);
|
|
1155
1250
|
}
|
|
1156
1251
|
/**
|
|
1157
1252
|
* Track `eventId` per stream and drop duplicates a resume re-delivers.
|
|
@@ -1556,6 +1651,24 @@ var AggWebSocket = class {
|
|
|
1556
1651
|
return this.enableLogs;
|
|
1557
1652
|
}
|
|
1558
1653
|
};
|
|
1654
|
+
/** Union of caller filters; an unset dimension on any caller leaves it unset. */
|
|
1655
|
+
function unionCatalogFilter(filters) {
|
|
1656
|
+
const union = {};
|
|
1657
|
+
if (filters.every((f) => f.venues?.length)) union.venues = [...new Set(filters.flatMap((f) => f.venues))].sort();
|
|
1658
|
+
if (filters.every((f) => f.entities?.length)) union.entities = [...new Set(filters.flatMap((f) => f.entities))].sort();
|
|
1659
|
+
return union;
|
|
1660
|
+
}
|
|
1661
|
+
/** Same rule as the server: deletes carry no venue and pass the venue filter. */
|
|
1662
|
+
function matchesCatalogFilter(filter, change) {
|
|
1663
|
+
if (filter.entities && !filter.entities.includes(change.entity)) return false;
|
|
1664
|
+
if (change.op === "deleted" || change.venue === null) return true;
|
|
1665
|
+
return !filter.venues || filter.venues.includes(change.venue);
|
|
1666
|
+
}
|
|
1667
|
+
function catalogFrameSeq(id) {
|
|
1668
|
+
if (typeof id !== "string" || !id.startsWith(CATALOG_FRAME_ID_PREFIX)) return void 0;
|
|
1669
|
+
const seq = Number(id.slice(8));
|
|
1670
|
+
return Number.isInteger(seq) ? seq : void 0;
|
|
1671
|
+
}
|
|
1559
1672
|
/** Order server event ids ("<ms>-<seq>"); an absent id sorts first. */
|
|
1560
1673
|
function compareEventIds(a, b) {
|
|
1561
1674
|
if (b === void 0) return 1;
|