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