@metamask-previews/perps-controller 3.1.0-preview-d6985be → 3.1.1-preview-9c8c0a0
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 +9 -1
- package/dist/PerpsController.cjs +5 -1
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +5 -1
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +63 -166
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +64 -167
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/services/DexDiscoveryCacheManager.cjs +147 -0
- package/dist/services/DexDiscoveryCacheManager.cjs.map +1 -0
- package/dist/services/DexDiscoveryCacheManager.d.cts +52 -0
- package/dist/services/DexDiscoveryCacheManager.d.cts.map +1 -0
- package/dist/services/DexDiscoveryCacheManager.d.mts +52 -0
- package/dist/services/DexDiscoveryCacheManager.d.mts.map +1 -0
- package/dist/services/DexDiscoveryCacheManager.mjs +143 -0
- package/dist/services/DexDiscoveryCacheManager.mjs.map +1 -0
- package/dist/services/HyperLiquidClientService.cjs +4 -3
- package/dist/services/HyperLiquidClientService.cjs.map +1 -1
- package/dist/services/HyperLiquidClientService.d.cts.map +1 -1
- package/dist/services/HyperLiquidClientService.d.mts.map +1 -1
- package/dist/services/HyperLiquidClientService.mjs +4 -3
- package/dist/services/HyperLiquidClientService.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +34 -2
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +34 -2
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/types/perps-types.cjs.map +1 -1
- package/dist/types/perps-types.d.cts +13 -0
- package/dist/types/perps-types.d.cts.map +1 -1
- package/dist/types/perps-types.d.mts +13 -0
- package/dist/types/perps-types.d.mts.map +1 -1
- package/dist/types/perps-types.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
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");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _DexDiscoveryCacheManager_deps;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.DexDiscoveryCacheManager = void 0;
|
|
16
|
+
const hyperLiquidConfig_1 = require("../constants/hyperLiquidConfig.cjs");
|
|
17
|
+
/**
|
|
18
|
+
* Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.
|
|
19
|
+
*
|
|
20
|
+
* Extracted from HyperLiquidProvider to isolate cache logic.
|
|
21
|
+
* All writes go through update(); readers use .state.
|
|
22
|
+
*/
|
|
23
|
+
class DexDiscoveryCacheManager {
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
/**
|
|
26
|
+
* Unified DEX discovery state.
|
|
27
|
+
* null = not yet fetched; object = raw + validated + timestamp.
|
|
28
|
+
*/
|
|
29
|
+
this.state = null;
|
|
30
|
+
_DexDiscoveryCacheManager_deps.set(this, void 0);
|
|
31
|
+
__classPrivateFieldSet(this, _DexDiscoveryCacheManager_deps, deps, "f");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Single atomic writer for DEX discovery state.
|
|
35
|
+
* All code paths that fetch perpDexs() MUST call this — no direct field writes.
|
|
36
|
+
*
|
|
37
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
38
|
+
* @returns The newly created unified discovery state.
|
|
39
|
+
*/
|
|
40
|
+
update(allDexs) {
|
|
41
|
+
const validated = this.computeValidatedDexs(allDexs);
|
|
42
|
+
const newState = {
|
|
43
|
+
raw: allDexs,
|
|
44
|
+
validated,
|
|
45
|
+
timestamp: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
this.state = newState;
|
|
48
|
+
return newState;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reset state to null (used on disconnect/reconnect).
|
|
52
|
+
*/
|
|
53
|
+
reset() {
|
|
54
|
+
this.state = null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Pure filtering of perpDexs() response into validated DEX names.
|
|
58
|
+
* Encapsulates testnet/mainnet feature-flag logic.
|
|
59
|
+
*
|
|
60
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
61
|
+
* @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).
|
|
62
|
+
*/
|
|
63
|
+
computeValidatedDexs(allDexs) {
|
|
64
|
+
const availableHip3Dexs = [];
|
|
65
|
+
allDexs.forEach((dex) => {
|
|
66
|
+
if (dex !== null) {
|
|
67
|
+
availableHip3Dexs.push(dex.name);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
if (__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").isTestnetMode()) {
|
|
71
|
+
const { EnabledDexs, AutoDiscoverAll } = hyperLiquidConfig_1.TESTNET_HIP3_CONFIG;
|
|
72
|
+
if (!AutoDiscoverAll) {
|
|
73
|
+
if (EnabledDexs.length === 0) {
|
|
74
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - using main DEX only (HIP-3 DEXs filtered)', {
|
|
75
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
76
|
+
reason: 'TESTNET_HIP3_CONFIG.EnabledDexs is empty',
|
|
77
|
+
});
|
|
78
|
+
return [null];
|
|
79
|
+
}
|
|
80
|
+
const filteredDexs = availableHip3Dexs.filter((dex) => EnabledDexs.includes(dex));
|
|
81
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - filtered to allowed DEXs', {
|
|
82
|
+
allowedDexs: EnabledDexs,
|
|
83
|
+
filteredDexs,
|
|
84
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
85
|
+
});
|
|
86
|
+
return [null, ...filteredDexs];
|
|
87
|
+
}
|
|
88
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - AUTO_DISCOVER_ALL enabled, using all DEXs', { totalDexCount: availableHip3Dexs.length + 1 });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const { AutoDiscoverAll } = hyperLiquidConfig_1.MAINNET_HIP3_CONFIG;
|
|
92
|
+
if (!AutoDiscoverAll) {
|
|
93
|
+
const allowedDexsFromAllowlist = this.extractDexsFromAllowlist();
|
|
94
|
+
if (allowedDexsFromAllowlist.length === 0) {
|
|
95
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - using main DEX only (no HIP-3 DEXs in allowlist)', {
|
|
96
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
97
|
+
allowlistMarkets: __classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").getAllowlistMarkets(),
|
|
98
|
+
});
|
|
99
|
+
return [null];
|
|
100
|
+
}
|
|
101
|
+
const filteredDexs = availableHip3Dexs.filter((dex) => allowedDexsFromAllowlist.includes(dex));
|
|
102
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - filtered to allowlist DEXs', {
|
|
103
|
+
allowedDexsFromAllowlist,
|
|
104
|
+
filteredDexs,
|
|
105
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
106
|
+
});
|
|
107
|
+
return [null, ...filteredDexs];
|
|
108
|
+
}
|
|
109
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - AUTO_DISCOVER_ALL enabled, using all DEXs', { totalDexCount: availableHip3Dexs.length + 1 });
|
|
110
|
+
}
|
|
111
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: All DEXs enabled (market filtering at data layer)', {
|
|
112
|
+
mainDex: true,
|
|
113
|
+
hip3Dexs: availableHip3Dexs,
|
|
114
|
+
totalDexCount: availableHip3Dexs.length + 1,
|
|
115
|
+
});
|
|
116
|
+
return [null, ...availableHip3Dexs];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Extract unique DEX names from allowlist market patterns.
|
|
120
|
+
* Patterns can be: "xyz:*" (wildcard), "xyz:TSLA" (exact), or "xyz" (DEX shorthand).
|
|
121
|
+
*
|
|
122
|
+
* @returns Array of unique DEX names from the allowlist.
|
|
123
|
+
*/
|
|
124
|
+
extractDexsFromAllowlist() {
|
|
125
|
+
const allowlistMarkets = __classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").getAllowlistMarkets();
|
|
126
|
+
if (allowlistMarkets.length === 0) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
const dexNames = new Set();
|
|
130
|
+
for (const pattern of allowlistMarkets) {
|
|
131
|
+
const colonIndex = pattern.indexOf(':');
|
|
132
|
+
if (colonIndex > 0) {
|
|
133
|
+
const dex = pattern.substring(0, colonIndex);
|
|
134
|
+
dexNames.add(dex);
|
|
135
|
+
}
|
|
136
|
+
else if (pattern.length > 0 && !pattern.includes('*')) {
|
|
137
|
+
if (/^[a-z][a-z0-9]*$/iu.test(pattern)) {
|
|
138
|
+
dexNames.add(pattern.toLowerCase());
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return Array.from(dexNames);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.DexDiscoveryCacheManager = DexDiscoveryCacheManager;
|
|
146
|
+
_DexDiscoveryCacheManager_deps = new WeakMap();
|
|
147
|
+
//# sourceMappingURL=DexDiscoveryCacheManager.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DexDiscoveryCacheManager.cjs","sourceRoot":"","sources":["../../src/services/DexDiscoveryCacheManager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n MAINNET_HIP3_CONFIG,\n TESTNET_HIP3_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport type { DexDiscoveryState, ExtendedPerpDex } from '../types/perps-types';\n\ntype DexDiscoveryDeps = {\n isTestnetMode: () => boolean;\n debugLogger: { log: (...args: unknown[]) => void };\n getAllowlistMarkets: () => string[];\n};\n\n/**\n * Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.\n *\n * Extracted from HyperLiquidProvider to isolate cache logic.\n * All writes go through update(); readers use .state.\n */\nexport class DexDiscoveryCacheManager {\n /**\n * Unified DEX discovery state.\n * null = not yet fetched; object = raw + validated + timestamp.\n */\n state: DexDiscoveryState | null = null;\n\n readonly #deps: DexDiscoveryDeps;\n\n constructor(deps: DexDiscoveryDeps) {\n this.#deps = deps;\n }\n\n /**\n * Single atomic writer for DEX discovery state.\n * All code paths that fetch perpDexs() MUST call this — no direct field writes.\n *\n * @param allDexs - Raw perpDexs() API response array.\n * @returns The newly created unified discovery state.\n */\n update(allDexs: (ExtendedPerpDex | null)[]): DexDiscoveryState {\n const validated = this.computeValidatedDexs(allDexs);\n const newState: DexDiscoveryState = {\n raw: allDexs,\n validated,\n timestamp: Date.now(),\n };\n this.state = newState;\n return newState;\n }\n\n /**\n * Reset state to null (used on disconnect/reconnect).\n */\n reset(): void {\n this.state = null;\n }\n\n /**\n * Pure filtering of perpDexs() response into validated DEX names.\n * Encapsulates testnet/mainnet feature-flag logic.\n *\n * @param allDexs - Raw perpDexs() API response array.\n * @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).\n */\n computeValidatedDexs(allDexs: (ExtendedPerpDex | null)[]): (string | null)[] {\n const availableHip3Dexs: string[] = [];\n allDexs.forEach((dex) => {\n if (dex !== null) {\n availableHip3Dexs.push(dex.name);\n }\n });\n\n if (this.#deps.isTestnetMode()) {\n const { EnabledDexs, AutoDiscoverAll } = TESTNET_HIP3_CONFIG;\n\n if (!AutoDiscoverAll) {\n if (EnabledDexs.length === 0) {\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - using main DEX only (HIP-3 DEXs filtered)',\n {\n availableHip3Dexs: availableHip3Dexs.length,\n reason: 'TESTNET_HIP3_CONFIG.EnabledDexs is empty',\n },\n );\n return [null];\n }\n\n const filteredDexs = availableHip3Dexs.filter((dex) =>\n EnabledDexs.includes(dex),\n );\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - filtered to allowed DEXs',\n {\n allowedDexs: EnabledDexs,\n filteredDexs,\n availableHip3Dexs: availableHip3Dexs.length,\n },\n );\n return [null, ...filteredDexs];\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - AUTO_DISCOVER_ALL enabled, using all DEXs',\n { totalDexCount: availableHip3Dexs.length + 1 },\n );\n } else {\n const { AutoDiscoverAll } = MAINNET_HIP3_CONFIG;\n\n if (!AutoDiscoverAll) {\n const allowedDexsFromAllowlist = this.extractDexsFromAllowlist();\n\n if (allowedDexsFromAllowlist.length === 0) {\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - using main DEX only (no HIP-3 DEXs in allowlist)',\n {\n availableHip3Dexs: availableHip3Dexs.length,\n allowlistMarkets: this.#deps.getAllowlistMarkets(),\n },\n );\n return [null];\n }\n\n const filteredDexs = availableHip3Dexs.filter((dex) =>\n allowedDexsFromAllowlist.includes(dex),\n );\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - filtered to allowlist DEXs',\n {\n allowedDexsFromAllowlist,\n filteredDexs,\n availableHip3Dexs: availableHip3Dexs.length,\n },\n );\n return [null, ...filteredDexs];\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - AUTO_DISCOVER_ALL enabled, using all DEXs',\n { totalDexCount: availableHip3Dexs.length + 1 },\n );\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: All DEXs enabled (market filtering at data layer)',\n {\n mainDex: true,\n hip3Dexs: availableHip3Dexs,\n totalDexCount: availableHip3Dexs.length + 1,\n },\n );\n return [null, ...availableHip3Dexs];\n }\n\n /**\n * Extract unique DEX names from allowlist market patterns.\n * Patterns can be: \"xyz:*\" (wildcard), \"xyz:TSLA\" (exact), or \"xyz\" (DEX shorthand).\n *\n * @returns Array of unique DEX names from the allowlist.\n */\n extractDexsFromAllowlist(): string[] {\n const allowlistMarkets = this.#deps.getAllowlistMarkets();\n if (allowlistMarkets.length === 0) {\n return [];\n }\n\n const dexNames = new Set<string>();\n\n for (const pattern of allowlistMarkets) {\n const colonIndex = pattern.indexOf(':');\n if (colonIndex > 0) {\n const dex = pattern.substring(0, colonIndex);\n dexNames.add(dex);\n } else if (pattern.length > 0 && !pattern.includes('*')) {\n if (/^[a-z][a-z0-9]*$/iu.test(pattern)) {\n dexNames.add(pattern.toLowerCase());\n }\n }\n }\n\n return Array.from(dexNames);\n }\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DexDiscoveryState, ExtendedPerpDex } from "../types/perps-types.cjs";
|
|
2
|
+
type DexDiscoveryDeps = {
|
|
3
|
+
isTestnetMode: () => boolean;
|
|
4
|
+
debugLogger: {
|
|
5
|
+
log: (...args: unknown[]) => void;
|
|
6
|
+
};
|
|
7
|
+
getAllowlistMarkets: () => string[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.
|
|
11
|
+
*
|
|
12
|
+
* Extracted from HyperLiquidProvider to isolate cache logic.
|
|
13
|
+
* All writes go through update(); readers use .state.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DexDiscoveryCacheManager {
|
|
16
|
+
#private;
|
|
17
|
+
/**
|
|
18
|
+
* Unified DEX discovery state.
|
|
19
|
+
* null = not yet fetched; object = raw + validated + timestamp.
|
|
20
|
+
*/
|
|
21
|
+
state: DexDiscoveryState | null;
|
|
22
|
+
constructor(deps: DexDiscoveryDeps);
|
|
23
|
+
/**
|
|
24
|
+
* Single atomic writer for DEX discovery state.
|
|
25
|
+
* All code paths that fetch perpDexs() MUST call this — no direct field writes.
|
|
26
|
+
*
|
|
27
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
28
|
+
* @returns The newly created unified discovery state.
|
|
29
|
+
*/
|
|
30
|
+
update(allDexs: (ExtendedPerpDex | null)[]): DexDiscoveryState;
|
|
31
|
+
/**
|
|
32
|
+
* Reset state to null (used on disconnect/reconnect).
|
|
33
|
+
*/
|
|
34
|
+
reset(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Pure filtering of perpDexs() response into validated DEX names.
|
|
37
|
+
* Encapsulates testnet/mainnet feature-flag logic.
|
|
38
|
+
*
|
|
39
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
40
|
+
* @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).
|
|
41
|
+
*/
|
|
42
|
+
computeValidatedDexs(allDexs: (ExtendedPerpDex | null)[]): (string | null)[];
|
|
43
|
+
/**
|
|
44
|
+
* Extract unique DEX names from allowlist market patterns.
|
|
45
|
+
* Patterns can be: "xyz:*" (wildcard), "xyz:TSLA" (exact), or "xyz" (DEX shorthand).
|
|
46
|
+
*
|
|
47
|
+
* @returns Array of unique DEX names from the allowlist.
|
|
48
|
+
*/
|
|
49
|
+
extractDexsFromAllowlist(): string[];
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=DexDiscoveryCacheManager.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DexDiscoveryCacheManager.d.cts","sourceRoot":"","sources":["../../src/services/DexDiscoveryCacheManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,iCAA6B;AAE/E,KAAK,gBAAgB,GAAG;IACtB,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,WAAW,EAAE;QAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;IACnD,mBAAmB,EAAE,MAAM,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,wBAAwB;;IACnC;;;OAGG;IACH,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAQ;gBAI3B,IAAI,EAAE,gBAAgB;IAIlC;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,eAAe,GAAG,IAAI,CAAC,EAAE,GAAG,iBAAiB;IAW9D;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;;OAMG;IACH,oBAAoB,CAAC,OAAO,EAAE,CAAC,eAAe,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAyF5E;;;;;OAKG;IACH,wBAAwB,IAAI,MAAM,EAAE;CAsBrC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DexDiscoveryState, ExtendedPerpDex } from "../types/perps-types.mjs";
|
|
2
|
+
type DexDiscoveryDeps = {
|
|
3
|
+
isTestnetMode: () => boolean;
|
|
4
|
+
debugLogger: {
|
|
5
|
+
log: (...args: unknown[]) => void;
|
|
6
|
+
};
|
|
7
|
+
getAllowlistMarkets: () => string[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.
|
|
11
|
+
*
|
|
12
|
+
* Extracted from HyperLiquidProvider to isolate cache logic.
|
|
13
|
+
* All writes go through update(); readers use .state.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DexDiscoveryCacheManager {
|
|
16
|
+
#private;
|
|
17
|
+
/**
|
|
18
|
+
* Unified DEX discovery state.
|
|
19
|
+
* null = not yet fetched; object = raw + validated + timestamp.
|
|
20
|
+
*/
|
|
21
|
+
state: DexDiscoveryState | null;
|
|
22
|
+
constructor(deps: DexDiscoveryDeps);
|
|
23
|
+
/**
|
|
24
|
+
* Single atomic writer for DEX discovery state.
|
|
25
|
+
* All code paths that fetch perpDexs() MUST call this — no direct field writes.
|
|
26
|
+
*
|
|
27
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
28
|
+
* @returns The newly created unified discovery state.
|
|
29
|
+
*/
|
|
30
|
+
update(allDexs: (ExtendedPerpDex | null)[]): DexDiscoveryState;
|
|
31
|
+
/**
|
|
32
|
+
* Reset state to null (used on disconnect/reconnect).
|
|
33
|
+
*/
|
|
34
|
+
reset(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Pure filtering of perpDexs() response into validated DEX names.
|
|
37
|
+
* Encapsulates testnet/mainnet feature-flag logic.
|
|
38
|
+
*
|
|
39
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
40
|
+
* @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).
|
|
41
|
+
*/
|
|
42
|
+
computeValidatedDexs(allDexs: (ExtendedPerpDex | null)[]): (string | null)[];
|
|
43
|
+
/**
|
|
44
|
+
* Extract unique DEX names from allowlist market patterns.
|
|
45
|
+
* Patterns can be: "xyz:*" (wildcard), "xyz:TSLA" (exact), or "xyz" (DEX shorthand).
|
|
46
|
+
*
|
|
47
|
+
* @returns Array of unique DEX names from the allowlist.
|
|
48
|
+
*/
|
|
49
|
+
extractDexsFromAllowlist(): string[];
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=DexDiscoveryCacheManager.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DexDiscoveryCacheManager.d.mts","sourceRoot":"","sources":["../../src/services/DexDiscoveryCacheManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,iCAA6B;AAE/E,KAAK,gBAAgB,GAAG;IACtB,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,WAAW,EAAE;QAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;IACnD,mBAAmB,EAAE,MAAM,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,wBAAwB;;IACnC;;;OAGG;IACH,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAQ;gBAI3B,IAAI,EAAE,gBAAgB;IAIlC;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,eAAe,GAAG,IAAI,CAAC,EAAE,GAAG,iBAAiB;IAW9D;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;;OAMG;IACH,oBAAoB,CAAC,OAAO,EAAE,CAAC,eAAe,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAyF5E;;;;;OAKG;IACH,wBAAwB,IAAI,MAAM,EAAE;CAsBrC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _DexDiscoveryCacheManager_deps;
|
|
13
|
+
import { MAINNET_HIP3_CONFIG, TESTNET_HIP3_CONFIG } from "../constants/hyperLiquidConfig.mjs";
|
|
14
|
+
/**
|
|
15
|
+
* Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.
|
|
16
|
+
*
|
|
17
|
+
* Extracted from HyperLiquidProvider to isolate cache logic.
|
|
18
|
+
* All writes go through update(); readers use .state.
|
|
19
|
+
*/
|
|
20
|
+
export class DexDiscoveryCacheManager {
|
|
21
|
+
constructor(deps) {
|
|
22
|
+
/**
|
|
23
|
+
* Unified DEX discovery state.
|
|
24
|
+
* null = not yet fetched; object = raw + validated + timestamp.
|
|
25
|
+
*/
|
|
26
|
+
this.state = null;
|
|
27
|
+
_DexDiscoveryCacheManager_deps.set(this, void 0);
|
|
28
|
+
__classPrivateFieldSet(this, _DexDiscoveryCacheManager_deps, deps, "f");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Single atomic writer for DEX discovery state.
|
|
32
|
+
* All code paths that fetch perpDexs() MUST call this — no direct field writes.
|
|
33
|
+
*
|
|
34
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
35
|
+
* @returns The newly created unified discovery state.
|
|
36
|
+
*/
|
|
37
|
+
update(allDexs) {
|
|
38
|
+
const validated = this.computeValidatedDexs(allDexs);
|
|
39
|
+
const newState = {
|
|
40
|
+
raw: allDexs,
|
|
41
|
+
validated,
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
};
|
|
44
|
+
this.state = newState;
|
|
45
|
+
return newState;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Reset state to null (used on disconnect/reconnect).
|
|
49
|
+
*/
|
|
50
|
+
reset() {
|
|
51
|
+
this.state = null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Pure filtering of perpDexs() response into validated DEX names.
|
|
55
|
+
* Encapsulates testnet/mainnet feature-flag logic.
|
|
56
|
+
*
|
|
57
|
+
* @param allDexs - Raw perpDexs() API response array.
|
|
58
|
+
* @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).
|
|
59
|
+
*/
|
|
60
|
+
computeValidatedDexs(allDexs) {
|
|
61
|
+
const availableHip3Dexs = [];
|
|
62
|
+
allDexs.forEach((dex) => {
|
|
63
|
+
if (dex !== null) {
|
|
64
|
+
availableHip3Dexs.push(dex.name);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
if (__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").isTestnetMode()) {
|
|
68
|
+
const { EnabledDexs, AutoDiscoverAll } = TESTNET_HIP3_CONFIG;
|
|
69
|
+
if (!AutoDiscoverAll) {
|
|
70
|
+
if (EnabledDexs.length === 0) {
|
|
71
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - using main DEX only (HIP-3 DEXs filtered)', {
|
|
72
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
73
|
+
reason: 'TESTNET_HIP3_CONFIG.EnabledDexs is empty',
|
|
74
|
+
});
|
|
75
|
+
return [null];
|
|
76
|
+
}
|
|
77
|
+
const filteredDexs = availableHip3Dexs.filter((dex) => EnabledDexs.includes(dex));
|
|
78
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - filtered to allowed DEXs', {
|
|
79
|
+
allowedDexs: EnabledDexs,
|
|
80
|
+
filteredDexs,
|
|
81
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
82
|
+
});
|
|
83
|
+
return [null, ...filteredDexs];
|
|
84
|
+
}
|
|
85
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Testnet - AUTO_DISCOVER_ALL enabled, using all DEXs', { totalDexCount: availableHip3Dexs.length + 1 });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const { AutoDiscoverAll } = MAINNET_HIP3_CONFIG;
|
|
89
|
+
if (!AutoDiscoverAll) {
|
|
90
|
+
const allowedDexsFromAllowlist = this.extractDexsFromAllowlist();
|
|
91
|
+
if (allowedDexsFromAllowlist.length === 0) {
|
|
92
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - using main DEX only (no HIP-3 DEXs in allowlist)', {
|
|
93
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
94
|
+
allowlistMarkets: __classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").getAllowlistMarkets(),
|
|
95
|
+
});
|
|
96
|
+
return [null];
|
|
97
|
+
}
|
|
98
|
+
const filteredDexs = availableHip3Dexs.filter((dex) => allowedDexsFromAllowlist.includes(dex));
|
|
99
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - filtered to allowlist DEXs', {
|
|
100
|
+
allowedDexsFromAllowlist,
|
|
101
|
+
filteredDexs,
|
|
102
|
+
availableHip3Dexs: availableHip3Dexs.length,
|
|
103
|
+
});
|
|
104
|
+
return [null, ...filteredDexs];
|
|
105
|
+
}
|
|
106
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: Mainnet - AUTO_DISCOVER_ALL enabled, using all DEXs', { totalDexCount: availableHip3Dexs.length + 1 });
|
|
107
|
+
}
|
|
108
|
+
__classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").debugLogger.log('HyperLiquidProvider: All DEXs enabled (market filtering at data layer)', {
|
|
109
|
+
mainDex: true,
|
|
110
|
+
hip3Dexs: availableHip3Dexs,
|
|
111
|
+
totalDexCount: availableHip3Dexs.length + 1,
|
|
112
|
+
});
|
|
113
|
+
return [null, ...availableHip3Dexs];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Extract unique DEX names from allowlist market patterns.
|
|
117
|
+
* Patterns can be: "xyz:*" (wildcard), "xyz:TSLA" (exact), or "xyz" (DEX shorthand).
|
|
118
|
+
*
|
|
119
|
+
* @returns Array of unique DEX names from the allowlist.
|
|
120
|
+
*/
|
|
121
|
+
extractDexsFromAllowlist() {
|
|
122
|
+
const allowlistMarkets = __classPrivateFieldGet(this, _DexDiscoveryCacheManager_deps, "f").getAllowlistMarkets();
|
|
123
|
+
if (allowlistMarkets.length === 0) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const dexNames = new Set();
|
|
127
|
+
for (const pattern of allowlistMarkets) {
|
|
128
|
+
const colonIndex = pattern.indexOf(':');
|
|
129
|
+
if (colonIndex > 0) {
|
|
130
|
+
const dex = pattern.substring(0, colonIndex);
|
|
131
|
+
dexNames.add(dex);
|
|
132
|
+
}
|
|
133
|
+
else if (pattern.length > 0 && !pattern.includes('*')) {
|
|
134
|
+
if (/^[a-z][a-z0-9]*$/iu.test(pattern)) {
|
|
135
|
+
dexNames.add(pattern.toLowerCase());
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return Array.from(dexNames);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
_DexDiscoveryCacheManager_deps = new WeakMap();
|
|
143
|
+
//# sourceMappingURL=DexDiscoveryCacheManager.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DexDiscoveryCacheManager.mjs","sourceRoot":"","sources":["../../src/services/DexDiscoveryCacheManager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n MAINNET_HIP3_CONFIG,\n TESTNET_HIP3_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport type { DexDiscoveryState, ExtendedPerpDex } from '../types/perps-types';\n\ntype DexDiscoveryDeps = {\n isTestnetMode: () => boolean;\n debugLogger: { log: (...args: unknown[]) => void };\n getAllowlistMarkets: () => string[];\n};\n\n/**\n * Manages the unified DEX discovery cache — single source of truth for all perpDexs() derivatives.\n *\n * Extracted from HyperLiquidProvider to isolate cache logic.\n * All writes go through update(); readers use .state.\n */\nexport class DexDiscoveryCacheManager {\n /**\n * Unified DEX discovery state.\n * null = not yet fetched; object = raw + validated + timestamp.\n */\n state: DexDiscoveryState | null = null;\n\n readonly #deps: DexDiscoveryDeps;\n\n constructor(deps: DexDiscoveryDeps) {\n this.#deps = deps;\n }\n\n /**\n * Single atomic writer for DEX discovery state.\n * All code paths that fetch perpDexs() MUST call this — no direct field writes.\n *\n * @param allDexs - Raw perpDexs() API response array.\n * @returns The newly created unified discovery state.\n */\n update(allDexs: (ExtendedPerpDex | null)[]): DexDiscoveryState {\n const validated = this.computeValidatedDexs(allDexs);\n const newState: DexDiscoveryState = {\n raw: allDexs,\n validated,\n timestamp: Date.now(),\n };\n this.state = newState;\n return newState;\n }\n\n /**\n * Reset state to null (used on disconnect/reconnect).\n */\n reset(): void {\n this.state = null;\n }\n\n /**\n * Pure filtering of perpDexs() response into validated DEX names.\n * Encapsulates testnet/mainnet feature-flag logic.\n *\n * @param allDexs - Raw perpDexs() API response array.\n * @returns Filtered DEX name list (null = main DEX, strings = HIP-3 DEXs).\n */\n computeValidatedDexs(allDexs: (ExtendedPerpDex | null)[]): (string | null)[] {\n const availableHip3Dexs: string[] = [];\n allDexs.forEach((dex) => {\n if (dex !== null) {\n availableHip3Dexs.push(dex.name);\n }\n });\n\n if (this.#deps.isTestnetMode()) {\n const { EnabledDexs, AutoDiscoverAll } = TESTNET_HIP3_CONFIG;\n\n if (!AutoDiscoverAll) {\n if (EnabledDexs.length === 0) {\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - using main DEX only (HIP-3 DEXs filtered)',\n {\n availableHip3Dexs: availableHip3Dexs.length,\n reason: 'TESTNET_HIP3_CONFIG.EnabledDexs is empty',\n },\n );\n return [null];\n }\n\n const filteredDexs = availableHip3Dexs.filter((dex) =>\n EnabledDexs.includes(dex),\n );\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - filtered to allowed DEXs',\n {\n allowedDexs: EnabledDexs,\n filteredDexs,\n availableHip3Dexs: availableHip3Dexs.length,\n },\n );\n return [null, ...filteredDexs];\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Testnet - AUTO_DISCOVER_ALL enabled, using all DEXs',\n { totalDexCount: availableHip3Dexs.length + 1 },\n );\n } else {\n const { AutoDiscoverAll } = MAINNET_HIP3_CONFIG;\n\n if (!AutoDiscoverAll) {\n const allowedDexsFromAllowlist = this.extractDexsFromAllowlist();\n\n if (allowedDexsFromAllowlist.length === 0) {\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - using main DEX only (no HIP-3 DEXs in allowlist)',\n {\n availableHip3Dexs: availableHip3Dexs.length,\n allowlistMarkets: this.#deps.getAllowlistMarkets(),\n },\n );\n return [null];\n }\n\n const filteredDexs = availableHip3Dexs.filter((dex) =>\n allowedDexsFromAllowlist.includes(dex),\n );\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - filtered to allowlist DEXs',\n {\n allowedDexsFromAllowlist,\n filteredDexs,\n availableHip3Dexs: availableHip3Dexs.length,\n },\n );\n return [null, ...filteredDexs];\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: Mainnet - AUTO_DISCOVER_ALL enabled, using all DEXs',\n { totalDexCount: availableHip3Dexs.length + 1 },\n );\n }\n\n this.#deps.debugLogger.log(\n 'HyperLiquidProvider: All DEXs enabled (market filtering at data layer)',\n {\n mainDex: true,\n hip3Dexs: availableHip3Dexs,\n totalDexCount: availableHip3Dexs.length + 1,\n },\n );\n return [null, ...availableHip3Dexs];\n }\n\n /**\n * Extract unique DEX names from allowlist market patterns.\n * Patterns can be: \"xyz:*\" (wildcard), \"xyz:TSLA\" (exact), or \"xyz\" (DEX shorthand).\n *\n * @returns Array of unique DEX names from the allowlist.\n */\n extractDexsFromAllowlist(): string[] {\n const allowlistMarkets = this.#deps.getAllowlistMarkets();\n if (allowlistMarkets.length === 0) {\n return [];\n }\n\n const dexNames = new Set<string>();\n\n for (const pattern of allowlistMarkets) {\n const colonIndex = pattern.indexOf(':');\n if (colonIndex > 0) {\n const dex = pattern.substring(0, colonIndex);\n dexNames.add(dex);\n } else if (pattern.length > 0 && !pattern.includes('*')) {\n if (/^[a-z][a-z0-9]*$/iu.test(pattern)) {\n dexNames.add(pattern.toLowerCase());\n }\n }\n }\n\n return Array.from(dexNames);\n }\n}\n"]}
|
|
@@ -315,9 +315,10 @@ class HyperLiquidClientService {
|
|
|
315
315
|
const now = endTime ?? Date.now();
|
|
316
316
|
const intervalMs = __classPrivateFieldGet(this, _HyperLiquidClientService_instances, "m", _HyperLiquidClientService_getIntervalMilliseconds).call(this, interval);
|
|
317
317
|
const startTime = now - limit * intervalMs;
|
|
318
|
-
// Use
|
|
319
|
-
//
|
|
320
|
-
|
|
318
|
+
// Use HTTP transport for historical candle snapshots (request/response).
|
|
319
|
+
// This avoids the WebSocket abort race condition that causes 429s
|
|
320
|
+
// during rapid market switching on extension (#TAT-2954).
|
|
321
|
+
const infoClient = this.getInfoClient({ useHttp: true });
|
|
321
322
|
const data = await infoClient.candleSnapshot({
|
|
322
323
|
coin: symbol, // Map to HyperLiquid SDK's 'coin' parameter
|
|
323
324
|
interval,
|