@taphubhq/sdk-core 0.15.3 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +209 -189
- package/dist/index.d.mts +94 -94
- package/dist/index.d.ts +94 -94
- package/dist/index.js +208 -188
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -509,8 +509,151 @@ var BidModule = class {
|
|
|
509
509
|
}
|
|
510
510
|
};
|
|
511
511
|
|
|
512
|
-
// src/modules/
|
|
513
|
-
function
|
|
512
|
+
// src/modules/leaderboard/normalise.ts
|
|
513
|
+
function normaliseLeaderboard(rows) {
|
|
514
|
+
if (!Array.isArray(rows)) {
|
|
515
|
+
throw new TaphubServerError("Invalid response from server", {
|
|
516
|
+
code: "InvalidResponse"
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
return rows.map((row) => ({
|
|
520
|
+
userId: row.user_id,
|
|
521
|
+
username: row.username,
|
|
522
|
+
rank: row.rank,
|
|
523
|
+
totalBids: row.total_bids,
|
|
524
|
+
totalWins: row.total_wins,
|
|
525
|
+
totalWagered: row.total_wagered,
|
|
526
|
+
totalPayout: row.total_payout,
|
|
527
|
+
gain: row.gain
|
|
528
|
+
}));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/modules/leaderboard/queries.ts
|
|
532
|
+
var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!) {
|
|
533
|
+
leaderboard(period: $period, sort_by: $sort_by) {
|
|
534
|
+
user_id username rank total_bids total_wins total_wagered total_payout gain
|
|
535
|
+
}
|
|
536
|
+
}`;
|
|
537
|
+
|
|
538
|
+
// src/modules/leaderboard/index.ts
|
|
539
|
+
var LeaderboardModule = class {
|
|
540
|
+
#graphql;
|
|
541
|
+
constructor(deps) {
|
|
542
|
+
this.#graphql = deps.graphql;
|
|
543
|
+
}
|
|
544
|
+
async list(args) {
|
|
545
|
+
const body = await this.#graphql.request(
|
|
546
|
+
LEADERBOARD_QUERY,
|
|
547
|
+
{ period: args.period, sort_by: args.sortBy },
|
|
548
|
+
args.signal ? { signal: args.signal } : void 0
|
|
549
|
+
);
|
|
550
|
+
return normaliseLeaderboard(body.leaderboard);
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// src/modules/locale/normalise.ts
|
|
555
|
+
function normaliseLocaleResponse(node) {
|
|
556
|
+
let translations = null;
|
|
557
|
+
if (node.translations !== null) {
|
|
558
|
+
try {
|
|
559
|
+
translations = JSON.parse(node.translations);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
throw new TaphubValidationError("Malformed translations JSON string from backend", {
|
|
562
|
+
code: "InvalidLocaleResponse",
|
|
563
|
+
details: {
|
|
564
|
+
lang: node.lang,
|
|
565
|
+
version: node.version,
|
|
566
|
+
parseError: err instanceof Error ? err.message : String(err)
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return {
|
|
572
|
+
lang: node.lang,
|
|
573
|
+
version: node.version,
|
|
574
|
+
notModified: node.notModified,
|
|
575
|
+
translations
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function normaliseRefreshLocalesPayload(node) {
|
|
579
|
+
let versions;
|
|
580
|
+
try {
|
|
581
|
+
versions = JSON.parse(node.versions);
|
|
582
|
+
} catch (err) {
|
|
583
|
+
throw new TaphubValidationError("Malformed versions JSON string from backend", {
|
|
584
|
+
code: "InvalidRefreshLocalesPayload",
|
|
585
|
+
details: {
|
|
586
|
+
parseError: err instanceof Error ? err.message : String(err)
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
refreshed: node.refreshed,
|
|
592
|
+
versions
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/modules/locale/queries.ts
|
|
597
|
+
var LOCALES_QUERY = `query Locales($input: LocalesInput!) {
|
|
598
|
+
locales(input: $input) {
|
|
599
|
+
lang
|
|
600
|
+
version
|
|
601
|
+
notModified
|
|
602
|
+
translations
|
|
603
|
+
}
|
|
604
|
+
}`;
|
|
605
|
+
var REFRESH_LOCALES_MUTATION = `mutation RefreshLocales {
|
|
606
|
+
refreshLocales {
|
|
607
|
+
refreshed
|
|
608
|
+
versions
|
|
609
|
+
}
|
|
610
|
+
}`;
|
|
611
|
+
|
|
612
|
+
// src/modules/locale/index.ts
|
|
613
|
+
var LocaleModule = class {
|
|
614
|
+
#graphql;
|
|
615
|
+
constructor(deps) {
|
|
616
|
+
this.#graphql = deps.graphql;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Fetch translations for a single language.
|
|
620
|
+
*
|
|
621
|
+
* Pass the last-seen `version` as `knownVersion` to opt into not-modified
|
|
622
|
+
* short-circuit semantics: backend returns `{notModified: true, translations: null}`
|
|
623
|
+
* when the cached body still matches, and the caller keeps prior state.
|
|
624
|
+
*
|
|
625
|
+
* Errors surface as TaphubError subclasses with `extensions.code` codes from
|
|
626
|
+
* the backend (e.g. `LangNotSupported`, `InsufficientUpstream`, `FeatureDisabled`).
|
|
627
|
+
* Caller decides the fallback strategy.
|
|
628
|
+
*/
|
|
629
|
+
async get(lang, knownVersion, opts) {
|
|
630
|
+
const input = { lang };
|
|
631
|
+
if (knownVersion !== void 0 && knownVersion !== "") {
|
|
632
|
+
input.knownVersion = knownVersion;
|
|
633
|
+
}
|
|
634
|
+
const body = await this.#graphql.request(LOCALES_QUERY, { input }, opts);
|
|
635
|
+
return normaliseLocaleResponse(body.locales);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Trigger an admin refresh — backend re-pulls the source Sheet, invalidates
|
|
639
|
+
* its cache, and writes fresh entries for every supported language.
|
|
640
|
+
*
|
|
641
|
+
* Requires `X-API-Key` header equal to backend `InternalApiKey`. The transport
|
|
642
|
+
* layer is responsible for attaching the header; this method does not handle
|
|
643
|
+
* auth concerns directly.
|
|
644
|
+
*/
|
|
645
|
+
async refresh(opts) {
|
|
646
|
+
const body = await this.#graphql.request(
|
|
647
|
+
REFRESH_LOCALES_MUTATION,
|
|
648
|
+
{},
|
|
649
|
+
opts
|
|
650
|
+
);
|
|
651
|
+
return normaliseRefreshLocalesPayload(body.refreshLocales);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// src/modules/pair/normalise.ts
|
|
656
|
+
function normalisePair(node) {
|
|
514
657
|
if (typeof node.id !== "string" || node.id === "" || typeof node.pair !== "string" || node.pair === "" || typeof node.status !== "string" || node.status === "" || !node.config) {
|
|
515
658
|
throw new TaphubServerError("Invalid response from server", {
|
|
516
659
|
code: "InvalidResponse"
|
|
@@ -569,7 +712,7 @@ function normaliseCandles(list) {
|
|
|
569
712
|
coefMults: c.coefMults
|
|
570
713
|
}));
|
|
571
714
|
}
|
|
572
|
-
function
|
|
715
|
+
function normalisePairInfo(node) {
|
|
573
716
|
if (typeof node.id !== "string" || node.id === "" || typeof node.pair !== "string" || node.pair === "") {
|
|
574
717
|
throw new TaphubServerError("Invalid response from server", { code: "InvalidResponse" });
|
|
575
718
|
}
|
|
@@ -579,13 +722,14 @@ function normaliseGamePairInfo(node) {
|
|
|
579
722
|
gameplayId: node.gameplayId,
|
|
580
723
|
gameplayName: node.gameplayName,
|
|
581
724
|
source: node.source,
|
|
582
|
-
|
|
725
|
+
// REVIEW[bid-260602]: maps node.agencyPairId (was: node.gameId)
|
|
726
|
+
agencyPairId: node.agencyPairId ?? null
|
|
583
727
|
};
|
|
584
728
|
}
|
|
585
729
|
|
|
586
|
-
// src/modules/
|
|
587
|
-
var
|
|
588
|
-
|
|
730
|
+
// src/modules/pair/queries.ts
|
|
731
|
+
var PAIR_QUERY = `query Pair($pair: String!, $gameplaySlug: String) {
|
|
732
|
+
pair(pair: $pair, gameplaySlug: $gameplaySlug) {
|
|
589
733
|
id pair status created_at
|
|
590
734
|
config {
|
|
591
735
|
gridConfig { cellSizeTime cellSizeValue candleSize baseline baselineTime }
|
|
@@ -594,8 +738,8 @@ var GAME_QUERY = `query Game($pair: String!, $gameplaySlug: String) {
|
|
|
594
738
|
}
|
|
595
739
|
}
|
|
596
740
|
}`;
|
|
597
|
-
var CHART_HISTORY_QUERY = `query ChartHistory($
|
|
598
|
-
chartHistory(
|
|
741
|
+
var CHART_HISTORY_QUERY = `query ChartHistory($agencyPairId: ID!, $limit: Int) {
|
|
742
|
+
chartHistory(agencyPairId: $agencyPairId, limit: $limit) {
|
|
599
743
|
time o h l c volatility coefMults
|
|
600
744
|
}
|
|
601
745
|
}`;
|
|
@@ -606,12 +750,12 @@ var BUILDER_AVAILABLE_GAME_PAIRS_QUERY = `query BuilderAvailableGamePairs($gamep
|
|
|
606
750
|
gameplayId
|
|
607
751
|
gameplayName
|
|
608
752
|
source
|
|
609
|
-
|
|
753
|
+
agencyPairId
|
|
610
754
|
}
|
|
611
755
|
}`;
|
|
612
756
|
|
|
613
|
-
// src/modules/
|
|
614
|
-
var
|
|
757
|
+
// src/modules/pair/index.ts
|
|
758
|
+
var PairModule = class {
|
|
615
759
|
#graphql;
|
|
616
760
|
constructor(deps) {
|
|
617
761
|
this.#graphql = deps.graphql;
|
|
@@ -621,7 +765,7 @@ var GameModule = class {
|
|
|
621
765
|
if (opts?.gameplaySlug) variables.gameplaySlug = opts.gameplaySlug;
|
|
622
766
|
let body;
|
|
623
767
|
try {
|
|
624
|
-
body = await this.#graphql.request(
|
|
768
|
+
body = await this.#graphql.request(PAIR_QUERY, variables, opts);
|
|
625
769
|
} catch (err) {
|
|
626
770
|
if (err instanceof TaphubValidationError && err.code === "NotExist") {
|
|
627
771
|
throw new TaphubValidationError("Game not found for pair", {
|
|
@@ -631,13 +775,13 @@ var GameModule = class {
|
|
|
631
775
|
}
|
|
632
776
|
throw err;
|
|
633
777
|
}
|
|
634
|
-
if (body.
|
|
778
|
+
if (body.pair === null) {
|
|
635
779
|
throw new TaphubValidationError("Game not found for pair", {
|
|
636
780
|
code: "GameNotFound",
|
|
637
781
|
details: { pair }
|
|
638
782
|
});
|
|
639
783
|
}
|
|
640
|
-
return
|
|
784
|
+
return normalisePair(body.pair);
|
|
641
785
|
}
|
|
642
786
|
/**
|
|
643
787
|
* Returns available game pairs, optionally filtered by gameplay.
|
|
@@ -646,9 +790,9 @@ var GameModule = class {
|
|
|
646
790
|
* `gameId` — use it directly as the MQTT topic `game/{gameId}/candle`.
|
|
647
791
|
*
|
|
648
792
|
* @example
|
|
649
|
-
* const pairs = await client.
|
|
650
|
-
* const game = await client.
|
|
651
|
-
* const ch = client.realtime?.subscribe(pairs[0].
|
|
793
|
+
* 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);
|
|
652
796
|
*/
|
|
653
797
|
async availableGamePairs(opts) {
|
|
654
798
|
const variables = {};
|
|
@@ -658,10 +802,11 @@ var GameModule = class {
|
|
|
658
802
|
variables,
|
|
659
803
|
opts
|
|
660
804
|
);
|
|
661
|
-
return body.builderAvailableGamePairs.map(
|
|
805
|
+
return body.builderAvailableGamePairs.map(normalisePairInfo);
|
|
662
806
|
}
|
|
663
|
-
|
|
664
|
-
|
|
807
|
+
// REVIEW[bid-260602]: chartHistory param/variable renamed agencyPairId (was: gameId)
|
|
808
|
+
async chartHistory(agencyPairId, limit, opts) {
|
|
809
|
+
const variables = { agencyPairId };
|
|
665
810
|
if (limit !== void 0) {
|
|
666
811
|
variables.limit = limit;
|
|
667
812
|
}
|
|
@@ -674,149 +819,6 @@ var GameModule = class {
|
|
|
674
819
|
}
|
|
675
820
|
};
|
|
676
821
|
|
|
677
|
-
// src/modules/leaderboard/normalise.ts
|
|
678
|
-
function normaliseLeaderboard(rows) {
|
|
679
|
-
if (!Array.isArray(rows)) {
|
|
680
|
-
throw new TaphubServerError("Invalid response from server", {
|
|
681
|
-
code: "InvalidResponse"
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
return rows.map((row) => ({
|
|
685
|
-
userId: row.user_id,
|
|
686
|
-
username: row.username,
|
|
687
|
-
rank: row.rank,
|
|
688
|
-
totalBids: row.total_bids,
|
|
689
|
-
totalWins: row.total_wins,
|
|
690
|
-
totalWagered: row.total_wagered,
|
|
691
|
-
totalPayout: row.total_payout,
|
|
692
|
-
gain: row.gain
|
|
693
|
-
}));
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
// src/modules/leaderboard/queries.ts
|
|
697
|
-
var LEADERBOARD_QUERY = `query Leaderboard($period: String!, $sort_by: String!) {
|
|
698
|
-
leaderboard(period: $period, sort_by: $sort_by) {
|
|
699
|
-
user_id username rank total_bids total_wins total_wagered total_payout gain
|
|
700
|
-
}
|
|
701
|
-
}`;
|
|
702
|
-
|
|
703
|
-
// src/modules/leaderboard/index.ts
|
|
704
|
-
var LeaderboardModule = class {
|
|
705
|
-
#graphql;
|
|
706
|
-
constructor(deps) {
|
|
707
|
-
this.#graphql = deps.graphql;
|
|
708
|
-
}
|
|
709
|
-
async list(args) {
|
|
710
|
-
const body = await this.#graphql.request(
|
|
711
|
-
LEADERBOARD_QUERY,
|
|
712
|
-
{ period: args.period, sort_by: args.sortBy },
|
|
713
|
-
args.signal ? { signal: args.signal } : void 0
|
|
714
|
-
);
|
|
715
|
-
return normaliseLeaderboard(body.leaderboard);
|
|
716
|
-
}
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
// src/modules/locale/normalise.ts
|
|
720
|
-
function normaliseLocaleResponse(node) {
|
|
721
|
-
let translations = null;
|
|
722
|
-
if (node.translations !== null) {
|
|
723
|
-
try {
|
|
724
|
-
translations = JSON.parse(node.translations);
|
|
725
|
-
} catch (err) {
|
|
726
|
-
throw new TaphubValidationError("Malformed translations JSON string from backend", {
|
|
727
|
-
code: "InvalidLocaleResponse",
|
|
728
|
-
details: {
|
|
729
|
-
lang: node.lang,
|
|
730
|
-
version: node.version,
|
|
731
|
-
parseError: err instanceof Error ? err.message : String(err)
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return {
|
|
737
|
-
lang: node.lang,
|
|
738
|
-
version: node.version,
|
|
739
|
-
notModified: node.notModified,
|
|
740
|
-
translations
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
function normaliseRefreshLocalesPayload(node) {
|
|
744
|
-
let versions;
|
|
745
|
-
try {
|
|
746
|
-
versions = JSON.parse(node.versions);
|
|
747
|
-
} catch (err) {
|
|
748
|
-
throw new TaphubValidationError("Malformed versions JSON string from backend", {
|
|
749
|
-
code: "InvalidRefreshLocalesPayload",
|
|
750
|
-
details: {
|
|
751
|
-
parseError: err instanceof Error ? err.message : String(err)
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
return {
|
|
756
|
-
refreshed: node.refreshed,
|
|
757
|
-
versions
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
// src/modules/locale/queries.ts
|
|
762
|
-
var LOCALES_QUERY = `query Locales($input: LocalesInput!) {
|
|
763
|
-
locales(input: $input) {
|
|
764
|
-
lang
|
|
765
|
-
version
|
|
766
|
-
notModified
|
|
767
|
-
translations
|
|
768
|
-
}
|
|
769
|
-
}`;
|
|
770
|
-
var REFRESH_LOCALES_MUTATION = `mutation RefreshLocales {
|
|
771
|
-
refreshLocales {
|
|
772
|
-
refreshed
|
|
773
|
-
versions
|
|
774
|
-
}
|
|
775
|
-
}`;
|
|
776
|
-
|
|
777
|
-
// src/modules/locale/index.ts
|
|
778
|
-
var LocaleModule = class {
|
|
779
|
-
#graphql;
|
|
780
|
-
constructor(deps) {
|
|
781
|
-
this.#graphql = deps.graphql;
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Fetch translations for a single language.
|
|
785
|
-
*
|
|
786
|
-
* Pass the last-seen `version` as `knownVersion` to opt into not-modified
|
|
787
|
-
* short-circuit semantics: backend returns `{notModified: true, translations: null}`
|
|
788
|
-
* when the cached body still matches, and the caller keeps prior state.
|
|
789
|
-
*
|
|
790
|
-
* Errors surface as TaphubError subclasses with `extensions.code` codes from
|
|
791
|
-
* the backend (e.g. `LangNotSupported`, `InsufficientUpstream`, `FeatureDisabled`).
|
|
792
|
-
* Caller decides the fallback strategy.
|
|
793
|
-
*/
|
|
794
|
-
async get(lang, knownVersion, opts) {
|
|
795
|
-
const input = { lang };
|
|
796
|
-
if (knownVersion !== void 0 && knownVersion !== "") {
|
|
797
|
-
input.knownVersion = knownVersion;
|
|
798
|
-
}
|
|
799
|
-
const body = await this.#graphql.request(LOCALES_QUERY, { input }, opts);
|
|
800
|
-
return normaliseLocaleResponse(body.locales);
|
|
801
|
-
}
|
|
802
|
-
/**
|
|
803
|
-
* Trigger an admin refresh — backend re-pulls the source Sheet, invalidates
|
|
804
|
-
* its cache, and writes fresh entries for every supported language.
|
|
805
|
-
*
|
|
806
|
-
* Requires `X-API-Key` header equal to backend `InternalApiKey`. The transport
|
|
807
|
-
* layer is responsible for attaching the header; this method does not handle
|
|
808
|
-
* auth concerns directly.
|
|
809
|
-
*/
|
|
810
|
-
async refresh(opts) {
|
|
811
|
-
const body = await this.#graphql.request(
|
|
812
|
-
REFRESH_LOCALES_MUTATION,
|
|
813
|
-
{},
|
|
814
|
-
opts
|
|
815
|
-
);
|
|
816
|
-
return normaliseRefreshLocalesPayload(body.refreshLocales);
|
|
817
|
-
}
|
|
818
|
-
};
|
|
819
|
-
|
|
820
822
|
// src/transport/mqtt/index.ts
|
|
821
823
|
import mqtt from "mqtt";
|
|
822
824
|
|
|
@@ -887,6 +889,19 @@ function createMqttTransport(endpoint, opts = {}) {
|
|
|
887
889
|
}
|
|
888
890
|
});
|
|
889
891
|
client.on("connect", () => {
|
|
892
|
+
const c = client;
|
|
893
|
+
for (const sub of subscriptions.values()) {
|
|
894
|
+
for (const t of sub.topics) c.subscribe(t, { qos: 1 });
|
|
895
|
+
}
|
|
896
|
+
for (const entry of candleSubscriptions.values()) {
|
|
897
|
+
c.subscribe(entry.topic, { qos: 0 });
|
|
898
|
+
}
|
|
899
|
+
for (const entry of statsSubscriptions.values()) {
|
|
900
|
+
c.subscribe(entry.topic, { qos: 0 });
|
|
901
|
+
}
|
|
902
|
+
for (const entry of walletSubscriptions.values()) {
|
|
903
|
+
c.subscribe(entry.topic, { qos: 1 });
|
|
904
|
+
}
|
|
890
905
|
fireLifecycle({ kind: "connect", rttMs: Date.now() - connectStartedAt });
|
|
891
906
|
});
|
|
892
907
|
client.on("reconnect", () => {
|
|
@@ -1601,10 +1616,18 @@ function classifyBackendHealth(samples) {
|
|
|
1601
1616
|
}
|
|
1602
1617
|
return "ok";
|
|
1603
1618
|
}
|
|
1604
|
-
var
|
|
1605
|
-
var
|
|
1606
|
-
var
|
|
1607
|
-
var
|
|
1619
|
+
var RTT_GOOD_TO_FAIR = 180;
|
|
1620
|
+
var RTT_FAIR_TO_GOOD = 120;
|
|
1621
|
+
var RTT_FAIR_TO_POOR = 450;
|
|
1622
|
+
var RTT_POOR_TO_FAIR = 350;
|
|
1623
|
+
var JITTER_POOR = 150;
|
|
1624
|
+
var JITTER_LEAVE_POOR = 120;
|
|
1625
|
+
var LOSS_POOR = 0.05;
|
|
1626
|
+
var LOSS_LEAVE_POOR = 0.03;
|
|
1627
|
+
var isPoor = (m) => m.rtt > RTT_FAIR_TO_POOR || m.jitter > JITTER_POOR || m.lossRate > LOSS_POOR;
|
|
1628
|
+
var canLeavePoor = (m) => m.rtt < RTT_POOR_TO_FAIR && m.jitter < JITTER_LEAVE_POOR && m.lossRate < LOSS_LEAVE_POOR;
|
|
1629
|
+
var isFairUpper = (rtt) => rtt > RTT_GOOD_TO_FAIR;
|
|
1630
|
+
var canReachGood = (rtt) => rtt < RTT_FAIR_TO_GOOD;
|
|
1608
1631
|
function classifyNetworkLevel(metrics, current) {
|
|
1609
1632
|
if (current === "offline") {
|
|
1610
1633
|
return isPoor(metrics) ? "poor" : "fair";
|
|
@@ -1731,13 +1754,11 @@ var NetworkQualityMonitor = class {
|
|
|
1731
1754
|
if (bucket.length > WINDOW_MAX_SAMPLES_PER_SOURCE) {
|
|
1732
1755
|
bucket.shift();
|
|
1733
1756
|
}
|
|
1734
|
-
if (sample.source !== "connection" && sample.source !== "browser") {
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
this.smoother.add(sample.rtt, this.deriveMetrics());
|
|
1740
|
-
}
|
|
1757
|
+
if (sample.reason === "ok" && sample.source !== "connection" && sample.source !== "browser") {
|
|
1758
|
+
this.lastSuccessfulHttpAt = sample.ts;
|
|
1759
|
+
}
|
|
1760
|
+
if (sample.source === "mqtt" && sample.reason === "ok") {
|
|
1761
|
+
this.smoother.add(sample.rtt, this.deriveMetrics());
|
|
1741
1762
|
}
|
|
1742
1763
|
this.recompute(prevMqttConnectedOverride);
|
|
1743
1764
|
}
|
|
@@ -1908,17 +1929,15 @@ var NetworkQualityMonitor = class {
|
|
|
1908
1929
|
(s) => s.reason === "network" || s.reason === "timeout" || s.reason === "offline"
|
|
1909
1930
|
).length;
|
|
1910
1931
|
const lossRate = total > 0 ? lossCount / total : 0;
|
|
1911
|
-
const
|
|
1912
|
-
(s) => s.reason === "ok" || s.reason === "backend5xx" || s.reason === "backend4xx" || s.reason === "gqlError"
|
|
1913
|
-
).map((s) => s.rtt).filter((r) => Number.isFinite(r));
|
|
1932
|
+
const mqttRtts = samples.filter((s) => s.source === "mqtt" && s.reason === "ok").map((s) => s.rtt).filter((r) => Number.isFinite(r));
|
|
1914
1933
|
let jitter = 0;
|
|
1915
|
-
if (
|
|
1916
|
-
const mean =
|
|
1917
|
-
const variance =
|
|
1934
|
+
if (mqttRtts.length > 1) {
|
|
1935
|
+
const mean = mqttRtts.reduce((a, b) => a + b, 0) / mqttRtts.length;
|
|
1936
|
+
const variance = mqttRtts.reduce((a, b) => a + (b - mean) ** 2, 0) / mqttRtts.length;
|
|
1918
1937
|
jitter = Math.sqrt(variance);
|
|
1919
1938
|
}
|
|
1920
1939
|
const connectionFallback = samples.filter((s) => s.source === "connection" && Number.isFinite(s.rtt)).slice(-1)[0]?.rtt;
|
|
1921
|
-
const emaForLevel = this.smoother.ema > 0 ? this.smoother.ema :
|
|
1940
|
+
const emaForLevel = this.smoother.ema > 0 ? this.smoother.ema : mqttRtts.length > 0 ? mqttRtts[mqttRtts.length - 1] ?? 0 : connectionFallback ?? 0;
|
|
1922
1941
|
return { jitter, lossRate, emaForLevel };
|
|
1923
1942
|
}
|
|
1924
1943
|
isHardOffline() {
|
|
@@ -2471,8 +2490,9 @@ var TaphubClient = class {
|
|
|
2471
2490
|
user;
|
|
2472
2491
|
/** @readonly Auth module — reassignment has no effect at runtime. */
|
|
2473
2492
|
auth;
|
|
2474
|
-
/** @readonly
|
|
2475
|
-
game
|
|
2493
|
+
/** @readonly Pair module — reassignment has no effect at runtime. */
|
|
2494
|
+
// REVIEW[bid-260602]: field pair: PairModule (was: game: GameModule)
|
|
2495
|
+
pair;
|
|
2476
2496
|
/** @readonly Bid module — reassignment has no effect at runtime. */
|
|
2477
2497
|
bid;
|
|
2478
2498
|
/** @readonly Leaderboard module — reassignment has no effect at runtime. */
|
|
@@ -2556,7 +2576,7 @@ var TaphubClient = class {
|
|
|
2556
2576
|
this.user.clearCurrencies();
|
|
2557
2577
|
}
|
|
2558
2578
|
});
|
|
2559
|
-
this.
|
|
2579
|
+
this.pair = new PairModule({ graphql: this.#graphql });
|
|
2560
2580
|
this.bid = new BidModule({ graphql: this.#graphql });
|
|
2561
2581
|
this.leaderboard = new LeaderboardModule({ graphql: this.#graphql });
|
|
2562
2582
|
this.agencyPairs = new AgencyPairModule({ graphql: this.#graphql });
|
|
@@ -2579,8 +2599,8 @@ var TaphubClient = class {
|
|
|
2579
2599
|
enumerable: true,
|
|
2580
2600
|
configurable: false
|
|
2581
2601
|
});
|
|
2582
|
-
Object.defineProperty(this, "
|
|
2583
|
-
value: this.
|
|
2602
|
+
Object.defineProperty(this, "pair", {
|
|
2603
|
+
value: this.pair,
|
|
2584
2604
|
writable: false,
|
|
2585
2605
|
enumerable: true,
|
|
2586
2606
|
configurable: false
|
|
@@ -2741,10 +2761,10 @@ export {
|
|
|
2741
2761
|
AgencyPairModule,
|
|
2742
2762
|
AuthModule,
|
|
2743
2763
|
BidModule,
|
|
2744
|
-
GameModule,
|
|
2745
2764
|
LeaderboardModule,
|
|
2746
2765
|
LocaleModule,
|
|
2747
2766
|
NetworkQualityMonitor,
|
|
2767
|
+
PairModule,
|
|
2748
2768
|
RealtimeModule,
|
|
2749
2769
|
TaphubAuthError,
|
|
2750
2770
|
TaphubClient,
|