@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 CHANGED
@@ -139,10 +139,11 @@ function normaliseAgencyPairs(rows) {
139
139
  });
140
140
  }
141
141
  return rows.map((row) => ({
142
- gamePairId: row.gamePairId,
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
- gamePairId pair thumb ordering maxCoef currentPrice currentVol24h
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, $gameId: ID) {
482
- myBids(statuses: $statuses, limit: $limit, offset: $offset, gameId: $gameId) {
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
- game_id: input.gameId,
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: { gameId: input.gameId }
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?.gameId !== void 0) {
566
- variables.gameId = opts.gameId;
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($pair: String!, $gameplaySlug: String) {
797
- pair(pair: $pair, gameplaySlug: $gameplaySlug) {
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($agencyPairId: ID!, $limit: Int) {
807
- chartHistory(agencyPairId: $agencyPairId, limit: $limit) {
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
- async get(pair, opts) {
829
- const variables = { pair };
830
- if (opts?.gameplaySlug) variables.gameplaySlug = opts.gameplaySlug;
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: { pair }
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: { pair }
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 game = await client.pair.get(pairs[0].pair, { gameplaySlug: pairs[0].gameplayId });
860
- * const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? game.id, userId);
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 agencyPairId (was: gameId)
873
- async chartHistory(agencyPairId, limit, opts) {
874
- const variables = { agencyPairId };
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, gamePairId) {
905
- return `public/agency/${aid}/pair/${gamePairId}/stats`;
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(pair, onCandle) {
1066
- const topic = `${MARKET_TOPIC_PREFIX}/${pair.replace(/\//g, "_")}/candle`;
1067
- if (candleSubscriptions.has(pair)) return;
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(pair, { topic, onCandle });
1074
+ candleSubscriptions.set(pairId, { topic, onCandle });
1070
1075
  mqttClient.subscribe(topic, { qos: 0 });
1071
1076
  },
1072
- unsubscribeCandle(pair) {
1073
- const entry = candleSubscriptions.get(pair);
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(pair);
1081
+ candleSubscriptions.delete(pairId);
1077
1082
  },
1078
- subscribeAgencyPairStats(aid, gamePairId, onStats) {
1079
- const topic = agencyPairStatsTopic(aid, gamePairId);
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, gamePairId) {
1086
- const topic = agencyPairStatsTopic(aid, gamePairId);
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 (e.g. "ETH/USD").
1423
- * Independent of game/agency — candle is market-wide public data.
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
- subscribeCandle(pair, onCandle) {
1426
- this.#transport.subscribeCandle(pair, onCandle);
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 pair. */
1429
- unsubscribeCandle(pair) {
1430
- this.#transport.unsubscribeCandle(pair);
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
- subscribeAgencyPairStats(gamePairId, handler) {
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, gamePairId, onStats);
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
- unsubscribeAgencyPairStats(gamePairId) {
1463
+ // REVIEW[bid-260602-v2]: param pairId (was: gamePairId).
1464
+ unsubscribeAgencyPairStats(pairId) {
1456
1465
  if (!this.#agencyId) return;
1457
- this.#transport.unsubscribeAgencyPairStats(this.#agencyId, gamePairId);
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 slug, e.g. "grid-ETH-USD". Use to build the stats MQTT topic. */
75
- gamePairId: string;
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
- gameId: string;
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
- gameId?: string;
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(pair: string, opts?: {
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 game = await client.pair.get(pairs[0].pair, { gameplaySlug: pairs[0].gameplayId });
419
- * const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? game.id, userId);
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(agencyPairId: string, limit?: number, opts?: {
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 (e.g. "ETH/USD").
540
- * Independent of game/agency context candle is market-wide public data.
541
- * Idempotent: multiple calls for the same pair are deduplicated.
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(pair: string, onCandle: MqttCandleHandler): void;
544
- /** Tear down the candle subscription for a pair. */
545
- unsubscribeCandle(pair: string): void;
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/{gamePairId}/stats`. `aid` and `gamePairId` are
549
- * used raw (no slash escaping) to byte-match the backend publisher.
550
- * Idempotent: multiple calls for the same `(aid, gamePairId)` are deduplicated.
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, gamePairId: string, onStats: MqttAgencyPairStatsHandler): void;
553
- /** Tear down the stats subscription for an `(aid, gamePairId)`. */
554
- unsubscribeAgencyPairStats(aid: string, gamePairId: string): void;
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/{gamePairId}/stats`. The backend suppresses
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 (e.g. "ETH/USD").
757
- * Independent of game/agency — candle is market-wide public data.
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(pair: string, onCandle: MqttCandleHandler): void;
760
- /** Unsubscribe from candle data for a pair. */
761
- unsubscribeCandle(pair: string): void;
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(gamePairId: string, handler: (event: MqttAgencyPairStatsEvent) => void): void;
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(gamePairId: string): void;
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 slug, e.g. "grid-ETH-USD". Use to build the stats MQTT topic. */
75
- gamePairId: string;
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
- gameId: string;
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
- gameId?: string;
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(pair: string, opts?: {
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 game = await client.pair.get(pairs[0].pair, { gameplaySlug: pairs[0].gameplayId });
419
- * const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? game.id, userId);
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(agencyPairId: string, limit?: number, opts?: {
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 (e.g. "ETH/USD").
540
- * Independent of game/agency context candle is market-wide public data.
541
- * Idempotent: multiple calls for the same pair are deduplicated.
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(pair: string, onCandle: MqttCandleHandler): void;
544
- /** Tear down the candle subscription for a pair. */
545
- unsubscribeCandle(pair: string): void;
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/{gamePairId}/stats`. `aid` and `gamePairId` are
549
- * used raw (no slash escaping) to byte-match the backend publisher.
550
- * Idempotent: multiple calls for the same `(aid, gamePairId)` are deduplicated.
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, gamePairId: string, onStats: MqttAgencyPairStatsHandler): void;
553
- /** Tear down the stats subscription for an `(aid, gamePairId)`. */
554
- unsubscribeAgencyPairStats(aid: string, gamePairId: string): void;
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/{gamePairId}/stats`. The backend suppresses
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 (e.g. "ETH/USD").
757
- * Independent of game/agency — candle is market-wide public data.
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(pair: string, onCandle: MqttCandleHandler): void;
760
- /** Unsubscribe from candle data for a pair. */
761
- unsubscribeCandle(pair: string): void;
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(gamePairId: string, handler: (event: MqttAgencyPairStatsEvent) => void): void;
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(gamePairId: string): void;
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
- gamePairId: row.gamePairId,
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
- gamePairId pair thumb ordering maxCoef currentPrice currentVol24h
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, $gameId: ID) {
417
- myBids(statuses: $statuses, limit: $limit, offset: $offset, gameId: $gameId) {
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
- game_id: input.gameId,
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: { gameId: input.gameId }
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?.gameId !== void 0) {
501
- variables.gameId = opts.gameId;
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($pair: String!, $gameplaySlug: String) {
732
- pair(pair: $pair, gameplaySlug: $gameplaySlug) {
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($agencyPairId: ID!, $limit: Int) {
742
- chartHistory(agencyPairId: $agencyPairId, limit: $limit) {
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
- async get(pair, opts) {
764
- const variables = { pair };
765
- if (opts?.gameplaySlug) variables.gameplaySlug = opts.gameplaySlug;
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: { pair }
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: { pair }
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 game = await client.pair.get(pairs[0].pair, { gameplaySlug: pairs[0].gameplayId });
795
- * const ch = client.realtime?.subscribe(pairs[0].agencyPairId ?? game.id, userId);
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 agencyPairId (was: gameId)
808
- async chartHistory(agencyPairId, limit, opts) {
809
- const variables = { agencyPairId };
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, gamePairId) {
840
- return `public/agency/${aid}/pair/${gamePairId}/stats`;
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(pair, onCandle) {
1001
- const topic = `${MARKET_TOPIC_PREFIX}/${pair.replace(/\//g, "_")}/candle`;
1002
- if (candleSubscriptions.has(pair)) return;
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(pair, { topic, onCandle });
1009
+ candleSubscriptions.set(pairId, { topic, onCandle });
1005
1010
  mqttClient.subscribe(topic, { qos: 0 });
1006
1011
  },
1007
- unsubscribeCandle(pair) {
1008
- const entry = candleSubscriptions.get(pair);
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(pair);
1016
+ candleSubscriptions.delete(pairId);
1012
1017
  },
1013
- subscribeAgencyPairStats(aid, gamePairId, onStats) {
1014
- const topic = agencyPairStatsTopic(aid, gamePairId);
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, gamePairId) {
1021
- const topic = agencyPairStatsTopic(aid, gamePairId);
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 (e.g. "ETH/USD").
1358
- * Independent of game/agency — candle is market-wide public data.
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
- subscribeCandle(pair, onCandle) {
1361
- this.#transport.subscribeCandle(pair, onCandle);
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 pair. */
1364
- unsubscribeCandle(pair) {
1365
- this.#transport.unsubscribeCandle(pair);
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
- subscribeAgencyPairStats(gamePairId, handler) {
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, gamePairId, onStats);
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
- unsubscribeAgencyPairStats(gamePairId) {
1398
+ // REVIEW[bid-260602-v2]: param pairId (was: gamePairId).
1399
+ unsubscribeAgencyPairStats(pairId) {
1391
1400
  if (!this.#agencyId) return;
1392
- this.#transport.unsubscribeAgencyPairStats(this.#agencyId, gamePairId);
1401
+ this.#transport.unsubscribeAgencyPairStats(this.#agencyId, pairId);
1393
1402
  }
1394
1403
  disconnect() {
1395
1404
  for (const entry of this.#entries.values()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taphubhq/sdk-core",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "Core SDK for building on the TabHub platform",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",