@metamask-previews/perps-controller 11.0.0-preview-9efd0b754 → 11.0.0-preview-ea8763e0c
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/CHANGELOG.md +8 -0
- package/dist/PerpsController-method-action-types.cjs.map +1 -1
- package/dist/PerpsController-method-action-types.d.cts +12 -1
- package/dist/PerpsController-method-action-types.d.cts.map +1 -1
- package/dist/PerpsController-method-action-types.d.mts +12 -1
- package/dist/PerpsController-method-action-types.d.mts.map +1 -1
- package/dist/PerpsController-method-action-types.mjs.map +1 -1
- package/dist/PerpsController.cjs +519 -99
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts +17 -4
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts +17 -4
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +522 -102
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/constants/eventNames.cjs +3 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +1 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +1 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +3 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.cjs +14 -2
- package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.cts +7 -0
- package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.mts +7 -0
- package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
- package/dist/constants/hyperLiquidConfig.mjs +11 -0
- package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
- package/dist/constants/perpsConfig.cjs +4 -1
- package/dist/constants/perpsConfig.cjs.map +1 -1
- package/dist/constants/perpsConfig.d.cts +25 -7
- package/dist/constants/perpsConfig.d.cts.map +1 -1
- package/dist/constants/perpsConfig.d.mts +25 -7
- package/dist/constants/perpsConfig.d.mts.map +1 -1
- package/dist/constants/perpsConfig.mjs +4 -1
- package/dist/constants/perpsConfig.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +148 -1
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +11 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +11 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +149 -2
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +15 -4
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +15 -4
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/MarketDataService.cjs +41 -3
- package/dist/services/MarketDataService.cjs.map +1 -1
- package/dist/services/MarketDataService.d.cts +2 -2
- package/dist/services/MarketDataService.d.cts.map +1 -1
- package/dist/services/MarketDataService.d.mts +2 -2
- package/dist/services/MarketDataService.d.mts.map +1 -1
- package/dist/services/MarketDataService.mjs +41 -3
- package/dist/services/MarketDataService.mjs.map +1 -1
- package/dist/services/ServiceContext.cjs.map +1 -1
- package/dist/services/ServiceContext.d.cts +10 -1
- package/dist/services/ServiceContext.d.cts.map +1 -1
- package/dist/services/ServiceContext.d.mts +10 -1
- package/dist/services/ServiceContext.d.mts.map +1 -1
- package/dist/services/ServiceContext.mjs.map +1 -1
- package/dist/services/TerminalMarketService.cjs +422 -7
- package/dist/services/TerminalMarketService.cjs.map +1 -1
- package/dist/services/TerminalMarketService.d.cts +10 -1
- package/dist/services/TerminalMarketService.d.cts.map +1 -1
- package/dist/services/TerminalMarketService.d.mts +10 -1
- package/dist/services/TerminalMarketService.d.mts.map +1 -1
- package/dist/services/TerminalMarketService.mjs +423 -8
- package/dist/services/TerminalMarketService.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +43 -7
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +43 -7
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/marketUtils.cjs +16 -1
- package/dist/utils/marketUtils.cjs.map +1 -1
- package/dist/utils/marketUtils.d.cts +1 -0
- package/dist/utils/marketUtils.d.cts.map +1 -1
- package/dist/utils/marketUtils.d.mts +1 -0
- package/dist/utils/marketUtils.d.mts.map +1 -1
- package/dist/utils/marketUtils.mjs +14 -0
- package/dist/utils/marketUtils.mjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.cjs +19 -12
- package/dist/utils/perpsDiskPersistence.cjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.cts +5 -1
- package/dist/utils/perpsDiskPersistence.d.cts.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.mts +5 -1
- package/dist/utils/perpsDiskPersistence.d.mts.map +1 -1
- package/dist/utils/perpsDiskPersistence.mjs +19 -12
- package/dist/utils/perpsDiskPersistence.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MarketInfo, PerpsPlatformDependencies, TerminalAssetMetadata } from "../types/index.cjs";
|
|
1
|
+
import type { MarketInfo, PerpsGlobalSnapshotRequest, PerpsGlobalSnapshotResult, PerpsPlatformDependencies, TerminalAssetMetadata } from "../types/index.cjs";
|
|
2
2
|
/**
|
|
3
3
|
* TerminalMarketService
|
|
4
4
|
*
|
|
@@ -21,6 +21,15 @@ export declare class TerminalMarketService {
|
|
|
21
21
|
markets: MarketInfo[];
|
|
22
22
|
metadata: Map<string, TerminalAssetMetadata>;
|
|
23
23
|
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Fetch, authenticate by exact identity, and map a schema-v2 atomic market
|
|
26
|
+
* snapshot. Accepted entries remain inside the source freshness window;
|
|
27
|
+
* rejected responses are never cached.
|
|
28
|
+
*
|
|
29
|
+
* @param request - Exact provider/network/DEX identity expected by the client.
|
|
30
|
+
* @returns UI-ready market data and its source-bounded expiry.
|
|
31
|
+
*/
|
|
32
|
+
fetchGlobalSnapshot(request: PerpsGlobalSnapshotRequest): Promise<PerpsGlobalSnapshotResult>;
|
|
24
33
|
/**
|
|
25
34
|
* Invalidate the internal cache so the next fetch hits the network.
|
|
26
35
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalMarketService.d.cts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TerminalMarketService.d.cts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,UAAU,EACV,0BAA0B,EAC1B,yBAAyB,EAEzB,yBAAyB,EACzB,qBAAqB,EACtB,2BAA0B;AAkG3B;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;;gBAcpB,IAAI,EAAE,yBAAyB;IAI3C;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC;QAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;KAC9C,CAAC;IAuDF;;;;;;;OAOG;IACG,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC;IA8brC;;OAEG;IACH,UAAU,IAAI,IAAI;IAoIlB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAiB/C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MarketInfo, PerpsPlatformDependencies, TerminalAssetMetadata } from "../types/index.mjs";
|
|
1
|
+
import type { MarketInfo, PerpsGlobalSnapshotRequest, PerpsGlobalSnapshotResult, PerpsPlatformDependencies, TerminalAssetMetadata } from "../types/index.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* TerminalMarketService
|
|
4
4
|
*
|
|
@@ -21,6 +21,15 @@ export declare class TerminalMarketService {
|
|
|
21
21
|
markets: MarketInfo[];
|
|
22
22
|
metadata: Map<string, TerminalAssetMetadata>;
|
|
23
23
|
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Fetch, authenticate by exact identity, and map a schema-v2 atomic market
|
|
26
|
+
* snapshot. Accepted entries remain inside the source freshness window;
|
|
27
|
+
* rejected responses are never cached.
|
|
28
|
+
*
|
|
29
|
+
* @param request - Exact provider/network/DEX identity expected by the client.
|
|
30
|
+
* @returns UI-ready market data and its source-bounded expiry.
|
|
31
|
+
*/
|
|
32
|
+
fetchGlobalSnapshot(request: PerpsGlobalSnapshotRequest): Promise<PerpsGlobalSnapshotResult>;
|
|
24
33
|
/**
|
|
25
34
|
* Invalidate the internal cache so the next fetch hits the network.
|
|
26
35
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalMarketService.d.mts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TerminalMarketService.d.mts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,UAAU,EACV,0BAA0B,EAC1B,yBAAyB,EAEzB,yBAAyB,EACzB,qBAAqB,EACtB,2BAA0B;AAkG3B;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;;gBAcpB,IAAI,EAAE,yBAAyB;IAI3C;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC;QAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;KAC9C,CAAC;IAuDF;;;;;;;OAOG;IACG,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC;IA8brC;;OAEG;IACH,UAAU,IAAI,IAAI;IAoIlB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAiB/C"}
|
|
@@ -9,15 +9,68 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _TerminalMarketService_instances, _TerminalMarketService_deps, _TerminalMarketService_cache, _TerminalMarketService_validateItems, _TerminalMarketService_mapToMarketInfo, _TerminalMarketService_extractMetadata;
|
|
13
|
-
import { array, boolean, is, nullable, number, optional, string, type, union } from "@metamask/superstruct";
|
|
12
|
+
var _TerminalMarketService_instances, _TerminalMarketService_deps, _TerminalMarketService_cache, _TerminalMarketService_globalSnapshotCache, _TerminalMarketService_globalSnapshotInFlight, _TerminalMarketService_globalSnapshotGeneration, _TerminalMarketService_fetchAndValidateGlobalSnapshot, _TerminalMarketService_validateAndMapGlobalSnapshot, _TerminalMarketService_validateRequestedIdentity, _TerminalMarketService_buildGlobalSnapshotUrl, _TerminalMarketService_normalizeDexes, _TerminalMarketService_createFingerprint, _TerminalMarketService_validateSnapshotMarket, _TerminalMarketService_mapSnapshotMarket, _TerminalMarketService_marketTypeFor, _TerminalMarketService_cloneGlobalSnapshotResult, _TerminalMarketService_isNonNegativeSafeInteger, _TerminalMarketService_isPositiveSafeInteger, _TerminalMarketService_validateItems, _TerminalMarketService_mapToMarketInfo, _TerminalMarketService_extractMetadata;
|
|
13
|
+
import { array, boolean, is, nullable, number, object, optional, string, tuple, type, union } from "@metamask/superstruct";
|
|
14
|
+
import { bytesToHex, sha256, stringToBytes } from "@metamask/utils";
|
|
15
|
+
import { canonicalizeHyperLiquidDexes } from "../constants/hyperLiquidConfig.mjs";
|
|
14
16
|
import { PERPS_CONSTANTS, TERMINAL_API_CONFIG } from "../constants/perpsConfig.mjs";
|
|
15
17
|
import { MarketCategory } from "../types/index.mjs";
|
|
16
18
|
import { ensureError } from "../utils/errorUtils.mjs";
|
|
19
|
+
import { formatChange } from "../utils/marketDataTransform.mjs";
|
|
20
|
+
import { clonePerpsMarketData } from "../utils/marketUtils.mjs";
|
|
17
21
|
const VALID_MARKET_TYPES = new Set(Object.values(MarketCategory));
|
|
22
|
+
const GLOBAL_SNAPSHOT_SCHEMA_VERSION = 2;
|
|
23
|
+
const GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS = 30000;
|
|
24
|
+
const GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES = 1048576;
|
|
25
|
+
const GLOBAL_SNAPSHOT_PERCENT_TOLERANCE = 0.01;
|
|
26
|
+
const GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS = 5000;
|
|
27
|
+
const MINIMUM_EPOCH_MILLISECONDS = Date.UTC(2000, 0, 1);
|
|
28
|
+
const DECIMAL_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
29
|
+
const NON_NEGATIVE_DECIMAL_PATTERN = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
30
|
+
const DEX_PATTERN = /^(?:main|[a-z0-9][a-z0-9-]*)$/u;
|
|
31
|
+
const GlobalSnapshotMarketStruct = object({
|
|
32
|
+
symbol: string(),
|
|
33
|
+
provider: string(),
|
|
34
|
+
dex: string(),
|
|
35
|
+
name: nullable(string()),
|
|
36
|
+
description: nullable(string()),
|
|
37
|
+
iconUrl: nullable(string()),
|
|
38
|
+
szDecimals: number(),
|
|
39
|
+
maxLeverage: number(),
|
|
40
|
+
markPrice: string(),
|
|
41
|
+
price: string(),
|
|
42
|
+
midPrice: nullable(string()),
|
|
43
|
+
oraclePrice: string(),
|
|
44
|
+
change24h: string(),
|
|
45
|
+
changePercent24h: number(),
|
|
46
|
+
funding: string(),
|
|
47
|
+
volume24h: string(),
|
|
48
|
+
openInterest: string(),
|
|
49
|
+
category: nullable(string()),
|
|
50
|
+
keywords: nullable(array(string())),
|
|
51
|
+
tags: nullable(array(string())),
|
|
52
|
+
listedAt: nullable(number()),
|
|
53
|
+
trend: array(tuple([number(), string()])),
|
|
54
|
+
});
|
|
55
|
+
const GlobalSnapshotStruct = object({
|
|
56
|
+
schemaVersion: number(),
|
|
57
|
+
provider: string(),
|
|
58
|
+
network: string(),
|
|
59
|
+
enabledDexes: array(string()),
|
|
60
|
+
fingerprint: string(),
|
|
61
|
+
generatedAt: number(),
|
|
62
|
+
receivedAt: number(),
|
|
63
|
+
maxAgeMs: number(),
|
|
64
|
+
complete: boolean(),
|
|
65
|
+
perDexErrors: array(object({
|
|
66
|
+
dex: string(),
|
|
67
|
+
error: string(),
|
|
68
|
+
})),
|
|
69
|
+
markets: array(GlobalSnapshotMarketStruct),
|
|
70
|
+
});
|
|
18
71
|
/**
|
|
19
72
|
* Runtime validation schema for a single market item returned by
|
|
20
|
-
* `GET {
|
|
73
|
+
* `GET {terminalApi.marketDataUrl}`.
|
|
21
74
|
*
|
|
22
75
|
* Uses `type()` (loose object matching) so that extra fields the API sends
|
|
23
76
|
* (e.g. `price`, `iconUrl`, `trend`) are silently accepted.
|
|
@@ -54,6 +107,9 @@ export class TerminalMarketService {
|
|
|
54
107
|
_TerminalMarketService_instances.add(this);
|
|
55
108
|
_TerminalMarketService_deps.set(this, void 0);
|
|
56
109
|
_TerminalMarketService_cache.set(this, null);
|
|
110
|
+
_TerminalMarketService_globalSnapshotCache.set(this, new Map());
|
|
111
|
+
_TerminalMarketService_globalSnapshotInFlight.set(this, new Map());
|
|
112
|
+
_TerminalMarketService_globalSnapshotGeneration.set(this, 0);
|
|
57
113
|
__classPrivateFieldSet(this, _TerminalMarketService_deps, deps, "f");
|
|
58
114
|
}
|
|
59
115
|
/**
|
|
@@ -70,10 +126,11 @@ export class TerminalMarketService {
|
|
|
70
126
|
metadata: __classPrivateFieldGet(this, _TerminalMarketService_cache, "f").metadata,
|
|
71
127
|
};
|
|
72
128
|
}
|
|
73
|
-
|
|
74
|
-
|
|
129
|
+
const marketDataUrl = __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.marketDataUrl ?? __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApiUrl;
|
|
130
|
+
if (!marketDataUrl) {
|
|
131
|
+
throw new Error('Terminal API market-data URL not configured');
|
|
75
132
|
}
|
|
76
|
-
const url =
|
|
133
|
+
const url = marketDataUrl;
|
|
77
134
|
const controller = new AbortController();
|
|
78
135
|
const timeoutId = setTimeout(() => controller.abort(new Error('Terminal API fetch timed out')), TERMINAL_API_CONFIG.FetchTimeoutMs);
|
|
79
136
|
let response;
|
|
@@ -100,11 +157,65 @@ export class TerminalMarketService {
|
|
|
100
157
|
__classPrivateFieldSet(this, _TerminalMarketService_cache, { markets, metadata, timestamp: Date.now() }, "f");
|
|
101
158
|
return { markets, metadata };
|
|
102
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Fetch, authenticate by exact identity, and map a schema-v2 atomic market
|
|
162
|
+
* snapshot. Accepted entries remain inside the source freshness window;
|
|
163
|
+
* rejected responses are never cached.
|
|
164
|
+
*
|
|
165
|
+
* @param request - Exact provider/network/DEX identity expected by the client.
|
|
166
|
+
* @returns UI-ready market data and its source-bounded expiry.
|
|
167
|
+
*/
|
|
168
|
+
async fetchGlobalSnapshot(request) {
|
|
169
|
+
const identity = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateRequestedIdentity).call(this, request);
|
|
170
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.globalSnapshotUrl) {
|
|
171
|
+
throw new Error('Terminal global snapshot URL not configured');
|
|
172
|
+
}
|
|
173
|
+
const url = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_buildGlobalSnapshotUrl).call(this, __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi.globalSnapshotUrl, identity);
|
|
174
|
+
const cacheKey = [
|
|
175
|
+
url,
|
|
176
|
+
String(GLOBAL_SNAPSHOT_SCHEMA_VERSION),
|
|
177
|
+
identity.provider,
|
|
178
|
+
identity.network,
|
|
179
|
+
identity.enabledDexes.join(','),
|
|
180
|
+
].join('|');
|
|
181
|
+
const now = Date.now();
|
|
182
|
+
const cached = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").get(cacheKey);
|
|
183
|
+
if (cached && now < cached.expiresAt) {
|
|
184
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, cached);
|
|
185
|
+
}
|
|
186
|
+
if (cached) {
|
|
187
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").delete(cacheKey);
|
|
188
|
+
}
|
|
189
|
+
const existing = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").get(cacheKey);
|
|
190
|
+
if (existing) {
|
|
191
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, await existing);
|
|
192
|
+
}
|
|
193
|
+
const generation = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f");
|
|
194
|
+
const pending = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_fetchAndValidateGlobalSnapshot).call(this, identity, url).then((result) => {
|
|
195
|
+
if (__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f") !== generation) {
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").set(cacheKey, result);
|
|
199
|
+
return result;
|
|
200
|
+
});
|
|
201
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").set(cacheKey, pending);
|
|
202
|
+
try {
|
|
203
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, await pending);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
if (__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").get(cacheKey) === pending) {
|
|
207
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").delete(cacheKey);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
103
211
|
/**
|
|
104
212
|
* Invalidate the internal cache so the next fetch hits the network.
|
|
105
213
|
*/
|
|
106
214
|
clearCache() {
|
|
107
215
|
__classPrivateFieldSet(this, _TerminalMarketService_cache, null, "f");
|
|
216
|
+
__classPrivateFieldSet(this, _TerminalMarketService_globalSnapshotGeneration, __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f") + 1, "f");
|
|
217
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").clear();
|
|
218
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").clear();
|
|
108
219
|
}
|
|
109
220
|
/**
|
|
110
221
|
* Log a Terminal API error to Sentry without surfacing it to the user.
|
|
@@ -117,12 +228,316 @@ export class TerminalMarketService {
|
|
|
117
228
|
tags: { feature: PERPS_CONSTANTS.FeatureName, source: 'terminal-api' },
|
|
118
229
|
context: {
|
|
119
230
|
name: `TerminalMarketService.${method}`,
|
|
120
|
-
data: {
|
|
231
|
+
data: {
|
|
232
|
+
url: method.includes('globalSnapshot')
|
|
233
|
+
? __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.globalSnapshotUrl
|
|
234
|
+
: (__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.marketDataUrl ??
|
|
235
|
+
__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApiUrl),
|
|
236
|
+
},
|
|
121
237
|
},
|
|
122
238
|
});
|
|
123
239
|
}
|
|
124
240
|
}
|
|
125
|
-
_TerminalMarketService_deps = new WeakMap(), _TerminalMarketService_cache = new WeakMap(), _TerminalMarketService_instances = new WeakSet(),
|
|
241
|
+
_TerminalMarketService_deps = new WeakMap(), _TerminalMarketService_cache = new WeakMap(), _TerminalMarketService_globalSnapshotCache = new WeakMap(), _TerminalMarketService_globalSnapshotInFlight = new WeakMap(), _TerminalMarketService_globalSnapshotGeneration = new WeakMap(), _TerminalMarketService_instances = new WeakSet(), _TerminalMarketService_fetchAndValidateGlobalSnapshot = async function _TerminalMarketService_fetchAndValidateGlobalSnapshot(identity, url) {
|
|
242
|
+
const controller = new AbortController();
|
|
243
|
+
const timeoutId = setTimeout(() => controller.abort(new Error('Terminal global snapshot timed out')), TERMINAL_API_CONFIG.FetchTimeoutMs);
|
|
244
|
+
try {
|
|
245
|
+
const response = await fetch(url, {
|
|
246
|
+
method: 'GET',
|
|
247
|
+
headers: { 'Content-Type': 'application/json' },
|
|
248
|
+
signal: controller.signal,
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
throw new Error(`Terminal global snapshot returned ${String(response.status)}: ${response.statusText}`);
|
|
252
|
+
}
|
|
253
|
+
const declaredLength = response.headers?.get('content-length');
|
|
254
|
+
if (declaredLength !== null &&
|
|
255
|
+
declaredLength !== undefined &&
|
|
256
|
+
/^\d+$/u.test(declaredLength) &&
|
|
257
|
+
Number(declaredLength) > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {
|
|
258
|
+
throw new Error('Terminal global snapshot payload exceeds 1 MiB');
|
|
259
|
+
}
|
|
260
|
+
// React Native fetch does not consistently expose a streaming reader.
|
|
261
|
+
// Reject declared oversize bodies before allocation, then enforce the same
|
|
262
|
+
// byte cap after text() for servers that omit Content-Length.
|
|
263
|
+
const text = await response.text();
|
|
264
|
+
if (stringToBytes(text).byteLength > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {
|
|
265
|
+
throw new Error('Terminal global snapshot payload exceeds 1 MiB');
|
|
266
|
+
}
|
|
267
|
+
let body;
|
|
268
|
+
try {
|
|
269
|
+
body = JSON.parse(text);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
throw new Error('Terminal global snapshot returned invalid JSON');
|
|
273
|
+
}
|
|
274
|
+
if (!is(body, GlobalSnapshotStruct)) {
|
|
275
|
+
throw new Error('Terminal global snapshot failed schema validation');
|
|
276
|
+
}
|
|
277
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateAndMapGlobalSnapshot).call(this, body, identity, Date.now());
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
clearTimeout(timeoutId);
|
|
281
|
+
}
|
|
282
|
+
}, _TerminalMarketService_validateAndMapGlobalSnapshot = async function _TerminalMarketService_validateAndMapGlobalSnapshot(snapshot, identity, now) {
|
|
283
|
+
if (snapshot.schemaVersion !== GLOBAL_SNAPSHOT_SCHEMA_VERSION) {
|
|
284
|
+
throw new Error('Terminal global snapshot schema version mismatch');
|
|
285
|
+
}
|
|
286
|
+
if (snapshot.provider !== identity.provider ||
|
|
287
|
+
snapshot.network !== identity.network) {
|
|
288
|
+
throw new Error('Terminal global snapshot identity mismatch');
|
|
289
|
+
}
|
|
290
|
+
const responseDexes = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_normalizeDexes).call(this, snapshot.enabledDexes);
|
|
291
|
+
if (responseDexes.length !== identity.enabledDexes.length ||
|
|
292
|
+
responseDexes.some((dex, index) => dex !== identity.enabledDexes[index])) {
|
|
293
|
+
throw new Error('Terminal global snapshot DEX mismatch');
|
|
294
|
+
}
|
|
295
|
+
const expectedFingerprint = await __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_createFingerprint).call(this, identity);
|
|
296
|
+
if (snapshot.fingerprint !== expectedFingerprint) {
|
|
297
|
+
throw new Error('Terminal global snapshot fingerprint mismatch');
|
|
298
|
+
}
|
|
299
|
+
if (!snapshot.complete || snapshot.perDexErrors.length > 0) {
|
|
300
|
+
throw new Error('Terminal global snapshot is incomplete');
|
|
301
|
+
}
|
|
302
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, snapshot.generatedAt) ||
|
|
303
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, snapshot.receivedAt) ||
|
|
304
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isPositiveSafeInteger).call(this, snapshot.maxAgeMs) ||
|
|
305
|
+
snapshot.receivedAt > snapshot.generatedAt ||
|
|
306
|
+
snapshot.generatedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS ||
|
|
307
|
+
snapshot.receivedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS) {
|
|
308
|
+
throw new Error('Terminal global snapshot has invalid timestamps');
|
|
309
|
+
}
|
|
310
|
+
const trustedMaxAgeMs = Math.min(snapshot.maxAgeMs, GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS);
|
|
311
|
+
const expiresAt = snapshot.receivedAt + trustedMaxAgeMs;
|
|
312
|
+
if (now >= expiresAt) {
|
|
313
|
+
throw new Error('Terminal global snapshot is stale');
|
|
314
|
+
}
|
|
315
|
+
if (snapshot.markets.length === 0) {
|
|
316
|
+
throw new Error('Terminal global snapshot has no markets');
|
|
317
|
+
}
|
|
318
|
+
const marketKeys = new Set();
|
|
319
|
+
const representedDexes = new Set();
|
|
320
|
+
const markets = snapshot.markets
|
|
321
|
+
.map((market, index) => {
|
|
322
|
+
__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateSnapshotMarket).call(this, market, identity, index, snapshot.generatedAt);
|
|
323
|
+
const key = `${market.dex}:${market.symbol}`;
|
|
324
|
+
if (marketKeys.has(key)) {
|
|
325
|
+
throw new Error(`Terminal global snapshot duplicates market ${key}`);
|
|
326
|
+
}
|
|
327
|
+
marketKeys.add(key);
|
|
328
|
+
representedDexes.add(market.dex);
|
|
329
|
+
return market;
|
|
330
|
+
})
|
|
331
|
+
.map((market) => __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_mapSnapshotMarket).call(this, market, expiresAt));
|
|
332
|
+
if (identity.enabledDexes.some((dex) => !representedDexes.has(dex))) {
|
|
333
|
+
throw new Error('Terminal global snapshot is missing a requested DEX');
|
|
334
|
+
}
|
|
335
|
+
if (markets.length === 0) {
|
|
336
|
+
throw new Error('Terminal global snapshot has no tradable markets');
|
|
337
|
+
}
|
|
338
|
+
return { markets, expiresAt };
|
|
339
|
+
}, _TerminalMarketService_validateRequestedIdentity = function _TerminalMarketService_validateRequestedIdentity(request) {
|
|
340
|
+
if (request.provider !== 'hyperliquid') {
|
|
341
|
+
throw new Error('Terminal global snapshot provider is unsupported');
|
|
342
|
+
}
|
|
343
|
+
if (request.network !== 'mainnet' && request.network !== 'testnet') {
|
|
344
|
+
throw new Error('Terminal global snapshot network is unsupported');
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
provider: request.provider,
|
|
348
|
+
network: request.network,
|
|
349
|
+
enabledDexes: __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_normalizeDexes).call(this, request.enabledDexes),
|
|
350
|
+
};
|
|
351
|
+
}, _TerminalMarketService_buildGlobalSnapshotUrl = function _TerminalMarketService_buildGlobalSnapshotUrl(baseUrl, identity) {
|
|
352
|
+
const query = new URLSearchParams({
|
|
353
|
+
provider: identity.provider,
|
|
354
|
+
network: identity.network,
|
|
355
|
+
dexes: identity.enabledDexes.join(','),
|
|
356
|
+
});
|
|
357
|
+
return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;
|
|
358
|
+
}, _TerminalMarketService_normalizeDexes = function _TerminalMarketService_normalizeDexes(dexes) {
|
|
359
|
+
if (!Array.isArray(dexes) || dexes.length === 0) {
|
|
360
|
+
throw new Error('Terminal global snapshot requires at least one DEX');
|
|
361
|
+
}
|
|
362
|
+
const normalized = dexes.map((dex) => {
|
|
363
|
+
if (typeof dex !== 'string' || !DEX_PATTERN.test(dex)) {
|
|
364
|
+
throw new Error('Terminal global snapshot contains an invalid DEX');
|
|
365
|
+
}
|
|
366
|
+
return dex;
|
|
367
|
+
});
|
|
368
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
369
|
+
throw new Error('Terminal global snapshot contains duplicate DEXes');
|
|
370
|
+
}
|
|
371
|
+
if (!normalized.includes('main')) {
|
|
372
|
+
throw new Error('Terminal global snapshot requires the main DEX');
|
|
373
|
+
}
|
|
374
|
+
return canonicalizeHyperLiquidDexes(normalized);
|
|
375
|
+
}, _TerminalMarketService_createFingerprint = async function _TerminalMarketService_createFingerprint(identity) {
|
|
376
|
+
const canonicalIdentity = JSON.stringify({
|
|
377
|
+
provider: identity.provider,
|
|
378
|
+
network: identity.network,
|
|
379
|
+
enabledDexes: identity.enabledDexes,
|
|
380
|
+
});
|
|
381
|
+
const digest = await sha256(stringToBytes(canonicalIdentity));
|
|
382
|
+
return `sha256:${bytesToHex(digest).slice(2)}`;
|
|
383
|
+
}, _TerminalMarketService_validateSnapshotMarket = function _TerminalMarketService_validateSnapshotMarket(market, identity, index, generatedAt) {
|
|
384
|
+
const invalid = (field) => new Error(`Terminal global snapshot market ${String(index)} has invalid ${field}`);
|
|
385
|
+
if (!identity.enabledDexes.includes(market.dex)) {
|
|
386
|
+
throw invalid('dex');
|
|
387
|
+
}
|
|
388
|
+
const expectedProvider = market.dex === 'main' ? 'hyperliquid' : market.dex;
|
|
389
|
+
if (market.provider !== expectedProvider) {
|
|
390
|
+
throw invalid('provider');
|
|
391
|
+
}
|
|
392
|
+
const expectedPrefix = market.dex === 'main' ? '' : `${market.dex}:`;
|
|
393
|
+
if (market.symbol.length === 0 ||
|
|
394
|
+
(expectedPrefix
|
|
395
|
+
? !market.symbol.startsWith(expectedPrefix)
|
|
396
|
+
: market.symbol.includes(':'))) {
|
|
397
|
+
throw invalid('symbol');
|
|
398
|
+
}
|
|
399
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, market.szDecimals) ||
|
|
400
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isPositiveSafeInteger).call(this, market.maxLeverage) ||
|
|
401
|
+
(market.listedAt !== null &&
|
|
402
|
+
(!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, market.listedAt) ||
|
|
403
|
+
market.listedAt < MINIMUM_EPOCH_MILLISECONDS ||
|
|
404
|
+
market.listedAt > generatedAt))) {
|
|
405
|
+
throw invalid('integer field');
|
|
406
|
+
}
|
|
407
|
+
const decimalFields = [
|
|
408
|
+
['markPrice', market.markPrice, true],
|
|
409
|
+
['price', market.price, true],
|
|
410
|
+
['oraclePrice', market.oraclePrice, true],
|
|
411
|
+
['change24h', market.change24h, false],
|
|
412
|
+
['volume24h', market.volume24h, true],
|
|
413
|
+
['openInterest', market.openInterest, true],
|
|
414
|
+
['funding', market.funding, false],
|
|
415
|
+
];
|
|
416
|
+
if (market.midPrice !== null) {
|
|
417
|
+
decimalFields.push(['midPrice', market.midPrice, true]);
|
|
418
|
+
}
|
|
419
|
+
for (const [field, value, nonNegative] of decimalFields) {
|
|
420
|
+
const pattern = nonNegative
|
|
421
|
+
? NON_NEGATIVE_DECIMAL_PATTERN
|
|
422
|
+
: DECIMAL_PATTERN;
|
|
423
|
+
if (!pattern.test(value) || !Number.isFinite(Number(value))) {
|
|
424
|
+
throw invalid(field);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (market.price !== market.markPrice) {
|
|
428
|
+
throw invalid('deprecated price alias');
|
|
429
|
+
}
|
|
430
|
+
if (Number(market.oraclePrice) <= 0 ||
|
|
431
|
+
(market.midPrice !== null && Number(market.midPrice) <= 0)) {
|
|
432
|
+
throw invalid('reference price');
|
|
433
|
+
}
|
|
434
|
+
const price = Number(market.markPrice);
|
|
435
|
+
const change24h = Number(market.change24h);
|
|
436
|
+
const previousPrice = price - change24h;
|
|
437
|
+
if (price <= 0 || previousPrice <= 0 || !Number.isFinite(previousPrice)) {
|
|
438
|
+
throw invalid('mark/change coherence');
|
|
439
|
+
}
|
|
440
|
+
const derivedPercent = (change24h / previousPrice) * 100;
|
|
441
|
+
if (!Number.isFinite(derivedPercent) ||
|
|
442
|
+
!Number.isFinite(market.changePercent24h) ||
|
|
443
|
+
Math.abs(market.changePercent24h - derivedPercent) >
|
|
444
|
+
GLOBAL_SNAPSHOT_PERCENT_TOLERANCE) {
|
|
445
|
+
throw invalid('changePercent24h coherence');
|
|
446
|
+
}
|
|
447
|
+
for (const [field, values] of [
|
|
448
|
+
['keywords', market.keywords],
|
|
449
|
+
['tags', market.tags],
|
|
450
|
+
]) {
|
|
451
|
+
if (values !== null &&
|
|
452
|
+
(values.some((value) => value.length === 0) ||
|
|
453
|
+
new Set(values).size !== values.length)) {
|
|
454
|
+
throw invalid(field);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
for (const [field, value] of [
|
|
458
|
+
['name', market.name],
|
|
459
|
+
['description', market.description],
|
|
460
|
+
['iconUrl', market.iconUrl],
|
|
461
|
+
['category', market.category],
|
|
462
|
+
]) {
|
|
463
|
+
if (value !== null && value.length === 0) {
|
|
464
|
+
throw invalid(field);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
let previousTrendTimestamp = -1;
|
|
468
|
+
for (const [timestamp, trendPrice] of market.trend) {
|
|
469
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, timestamp) ||
|
|
470
|
+
timestamp < MINIMUM_EPOCH_MILLISECONDS ||
|
|
471
|
+
timestamp > generatedAt ||
|
|
472
|
+
timestamp <= previousTrendTimestamp ||
|
|
473
|
+
!NON_NEGATIVE_DECIMAL_PATTERN.test(trendPrice) ||
|
|
474
|
+
!Number.isFinite(Number(trendPrice)) ||
|
|
475
|
+
Number(trendPrice) <= 0) {
|
|
476
|
+
throw invalid('trend');
|
|
477
|
+
}
|
|
478
|
+
previousTrendTimestamp = timestamp;
|
|
479
|
+
}
|
|
480
|
+
}, _TerminalMarketService_mapSnapshotMarket = function _TerminalMarketService_mapSnapshotMarket(market, sourceExpiresAt) {
|
|
481
|
+
const formatters = __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").marketDataFormatters;
|
|
482
|
+
// Keep both provider price semantics explicit in the wire contract. Core
|
|
483
|
+
// maps markPrice to its UI price while retaining validation of midPrice.
|
|
484
|
+
const price = Number(market.markPrice);
|
|
485
|
+
const change24h = Number(market.change24h);
|
|
486
|
+
const volume = Number(market.volume24h);
|
|
487
|
+
const openInterest = Number(market.openInterest);
|
|
488
|
+
const isHip3 = market.dex !== 'main';
|
|
489
|
+
const marketType = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_marketTypeFor).call(this, market.dex, market.category);
|
|
490
|
+
return {
|
|
491
|
+
symbol: market.symbol,
|
|
492
|
+
name: market.name ?? market.symbol,
|
|
493
|
+
...(market.description !== null && {
|
|
494
|
+
description: market.description,
|
|
495
|
+
}),
|
|
496
|
+
maxLeverage: `${String(market.maxLeverage)}x`,
|
|
497
|
+
price: formatters.formatPerpsFiat(price, {
|
|
498
|
+
ranges: formatters.priceRangesUniversal,
|
|
499
|
+
}),
|
|
500
|
+
change24h: formatChange(change24h, formatters),
|
|
501
|
+
change24hPercent: formatters.formatPercentage(market.changePercent24h),
|
|
502
|
+
volume: formatters.formatVolume(volume),
|
|
503
|
+
openInterest: formatters.formatVolume(openInterest),
|
|
504
|
+
fundingRate: Number(market.funding),
|
|
505
|
+
marketSource: isHip3 ? market.dex : undefined,
|
|
506
|
+
marketType,
|
|
507
|
+
isHip3,
|
|
508
|
+
isNewMarket: isHip3 && marketType === undefined,
|
|
509
|
+
...(market.keywords && { keywords: market.keywords }),
|
|
510
|
+
...(market.tags && { tags: market.tags }),
|
|
511
|
+
...(market.category && { categories: [market.category] }),
|
|
512
|
+
...(market.listedAt !== null && { listedAt: market.listedAt }),
|
|
513
|
+
trend: market.trend,
|
|
514
|
+
dataSource: 'terminal-global-snapshot-mark',
|
|
515
|
+
sourceExpiresAt,
|
|
516
|
+
};
|
|
517
|
+
}, _TerminalMarketService_marketTypeFor = function _TerminalMarketService_marketTypeFor(dex, category) {
|
|
518
|
+
if (dex === 'main') {
|
|
519
|
+
return MarketCategory.CryptoCurrency;
|
|
520
|
+
}
|
|
521
|
+
if (category === 'stocks') {
|
|
522
|
+
return MarketCategory.Stock;
|
|
523
|
+
}
|
|
524
|
+
if (category === 'pre_ipo') {
|
|
525
|
+
return MarketCategory.PreIpo;
|
|
526
|
+
}
|
|
527
|
+
if (category && VALID_MARKET_TYPES.has(category)) {
|
|
528
|
+
return category;
|
|
529
|
+
}
|
|
530
|
+
return undefined;
|
|
531
|
+
}, _TerminalMarketService_cloneGlobalSnapshotResult = function _TerminalMarketService_cloneGlobalSnapshotResult(result) {
|
|
532
|
+
return {
|
|
533
|
+
expiresAt: result.expiresAt,
|
|
534
|
+
markets: clonePerpsMarketData(result.markets),
|
|
535
|
+
};
|
|
536
|
+
}, _TerminalMarketService_isNonNegativeSafeInteger = function _TerminalMarketService_isNonNegativeSafeInteger(value) {
|
|
537
|
+
return (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0);
|
|
538
|
+
}, _TerminalMarketService_isPositiveSafeInteger = function _TerminalMarketService_isPositiveSafeInteger(value) {
|
|
539
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, value) && value > 0;
|
|
540
|
+
}, _TerminalMarketService_validateItems = function _TerminalMarketService_validateItems(raw) {
|
|
126
541
|
const valid = [];
|
|
127
542
|
for (const item of raw) {
|
|
128
543
|
if (is(item, TerminalPerpetualItemStruct)) {
|