@taphubhq/sdk-core 0.23.1 → 0.23.3
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 +47 -33
- package/dist/index.d.mts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +47 -33
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -472,6 +472,8 @@ function normaliseBid(node) {
|
|
|
472
472
|
price2: node.price2,
|
|
473
473
|
status: coerceStatus(node.status),
|
|
474
474
|
payout: node.payout || null,
|
|
475
|
+
refundRate: node.refund_rate ?? null,
|
|
476
|
+
refundAmount: node.refund_amount ?? null,
|
|
475
477
|
slippage: node.slippage,
|
|
476
478
|
createdAt: node.created_at || null,
|
|
477
479
|
meta: parseMeta(node.meta)
|
|
@@ -494,12 +496,12 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
494
496
|
}`;
|
|
495
497
|
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
496
498
|
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
497
|
-
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at meta
|
|
499
|
+
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout refund_rate refund_amount slippage created_at meta
|
|
498
500
|
}
|
|
499
501
|
}`;
|
|
500
502
|
var CANCEL_BID_MUTATION = `mutation CancelBid($input: CancelBidInput!) {
|
|
501
503
|
cancelBid(input: $input) {
|
|
502
|
-
bid { id user_id pair_id currency amount coefficient time1 time2 price1 price2 status cancelled payout slippage created_at meta }
|
|
504
|
+
bid { id user_id pair_id currency amount coefficient time1 time2 price1 price2 status cancelled payout refund_rate refund_amount slippage created_at meta }
|
|
503
505
|
refund_amount
|
|
504
506
|
new_balance
|
|
505
507
|
}
|
|
@@ -1634,15 +1636,15 @@ function normaliseMeResponse(body) {
|
|
|
1634
1636
|
};
|
|
1635
1637
|
}
|
|
1636
1638
|
function normaliseCurrencies(body) {
|
|
1637
|
-
if (!Array.isArray(body)) {
|
|
1639
|
+
if (!body || !Array.isArray(body.listEnabledCurrencies)) {
|
|
1638
1640
|
throw new TaphubServerError("Invalid response from server", {
|
|
1639
1641
|
code: "InvalidResponse"
|
|
1640
1642
|
});
|
|
1641
1643
|
}
|
|
1642
|
-
return body.map((entry) => ({
|
|
1644
|
+
return body.listEnabledCurrencies.map((entry) => ({
|
|
1643
1645
|
code: entry.code,
|
|
1644
1646
|
unit: entry.unit,
|
|
1645
|
-
unitSymbol: entry.
|
|
1647
|
+
unitSymbol: entry.unitSymbol
|
|
1646
1648
|
}));
|
|
1647
1649
|
}
|
|
1648
1650
|
function normaliseWalletNode(node) {
|
|
@@ -1698,6 +1700,9 @@ function normaliseUserPnL(node) {
|
|
|
1698
1700
|
// src/modules/user/queries.ts
|
|
1699
1701
|
var ME_QUERY = "query Me { me { id username wallet_address balance is_demo } }";
|
|
1700
1702
|
var MY_WALLETS_QUERY = "query MyWallets { myWallets { id amount currency isEnable } }";
|
|
1703
|
+
var LIST_ENABLED_CURRENCIES_QUERY = `query ListEnabledCurrencies($input: ListEnabledCurrenciesInput!) {
|
|
1704
|
+
listEnabledCurrencies(input: $input) { code unit unitSymbol }
|
|
1705
|
+
}`;
|
|
1701
1706
|
var MY_WALLET_BY_CURRENCY_QUERY = "query MyWalletByCurrency($currency: String!) { myWalletByCurrency(currency: $currency) { id amount currency isEnable } }";
|
|
1702
1707
|
var USER_PNL_QUERY = `query UserPnL($period: String) {
|
|
1703
1708
|
userPnL(period: $period) {
|
|
@@ -1707,12 +1712,10 @@ var USER_PNL_QUERY = `query UserPnL($period: String) {
|
|
|
1707
1712
|
|
|
1708
1713
|
// src/modules/user/index.ts
|
|
1709
1714
|
var UserModule = class {
|
|
1710
|
-
#rest;
|
|
1711
1715
|
#graphql;
|
|
1712
1716
|
#graphqlUser;
|
|
1713
1717
|
#currencies = null;
|
|
1714
1718
|
constructor(deps) {
|
|
1715
|
-
this.#rest = deps.rest;
|
|
1716
1719
|
this.#graphql = deps.graphql;
|
|
1717
1720
|
this.#graphqlUser = deps.graphqlUser;
|
|
1718
1721
|
}
|
|
@@ -1754,7 +1757,10 @@ var UserModule = class {
|
|
|
1754
1757
|
return this.#currencies;
|
|
1755
1758
|
}
|
|
1756
1759
|
async refreshCurrencies() {
|
|
1757
|
-
const body = await this.#
|
|
1760
|
+
const body = await this.#graphqlUser.request(
|
|
1761
|
+
LIST_ENABLED_CURRENCIES_QUERY,
|
|
1762
|
+
{ input: {} }
|
|
1763
|
+
);
|
|
1758
1764
|
const currencies = normaliseCurrencies(body);
|
|
1759
1765
|
this.#currencies = currencies;
|
|
1760
1766
|
return currencies;
|
|
@@ -1930,23 +1936,28 @@ var NetworkQualityMonitor = class {
|
|
|
1930
1936
|
mqttDisconnectedAt = null;
|
|
1931
1937
|
committedNetwork = "good";
|
|
1932
1938
|
committedBackend = "ok";
|
|
1939
|
+
// The last snapshot we emitted, used to decide whether the next recompute is
|
|
1940
|
+
// worth emitting. Seeded with the initial default so the first real change
|
|
1941
|
+
// (e.g. first backend5xx, first ping) emits against the true starting state.
|
|
1942
|
+
lastEmitted;
|
|
1933
1943
|
tickHandle = null;
|
|
1934
1944
|
onlineListener = null;
|
|
1935
1945
|
offlineListener = null;
|
|
1936
1946
|
disposed = false;
|
|
1937
1947
|
constructor(opts) {
|
|
1938
1948
|
this.bus = opts.bus;
|
|
1949
|
+
this.lastEmitted = this.snapshot();
|
|
1939
1950
|
this.attachBrowserListeners();
|
|
1940
1951
|
this.startTick();
|
|
1941
1952
|
}
|
|
1942
|
-
addSample(sample
|
|
1953
|
+
addSample(sample) {
|
|
1943
1954
|
if (this.disposed) return;
|
|
1944
1955
|
const bucket = this.buckets[sample.source];
|
|
1945
1956
|
bucket.push(sample);
|
|
1946
1957
|
if (bucket.length > WINDOW_MAX_SAMPLES_PER_SOURCE) {
|
|
1947
1958
|
bucket.shift();
|
|
1948
1959
|
}
|
|
1949
|
-
this.recompute(
|
|
1960
|
+
this.recompute();
|
|
1950
1961
|
}
|
|
1951
1962
|
seedFromConnection(seed) {
|
|
1952
1963
|
const rtt = this.resolveSeedRtt(seed);
|
|
@@ -1959,24 +1970,19 @@ var NetworkQualityMonitor = class {
|
|
|
1959
1970
|
});
|
|
1960
1971
|
}
|
|
1961
1972
|
notifyMqttConnect(rttMs) {
|
|
1962
|
-
const prevMqttConnected = this.mqttConnected;
|
|
1963
1973
|
this.mqttConnected = true;
|
|
1964
1974
|
this.mqttDisconnectedAt = null;
|
|
1965
|
-
this.addSample(
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
},
|
|
1972
|
-
prevMqttConnected
|
|
1973
|
-
);
|
|
1975
|
+
this.addSample({
|
|
1976
|
+
ts: this.now(),
|
|
1977
|
+
rtt: rttMs,
|
|
1978
|
+
source: "mqtt",
|
|
1979
|
+
reason: "connect"
|
|
1980
|
+
});
|
|
1974
1981
|
}
|
|
1975
1982
|
notifyMqttDisconnect() {
|
|
1976
|
-
const prevMqttConnected = this.mqttConnected;
|
|
1977
1983
|
this.mqttConnected = false;
|
|
1978
1984
|
this.mqttDisconnectedAt = this.now();
|
|
1979
|
-
this.recompute(
|
|
1985
|
+
this.recompute();
|
|
1980
1986
|
}
|
|
1981
1987
|
notifyMqttPing(rttMs) {
|
|
1982
1988
|
this.smoother.add(rttMs);
|
|
@@ -2000,7 +2006,6 @@ var NetworkQualityMonitor = class {
|
|
|
2000
2006
|
return this.snapshot();
|
|
2001
2007
|
}
|
|
2002
2008
|
reset() {
|
|
2003
|
-
const prev = this.snapshot();
|
|
2004
2009
|
for (const key of Object.keys(this.buckets)) {
|
|
2005
2010
|
this.buckets[key] = [];
|
|
2006
2011
|
}
|
|
@@ -2009,10 +2014,7 @@ var NetworkQualityMonitor = class {
|
|
|
2009
2014
|
this.mqttDisconnectedAt = null;
|
|
2010
2015
|
this.committedNetwork = "good";
|
|
2011
2016
|
this.committedBackend = "ok";
|
|
2012
|
-
|
|
2013
|
-
if (prev.network !== current.network || prev.backend !== current.backend) {
|
|
2014
|
-
this.bus.emit("network:change", { previous: prev, current });
|
|
2015
|
-
}
|
|
2017
|
+
this.emitIfChanged(this.snapshot());
|
|
2016
2018
|
}
|
|
2017
2019
|
tick() {
|
|
2018
2020
|
this.pruneWindow();
|
|
@@ -2067,9 +2069,8 @@ var NetworkQualityMonitor = class {
|
|
|
2067
2069
|
this.buckets[key] = this.buckets[key].filter((s) => s.ts >= cutoff);
|
|
2068
2070
|
}
|
|
2069
2071
|
}
|
|
2070
|
-
recompute(
|
|
2072
|
+
recompute() {
|
|
2071
2073
|
this.pruneWindow();
|
|
2072
|
-
const prev = this.snapshot();
|
|
2073
2074
|
const allSamples = this.allHttpAndMqttSamples();
|
|
2074
2075
|
const realSamples = allSamples.filter((s) => s.source !== "connection");
|
|
2075
2076
|
const useConnection = realSamples.length < COLD_START_REAL_SAMPLE_THRESHOLD;
|
|
@@ -2093,12 +2094,26 @@ var NetworkQualityMonitor = class {
|
|
|
2093
2094
|
this.smoother.releaseOffline();
|
|
2094
2095
|
nextNetwork = this.smoother.level;
|
|
2095
2096
|
}
|
|
2096
|
-
const prevMqttConnected = prevMqttConnectedOverride ?? prev.mqttConnected;
|
|
2097
|
-
const changed = nextNetwork !== this.committedNetwork || backend !== this.committedBackend || this.mqttConnected !== prevMqttConnected;
|
|
2098
2097
|
this.committedNetwork = nextNetwork;
|
|
2099
2098
|
this.committedBackend = backend;
|
|
2099
|
+
this.emitIfChanged(this.snapshot());
|
|
2100
|
+
}
|
|
2101
|
+
// Emits network:change when any *displayed* field of the snapshot moves. This
|
|
2102
|
+
// is compared against the last emitted snapshot (not a snapshot taken at the
|
|
2103
|
+
// top of recompute): notifyMqttPing feeds the smoother BEFORE recompute, so a
|
|
2104
|
+
// same-call snapshot would already carry the new rtt and the change would be
|
|
2105
|
+
// invisible (the original "rtt label freezes on a stable connection" bug).
|
|
2106
|
+
//
|
|
2107
|
+
// Trigger fields: network, backend, mqttConnected, rtt, jitter. rtt/jitter are
|
|
2108
|
+
// bounded by the MQTT ping cadence (~keepalive), so this cannot spam. lossRate
|
|
2109
|
+
// and samplesInWindow are deliberately excluded — they move on every HTTP
|
|
2110
|
+
// sample (request-volume driven) and are diagnostics only; consumers that show
|
|
2111
|
+
// them poll getCurrent().
|
|
2112
|
+
emitIfChanged(current) {
|
|
2113
|
+
const prev = this.lastEmitted;
|
|
2114
|
+
this.lastEmitted = current;
|
|
2115
|
+
const changed = current.network !== prev.network || current.backend !== prev.backend || current.mqttConnected !== prev.mqttConnected || current.rtt !== prev.rtt || current.jitter !== prev.jitter;
|
|
2100
2116
|
if (changed) {
|
|
2101
|
-
const current = this.snapshot();
|
|
2102
2117
|
this.bus.emit("network:change", { previous: prev, current });
|
|
2103
2118
|
}
|
|
2104
2119
|
}
|
|
@@ -2738,7 +2753,6 @@ var TaphubClient = class {
|
|
|
2738
2753
|
onRequest: graphqlProbe
|
|
2739
2754
|
});
|
|
2740
2755
|
this.user = new UserModule({
|
|
2741
|
-
rest: this.#rest,
|
|
2742
2756
|
graphql: this.#graphql,
|
|
2743
2757
|
graphqlUser: this.#graphqlUser
|
|
2744
2758
|
});
|
package/dist/index.d.mts
CHANGED
|
@@ -35,7 +35,7 @@ interface TaphubClientConfig {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
type SignalSource = 'graphql' | 'rest' | 'mqtt' | 'browser' | 'connection';
|
|
38
|
-
type SampleReason = 'ok' | 'network' | 'timeout' | 'offline' | 'backend5xx' | 'backend4xx' | 'gqlError';
|
|
38
|
+
type SampleReason = 'ok' | 'connect' | 'network' | 'timeout' | 'offline' | 'backend5xx' | 'backend4xx' | 'gqlError';
|
|
39
39
|
type Sample = {
|
|
40
40
|
ts: number;
|
|
41
41
|
rtt: number;
|
|
@@ -211,6 +211,16 @@ interface Bid {
|
|
|
211
211
|
status: BidStatus;
|
|
212
212
|
payout: string | null;
|
|
213
213
|
slippage: number;
|
|
214
|
+
/**
|
|
215
|
+
* Refund terms frozen at cancel time. Present only on cancelled bids — absent
|
|
216
|
+
* (or null) on pending/won/lost bids, and on bids reconstructed from realtime
|
|
217
|
+
* store state which doesn't carry per-bid refund. `refundRate` is the rate
|
|
218
|
+
* applied (0.0–1.0); `refundAmount` is the credited amount. Prefer
|
|
219
|
+
* `refundAmount` for display — it's the exact value the server returned, so
|
|
220
|
+
* it needs no recompute from a config rate.
|
|
221
|
+
*/
|
|
222
|
+
refundRate?: string | null;
|
|
223
|
+
refundAmount?: string | null;
|
|
214
224
|
/** ISO-8601 string passthrough from the server. */
|
|
215
225
|
createdAt: string | null;
|
|
216
226
|
/**
|
|
@@ -982,7 +992,6 @@ interface UserPnL {
|
|
|
982
992
|
}
|
|
983
993
|
|
|
984
994
|
interface UserModuleDeps {
|
|
985
|
-
rest: RestTransport;
|
|
986
995
|
graphql: GraphQLTransport;
|
|
987
996
|
graphqlUser: GraphQLTransport;
|
|
988
997
|
}
|
|
@@ -1029,6 +1038,7 @@ declare class NetworkQualityMonitor {
|
|
|
1029
1038
|
private mqttDisconnectedAt;
|
|
1030
1039
|
private committedNetwork;
|
|
1031
1040
|
private committedBackend;
|
|
1041
|
+
private lastEmitted;
|
|
1032
1042
|
private tickHandle;
|
|
1033
1043
|
private onlineListener;
|
|
1034
1044
|
private offlineListener;
|
|
@@ -1036,7 +1046,7 @@ declare class NetworkQualityMonitor {
|
|
|
1036
1046
|
constructor(opts: {
|
|
1037
1047
|
bus: TaphubEventBus<EventMapWithNetwork>;
|
|
1038
1048
|
});
|
|
1039
|
-
addSample(sample: Sample
|
|
1049
|
+
addSample(sample: Sample): void;
|
|
1040
1050
|
seedFromConnection(seed: ConnectionSeed): void;
|
|
1041
1051
|
notifyMqttConnect(rttMs: number): void;
|
|
1042
1052
|
notifyMqttDisconnect(): void;
|
|
@@ -1052,6 +1062,7 @@ declare class NetworkQualityMonitor {
|
|
|
1052
1062
|
private detachBrowserListeners;
|
|
1053
1063
|
private pruneWindow;
|
|
1054
1064
|
private recompute;
|
|
1065
|
+
private emitIfChanged;
|
|
1055
1066
|
private deriveMetricsFrom;
|
|
1056
1067
|
private isHardOffline;
|
|
1057
1068
|
private allHttpAndMqttSamples;
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ interface TaphubClientConfig {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
type SignalSource = 'graphql' | 'rest' | 'mqtt' | 'browser' | 'connection';
|
|
38
|
-
type SampleReason = 'ok' | 'network' | 'timeout' | 'offline' | 'backend5xx' | 'backend4xx' | 'gqlError';
|
|
38
|
+
type SampleReason = 'ok' | 'connect' | 'network' | 'timeout' | 'offline' | 'backend5xx' | 'backend4xx' | 'gqlError';
|
|
39
39
|
type Sample = {
|
|
40
40
|
ts: number;
|
|
41
41
|
rtt: number;
|
|
@@ -211,6 +211,16 @@ interface Bid {
|
|
|
211
211
|
status: BidStatus;
|
|
212
212
|
payout: string | null;
|
|
213
213
|
slippage: number;
|
|
214
|
+
/**
|
|
215
|
+
* Refund terms frozen at cancel time. Present only on cancelled bids — absent
|
|
216
|
+
* (or null) on pending/won/lost bids, and on bids reconstructed from realtime
|
|
217
|
+
* store state which doesn't carry per-bid refund. `refundRate` is the rate
|
|
218
|
+
* applied (0.0–1.0); `refundAmount` is the credited amount. Prefer
|
|
219
|
+
* `refundAmount` for display — it's the exact value the server returned, so
|
|
220
|
+
* it needs no recompute from a config rate.
|
|
221
|
+
*/
|
|
222
|
+
refundRate?: string | null;
|
|
223
|
+
refundAmount?: string | null;
|
|
214
224
|
/** ISO-8601 string passthrough from the server. */
|
|
215
225
|
createdAt: string | null;
|
|
216
226
|
/**
|
|
@@ -982,7 +992,6 @@ interface UserPnL {
|
|
|
982
992
|
}
|
|
983
993
|
|
|
984
994
|
interface UserModuleDeps {
|
|
985
|
-
rest: RestTransport;
|
|
986
995
|
graphql: GraphQLTransport;
|
|
987
996
|
graphqlUser: GraphQLTransport;
|
|
988
997
|
}
|
|
@@ -1029,6 +1038,7 @@ declare class NetworkQualityMonitor {
|
|
|
1029
1038
|
private mqttDisconnectedAt;
|
|
1030
1039
|
private committedNetwork;
|
|
1031
1040
|
private committedBackend;
|
|
1041
|
+
private lastEmitted;
|
|
1032
1042
|
private tickHandle;
|
|
1033
1043
|
private onlineListener;
|
|
1034
1044
|
private offlineListener;
|
|
@@ -1036,7 +1046,7 @@ declare class NetworkQualityMonitor {
|
|
|
1036
1046
|
constructor(opts: {
|
|
1037
1047
|
bus: TaphubEventBus<EventMapWithNetwork>;
|
|
1038
1048
|
});
|
|
1039
|
-
addSample(sample: Sample
|
|
1049
|
+
addSample(sample: Sample): void;
|
|
1040
1050
|
seedFromConnection(seed: ConnectionSeed): void;
|
|
1041
1051
|
notifyMqttConnect(rttMs: number): void;
|
|
1042
1052
|
notifyMqttDisconnect(): void;
|
|
@@ -1052,6 +1062,7 @@ declare class NetworkQualityMonitor {
|
|
|
1052
1062
|
private detachBrowserListeners;
|
|
1053
1063
|
private pruneWindow;
|
|
1054
1064
|
private recompute;
|
|
1065
|
+
private emitIfChanged;
|
|
1055
1066
|
private deriveMetricsFrom;
|
|
1056
1067
|
private isHardOffline;
|
|
1057
1068
|
private allHttpAndMqttSamples;
|
package/dist/index.js
CHANGED
|
@@ -407,6 +407,8 @@ function normaliseBid(node) {
|
|
|
407
407
|
price2: node.price2,
|
|
408
408
|
status: coerceStatus(node.status),
|
|
409
409
|
payout: node.payout || null,
|
|
410
|
+
refundRate: node.refund_rate ?? null,
|
|
411
|
+
refundAmount: node.refund_amount ?? null,
|
|
410
412
|
slippage: node.slippage,
|
|
411
413
|
createdAt: node.created_at || null,
|
|
412
414
|
meta: parseMeta(node.meta)
|
|
@@ -429,12 +431,12 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
429
431
|
}`;
|
|
430
432
|
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
431
433
|
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
432
|
-
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout slippage created_at meta
|
|
434
|
+
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout refund_rate refund_amount slippage created_at meta
|
|
433
435
|
}
|
|
434
436
|
}`;
|
|
435
437
|
var CANCEL_BID_MUTATION = `mutation CancelBid($input: CancelBidInput!) {
|
|
436
438
|
cancelBid(input: $input) {
|
|
437
|
-
bid { id user_id pair_id currency amount coefficient time1 time2 price1 price2 status cancelled payout slippage created_at meta }
|
|
439
|
+
bid { id user_id pair_id currency amount coefficient time1 time2 price1 price2 status cancelled payout refund_rate refund_amount slippage created_at meta }
|
|
438
440
|
refund_amount
|
|
439
441
|
new_balance
|
|
440
442
|
}
|
|
@@ -1569,15 +1571,15 @@ function normaliseMeResponse(body) {
|
|
|
1569
1571
|
};
|
|
1570
1572
|
}
|
|
1571
1573
|
function normaliseCurrencies(body) {
|
|
1572
|
-
if (!Array.isArray(body)) {
|
|
1574
|
+
if (!body || !Array.isArray(body.listEnabledCurrencies)) {
|
|
1573
1575
|
throw new TaphubServerError("Invalid response from server", {
|
|
1574
1576
|
code: "InvalidResponse"
|
|
1575
1577
|
});
|
|
1576
1578
|
}
|
|
1577
|
-
return body.map((entry) => ({
|
|
1579
|
+
return body.listEnabledCurrencies.map((entry) => ({
|
|
1578
1580
|
code: entry.code,
|
|
1579
1581
|
unit: entry.unit,
|
|
1580
|
-
unitSymbol: entry.
|
|
1582
|
+
unitSymbol: entry.unitSymbol
|
|
1581
1583
|
}));
|
|
1582
1584
|
}
|
|
1583
1585
|
function normaliseWalletNode(node) {
|
|
@@ -1633,6 +1635,9 @@ function normaliseUserPnL(node) {
|
|
|
1633
1635
|
// src/modules/user/queries.ts
|
|
1634
1636
|
var ME_QUERY = "query Me { me { id username wallet_address balance is_demo } }";
|
|
1635
1637
|
var MY_WALLETS_QUERY = "query MyWallets { myWallets { id amount currency isEnable } }";
|
|
1638
|
+
var LIST_ENABLED_CURRENCIES_QUERY = `query ListEnabledCurrencies($input: ListEnabledCurrenciesInput!) {
|
|
1639
|
+
listEnabledCurrencies(input: $input) { code unit unitSymbol }
|
|
1640
|
+
}`;
|
|
1636
1641
|
var MY_WALLET_BY_CURRENCY_QUERY = "query MyWalletByCurrency($currency: String!) { myWalletByCurrency(currency: $currency) { id amount currency isEnable } }";
|
|
1637
1642
|
var USER_PNL_QUERY = `query UserPnL($period: String) {
|
|
1638
1643
|
userPnL(period: $period) {
|
|
@@ -1642,12 +1647,10 @@ var USER_PNL_QUERY = `query UserPnL($period: String) {
|
|
|
1642
1647
|
|
|
1643
1648
|
// src/modules/user/index.ts
|
|
1644
1649
|
var UserModule = class {
|
|
1645
|
-
#rest;
|
|
1646
1650
|
#graphql;
|
|
1647
1651
|
#graphqlUser;
|
|
1648
1652
|
#currencies = null;
|
|
1649
1653
|
constructor(deps) {
|
|
1650
|
-
this.#rest = deps.rest;
|
|
1651
1654
|
this.#graphql = deps.graphql;
|
|
1652
1655
|
this.#graphqlUser = deps.graphqlUser;
|
|
1653
1656
|
}
|
|
@@ -1689,7 +1692,10 @@ var UserModule = class {
|
|
|
1689
1692
|
return this.#currencies;
|
|
1690
1693
|
}
|
|
1691
1694
|
async refreshCurrencies() {
|
|
1692
|
-
const body = await this.#
|
|
1695
|
+
const body = await this.#graphqlUser.request(
|
|
1696
|
+
LIST_ENABLED_CURRENCIES_QUERY,
|
|
1697
|
+
{ input: {} }
|
|
1698
|
+
);
|
|
1693
1699
|
const currencies = normaliseCurrencies(body);
|
|
1694
1700
|
this.#currencies = currencies;
|
|
1695
1701
|
return currencies;
|
|
@@ -1865,23 +1871,28 @@ var NetworkQualityMonitor = class {
|
|
|
1865
1871
|
mqttDisconnectedAt = null;
|
|
1866
1872
|
committedNetwork = "good";
|
|
1867
1873
|
committedBackend = "ok";
|
|
1874
|
+
// The last snapshot we emitted, used to decide whether the next recompute is
|
|
1875
|
+
// worth emitting. Seeded with the initial default so the first real change
|
|
1876
|
+
// (e.g. first backend5xx, first ping) emits against the true starting state.
|
|
1877
|
+
lastEmitted;
|
|
1868
1878
|
tickHandle = null;
|
|
1869
1879
|
onlineListener = null;
|
|
1870
1880
|
offlineListener = null;
|
|
1871
1881
|
disposed = false;
|
|
1872
1882
|
constructor(opts) {
|
|
1873
1883
|
this.bus = opts.bus;
|
|
1884
|
+
this.lastEmitted = this.snapshot();
|
|
1874
1885
|
this.attachBrowserListeners();
|
|
1875
1886
|
this.startTick();
|
|
1876
1887
|
}
|
|
1877
|
-
addSample(sample
|
|
1888
|
+
addSample(sample) {
|
|
1878
1889
|
if (this.disposed) return;
|
|
1879
1890
|
const bucket = this.buckets[sample.source];
|
|
1880
1891
|
bucket.push(sample);
|
|
1881
1892
|
if (bucket.length > WINDOW_MAX_SAMPLES_PER_SOURCE) {
|
|
1882
1893
|
bucket.shift();
|
|
1883
1894
|
}
|
|
1884
|
-
this.recompute(
|
|
1895
|
+
this.recompute();
|
|
1885
1896
|
}
|
|
1886
1897
|
seedFromConnection(seed) {
|
|
1887
1898
|
const rtt = this.resolveSeedRtt(seed);
|
|
@@ -1894,24 +1905,19 @@ var NetworkQualityMonitor = class {
|
|
|
1894
1905
|
});
|
|
1895
1906
|
}
|
|
1896
1907
|
notifyMqttConnect(rttMs) {
|
|
1897
|
-
const prevMqttConnected = this.mqttConnected;
|
|
1898
1908
|
this.mqttConnected = true;
|
|
1899
1909
|
this.mqttDisconnectedAt = null;
|
|
1900
|
-
this.addSample(
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
},
|
|
1907
|
-
prevMqttConnected
|
|
1908
|
-
);
|
|
1910
|
+
this.addSample({
|
|
1911
|
+
ts: this.now(),
|
|
1912
|
+
rtt: rttMs,
|
|
1913
|
+
source: "mqtt",
|
|
1914
|
+
reason: "connect"
|
|
1915
|
+
});
|
|
1909
1916
|
}
|
|
1910
1917
|
notifyMqttDisconnect() {
|
|
1911
|
-
const prevMqttConnected = this.mqttConnected;
|
|
1912
1918
|
this.mqttConnected = false;
|
|
1913
1919
|
this.mqttDisconnectedAt = this.now();
|
|
1914
|
-
this.recompute(
|
|
1920
|
+
this.recompute();
|
|
1915
1921
|
}
|
|
1916
1922
|
notifyMqttPing(rttMs) {
|
|
1917
1923
|
this.smoother.add(rttMs);
|
|
@@ -1935,7 +1941,6 @@ var NetworkQualityMonitor = class {
|
|
|
1935
1941
|
return this.snapshot();
|
|
1936
1942
|
}
|
|
1937
1943
|
reset() {
|
|
1938
|
-
const prev = this.snapshot();
|
|
1939
1944
|
for (const key of Object.keys(this.buckets)) {
|
|
1940
1945
|
this.buckets[key] = [];
|
|
1941
1946
|
}
|
|
@@ -1944,10 +1949,7 @@ var NetworkQualityMonitor = class {
|
|
|
1944
1949
|
this.mqttDisconnectedAt = null;
|
|
1945
1950
|
this.committedNetwork = "good";
|
|
1946
1951
|
this.committedBackend = "ok";
|
|
1947
|
-
|
|
1948
|
-
if (prev.network !== current.network || prev.backend !== current.backend) {
|
|
1949
|
-
this.bus.emit("network:change", { previous: prev, current });
|
|
1950
|
-
}
|
|
1952
|
+
this.emitIfChanged(this.snapshot());
|
|
1951
1953
|
}
|
|
1952
1954
|
tick() {
|
|
1953
1955
|
this.pruneWindow();
|
|
@@ -2002,9 +2004,8 @@ var NetworkQualityMonitor = class {
|
|
|
2002
2004
|
this.buckets[key] = this.buckets[key].filter((s) => s.ts >= cutoff);
|
|
2003
2005
|
}
|
|
2004
2006
|
}
|
|
2005
|
-
recompute(
|
|
2007
|
+
recompute() {
|
|
2006
2008
|
this.pruneWindow();
|
|
2007
|
-
const prev = this.snapshot();
|
|
2008
2009
|
const allSamples = this.allHttpAndMqttSamples();
|
|
2009
2010
|
const realSamples = allSamples.filter((s) => s.source !== "connection");
|
|
2010
2011
|
const useConnection = realSamples.length < COLD_START_REAL_SAMPLE_THRESHOLD;
|
|
@@ -2028,12 +2029,26 @@ var NetworkQualityMonitor = class {
|
|
|
2028
2029
|
this.smoother.releaseOffline();
|
|
2029
2030
|
nextNetwork = this.smoother.level;
|
|
2030
2031
|
}
|
|
2031
|
-
const prevMqttConnected = prevMqttConnectedOverride ?? prev.mqttConnected;
|
|
2032
|
-
const changed = nextNetwork !== this.committedNetwork || backend !== this.committedBackend || this.mqttConnected !== prevMqttConnected;
|
|
2033
2032
|
this.committedNetwork = nextNetwork;
|
|
2034
2033
|
this.committedBackend = backend;
|
|
2034
|
+
this.emitIfChanged(this.snapshot());
|
|
2035
|
+
}
|
|
2036
|
+
// Emits network:change when any *displayed* field of the snapshot moves. This
|
|
2037
|
+
// is compared against the last emitted snapshot (not a snapshot taken at the
|
|
2038
|
+
// top of recompute): notifyMqttPing feeds the smoother BEFORE recompute, so a
|
|
2039
|
+
// same-call snapshot would already carry the new rtt and the change would be
|
|
2040
|
+
// invisible (the original "rtt label freezes on a stable connection" bug).
|
|
2041
|
+
//
|
|
2042
|
+
// Trigger fields: network, backend, mqttConnected, rtt, jitter. rtt/jitter are
|
|
2043
|
+
// bounded by the MQTT ping cadence (~keepalive), so this cannot spam. lossRate
|
|
2044
|
+
// and samplesInWindow are deliberately excluded — they move on every HTTP
|
|
2045
|
+
// sample (request-volume driven) and are diagnostics only; consumers that show
|
|
2046
|
+
// them poll getCurrent().
|
|
2047
|
+
emitIfChanged(current) {
|
|
2048
|
+
const prev = this.lastEmitted;
|
|
2049
|
+
this.lastEmitted = current;
|
|
2050
|
+
const changed = current.network !== prev.network || current.backend !== prev.backend || current.mqttConnected !== prev.mqttConnected || current.rtt !== prev.rtt || current.jitter !== prev.jitter;
|
|
2035
2051
|
if (changed) {
|
|
2036
|
-
const current = this.snapshot();
|
|
2037
2052
|
this.bus.emit("network:change", { previous: prev, current });
|
|
2038
2053
|
}
|
|
2039
2054
|
}
|
|
@@ -2673,7 +2688,6 @@ var TaphubClient = class {
|
|
|
2673
2688
|
onRequest: graphqlProbe
|
|
2674
2689
|
});
|
|
2675
2690
|
this.user = new UserModule({
|
|
2676
|
-
rest: this.#rest,
|
|
2677
2691
|
graphql: this.#graphql,
|
|
2678
2692
|
graphqlUser: this.#graphqlUser
|
|
2679
2693
|
});
|