@taphubhq/sdk-core 0.16.2 → 0.17.1
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/index.cjs +56 -47
- package/dist/index.d.mts +30 -29
- package/dist/index.d.ts +30 -29
- package/dist/index.js +56 -47
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -139,7 +139,7 @@ function normaliseAgencyPairs(rows) {
|
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
return rows.map((row) => ({
|
|
142
|
-
|
|
142
|
+
pairId: row.pairId,
|
|
143
143
|
pair: row.pair,
|
|
144
144
|
thumb: row.thumb,
|
|
145
145
|
ordering: Number(row.ordering),
|
|
@@ -153,7 +153,7 @@ function normaliseAgencyPairs(rows) {
|
|
|
153
153
|
// src/modules/agencyPair/queries.ts
|
|
154
154
|
var FETCH_AGENCY_PAIRS_QUERY = `query FetchAgencyPairs($filter: AgencyPairFilter) {
|
|
155
155
|
fetchAgencyPairs(filter: $filter) {
|
|
156
|
-
|
|
156
|
+
pairId pair thumb ordering status maxCoef currentPrice currentVol24h
|
|
157
157
|
}
|
|
158
158
|
}`;
|
|
159
159
|
|
|
@@ -479,8 +479,8 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
479
479
|
id user_id game_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at
|
|
480
480
|
}
|
|
481
481
|
}`;
|
|
482
|
-
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $
|
|
483
|
-
myBids(statuses: $statuses, limit: $limit, offset: $offset,
|
|
482
|
+
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
483
|
+
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
484
484
|
id user_id game_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at
|
|
485
485
|
}
|
|
486
486
|
}`;
|
|
@@ -508,7 +508,9 @@ var BidModule = class {
|
|
|
508
508
|
async placeBid(input, opts) {
|
|
509
509
|
const variables = {
|
|
510
510
|
input: {
|
|
511
|
-
|
|
511
|
+
// REVIEW[bid-260602-v2]: input field pairId (was: game_id) — the #2 game_pairs.id.
|
|
512
|
+
// Server composes the agencyPairId composite and stores it in bids.game_id (frozen).
|
|
513
|
+
pairId: input.pairId,
|
|
512
514
|
// wallet_id is forwarded as-is — grid-api enforces ownership +
|
|
513
515
|
// currency validation. See openspec/bid-260518-wallet-id D1/D8.
|
|
514
516
|
wallet_id: input.walletId,
|
|
@@ -532,7 +534,7 @@ var BidModule = class {
|
|
|
532
534
|
if (err instanceof TaphubValidationError && err.code === "NotExist") {
|
|
533
535
|
throw new TaphubValidationError("Game not found", {
|
|
534
536
|
code: "GameNotFound",
|
|
535
|
-
details: {
|
|
537
|
+
details: { pairId: input.pairId }
|
|
536
538
|
});
|
|
537
539
|
}
|
|
538
540
|
throw err;
|
|
@@ -563,8 +565,8 @@ var BidModule = class {
|
|
|
563
565
|
if (opts?.offset !== void 0) {
|
|
564
566
|
variables.offset = opts.offset;
|
|
565
567
|
}
|
|
566
|
-
if (opts?.
|
|
567
|
-
variables.
|
|
568
|
+
if (opts?.pairId !== void 0) {
|
|
569
|
+
variables.pairId = opts.pairId;
|
|
568
570
|
}
|
|
569
571
|
const body = await this.#graphql.request(
|
|
570
572
|
MY_BIDS_QUERY,
|
|
@@ -794,8 +796,8 @@ function normalisePairInfo(node) {
|
|
|
794
796
|
}
|
|
795
797
|
|
|
796
798
|
// src/modules/pair/queries.ts
|
|
797
|
-
var PAIR_QUERY = `query Pair($
|
|
798
|
-
pair(
|
|
799
|
+
var PAIR_QUERY = `query Pair($pairId: ID!) {
|
|
800
|
+
pair(pairId: $pairId) {
|
|
799
801
|
id pair status created_at
|
|
800
802
|
config {
|
|
801
803
|
gridConfig { cellSizeTime cellSizeValue candleSize baseline baselineTime }
|
|
@@ -804,8 +806,8 @@ var PAIR_QUERY = `query Pair($pair: String!, $gameplaySlug: String) {
|
|
|
804
806
|
}
|
|
805
807
|
}
|
|
806
808
|
}`;
|
|
807
|
-
var CHART_HISTORY_QUERY = `query ChartHistory($
|
|
808
|
-
chartHistory(
|
|
809
|
+
var CHART_HISTORY_QUERY = `query ChartHistory($pairId: ID!, $limit: Int) {
|
|
810
|
+
chartHistory(pairId: $pairId, limit: $limit) {
|
|
809
811
|
time o h l c volatility coefMults
|
|
810
812
|
}
|
|
811
813
|
}`;
|
|
@@ -826,9 +828,11 @@ var PairModule = class {
|
|
|
826
828
|
constructor(deps) {
|
|
827
829
|
this.#graphql = deps.graphql;
|
|
828
830
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
831
|
+
// REVIEW[bid-260602-v2]: keyed by pairId (the #2 game_pairs.id, e.g. "grid-ETH-USD").
|
|
832
|
+
// Dropped the `pair` symbol arg + `gameplaySlug` option — the gameplay is already
|
|
833
|
+
// encoded in pairId, and the server composes agencyPairId from agency context.
|
|
834
|
+
async get(pairId, opts) {
|
|
835
|
+
const variables = { pairId };
|
|
832
836
|
let body;
|
|
833
837
|
try {
|
|
834
838
|
body = await this.#graphql.request(PAIR_QUERY, variables, opts);
|
|
@@ -836,7 +840,7 @@ var PairModule = class {
|
|
|
836
840
|
if (err instanceof TaphubValidationError && err.code === "NotExist") {
|
|
837
841
|
throw new TaphubValidationError("Game not found for pair", {
|
|
838
842
|
code: "GameNotFound",
|
|
839
|
-
details: {
|
|
843
|
+
details: { pairId }
|
|
840
844
|
});
|
|
841
845
|
}
|
|
842
846
|
throw err;
|
|
@@ -844,7 +848,7 @@ var PairModule = class {
|
|
|
844
848
|
if (body.pair === null) {
|
|
845
849
|
throw new TaphubValidationError("Game not found for pair", {
|
|
846
850
|
code: "GameNotFound",
|
|
847
|
-
details: {
|
|
851
|
+
details: { pairId }
|
|
848
852
|
});
|
|
849
853
|
}
|
|
850
854
|
return normalisePair(body.pair);
|
|
@@ -857,8 +861,8 @@ var PairModule = class {
|
|
|
857
861
|
*
|
|
858
862
|
* @example
|
|
859
863
|
* const pairs = await client.pair.availableGamePairs({ gameplayId: 'taptrading' });
|
|
860
|
-
* const
|
|
861
|
-
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ??
|
|
864
|
+
* const pair = await client.pair.get(pairs[0].id);
|
|
865
|
+
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? pair.id, userId);
|
|
862
866
|
*/
|
|
863
867
|
async availableGamePairs(opts) {
|
|
864
868
|
const variables = {};
|
|
@@ -870,9 +874,9 @@ var PairModule = class {
|
|
|
870
874
|
);
|
|
871
875
|
return body.builderAvailableGamePairs.map(normalisePairInfo);
|
|
872
876
|
}
|
|
873
|
-
// REVIEW[bid-260602]: chartHistory param/variable renamed
|
|
874
|
-
async chartHistory(
|
|
875
|
-
const variables = {
|
|
877
|
+
// REVIEW[bid-260602-v2]: chartHistory param/variable renamed pairId (was: agencyPairId/gameId)
|
|
878
|
+
async chartHistory(pairId, limit, opts) {
|
|
879
|
+
const variables = { pairId };
|
|
876
880
|
if (limit !== void 0) {
|
|
877
881
|
variables.limit = limit;
|
|
878
882
|
}
|
|
@@ -899,17 +903,18 @@ var USER_SCOPED_SUFFIXES = ["bid_result", "balance_update"];
|
|
|
899
903
|
var TOPIC_PREFIX = "game";
|
|
900
904
|
var MARKET_TOPIC_PREFIX = "market";
|
|
901
905
|
var WALLET_TOPIC_PREFIX = "wallet";
|
|
906
|
+
var PUBLIC_PREFIX = "public";
|
|
902
907
|
function walletBalanceTopic(userId) {
|
|
903
908
|
return `${WALLET_TOPIC_PREFIX}/users/${userId}/balance`;
|
|
904
909
|
}
|
|
905
|
-
function agencyPairStatsTopic(aid,
|
|
906
|
-
return `public/agency/${aid}/pair/${
|
|
910
|
+
function agencyPairStatsTopic(aid, pairId) {
|
|
911
|
+
return `public/agency/${aid}/pair/${pairId}/stats`;
|
|
907
912
|
}
|
|
908
913
|
function topicFor(gameId, suffix, userId) {
|
|
909
914
|
if (USER_SCOPED_SUFFIXES.includes(suffix)) {
|
|
910
915
|
return `${TOPIC_PREFIX}/${gameId}/user/${userId}/${suffix}`;
|
|
911
916
|
}
|
|
912
|
-
return `${TOPIC_PREFIX}/${gameId}/${suffix}`;
|
|
917
|
+
return `${PUBLIC_PREFIX}/${TOPIC_PREFIX}/${gameId}/${suffix}`;
|
|
913
918
|
}
|
|
914
919
|
function normaliseUserId(userId) {
|
|
915
920
|
return userId && userId !== "" ? userId : null;
|
|
@@ -1063,28 +1068,28 @@ function createMqttTransport(endpoint, opts = {}) {
|
|
|
1063
1068
|
mqttClient.subscribe(t, { qos: 1 });
|
|
1064
1069
|
}
|
|
1065
1070
|
},
|
|
1066
|
-
subscribeCandle(
|
|
1067
|
-
const topic = `${MARKET_TOPIC_PREFIX}/${
|
|
1068
|
-
if (candleSubscriptions.has(
|
|
1071
|
+
subscribeCandle(pairId, onCandle) {
|
|
1072
|
+
const topic = `${PUBLIC_PREFIX}/${MARKET_TOPIC_PREFIX}/${pairId}/candle`;
|
|
1073
|
+
if (candleSubscriptions.has(pairId)) return;
|
|
1069
1074
|
const mqttClient = ensureConnected();
|
|
1070
|
-
candleSubscriptions.set(
|
|
1075
|
+
candleSubscriptions.set(pairId, { topic, onCandle });
|
|
1071
1076
|
mqttClient.subscribe(topic, { qos: 0 });
|
|
1072
1077
|
},
|
|
1073
|
-
unsubscribeCandle(
|
|
1074
|
-
const entry = candleSubscriptions.get(
|
|
1078
|
+
unsubscribeCandle(pairId) {
|
|
1079
|
+
const entry = candleSubscriptions.get(pairId);
|
|
1075
1080
|
if (!entry) return;
|
|
1076
1081
|
if (client) client.unsubscribe(entry.topic);
|
|
1077
|
-
candleSubscriptions.delete(
|
|
1082
|
+
candleSubscriptions.delete(pairId);
|
|
1078
1083
|
},
|
|
1079
|
-
subscribeAgencyPairStats(aid,
|
|
1080
|
-
const topic = agencyPairStatsTopic(aid,
|
|
1084
|
+
subscribeAgencyPairStats(aid, pairId, onStats) {
|
|
1085
|
+
const topic = agencyPairStatsTopic(aid, pairId);
|
|
1081
1086
|
if (statsSubscriptions.has(topic)) return;
|
|
1082
1087
|
const mqttClient = ensureConnected();
|
|
1083
1088
|
statsSubscriptions.set(topic, { topic, onStats });
|
|
1084
1089
|
mqttClient.subscribe(topic, { qos: 0 });
|
|
1085
1090
|
},
|
|
1086
|
-
unsubscribeAgencyPairStats(aid,
|
|
1087
|
-
const topic = agencyPairStatsTopic(aid,
|
|
1091
|
+
unsubscribeAgencyPairStats(aid, pairId) {
|
|
1092
|
+
const topic = agencyPairStatsTopic(aid, pairId);
|
|
1088
1093
|
const entry = statsSubscriptions.get(topic);
|
|
1089
1094
|
if (!entry) return;
|
|
1090
1095
|
if (client) client.unsubscribe(entry.topic);
|
|
@@ -1420,22 +1425,25 @@ var RealtimeModule = class extends import_eventemitter33.default {
|
|
|
1420
1425
|
this.#transport.unsubscribeWallet(cleanUserId);
|
|
1421
1426
|
}
|
|
1422
1427
|
/**
|
|
1423
|
-
* Subscribe to public market candle data for a pair
|
|
1424
|
-
* Independent of game/agency —
|
|
1428
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
1429
|
+
* (the #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of game/agency —
|
|
1430
|
+
* candle is market-wide public data.
|
|
1425
1431
|
*/
|
|
1426
|
-
|
|
1427
|
-
|
|
1432
|
+
// REVIEW[bid-260602-v2]: param pairId (was: pair) — slash-free #2 game_pairs.id.
|
|
1433
|
+
subscribeCandle(pairId, onCandle) {
|
|
1434
|
+
this.#transport.subscribeCandle(pairId, onCandle);
|
|
1428
1435
|
}
|
|
1429
|
-
/** Unsubscribe from candle data for a
|
|
1430
|
-
unsubscribeCandle(
|
|
1431
|
-
this.#transport.unsubscribeCandle(
|
|
1436
|
+
/** Unsubscribe from candle data for a pairId. */
|
|
1437
|
+
unsubscribeCandle(pairId) {
|
|
1438
|
+
this.#transport.unsubscribeCandle(pairId);
|
|
1432
1439
|
}
|
|
1433
1440
|
/**
|
|
1434
1441
|
* Subscribe to the live per-pair stats stream for the client's own agency.
|
|
1435
1442
|
* Scoped to the agency the client was constructed with — there is no argument
|
|
1436
1443
|
* to target another agency by design.
|
|
1437
1444
|
*/
|
|
1438
|
-
|
|
1445
|
+
// REVIEW[bid-260602-v2]: param pairId (was: gamePairId) — the #2 game_pairs.id.
|
|
1446
|
+
subscribeAgencyPairStats(pairId, handler) {
|
|
1439
1447
|
if (!this.#agencyId) {
|
|
1440
1448
|
throw new TaphubError("agencyId is required to subscribe to agency pair stats", {
|
|
1441
1449
|
code: "AgencyIdRequired"
|
|
@@ -1450,12 +1458,13 @@ var RealtimeModule = class extends import_eventemitter33.default {
|
|
|
1450
1458
|
ts: Number(p.ts)
|
|
1451
1459
|
});
|
|
1452
1460
|
};
|
|
1453
|
-
this.#transport.subscribeAgencyPairStats(this.#agencyId,
|
|
1461
|
+
this.#transport.subscribeAgencyPairStats(this.#agencyId, pairId, onStats);
|
|
1454
1462
|
}
|
|
1455
1463
|
/** Unsubscribe from the per-pair stats stream for the client's own agency. */
|
|
1456
|
-
|
|
1464
|
+
// REVIEW[bid-260602-v2]: param pairId (was: gamePairId).
|
|
1465
|
+
unsubscribeAgencyPairStats(pairId) {
|
|
1457
1466
|
if (!this.#agencyId) return;
|
|
1458
|
-
this.#transport.unsubscribeAgencyPairStats(this.#agencyId,
|
|
1467
|
+
this.#transport.unsubscribeAgencyPairStats(this.#agencyId, pairId);
|
|
1459
1468
|
}
|
|
1460
1469
|
disconnect() {
|
|
1461
1470
|
for (const entry of this.#entries.values()) {
|
package/dist/index.d.mts
CHANGED
|
@@ -71,8 +71,8 @@ interface AgencyPairFilter {
|
|
|
71
71
|
status?: AgencyPairStatus;
|
|
72
72
|
}
|
|
73
73
|
interface AgencyPairStats {
|
|
74
|
-
/** game_pairs.id
|
|
75
|
-
|
|
74
|
+
/** game_pairs.id, e.g. "grid-ETH-USD". Use to build the stats MQTT topic. */
|
|
75
|
+
pairId: string;
|
|
76
76
|
/** Display name, e.g. "ETH/USD". */
|
|
77
77
|
pair: string;
|
|
78
78
|
/** Icon URL. */
|
|
@@ -186,7 +186,7 @@ interface CancelBidResult {
|
|
|
186
186
|
newBalance: string;
|
|
187
187
|
}
|
|
188
188
|
interface PlaceBidInput {
|
|
189
|
-
|
|
189
|
+
pairId: string;
|
|
190
190
|
/**
|
|
191
191
|
* UUID of the user's wallet to debit. Required (non-optional) since
|
|
192
192
|
* grid-api's `PlaceBidInput.wallet_id` is NON_NULL (`ID!`). The SDK stays
|
|
@@ -230,7 +230,7 @@ declare class BidModule {
|
|
|
230
230
|
statuses?: BidStatus[];
|
|
231
231
|
limit?: number;
|
|
232
232
|
offset?: number;
|
|
233
|
-
|
|
233
|
+
pairId?: string;
|
|
234
234
|
signal?: AbortSignal;
|
|
235
235
|
}): Promise<Bid[]>;
|
|
236
236
|
}
|
|
@@ -405,8 +405,7 @@ interface PairModuleDeps {
|
|
|
405
405
|
declare class PairModule {
|
|
406
406
|
#private;
|
|
407
407
|
constructor(deps: PairModuleDeps);
|
|
408
|
-
get(
|
|
409
|
-
gameplaySlug?: string;
|
|
408
|
+
get(pairId: string, opts?: {
|
|
410
409
|
signal?: AbortSignal;
|
|
411
410
|
}): Promise<Pair>;
|
|
412
411
|
/**
|
|
@@ -417,14 +416,14 @@ declare class PairModule {
|
|
|
417
416
|
*
|
|
418
417
|
* @example
|
|
419
418
|
* const pairs = await client.pair.availableGamePairs({ gameplayId: 'taptrading' });
|
|
420
|
-
* const
|
|
421
|
-
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ??
|
|
419
|
+
* const pair = await client.pair.get(pairs[0].id);
|
|
420
|
+
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? pair.id, userId);
|
|
422
421
|
*/
|
|
423
422
|
availableGamePairs(opts?: {
|
|
424
423
|
gameplayId?: string;
|
|
425
424
|
signal?: AbortSignal;
|
|
426
425
|
}): Promise<PairInfo[]>;
|
|
427
|
-
chartHistory(
|
|
426
|
+
chartHistory(pairId: string, limit?: number, opts?: {
|
|
428
427
|
signal?: AbortSignal;
|
|
429
428
|
}): Promise<Candle[]>;
|
|
430
429
|
}
|
|
@@ -538,22 +537,23 @@ interface MqttTransport {
|
|
|
538
537
|
*/
|
|
539
538
|
unsubscribeAll(gameId: string, userId?: string | null): void;
|
|
540
539
|
/**
|
|
541
|
-
* Subscribe to public market candle data for a pair
|
|
542
|
-
*
|
|
543
|
-
*
|
|
540
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
541
|
+
* (the slash-free #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of
|
|
542
|
+
* game/agency context — candle is market-wide public data.
|
|
543
|
+
* Idempotent: multiple calls for the same pairId are deduplicated.
|
|
544
544
|
*/
|
|
545
|
-
subscribeCandle(
|
|
546
|
-
/** Tear down the candle subscription for a
|
|
547
|
-
unsubscribeCandle(
|
|
545
|
+
subscribeCandle(pairId: string, onCandle: MqttCandleHandler): void;
|
|
546
|
+
/** Tear down the candle subscription for a pairId. */
|
|
547
|
+
unsubscribeCandle(pairId: string): void;
|
|
548
548
|
/**
|
|
549
549
|
* Subscribe to the public per-pair stats stream for an agency, topic
|
|
550
|
-
* `public/agency/{aid}/pair/{
|
|
551
|
-
*
|
|
552
|
-
* Idempotent: multiple calls for the same `(aid,
|
|
550
|
+
* `public/agency/{aid}/pair/{pairId}/stats`. `aid` and `pairId` are used raw
|
|
551
|
+
* (no slash escaping — pairId is slash-free) to byte-match the backend publisher.
|
|
552
|
+
* Idempotent: multiple calls for the same `(aid, pairId)` are deduplicated.
|
|
553
553
|
*/
|
|
554
|
-
subscribeAgencyPairStats(aid: string,
|
|
555
|
-
/** Tear down the stats subscription for an `(aid,
|
|
556
|
-
unsubscribeAgencyPairStats(aid: string,
|
|
554
|
+
subscribeAgencyPairStats(aid: string, pairId: string, onStats: MqttAgencyPairStatsHandler): void;
|
|
555
|
+
/** Tear down the stats subscription for an `(aid, pairId)`. */
|
|
556
|
+
unsubscribeAgencyPairStats(aid: string, pairId: string): void;
|
|
557
557
|
/**
|
|
558
558
|
* Subscribe to the user-scoped wallet balance stream, topic
|
|
559
559
|
* `wallet/users/{userId}/balance`. Independent of any game subscription — NOT
|
|
@@ -667,7 +667,7 @@ interface MqttIdealConfigEvent {
|
|
|
667
667
|
}
|
|
668
668
|
/**
|
|
669
669
|
* Live per-pair stats tick from the public stream
|
|
670
|
-
* `public/agency/{aid}/pair/{
|
|
670
|
+
* `public/agency/{aid}/pair/{pairId}/stats`. The backend suppresses
|
|
671
671
|
* unchanged ticks, so a subscriber may not receive an event until price or
|
|
672
672
|
* vol24h actually moves — seed initial values from `agencyPairs.list()`.
|
|
673
673
|
*/
|
|
@@ -755,20 +755,21 @@ declare class RealtimeModule extends EventEmitter<RealtimeModuleEvents> {
|
|
|
755
755
|
*/
|
|
756
756
|
unsubscribeWallet(userId: string): void;
|
|
757
757
|
/**
|
|
758
|
-
* Subscribe to public market candle data for a pair
|
|
759
|
-
* Independent of game/agency —
|
|
758
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
759
|
+
* (the #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of game/agency —
|
|
760
|
+
* candle is market-wide public data.
|
|
760
761
|
*/
|
|
761
|
-
subscribeCandle(
|
|
762
|
-
/** Unsubscribe from candle data for a
|
|
763
|
-
unsubscribeCandle(
|
|
762
|
+
subscribeCandle(pairId: string, onCandle: MqttCandleHandler): void;
|
|
763
|
+
/** Unsubscribe from candle data for a pairId. */
|
|
764
|
+
unsubscribeCandle(pairId: string): void;
|
|
764
765
|
/**
|
|
765
766
|
* Subscribe to the live per-pair stats stream for the client's own agency.
|
|
766
767
|
* Scoped to the agency the client was constructed with — there is no argument
|
|
767
768
|
* to target another agency by design.
|
|
768
769
|
*/
|
|
769
|
-
subscribeAgencyPairStats(
|
|
770
|
+
subscribeAgencyPairStats(pairId: string, handler: (event: MqttAgencyPairStatsEvent) => void): void;
|
|
770
771
|
/** Unsubscribe from the per-pair stats stream for the client's own agency. */
|
|
771
|
-
unsubscribeAgencyPairStats(
|
|
772
|
+
unsubscribeAgencyPairStats(pairId: string): void;
|
|
772
773
|
disconnect(): void;
|
|
773
774
|
}
|
|
774
775
|
|
package/dist/index.d.ts
CHANGED
|
@@ -71,8 +71,8 @@ interface AgencyPairFilter {
|
|
|
71
71
|
status?: AgencyPairStatus;
|
|
72
72
|
}
|
|
73
73
|
interface AgencyPairStats {
|
|
74
|
-
/** game_pairs.id
|
|
75
|
-
|
|
74
|
+
/** game_pairs.id, e.g. "grid-ETH-USD". Use to build the stats MQTT topic. */
|
|
75
|
+
pairId: string;
|
|
76
76
|
/** Display name, e.g. "ETH/USD". */
|
|
77
77
|
pair: string;
|
|
78
78
|
/** Icon URL. */
|
|
@@ -186,7 +186,7 @@ interface CancelBidResult {
|
|
|
186
186
|
newBalance: string;
|
|
187
187
|
}
|
|
188
188
|
interface PlaceBidInput {
|
|
189
|
-
|
|
189
|
+
pairId: string;
|
|
190
190
|
/**
|
|
191
191
|
* UUID of the user's wallet to debit. Required (non-optional) since
|
|
192
192
|
* grid-api's `PlaceBidInput.wallet_id` is NON_NULL (`ID!`). The SDK stays
|
|
@@ -230,7 +230,7 @@ declare class BidModule {
|
|
|
230
230
|
statuses?: BidStatus[];
|
|
231
231
|
limit?: number;
|
|
232
232
|
offset?: number;
|
|
233
|
-
|
|
233
|
+
pairId?: string;
|
|
234
234
|
signal?: AbortSignal;
|
|
235
235
|
}): Promise<Bid[]>;
|
|
236
236
|
}
|
|
@@ -405,8 +405,7 @@ interface PairModuleDeps {
|
|
|
405
405
|
declare class PairModule {
|
|
406
406
|
#private;
|
|
407
407
|
constructor(deps: PairModuleDeps);
|
|
408
|
-
get(
|
|
409
|
-
gameplaySlug?: string;
|
|
408
|
+
get(pairId: string, opts?: {
|
|
410
409
|
signal?: AbortSignal;
|
|
411
410
|
}): Promise<Pair>;
|
|
412
411
|
/**
|
|
@@ -417,14 +416,14 @@ declare class PairModule {
|
|
|
417
416
|
*
|
|
418
417
|
* @example
|
|
419
418
|
* const pairs = await client.pair.availableGamePairs({ gameplayId: 'taptrading' });
|
|
420
|
-
* const
|
|
421
|
-
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ??
|
|
419
|
+
* const pair = await client.pair.get(pairs[0].id);
|
|
420
|
+
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? pair.id, userId);
|
|
422
421
|
*/
|
|
423
422
|
availableGamePairs(opts?: {
|
|
424
423
|
gameplayId?: string;
|
|
425
424
|
signal?: AbortSignal;
|
|
426
425
|
}): Promise<PairInfo[]>;
|
|
427
|
-
chartHistory(
|
|
426
|
+
chartHistory(pairId: string, limit?: number, opts?: {
|
|
428
427
|
signal?: AbortSignal;
|
|
429
428
|
}): Promise<Candle[]>;
|
|
430
429
|
}
|
|
@@ -538,22 +537,23 @@ interface MqttTransport {
|
|
|
538
537
|
*/
|
|
539
538
|
unsubscribeAll(gameId: string, userId?: string | null): void;
|
|
540
539
|
/**
|
|
541
|
-
* Subscribe to public market candle data for a pair
|
|
542
|
-
*
|
|
543
|
-
*
|
|
540
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
541
|
+
* (the slash-free #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of
|
|
542
|
+
* game/agency context — candle is market-wide public data.
|
|
543
|
+
* Idempotent: multiple calls for the same pairId are deduplicated.
|
|
544
544
|
*/
|
|
545
|
-
subscribeCandle(
|
|
546
|
-
/** Tear down the candle subscription for a
|
|
547
|
-
unsubscribeCandle(
|
|
545
|
+
subscribeCandle(pairId: string, onCandle: MqttCandleHandler): void;
|
|
546
|
+
/** Tear down the candle subscription for a pairId. */
|
|
547
|
+
unsubscribeCandle(pairId: string): void;
|
|
548
548
|
/**
|
|
549
549
|
* Subscribe to the public per-pair stats stream for an agency, topic
|
|
550
|
-
* `public/agency/{aid}/pair/{
|
|
551
|
-
*
|
|
552
|
-
* Idempotent: multiple calls for the same `(aid,
|
|
550
|
+
* `public/agency/{aid}/pair/{pairId}/stats`. `aid` and `pairId` are used raw
|
|
551
|
+
* (no slash escaping — pairId is slash-free) to byte-match the backend publisher.
|
|
552
|
+
* Idempotent: multiple calls for the same `(aid, pairId)` are deduplicated.
|
|
553
553
|
*/
|
|
554
|
-
subscribeAgencyPairStats(aid: string,
|
|
555
|
-
/** Tear down the stats subscription for an `(aid,
|
|
556
|
-
unsubscribeAgencyPairStats(aid: string,
|
|
554
|
+
subscribeAgencyPairStats(aid: string, pairId: string, onStats: MqttAgencyPairStatsHandler): void;
|
|
555
|
+
/** Tear down the stats subscription for an `(aid, pairId)`. */
|
|
556
|
+
unsubscribeAgencyPairStats(aid: string, pairId: string): void;
|
|
557
557
|
/**
|
|
558
558
|
* Subscribe to the user-scoped wallet balance stream, topic
|
|
559
559
|
* `wallet/users/{userId}/balance`. Independent of any game subscription — NOT
|
|
@@ -667,7 +667,7 @@ interface MqttIdealConfigEvent {
|
|
|
667
667
|
}
|
|
668
668
|
/**
|
|
669
669
|
* Live per-pair stats tick from the public stream
|
|
670
|
-
* `public/agency/{aid}/pair/{
|
|
670
|
+
* `public/agency/{aid}/pair/{pairId}/stats`. The backend suppresses
|
|
671
671
|
* unchanged ticks, so a subscriber may not receive an event until price or
|
|
672
672
|
* vol24h actually moves — seed initial values from `agencyPairs.list()`.
|
|
673
673
|
*/
|
|
@@ -755,20 +755,21 @@ declare class RealtimeModule extends EventEmitter<RealtimeModuleEvents> {
|
|
|
755
755
|
*/
|
|
756
756
|
unsubscribeWallet(userId: string): void;
|
|
757
757
|
/**
|
|
758
|
-
* Subscribe to public market candle data for a pair
|
|
759
|
-
* Independent of game/agency —
|
|
758
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
759
|
+
* (the #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of game/agency —
|
|
760
|
+
* candle is market-wide public data.
|
|
760
761
|
*/
|
|
761
|
-
subscribeCandle(
|
|
762
|
-
/** Unsubscribe from candle data for a
|
|
763
|
-
unsubscribeCandle(
|
|
762
|
+
subscribeCandle(pairId: string, onCandle: MqttCandleHandler): void;
|
|
763
|
+
/** Unsubscribe from candle data for a pairId. */
|
|
764
|
+
unsubscribeCandle(pairId: string): void;
|
|
764
765
|
/**
|
|
765
766
|
* Subscribe to the live per-pair stats stream for the client's own agency.
|
|
766
767
|
* Scoped to the agency the client was constructed with — there is no argument
|
|
767
768
|
* to target another agency by design.
|
|
768
769
|
*/
|
|
769
|
-
subscribeAgencyPairStats(
|
|
770
|
+
subscribeAgencyPairStats(pairId: string, handler: (event: MqttAgencyPairStatsEvent) => void): void;
|
|
770
771
|
/** Unsubscribe from the per-pair stats stream for the client's own agency. */
|
|
771
|
-
unsubscribeAgencyPairStats(
|
|
772
|
+
unsubscribeAgencyPairStats(pairId: string): void;
|
|
772
773
|
disconnect(): void;
|
|
773
774
|
}
|
|
774
775
|
|
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ function normaliseAgencyPairs(rows) {
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
return rows.map((row) => ({
|
|
77
|
-
|
|
77
|
+
pairId: row.pairId,
|
|
78
78
|
pair: row.pair,
|
|
79
79
|
thumb: row.thumb,
|
|
80
80
|
ordering: Number(row.ordering),
|
|
@@ -88,7 +88,7 @@ function normaliseAgencyPairs(rows) {
|
|
|
88
88
|
// src/modules/agencyPair/queries.ts
|
|
89
89
|
var FETCH_AGENCY_PAIRS_QUERY = `query FetchAgencyPairs($filter: AgencyPairFilter) {
|
|
90
90
|
fetchAgencyPairs(filter: $filter) {
|
|
91
|
-
|
|
91
|
+
pairId pair thumb ordering status maxCoef currentPrice currentVol24h
|
|
92
92
|
}
|
|
93
93
|
}`;
|
|
94
94
|
|
|
@@ -414,8 +414,8 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
414
414
|
id user_id game_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at
|
|
415
415
|
}
|
|
416
416
|
}`;
|
|
417
|
-
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $
|
|
418
|
-
myBids(statuses: $statuses, limit: $limit, offset: $offset,
|
|
417
|
+
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
418
|
+
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
419
419
|
id user_id game_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at
|
|
420
420
|
}
|
|
421
421
|
}`;
|
|
@@ -443,7 +443,9 @@ var BidModule = class {
|
|
|
443
443
|
async placeBid(input, opts) {
|
|
444
444
|
const variables = {
|
|
445
445
|
input: {
|
|
446
|
-
|
|
446
|
+
// REVIEW[bid-260602-v2]: input field pairId (was: game_id) — the #2 game_pairs.id.
|
|
447
|
+
// Server composes the agencyPairId composite and stores it in bids.game_id (frozen).
|
|
448
|
+
pairId: input.pairId,
|
|
447
449
|
// wallet_id is forwarded as-is — grid-api enforces ownership +
|
|
448
450
|
// currency validation. See openspec/bid-260518-wallet-id D1/D8.
|
|
449
451
|
wallet_id: input.walletId,
|
|
@@ -467,7 +469,7 @@ var BidModule = class {
|
|
|
467
469
|
if (err instanceof TaphubValidationError && err.code === "NotExist") {
|
|
468
470
|
throw new TaphubValidationError("Game not found", {
|
|
469
471
|
code: "GameNotFound",
|
|
470
|
-
details: {
|
|
472
|
+
details: { pairId: input.pairId }
|
|
471
473
|
});
|
|
472
474
|
}
|
|
473
475
|
throw err;
|
|
@@ -498,8 +500,8 @@ var BidModule = class {
|
|
|
498
500
|
if (opts?.offset !== void 0) {
|
|
499
501
|
variables.offset = opts.offset;
|
|
500
502
|
}
|
|
501
|
-
if (opts?.
|
|
502
|
-
variables.
|
|
503
|
+
if (opts?.pairId !== void 0) {
|
|
504
|
+
variables.pairId = opts.pairId;
|
|
503
505
|
}
|
|
504
506
|
const body = await this.#graphql.request(
|
|
505
507
|
MY_BIDS_QUERY,
|
|
@@ -729,8 +731,8 @@ function normalisePairInfo(node) {
|
|
|
729
731
|
}
|
|
730
732
|
|
|
731
733
|
// src/modules/pair/queries.ts
|
|
732
|
-
var PAIR_QUERY = `query Pair($
|
|
733
|
-
pair(
|
|
734
|
+
var PAIR_QUERY = `query Pair($pairId: ID!) {
|
|
735
|
+
pair(pairId: $pairId) {
|
|
734
736
|
id pair status created_at
|
|
735
737
|
config {
|
|
736
738
|
gridConfig { cellSizeTime cellSizeValue candleSize baseline baselineTime }
|
|
@@ -739,8 +741,8 @@ var PAIR_QUERY = `query Pair($pair: String!, $gameplaySlug: String) {
|
|
|
739
741
|
}
|
|
740
742
|
}
|
|
741
743
|
}`;
|
|
742
|
-
var CHART_HISTORY_QUERY = `query ChartHistory($
|
|
743
|
-
chartHistory(
|
|
744
|
+
var CHART_HISTORY_QUERY = `query ChartHistory($pairId: ID!, $limit: Int) {
|
|
745
|
+
chartHistory(pairId: $pairId, limit: $limit) {
|
|
744
746
|
time o h l c volatility coefMults
|
|
745
747
|
}
|
|
746
748
|
}`;
|
|
@@ -761,9 +763,11 @@ var PairModule = class {
|
|
|
761
763
|
constructor(deps) {
|
|
762
764
|
this.#graphql = deps.graphql;
|
|
763
765
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
766
|
+
// REVIEW[bid-260602-v2]: keyed by pairId (the #2 game_pairs.id, e.g. "grid-ETH-USD").
|
|
767
|
+
// Dropped the `pair` symbol arg + `gameplaySlug` option — the gameplay is already
|
|
768
|
+
// encoded in pairId, and the server composes agencyPairId from agency context.
|
|
769
|
+
async get(pairId, opts) {
|
|
770
|
+
const variables = { pairId };
|
|
767
771
|
let body;
|
|
768
772
|
try {
|
|
769
773
|
body = await this.#graphql.request(PAIR_QUERY, variables, opts);
|
|
@@ -771,7 +775,7 @@ var PairModule = class {
|
|
|
771
775
|
if (err instanceof TaphubValidationError && err.code === "NotExist") {
|
|
772
776
|
throw new TaphubValidationError("Game not found for pair", {
|
|
773
777
|
code: "GameNotFound",
|
|
774
|
-
details: {
|
|
778
|
+
details: { pairId }
|
|
775
779
|
});
|
|
776
780
|
}
|
|
777
781
|
throw err;
|
|
@@ -779,7 +783,7 @@ var PairModule = class {
|
|
|
779
783
|
if (body.pair === null) {
|
|
780
784
|
throw new TaphubValidationError("Game not found for pair", {
|
|
781
785
|
code: "GameNotFound",
|
|
782
|
-
details: {
|
|
786
|
+
details: { pairId }
|
|
783
787
|
});
|
|
784
788
|
}
|
|
785
789
|
return normalisePair(body.pair);
|
|
@@ -792,8 +796,8 @@ var PairModule = class {
|
|
|
792
796
|
*
|
|
793
797
|
* @example
|
|
794
798
|
* const pairs = await client.pair.availableGamePairs({ gameplayId: 'taptrading' });
|
|
795
|
-
* const
|
|
796
|
-
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ??
|
|
799
|
+
* const pair = await client.pair.get(pairs[0].id);
|
|
800
|
+
* const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? pair.id, userId);
|
|
797
801
|
*/
|
|
798
802
|
async availableGamePairs(opts) {
|
|
799
803
|
const variables = {};
|
|
@@ -805,9 +809,9 @@ var PairModule = class {
|
|
|
805
809
|
);
|
|
806
810
|
return body.builderAvailableGamePairs.map(normalisePairInfo);
|
|
807
811
|
}
|
|
808
|
-
// REVIEW[bid-260602]: chartHistory param/variable renamed
|
|
809
|
-
async chartHistory(
|
|
810
|
-
const variables = {
|
|
812
|
+
// REVIEW[bid-260602-v2]: chartHistory param/variable renamed pairId (was: agencyPairId/gameId)
|
|
813
|
+
async chartHistory(pairId, limit, opts) {
|
|
814
|
+
const variables = { pairId };
|
|
811
815
|
if (limit !== void 0) {
|
|
812
816
|
variables.limit = limit;
|
|
813
817
|
}
|
|
@@ -834,17 +838,18 @@ var USER_SCOPED_SUFFIXES = ["bid_result", "balance_update"];
|
|
|
834
838
|
var TOPIC_PREFIX = "game";
|
|
835
839
|
var MARKET_TOPIC_PREFIX = "market";
|
|
836
840
|
var WALLET_TOPIC_PREFIX = "wallet";
|
|
841
|
+
var PUBLIC_PREFIX = "public";
|
|
837
842
|
function walletBalanceTopic(userId) {
|
|
838
843
|
return `${WALLET_TOPIC_PREFIX}/users/${userId}/balance`;
|
|
839
844
|
}
|
|
840
|
-
function agencyPairStatsTopic(aid,
|
|
841
|
-
return `public/agency/${aid}/pair/${
|
|
845
|
+
function agencyPairStatsTopic(aid, pairId) {
|
|
846
|
+
return `public/agency/${aid}/pair/${pairId}/stats`;
|
|
842
847
|
}
|
|
843
848
|
function topicFor(gameId, suffix, userId) {
|
|
844
849
|
if (USER_SCOPED_SUFFIXES.includes(suffix)) {
|
|
845
850
|
return `${TOPIC_PREFIX}/${gameId}/user/${userId}/${suffix}`;
|
|
846
851
|
}
|
|
847
|
-
return `${TOPIC_PREFIX}/${gameId}/${suffix}`;
|
|
852
|
+
return `${PUBLIC_PREFIX}/${TOPIC_PREFIX}/${gameId}/${suffix}`;
|
|
848
853
|
}
|
|
849
854
|
function normaliseUserId(userId) {
|
|
850
855
|
return userId && userId !== "" ? userId : null;
|
|
@@ -998,28 +1003,28 @@ function createMqttTransport(endpoint, opts = {}) {
|
|
|
998
1003
|
mqttClient.subscribe(t, { qos: 1 });
|
|
999
1004
|
}
|
|
1000
1005
|
},
|
|
1001
|
-
subscribeCandle(
|
|
1002
|
-
const topic = `${MARKET_TOPIC_PREFIX}/${
|
|
1003
|
-
if (candleSubscriptions.has(
|
|
1006
|
+
subscribeCandle(pairId, onCandle) {
|
|
1007
|
+
const topic = `${PUBLIC_PREFIX}/${MARKET_TOPIC_PREFIX}/${pairId}/candle`;
|
|
1008
|
+
if (candleSubscriptions.has(pairId)) return;
|
|
1004
1009
|
const mqttClient = ensureConnected();
|
|
1005
|
-
candleSubscriptions.set(
|
|
1010
|
+
candleSubscriptions.set(pairId, { topic, onCandle });
|
|
1006
1011
|
mqttClient.subscribe(topic, { qos: 0 });
|
|
1007
1012
|
},
|
|
1008
|
-
unsubscribeCandle(
|
|
1009
|
-
const entry = candleSubscriptions.get(
|
|
1013
|
+
unsubscribeCandle(pairId) {
|
|
1014
|
+
const entry = candleSubscriptions.get(pairId);
|
|
1010
1015
|
if (!entry) return;
|
|
1011
1016
|
if (client) client.unsubscribe(entry.topic);
|
|
1012
|
-
candleSubscriptions.delete(
|
|
1017
|
+
candleSubscriptions.delete(pairId);
|
|
1013
1018
|
},
|
|
1014
|
-
subscribeAgencyPairStats(aid,
|
|
1015
|
-
const topic = agencyPairStatsTopic(aid,
|
|
1019
|
+
subscribeAgencyPairStats(aid, pairId, onStats) {
|
|
1020
|
+
const topic = agencyPairStatsTopic(aid, pairId);
|
|
1016
1021
|
if (statsSubscriptions.has(topic)) return;
|
|
1017
1022
|
const mqttClient = ensureConnected();
|
|
1018
1023
|
statsSubscriptions.set(topic, { topic, onStats });
|
|
1019
1024
|
mqttClient.subscribe(topic, { qos: 0 });
|
|
1020
1025
|
},
|
|
1021
|
-
unsubscribeAgencyPairStats(aid,
|
|
1022
|
-
const topic = agencyPairStatsTopic(aid,
|
|
1026
|
+
unsubscribeAgencyPairStats(aid, pairId) {
|
|
1027
|
+
const topic = agencyPairStatsTopic(aid, pairId);
|
|
1023
1028
|
const entry = statsSubscriptions.get(topic);
|
|
1024
1029
|
if (!entry) return;
|
|
1025
1030
|
if (client) client.unsubscribe(entry.topic);
|
|
@@ -1355,22 +1360,25 @@ var RealtimeModule = class extends EventEmitter3 {
|
|
|
1355
1360
|
this.#transport.unsubscribeWallet(cleanUserId);
|
|
1356
1361
|
}
|
|
1357
1362
|
/**
|
|
1358
|
-
* Subscribe to public market candle data for a pair
|
|
1359
|
-
* Independent of game/agency —
|
|
1363
|
+
* Subscribe to public market candle data for a pair, keyed by pairId
|
|
1364
|
+
* (the #2 game_pairs.id, e.g. "grid-ETH-USD"). Independent of game/agency —
|
|
1365
|
+
* candle is market-wide public data.
|
|
1360
1366
|
*/
|
|
1361
|
-
|
|
1362
|
-
|
|
1367
|
+
// REVIEW[bid-260602-v2]: param pairId (was: pair) — slash-free #2 game_pairs.id.
|
|
1368
|
+
subscribeCandle(pairId, onCandle) {
|
|
1369
|
+
this.#transport.subscribeCandle(pairId, onCandle);
|
|
1363
1370
|
}
|
|
1364
|
-
/** Unsubscribe from candle data for a
|
|
1365
|
-
unsubscribeCandle(
|
|
1366
|
-
this.#transport.unsubscribeCandle(
|
|
1371
|
+
/** Unsubscribe from candle data for a pairId. */
|
|
1372
|
+
unsubscribeCandle(pairId) {
|
|
1373
|
+
this.#transport.unsubscribeCandle(pairId);
|
|
1367
1374
|
}
|
|
1368
1375
|
/**
|
|
1369
1376
|
* Subscribe to the live per-pair stats stream for the client's own agency.
|
|
1370
1377
|
* Scoped to the agency the client was constructed with — there is no argument
|
|
1371
1378
|
* to target another agency by design.
|
|
1372
1379
|
*/
|
|
1373
|
-
|
|
1380
|
+
// REVIEW[bid-260602-v2]: param pairId (was: gamePairId) — the #2 game_pairs.id.
|
|
1381
|
+
subscribeAgencyPairStats(pairId, handler) {
|
|
1374
1382
|
if (!this.#agencyId) {
|
|
1375
1383
|
throw new TaphubError("agencyId is required to subscribe to agency pair stats", {
|
|
1376
1384
|
code: "AgencyIdRequired"
|
|
@@ -1385,12 +1393,13 @@ var RealtimeModule = class extends EventEmitter3 {
|
|
|
1385
1393
|
ts: Number(p.ts)
|
|
1386
1394
|
});
|
|
1387
1395
|
};
|
|
1388
|
-
this.#transport.subscribeAgencyPairStats(this.#agencyId,
|
|
1396
|
+
this.#transport.subscribeAgencyPairStats(this.#agencyId, pairId, onStats);
|
|
1389
1397
|
}
|
|
1390
1398
|
/** Unsubscribe from the per-pair stats stream for the client's own agency. */
|
|
1391
|
-
|
|
1399
|
+
// REVIEW[bid-260602-v2]: param pairId (was: gamePairId).
|
|
1400
|
+
unsubscribeAgencyPairStats(pairId) {
|
|
1392
1401
|
if (!this.#agencyId) return;
|
|
1393
|
-
this.#transport.unsubscribeAgencyPairStats(this.#agencyId,
|
|
1402
|
+
this.#transport.unsubscribeAgencyPairStats(this.#agencyId, pairId);
|
|
1394
1403
|
}
|
|
1395
1404
|
disconnect() {
|
|
1396
1405
|
for (const entry of this.#entries.values()) {
|