@taphubhq/sdk-core 0.20.0 → 0.21.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
@@ -608,6 +608,41 @@ function normaliseLeaderboard(rows) {
608
608
  gain: row.gain
609
609
  }));
610
610
  }
611
+ function normaliseRankEntry(row) {
612
+ return {
613
+ userId: row.userId,
614
+ loginBy: row.loginBy,
615
+ username: row.username,
616
+ rank: row.rank,
617
+ pnl: row.pnl,
618
+ vol: row.vol,
619
+ payout: row.payout,
620
+ wins: row.wins,
621
+ bids: row.bids
622
+ };
623
+ }
624
+ function normaliseRankBoard(wire) {
625
+ if (wire == null || typeof wire !== "object") {
626
+ throw new TaphubServerError("Invalid response from server", {
627
+ code: "InvalidResponse"
628
+ });
629
+ }
630
+ return {
631
+ period: wire.period,
632
+ range: { from: wire.range?.from, to: wire.range?.to },
633
+ sort: wire.sort,
634
+ sortDir: wire.sortDir,
635
+ total: wire.total,
636
+ entries: Array.isArray(wire.entries) ? wire.entries.map(normaliseRankEntry) : []
637
+ };
638
+ }
639
+ function normaliseRankMe(wire) {
640
+ return {
641
+ rank: wire.rank,
642
+ total: wire.total,
643
+ entry: wire.entry ? normaliseRankEntry(wire.entry) : null
644
+ };
645
+ }
611
646
 
612
647
  // src/modules/leaderboard/queries.ts
613
648
  var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!) {
@@ -615,6 +650,23 @@ var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!)
615
650
  user_id username rank total_bids total_wins total_wagered total_payout gain
616
651
  }
617
652
  }`;
653
+ var RANK_LEADERBOARD_V2_QUERY = `query RankLeaderboardV2($input: RankBoardInput!) {
654
+ rank_leaderboardV2(input: $input) {
655
+ period
656
+ range { from to }
657
+ sort
658
+ sortDir
659
+ total
660
+ entries { userId loginBy username rank pnl vol payout wins bids }
661
+ }
662
+ }`;
663
+ var RANK_ME_QUERY = `query RankMe($input: RankMeInput!) {
664
+ rank_me(input: $input) {
665
+ rank
666
+ total
667
+ entry { userId loginBy username rank pnl vol payout wins bids }
668
+ }
669
+ }`;
618
670
 
619
671
  // src/modules/leaderboard/index.ts
620
672
  var LeaderboardModule = class {
@@ -622,6 +674,11 @@ var LeaderboardModule = class {
622
674
  constructor(deps) {
623
675
  this.#graphql = deps.graphql;
624
676
  }
677
+ /**
678
+ * @deprecated Use {@link LeaderboardModule.rankBoard}. The backend
679
+ * `leaderboard` query is `@deprecated` in favour of `rank_leaderboardV2`
680
+ * (duration presets, pnl/vol sort, pagination, current-user `me`).
681
+ */
625
682
  async list(args) {
626
683
  const body = await this.#graphql.publicRequest(
627
684
  LEADERBOARD_QUERY,
@@ -630,6 +687,55 @@ var LeaderboardModule = class {
630
687
  );
631
688
  return normaliseLeaderboard(body.leaderboard);
632
689
  }
690
+ /**
691
+ * Fetch the public duration-scoped rank board (`rank_leaderboardV2`).
692
+ *
693
+ * Supports the fixed period presets plus `custom` (which requires an
694
+ * hour-aligned `range`), `pnl`/`vol` sort with an explicit direction, offset
695
+ * pagination, and a `total` count for "#X of N" UI. Optional args are omitted
696
+ * from the wire `input` when undefined so the server defaults apply
697
+ * (`sort = pnl`, `sortDir = desc`, `limit = 50`, `offset = 0`).
698
+ *
699
+ * bid-260606-leaderboard-split-my-rank: the board is **public and identical for
700
+ * every caller** — it carries no per-user data. For the signed-in caller's own
701
+ * row+rank, use {@link LeaderboardModule.myRank}.
702
+ */
703
+ async rankBoard(args) {
704
+ const input = { period: args.period };
705
+ if (args.range) input.range = { from: args.range.from, to: args.range.to };
706
+ if (args.sort) input.sort = args.sort;
707
+ if (args.sortDir) input.sortDir = args.sortDir;
708
+ if (args.limit != null || args.offset != null) {
709
+ input.p = { limit: args.limit, offset: args.offset };
710
+ }
711
+ const body = await this.#graphql.publicRequest(
712
+ RANK_LEADERBOARD_V2_QUERY,
713
+ { input },
714
+ args.signal ? { signal: args.signal } : void 0
715
+ );
716
+ return normaliseRankBoard(body.rank_leaderboardV2);
717
+ }
718
+ /**
719
+ * Fetch the signed-in caller's own row + rank for the same window (`rank_me`) —
720
+ * the per-user companion to {@link LeaderboardModule.rankBoard}.
721
+ *
722
+ * Unlike the board, this attaches the user JWT (`request`, not `publicRequest`)
723
+ * so the backend resolves the caller. Returns `null` when no user is signed in
724
+ * (the backend returns `rank_me: null`). `MyRank.entry` is `null` when the
725
+ * caller has no activity in the window.
726
+ */
727
+ async myRank(args) {
728
+ const input = { period: args.period };
729
+ if (args.range) input.range = { from: args.range.from, to: args.range.to };
730
+ if (args.sort) input.sort = args.sort;
731
+ if (args.sortDir) input.sortDir = args.sortDir;
732
+ const body = await this.#graphql.request(
733
+ RANK_ME_QUERY,
734
+ { input },
735
+ args.signal ? { signal: args.signal } : void 0
736
+ );
737
+ return body.rank_me ? normaliseRankMe(body.rank_me) : null;
738
+ }
633
739
  };
634
740
 
635
741
  // src/modules/locale/normalise.ts
package/dist/index.d.mts CHANGED
@@ -261,7 +261,15 @@ declare class BidModule {
261
261
  }): Promise<Bid[]>;
262
262
  }
263
263
 
264
+ /**
265
+ * @deprecated Use {@link RankPeriod} with `client.leaderboard.rankBoard`. The
266
+ * v1 `leaderboard` query is `@deprecated` on the backend in favour of
267
+ * `rank_leaderboardV2` (duration presets + current-user rank + pnl/vol).
268
+ */
264
269
  type LeaderboardPeriod = 'weekly' | 'all_time';
270
+ /**
271
+ * @deprecated Use {@link RankSort} with `client.leaderboard.rankBoard`.
272
+ */
265
273
  type LeaderboardSortBy = 'gain' | 'wagered';
266
274
  interface LeaderboardEntry {
267
275
  userId: string;
@@ -273,6 +281,48 @@ interface LeaderboardEntry {
273
281
  totalPayout: string;
274
282
  gain: string;
275
283
  }
284
+ /** Fixed duration filters. `custom` requires an hour-aligned `range`. */
285
+ type RankPeriod = 'today' | 'yesterday' | 'last_7d' | 'last_30d' | 'all_time' | 'custom';
286
+ /** `pnl` = net profit (payout - vol); `vol` = wagered volume. */
287
+ type RankSort = 'pnl' | 'vol';
288
+ type SortDir = 'asc' | 'desc';
289
+ interface RankEntry {
290
+ userId: string;
291
+ /** Same denormalised value as `username`; dashboard display alias. */
292
+ loginBy: string;
293
+ username: string;
294
+ rank: number;
295
+ /** Net profit = payout - vol (decimal as string). */
296
+ pnl: string;
297
+ /** Total wagered volume (decimal as string). */
298
+ vol: string;
299
+ payout: string;
300
+ wins: number;
301
+ bids: number;
302
+ }
303
+ interface RankBoard {
304
+ period: RankPeriod;
305
+ /** Resolved window (after hour-align) for UI display. */
306
+ range: {
307
+ from: string;
308
+ to: string;
309
+ };
310
+ sort: RankSort;
311
+ sortDir: SortDir;
312
+ /** All active users in the window → "#X of N". */
313
+ total: number;
314
+ entries: RankEntry[];
315
+ }
316
+ /**
317
+ * The signed-in caller's own row + rank (`rank_me`), split out of {@link RankBoard} so the
318
+ * board stays a pure public/cacheable read. `entry` is `null` when the caller has no activity
319
+ * in the window (`rank` is then 0); `total` is the ranked-pool size for "#rank of total".
320
+ */
321
+ interface MyRank {
322
+ rank: number;
323
+ entry: RankEntry | null;
324
+ total: number;
325
+ }
276
326
 
277
327
  interface LeaderboardModuleDeps {
278
328
  graphql: GraphQLTransport;
@@ -280,11 +330,62 @@ interface LeaderboardModuleDeps {
280
330
  declare class LeaderboardModule {
281
331
  #private;
282
332
  constructor(deps: LeaderboardModuleDeps);
333
+ /**
334
+ * @deprecated Use {@link LeaderboardModule.rankBoard}. The backend
335
+ * `leaderboard` query is `@deprecated` in favour of `rank_leaderboardV2`
336
+ * (duration presets, pnl/vol sort, pagination, current-user `me`).
337
+ */
283
338
  list(args: {
284
339
  period: LeaderboardPeriod;
285
340
  sortBy: LeaderboardSortBy;
286
341
  signal?: AbortSignal;
287
342
  }): Promise<LeaderboardEntry[]>;
343
+ /**
344
+ * Fetch the public duration-scoped rank board (`rank_leaderboardV2`).
345
+ *
346
+ * Supports the fixed period presets plus `custom` (which requires an
347
+ * hour-aligned `range`), `pnl`/`vol` sort with an explicit direction, offset
348
+ * pagination, and a `total` count for "#X of N" UI. Optional args are omitted
349
+ * from the wire `input` when undefined so the server defaults apply
350
+ * (`sort = pnl`, `sortDir = desc`, `limit = 50`, `offset = 0`).
351
+ *
352
+ * bid-260606-leaderboard-split-my-rank: the board is **public and identical for
353
+ * every caller** — it carries no per-user data. For the signed-in caller's own
354
+ * row+rank, use {@link LeaderboardModule.myRank}.
355
+ */
356
+ rankBoard(args: {
357
+ period: RankPeriod;
358
+ /** ISO 8601 UTC, hour-aligned. Required iff `period === 'custom'`. */
359
+ range?: {
360
+ from: string;
361
+ to: string;
362
+ };
363
+ sort?: RankSort;
364
+ sortDir?: SortDir;
365
+ limit?: number;
366
+ offset?: number;
367
+ signal?: AbortSignal;
368
+ }): Promise<RankBoard>;
369
+ /**
370
+ * Fetch the signed-in caller's own row + rank for the same window (`rank_me`) —
371
+ * the per-user companion to {@link LeaderboardModule.rankBoard}.
372
+ *
373
+ * Unlike the board, this attaches the user JWT (`request`, not `publicRequest`)
374
+ * so the backend resolves the caller. Returns `null` when no user is signed in
375
+ * (the backend returns `rank_me: null`). `MyRank.entry` is `null` when the
376
+ * caller has no activity in the window.
377
+ */
378
+ myRank(args: {
379
+ period: RankPeriod;
380
+ /** ISO 8601 UTC, hour-aligned. Required iff `period === 'custom'`. */
381
+ range?: {
382
+ from: string;
383
+ to: string;
384
+ };
385
+ sort?: RankSort;
386
+ sortDir?: SortDir;
387
+ signal?: AbortSignal;
388
+ }): Promise<MyRank | null>;
288
389
  }
289
390
 
290
391
  /**
@@ -1023,4 +1124,4 @@ declare function adaptiveSimpson(f: (x: number) => number, a: number, b: number,
1023
1124
  declare function calculateProbWin(time1: number, time2: number, _price1: number, price2: number, creationTime: number, currentPrice: number, volatility: number): number;
1024
1125
  declare function calculateProbWin_v2(time1: number, time2: number, _price1: number, price2: number, creationTime: number, currentPrice: number, volatility: number): number;
1025
1126
 
1026
- export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, type CancelBidResult, type Candle, type Constraints, type Currency, GameChannel, type GameConfig, type GridConfig, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, RealtimeModule, type Sample, type SampleReason, type SignalSource, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateProbWin, calculateProbWin_v2, errorFunction, isCancelled, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF };
1127
+ export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, type CancelBidResult, type Candle, type Constraints, type Currency, GameChannel, type GameConfig, type GridConfig, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateProbWin, calculateProbWin_v2, errorFunction, isCancelled, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF };
package/dist/index.d.ts CHANGED
@@ -261,7 +261,15 @@ declare class BidModule {
261
261
  }): Promise<Bid[]>;
262
262
  }
263
263
 
264
+ /**
265
+ * @deprecated Use {@link RankPeriod} with `client.leaderboard.rankBoard`. The
266
+ * v1 `leaderboard` query is `@deprecated` on the backend in favour of
267
+ * `rank_leaderboardV2` (duration presets + current-user rank + pnl/vol).
268
+ */
264
269
  type LeaderboardPeriod = 'weekly' | 'all_time';
270
+ /**
271
+ * @deprecated Use {@link RankSort} with `client.leaderboard.rankBoard`.
272
+ */
265
273
  type LeaderboardSortBy = 'gain' | 'wagered';
266
274
  interface LeaderboardEntry {
267
275
  userId: string;
@@ -273,6 +281,48 @@ interface LeaderboardEntry {
273
281
  totalPayout: string;
274
282
  gain: string;
275
283
  }
284
+ /** Fixed duration filters. `custom` requires an hour-aligned `range`. */
285
+ type RankPeriod = 'today' | 'yesterday' | 'last_7d' | 'last_30d' | 'all_time' | 'custom';
286
+ /** `pnl` = net profit (payout - vol); `vol` = wagered volume. */
287
+ type RankSort = 'pnl' | 'vol';
288
+ type SortDir = 'asc' | 'desc';
289
+ interface RankEntry {
290
+ userId: string;
291
+ /** Same denormalised value as `username`; dashboard display alias. */
292
+ loginBy: string;
293
+ username: string;
294
+ rank: number;
295
+ /** Net profit = payout - vol (decimal as string). */
296
+ pnl: string;
297
+ /** Total wagered volume (decimal as string). */
298
+ vol: string;
299
+ payout: string;
300
+ wins: number;
301
+ bids: number;
302
+ }
303
+ interface RankBoard {
304
+ period: RankPeriod;
305
+ /** Resolved window (after hour-align) for UI display. */
306
+ range: {
307
+ from: string;
308
+ to: string;
309
+ };
310
+ sort: RankSort;
311
+ sortDir: SortDir;
312
+ /** All active users in the window → "#X of N". */
313
+ total: number;
314
+ entries: RankEntry[];
315
+ }
316
+ /**
317
+ * The signed-in caller's own row + rank (`rank_me`), split out of {@link RankBoard} so the
318
+ * board stays a pure public/cacheable read. `entry` is `null` when the caller has no activity
319
+ * in the window (`rank` is then 0); `total` is the ranked-pool size for "#rank of total".
320
+ */
321
+ interface MyRank {
322
+ rank: number;
323
+ entry: RankEntry | null;
324
+ total: number;
325
+ }
276
326
 
277
327
  interface LeaderboardModuleDeps {
278
328
  graphql: GraphQLTransport;
@@ -280,11 +330,62 @@ interface LeaderboardModuleDeps {
280
330
  declare class LeaderboardModule {
281
331
  #private;
282
332
  constructor(deps: LeaderboardModuleDeps);
333
+ /**
334
+ * @deprecated Use {@link LeaderboardModule.rankBoard}. The backend
335
+ * `leaderboard` query is `@deprecated` in favour of `rank_leaderboardV2`
336
+ * (duration presets, pnl/vol sort, pagination, current-user `me`).
337
+ */
283
338
  list(args: {
284
339
  period: LeaderboardPeriod;
285
340
  sortBy: LeaderboardSortBy;
286
341
  signal?: AbortSignal;
287
342
  }): Promise<LeaderboardEntry[]>;
343
+ /**
344
+ * Fetch the public duration-scoped rank board (`rank_leaderboardV2`).
345
+ *
346
+ * Supports the fixed period presets plus `custom` (which requires an
347
+ * hour-aligned `range`), `pnl`/`vol` sort with an explicit direction, offset
348
+ * pagination, and a `total` count for "#X of N" UI. Optional args are omitted
349
+ * from the wire `input` when undefined so the server defaults apply
350
+ * (`sort = pnl`, `sortDir = desc`, `limit = 50`, `offset = 0`).
351
+ *
352
+ * bid-260606-leaderboard-split-my-rank: the board is **public and identical for
353
+ * every caller** — it carries no per-user data. For the signed-in caller's own
354
+ * row+rank, use {@link LeaderboardModule.myRank}.
355
+ */
356
+ rankBoard(args: {
357
+ period: RankPeriod;
358
+ /** ISO 8601 UTC, hour-aligned. Required iff `period === 'custom'`. */
359
+ range?: {
360
+ from: string;
361
+ to: string;
362
+ };
363
+ sort?: RankSort;
364
+ sortDir?: SortDir;
365
+ limit?: number;
366
+ offset?: number;
367
+ signal?: AbortSignal;
368
+ }): Promise<RankBoard>;
369
+ /**
370
+ * Fetch the signed-in caller's own row + rank for the same window (`rank_me`) —
371
+ * the per-user companion to {@link LeaderboardModule.rankBoard}.
372
+ *
373
+ * Unlike the board, this attaches the user JWT (`request`, not `publicRequest`)
374
+ * so the backend resolves the caller. Returns `null` when no user is signed in
375
+ * (the backend returns `rank_me: null`). `MyRank.entry` is `null` when the
376
+ * caller has no activity in the window.
377
+ */
378
+ myRank(args: {
379
+ period: RankPeriod;
380
+ /** ISO 8601 UTC, hour-aligned. Required iff `period === 'custom'`. */
381
+ range?: {
382
+ from: string;
383
+ to: string;
384
+ };
385
+ sort?: RankSort;
386
+ sortDir?: SortDir;
387
+ signal?: AbortSignal;
388
+ }): Promise<MyRank | null>;
288
389
  }
289
390
 
290
391
  /**
@@ -1023,4 +1124,4 @@ declare function adaptiveSimpson(f: (x: number) => number, a: number, b: number,
1023
1124
  declare function calculateProbWin(time1: number, time2: number, _price1: number, price2: number, creationTime: number, currentPrice: number, volatility: number): number;
1024
1125
  declare function calculateProbWin_v2(time1: number, time2: number, _price1: number, price2: number, creationTime: number, currentPrice: number, volatility: number): number;
1025
1126
 
1026
- export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, type CancelBidResult, type Candle, type Constraints, type Currency, GameChannel, type GameConfig, type GridConfig, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, RealtimeModule, type Sample, type SampleReason, type SignalSource, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateProbWin, calculateProbWin_v2, errorFunction, isCancelled, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF };
1127
+ export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, type CancelBidResult, type Candle, type Constraints, type Currency, GameChannel, type GameConfig, type GridConfig, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateProbWin, calculateProbWin_v2, errorFunction, isCancelled, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF };
package/dist/index.js CHANGED
@@ -543,6 +543,41 @@ function normaliseLeaderboard(rows) {
543
543
  gain: row.gain
544
544
  }));
545
545
  }
546
+ function normaliseRankEntry(row) {
547
+ return {
548
+ userId: row.userId,
549
+ loginBy: row.loginBy,
550
+ username: row.username,
551
+ rank: row.rank,
552
+ pnl: row.pnl,
553
+ vol: row.vol,
554
+ payout: row.payout,
555
+ wins: row.wins,
556
+ bids: row.bids
557
+ };
558
+ }
559
+ function normaliseRankBoard(wire) {
560
+ if (wire == null || typeof wire !== "object") {
561
+ throw new TaphubServerError("Invalid response from server", {
562
+ code: "InvalidResponse"
563
+ });
564
+ }
565
+ return {
566
+ period: wire.period,
567
+ range: { from: wire.range?.from, to: wire.range?.to },
568
+ sort: wire.sort,
569
+ sortDir: wire.sortDir,
570
+ total: wire.total,
571
+ entries: Array.isArray(wire.entries) ? wire.entries.map(normaliseRankEntry) : []
572
+ };
573
+ }
574
+ function normaliseRankMe(wire) {
575
+ return {
576
+ rank: wire.rank,
577
+ total: wire.total,
578
+ entry: wire.entry ? normaliseRankEntry(wire.entry) : null
579
+ };
580
+ }
546
581
 
547
582
  // src/modules/leaderboard/queries.ts
548
583
  var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!) {
@@ -550,6 +585,23 @@ var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!)
550
585
  user_id username rank total_bids total_wins total_wagered total_payout gain
551
586
  }
552
587
  }`;
588
+ var RANK_LEADERBOARD_V2_QUERY = `query RankLeaderboardV2($input: RankBoardInput!) {
589
+ rank_leaderboardV2(input: $input) {
590
+ period
591
+ range { from to }
592
+ sort
593
+ sortDir
594
+ total
595
+ entries { userId loginBy username rank pnl vol payout wins bids }
596
+ }
597
+ }`;
598
+ var RANK_ME_QUERY = `query RankMe($input: RankMeInput!) {
599
+ rank_me(input: $input) {
600
+ rank
601
+ total
602
+ entry { userId loginBy username rank pnl vol payout wins bids }
603
+ }
604
+ }`;
553
605
 
554
606
  // src/modules/leaderboard/index.ts
555
607
  var LeaderboardModule = class {
@@ -557,6 +609,11 @@ var LeaderboardModule = class {
557
609
  constructor(deps) {
558
610
  this.#graphql = deps.graphql;
559
611
  }
612
+ /**
613
+ * @deprecated Use {@link LeaderboardModule.rankBoard}. The backend
614
+ * `leaderboard` query is `@deprecated` in favour of `rank_leaderboardV2`
615
+ * (duration presets, pnl/vol sort, pagination, current-user `me`).
616
+ */
560
617
  async list(args) {
561
618
  const body = await this.#graphql.publicRequest(
562
619
  LEADERBOARD_QUERY,
@@ -565,6 +622,55 @@ var LeaderboardModule = class {
565
622
  );
566
623
  return normaliseLeaderboard(body.leaderboard);
567
624
  }
625
+ /**
626
+ * Fetch the public duration-scoped rank board (`rank_leaderboardV2`).
627
+ *
628
+ * Supports the fixed period presets plus `custom` (which requires an
629
+ * hour-aligned `range`), `pnl`/`vol` sort with an explicit direction, offset
630
+ * pagination, and a `total` count for "#X of N" UI. Optional args are omitted
631
+ * from the wire `input` when undefined so the server defaults apply
632
+ * (`sort = pnl`, `sortDir = desc`, `limit = 50`, `offset = 0`).
633
+ *
634
+ * bid-260606-leaderboard-split-my-rank: the board is **public and identical for
635
+ * every caller** — it carries no per-user data. For the signed-in caller's own
636
+ * row+rank, use {@link LeaderboardModule.myRank}.
637
+ */
638
+ async rankBoard(args) {
639
+ const input = { period: args.period };
640
+ if (args.range) input.range = { from: args.range.from, to: args.range.to };
641
+ if (args.sort) input.sort = args.sort;
642
+ if (args.sortDir) input.sortDir = args.sortDir;
643
+ if (args.limit != null || args.offset != null) {
644
+ input.p = { limit: args.limit, offset: args.offset };
645
+ }
646
+ const body = await this.#graphql.publicRequest(
647
+ RANK_LEADERBOARD_V2_QUERY,
648
+ { input },
649
+ args.signal ? { signal: args.signal } : void 0
650
+ );
651
+ return normaliseRankBoard(body.rank_leaderboardV2);
652
+ }
653
+ /**
654
+ * Fetch the signed-in caller's own row + rank for the same window (`rank_me`) —
655
+ * the per-user companion to {@link LeaderboardModule.rankBoard}.
656
+ *
657
+ * Unlike the board, this attaches the user JWT (`request`, not `publicRequest`)
658
+ * so the backend resolves the caller. Returns `null` when no user is signed in
659
+ * (the backend returns `rank_me: null`). `MyRank.entry` is `null` when the
660
+ * caller has no activity in the window.
661
+ */
662
+ async myRank(args) {
663
+ const input = { period: args.period };
664
+ if (args.range) input.range = { from: args.range.from, to: args.range.to };
665
+ if (args.sort) input.sort = args.sort;
666
+ if (args.sortDir) input.sortDir = args.sortDir;
667
+ const body = await this.#graphql.request(
668
+ RANK_ME_QUERY,
669
+ { input },
670
+ args.signal ? { signal: args.signal } : void 0
671
+ );
672
+ return body.rank_me ? normaliseRankMe(body.rank_me) : null;
673
+ }
568
674
  };
569
675
 
570
676
  // src/modules/locale/normalise.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taphubhq/sdk-core",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Core SDK for building on the TabHub platform",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",