@vtxmacro/cli 2026.9.55 → 2026.9.57
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/bin/vtx-service-bootstrap.js +25 -1
- package/bin/vtx-service-launcher.js +24 -0
- package/bin/vtx.js +398 -288
- package/package.json +1 -1
|
@@ -16,7 +16,7 @@ import { fileURLToPath } from "node:url";
|
|
|
16
16
|
// agent-cli-release.json
|
|
17
17
|
var agent_cli_release_default = {
|
|
18
18
|
package_name: "@vtxmacro/cli",
|
|
19
|
-
package_version: "2026.9.
|
|
19
|
+
package_version: "2026.9.57",
|
|
20
20
|
codex_package_name: "@openai/codex",
|
|
21
21
|
codex_version: "0.155.0",
|
|
22
22
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -203,6 +203,8 @@ var runtime_policy_generated_default = {
|
|
|
203
203
|
},
|
|
204
204
|
server_runtime: {
|
|
205
205
|
prompt_rescue: {
|
|
206
|
+
snapshot_max_age_seconds: 5,
|
|
207
|
+
snapshot_component_max_skew_seconds: 2,
|
|
206
208
|
client_long_poll_seconds: 20,
|
|
207
209
|
client_claim_http_timeout_milliseconds: 25e3,
|
|
208
210
|
client_presence_heartbeat_interval_milliseconds: 3e4,
|
|
@@ -296,6 +298,28 @@ var runtime_policy_generated_default = {
|
|
|
296
298
|
apiWallets: 20
|
|
297
299
|
},
|
|
298
300
|
exchange_action_batch_size: 40
|
|
301
|
+
},
|
|
302
|
+
public_recovery: {
|
|
303
|
+
fallback_initial_seconds: 2,
|
|
304
|
+
fallback_max_seconds: 60,
|
|
305
|
+
permit_lease_seconds: 60,
|
|
306
|
+
recovery_initial_concurrency: 1,
|
|
307
|
+
recovery_max_concurrency: 8,
|
|
308
|
+
recovery_successes_per_step: 4,
|
|
309
|
+
recovery_min_spacing_ms: 100,
|
|
310
|
+
queue_poll_ms: 50,
|
|
311
|
+
recovery_queue_wait_seconds: 10,
|
|
312
|
+
recovery_quiet_seconds: 30
|
|
313
|
+
},
|
|
314
|
+
http: {
|
|
315
|
+
exchange: {
|
|
316
|
+
request_timeout_seconds: 10,
|
|
317
|
+
pool_timeout_seconds: 10
|
|
318
|
+
},
|
|
319
|
+
public_critical: {
|
|
320
|
+
request_timeout_seconds: 10,
|
|
321
|
+
pool_timeout_seconds: 5
|
|
322
|
+
}
|
|
299
323
|
}
|
|
300
324
|
}
|
|
301
325
|
}
|
|
@@ -86,6 +86,8 @@ var runtime_policy_generated_default = {
|
|
|
86
86
|
},
|
|
87
87
|
server_runtime: {
|
|
88
88
|
prompt_rescue: {
|
|
89
|
+
snapshot_max_age_seconds: 5,
|
|
90
|
+
snapshot_component_max_skew_seconds: 2,
|
|
89
91
|
client_long_poll_seconds: 20,
|
|
90
92
|
client_claim_http_timeout_milliseconds: 25e3,
|
|
91
93
|
client_presence_heartbeat_interval_milliseconds: 3e4,
|
|
@@ -179,6 +181,28 @@ var runtime_policy_generated_default = {
|
|
|
179
181
|
apiWallets: 20
|
|
180
182
|
},
|
|
181
183
|
exchange_action_batch_size: 40
|
|
184
|
+
},
|
|
185
|
+
public_recovery: {
|
|
186
|
+
fallback_initial_seconds: 2,
|
|
187
|
+
fallback_max_seconds: 60,
|
|
188
|
+
permit_lease_seconds: 60,
|
|
189
|
+
recovery_initial_concurrency: 1,
|
|
190
|
+
recovery_max_concurrency: 8,
|
|
191
|
+
recovery_successes_per_step: 4,
|
|
192
|
+
recovery_min_spacing_ms: 100,
|
|
193
|
+
queue_poll_ms: 50,
|
|
194
|
+
recovery_queue_wait_seconds: 10,
|
|
195
|
+
recovery_quiet_seconds: 30
|
|
196
|
+
},
|
|
197
|
+
http: {
|
|
198
|
+
exchange: {
|
|
199
|
+
request_timeout_seconds: 10,
|
|
200
|
+
pool_timeout_seconds: 10
|
|
201
|
+
},
|
|
202
|
+
public_critical: {
|
|
203
|
+
request_timeout_seconds: 10,
|
|
204
|
+
pool_timeout_seconds: 5
|
|
205
|
+
}
|
|
182
206
|
}
|
|
183
207
|
}
|
|
184
208
|
}
|
package/bin/vtx.js
CHANGED
|
@@ -77,7 +77,7 @@ var init_agent_cli_release = __esm({
|
|
|
77
77
|
"agent-cli-release.json"() {
|
|
78
78
|
agent_cli_release_default = {
|
|
79
79
|
package_name: "@vtxmacro/cli",
|
|
80
|
-
package_version: "2026.9.
|
|
80
|
+
package_version: "2026.9.57",
|
|
81
81
|
codex_package_name: "@openai/codex",
|
|
82
82
|
codex_version: "0.155.0",
|
|
83
83
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -20544,6 +20544,8 @@ var init_runtime_policy_generated = __esm({
|
|
|
20544
20544
|
},
|
|
20545
20545
|
server_runtime: {
|
|
20546
20546
|
prompt_rescue: {
|
|
20547
|
+
snapshot_max_age_seconds: 5,
|
|
20548
|
+
snapshot_component_max_skew_seconds: 2,
|
|
20547
20549
|
client_long_poll_seconds: 20,
|
|
20548
20550
|
client_claim_http_timeout_milliseconds: 25e3,
|
|
20549
20551
|
client_presence_heartbeat_interval_milliseconds: 3e4,
|
|
@@ -20637,6 +20639,28 @@ var init_runtime_policy_generated = __esm({
|
|
|
20637
20639
|
apiWallets: 20
|
|
20638
20640
|
},
|
|
20639
20641
|
exchange_action_batch_size: 40
|
|
20642
|
+
},
|
|
20643
|
+
public_recovery: {
|
|
20644
|
+
fallback_initial_seconds: 2,
|
|
20645
|
+
fallback_max_seconds: 60,
|
|
20646
|
+
permit_lease_seconds: 60,
|
|
20647
|
+
recovery_initial_concurrency: 1,
|
|
20648
|
+
recovery_max_concurrency: 8,
|
|
20649
|
+
recovery_successes_per_step: 4,
|
|
20650
|
+
recovery_min_spacing_ms: 100,
|
|
20651
|
+
queue_poll_ms: 50,
|
|
20652
|
+
recovery_queue_wait_seconds: 10,
|
|
20653
|
+
recovery_quiet_seconds: 30
|
|
20654
|
+
},
|
|
20655
|
+
http: {
|
|
20656
|
+
exchange: {
|
|
20657
|
+
request_timeout_seconds: 10,
|
|
20658
|
+
pool_timeout_seconds: 10
|
|
20659
|
+
},
|
|
20660
|
+
public_critical: {
|
|
20661
|
+
request_timeout_seconds: 10,
|
|
20662
|
+
pool_timeout_seconds: 5
|
|
20663
|
+
}
|
|
20640
20664
|
}
|
|
20641
20665
|
}
|
|
20642
20666
|
}
|
|
@@ -42582,6 +42606,8 @@ var init_runtime_policy_generated2 = __esm({
|
|
|
42582
42606
|
},
|
|
42583
42607
|
server_runtime: {
|
|
42584
42608
|
prompt_rescue: {
|
|
42609
|
+
snapshot_max_age_seconds: 5,
|
|
42610
|
+
snapshot_component_max_skew_seconds: 2,
|
|
42585
42611
|
client_long_poll_seconds: 20,
|
|
42586
42612
|
client_claim_http_timeout_milliseconds: 25e3,
|
|
42587
42613
|
client_presence_heartbeat_interval_milliseconds: 3e4,
|
|
@@ -42675,6 +42701,28 @@ var init_runtime_policy_generated2 = __esm({
|
|
|
42675
42701
|
apiWallets: 20
|
|
42676
42702
|
},
|
|
42677
42703
|
exchange_action_batch_size: 40
|
|
42704
|
+
},
|
|
42705
|
+
public_recovery: {
|
|
42706
|
+
fallback_initial_seconds: 2,
|
|
42707
|
+
fallback_max_seconds: 60,
|
|
42708
|
+
permit_lease_seconds: 60,
|
|
42709
|
+
recovery_initial_concurrency: 1,
|
|
42710
|
+
recovery_max_concurrency: 8,
|
|
42711
|
+
recovery_successes_per_step: 4,
|
|
42712
|
+
recovery_min_spacing_ms: 100,
|
|
42713
|
+
queue_poll_ms: 50,
|
|
42714
|
+
recovery_queue_wait_seconds: 10,
|
|
42715
|
+
recovery_quiet_seconds: 30
|
|
42716
|
+
},
|
|
42717
|
+
http: {
|
|
42718
|
+
exchange: {
|
|
42719
|
+
request_timeout_seconds: 10,
|
|
42720
|
+
pool_timeout_seconds: 10
|
|
42721
|
+
},
|
|
42722
|
+
public_critical: {
|
|
42723
|
+
request_timeout_seconds: 10,
|
|
42724
|
+
pool_timeout_seconds: 5
|
|
42725
|
+
}
|
|
42678
42726
|
}
|
|
42679
42727
|
}
|
|
42680
42728
|
}
|
|
@@ -48616,7 +48664,7 @@ var init_runtime_redaction = __esm({
|
|
|
48616
48664
|
});
|
|
48617
48665
|
|
|
48618
48666
|
// lib/runtime/hyperliquid-public-read.ts
|
|
48619
|
-
var policy, weights, budgets, unpersistedBudgets, cache, pending2, PREFIX, abortError2, checkAbort, wait, storage, loadBudget, saveBudget, withBudgetLock, HyperliquidPublicReadError, cooldownError, admit, cooldown, cacheTtlMs, eligibleCache, reserveHyperliquidPublicReads, releaseHyperliquidPublicReadReservation, admitHyperliquidExchangeRequest, recordHyperliquidExchangeResponse, readHyperliquidPublicInfo;
|
|
48667
|
+
var policy, weights, recoveryPolicy, budgets, unpersistedBudgets, cache, pending2, PREFIX, abortError2, checkAbort, wait, storage, loadBudget, saveBudget, withBudgetLock, HyperliquidPublicReadError, getHyperliquidPublicReadBudget, cooldownError, recoveryWaitError, fallbackDelayMs, admit, cooldown, finishHyperliquidRecoveryRequest, assertHyperliquidRecoveryDispatch, cacheTtlMs, eligibleCache, reserveHyperliquidPublicReads, releaseHyperliquidPublicReadReservation, admitHyperliquidExchangeRequest, recordHyperliquidExchangeResponse, readHyperliquidPublicInfo;
|
|
48620
48668
|
var init_hyperliquid_public_read = __esm({
|
|
48621
48669
|
"lib/runtime/hyperliquid-public-read.ts"() {
|
|
48622
48670
|
"use strict";
|
|
@@ -48627,6 +48675,7 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48627
48675
|
init_runtime_policy_generated();
|
|
48628
48676
|
policy = runtime_policy_generated_default.exchange.hyperliquid.client_public_read_budget;
|
|
48629
48677
|
weights = runtime_policy_generated_default.exchange.hyperliquid.read_budget.weights;
|
|
48678
|
+
recoveryPolicy = runtime_policy_generated_default.exchange.hyperliquid.public_recovery;
|
|
48630
48679
|
budgets = /* @__PURE__ */ new Map();
|
|
48631
48680
|
unpersistedBudgets = /* @__PURE__ */ new Set();
|
|
48632
48681
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -48684,7 +48733,15 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48684
48733
|
withBudgetLock = async (key, signal, work) => {
|
|
48685
48734
|
checkAbort(signal);
|
|
48686
48735
|
if (typeof navigator !== "undefined" && navigator.locks?.request) {
|
|
48687
|
-
|
|
48736
|
+
const result2 = await navigator.locks.request(key, { ...signal ? { signal } : {} }, () => {
|
|
48737
|
+
try {
|
|
48738
|
+
return { ok: true, value: work() };
|
|
48739
|
+
} catch (error48) {
|
|
48740
|
+
return { ok: false, error: error48 };
|
|
48741
|
+
}
|
|
48742
|
+
});
|
|
48743
|
+
if (!result2.ok) throw result2.error;
|
|
48744
|
+
return result2.value;
|
|
48688
48745
|
}
|
|
48689
48746
|
return work();
|
|
48690
48747
|
};
|
|
@@ -48701,6 +48758,15 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48701
48758
|
this.name = "HyperliquidPublicReadError";
|
|
48702
48759
|
}
|
|
48703
48760
|
};
|
|
48761
|
+
getHyperliquidPublicReadBudget = (endpoint) => {
|
|
48762
|
+
const budget = loadBudget(`${PREFIX}${endpoint.replace(/\/$/, "")}`);
|
|
48763
|
+
return {
|
|
48764
|
+
usedWeight: budget.reservations.filter((r) => r.at > Date.now() - policy.window_seconds * 1e3).reduce((sum, r) => sum + r.weight, 0),
|
|
48765
|
+
maxWeight: policy.max_weight,
|
|
48766
|
+
windowSeconds: policy.window_seconds,
|
|
48767
|
+
cooldownUntilMs: budget.cooldownUntil
|
|
48768
|
+
};
|
|
48769
|
+
};
|
|
48704
48770
|
cooldownError = (requestType, until) => new HyperliquidPublicReadError(
|
|
48705
48771
|
"public_cooldown_active",
|
|
48706
48772
|
"Hyperliquid public request cooldown is active.",
|
|
@@ -48708,48 +48774,129 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48708
48774
|
void 0,
|
|
48709
48775
|
Math.max(0, until - Date.now())
|
|
48710
48776
|
);
|
|
48711
|
-
|
|
48777
|
+
recoveryWaitError = (requestType) => new HyperliquidPublicReadError(
|
|
48778
|
+
"public_recovery_wait",
|
|
48779
|
+
"Hyperliquid provider recovery could not dispatch before the request deadline.",
|
|
48780
|
+
requestType
|
|
48781
|
+
);
|
|
48782
|
+
fallbackDelayMs = (failures) => Math.min(
|
|
48783
|
+
recoveryPolicy.fallback_max_seconds * 1e3,
|
|
48784
|
+
recoveryPolicy.fallback_initial_seconds * 1e3 * 2 ** Math.min(30, Math.max(0, failures - 1)) * (0.5 + Math.random())
|
|
48785
|
+
);
|
|
48786
|
+
admit = async (apiUrl, requestType, signal, weightOverride, deadlineMs) => {
|
|
48712
48787
|
const key = `${PREFIX}${apiUrl}`;
|
|
48713
|
-
const weight =
|
|
48714
|
-
|
|
48715
|
-
|
|
48716
|
-
|
|
48717
|
-
|
|
48718
|
-
|
|
48719
|
-
|
|
48720
|
-
|
|
48721
|
-
|
|
48722
|
-
|
|
48723
|
-
|
|
48724
|
-
|
|
48725
|
-
|
|
48788
|
+
const weight = weightOverride ?? weights[requestType] ?? policy.default_request_weight;
|
|
48789
|
+
const ticket = crypto.randomUUID();
|
|
48790
|
+
const deadline = Math.min(deadlineMs ?? Infinity, Date.now() + recoveryPolicy.recovery_queue_wait_seconds * 1e3);
|
|
48791
|
+
let admitted = false;
|
|
48792
|
+
try {
|
|
48793
|
+
for (; ; ) {
|
|
48794
|
+
checkAbort(signal);
|
|
48795
|
+
if (deadlineMs != null && Date.now() >= deadlineMs) throw recoveryWaitError(requestType);
|
|
48796
|
+
const result2 = await withBudgetLock(key, signal, () => {
|
|
48797
|
+
const now = Date.now();
|
|
48798
|
+
const budget = loadBudget(key);
|
|
48799
|
+
if (budget.cooldownUntil > now) throw cooldownError(requestType, budget.cooldownUntil);
|
|
48800
|
+
const recovery = budget.recovery;
|
|
48801
|
+
let permit = null;
|
|
48802
|
+
if (recovery) {
|
|
48803
|
+
recovery.active = recovery.active.filter((entry) => entry.expiresAt > now);
|
|
48804
|
+
recovery.queue = recovery.queue.filter((entry) => entry.expiresAt > now);
|
|
48805
|
+
if (now >= deadline) throw recoveryWaitError(requestType);
|
|
48806
|
+
if (!recovery.queue.some((entry) => entry.id === ticket)) recovery.queue.push({ id: ticket, expiresAt: deadline });
|
|
48807
|
+
if (recovery.queue[0]?.id !== ticket || recovery.active.length >= recovery.concurrency || recovery.nextAt > now) {
|
|
48808
|
+
saveBudget(key, budget);
|
|
48809
|
+
return { ready: false, permit: null };
|
|
48810
|
+
}
|
|
48811
|
+
recovery.queue.shift();
|
|
48812
|
+
const expiresAt = now + recoveryPolicy.permit_lease_seconds * 1e3;
|
|
48813
|
+
recovery.active.push({ id: ticket, expiresAt });
|
|
48814
|
+
recovery.nextAt = now + recoveryPolicy.recovery_min_spacing_ms;
|
|
48815
|
+
permit = { endpoint: apiUrl, id: ticket, generation: recovery.generation, expiresAt };
|
|
48816
|
+
}
|
|
48817
|
+
budget.reservations = budget.reservations.filter((entry) => entry.at > now - policy.window_seconds * 1e3);
|
|
48818
|
+
budget.reservations.push({ at: now, weight });
|
|
48726
48819
|
saveBudget(key, budget);
|
|
48727
|
-
return {
|
|
48820
|
+
return { ready: true, permit };
|
|
48821
|
+
});
|
|
48822
|
+
if (result2.ready) {
|
|
48823
|
+
admitted = true;
|
|
48824
|
+
return result2.permit;
|
|
48728
48825
|
}
|
|
48729
|
-
|
|
48730
|
-
|
|
48731
|
-
|
|
48826
|
+
await wait(Math.min(recoveryPolicy.queue_poll_ms, Math.max(1, deadline - Date.now())), signal);
|
|
48827
|
+
}
|
|
48828
|
+
} finally {
|
|
48829
|
+
if (!admitted) await withBudgetLock(key, void 0, () => {
|
|
48830
|
+
const budget = loadBudget(key);
|
|
48831
|
+
if (budget.recovery) {
|
|
48832
|
+
budget.recovery.queue = budget.recovery.queue.filter((entry) => entry.id !== ticket);
|
|
48833
|
+
saveBudget(key, budget);
|
|
48732
48834
|
}
|
|
48733
|
-
throw new Error("Invalid Hyperliquid public read budget.");
|
|
48734
48835
|
});
|
|
48735
|
-
if (!delay2) return;
|
|
48736
|
-
if (bundleWeight != null || deadlineMs != null && Date.now() + delay2 >= deadlineMs) {
|
|
48737
|
-
throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid local public request allowance is exhausted.", requestType, void 0, delay2, weight, usedWeight, policy.max_weight);
|
|
48738
|
-
}
|
|
48739
|
-
await wait(delay2, signal);
|
|
48740
48836
|
}
|
|
48741
48837
|
};
|
|
48742
48838
|
cooldown = async (apiUrl, retryAfter) => {
|
|
48743
48839
|
const key = `${PREFIX}${apiUrl}`;
|
|
48744
48840
|
await withBudgetLock(key, void 0, () => {
|
|
48745
48841
|
const now = Date.now();
|
|
48746
|
-
const seconds = retryAfter == null ? NaN : Number(retryAfter);
|
|
48747
|
-
const providerUntil = Number.isFinite(seconds) ? now + seconds * 1e3 : Date.parse(retryAfter ?? "");
|
|
48748
48842
|
const budget = loadBudget(key);
|
|
48749
|
-
budget.
|
|
48843
|
+
if (!budget.recovery && now - (budget.lastFailure ?? 0) >= recoveryPolicy.recovery_quiet_seconds * 1e3) budget.failures = 0;
|
|
48844
|
+
budget.failures = (budget.failures ?? 0) + 1;
|
|
48845
|
+
const trimmed = retryAfter?.trim() ?? "";
|
|
48846
|
+
const seconds = trimmed !== "" ? Number(trimmed) : NaN;
|
|
48847
|
+
const providerUntil = Number.isFinite(seconds) && seconds >= 0 ? now + seconds * 1e3 : trimmed && !Number.isFinite(seconds) ? Date.parse(trimmed) : NaN;
|
|
48848
|
+
const until = Number.isFinite(providerUntil) ? Math.max(now, Number(providerUntil)) : now + fallbackDelayMs(budget.failures);
|
|
48849
|
+
budget.cooldownUntil = Math.max(budget.cooldownUntil, until);
|
|
48850
|
+
budget.lastFailure = now;
|
|
48851
|
+
budget.recovery = {
|
|
48852
|
+
generation: crypto.randomUUID(),
|
|
48853
|
+
concurrency: recoveryPolicy.recovery_initial_concurrency,
|
|
48854
|
+
successes: 0,
|
|
48855
|
+
nextAt: budget.cooldownUntil,
|
|
48856
|
+
queue: budget.recovery?.queue ?? [],
|
|
48857
|
+
active: []
|
|
48858
|
+
};
|
|
48750
48859
|
saveBudget(key, budget);
|
|
48751
48860
|
});
|
|
48752
48861
|
};
|
|
48862
|
+
finishHyperliquidRecoveryRequest = async (permit, outcome) => {
|
|
48863
|
+
if (!permit) return;
|
|
48864
|
+
const key = `${PREFIX}${permit.endpoint}`;
|
|
48865
|
+
await withBudgetLock(key, void 0, () => {
|
|
48866
|
+
const budget = loadBudget(key);
|
|
48867
|
+
const recovery = budget.recovery;
|
|
48868
|
+
if (!recovery || recovery.generation !== permit.generation) return;
|
|
48869
|
+
const now = Date.now();
|
|
48870
|
+
const member = recovery.active.find((entry) => entry.id === permit.id);
|
|
48871
|
+
recovery.active = recovery.active.filter((entry) => entry.id !== permit.id);
|
|
48872
|
+
if (member && member.expiresAt > now) {
|
|
48873
|
+
if (outcome === "success") {
|
|
48874
|
+
recovery.successes += 1;
|
|
48875
|
+
if (recovery.successes >= recoveryPolicy.recovery_successes_per_step) {
|
|
48876
|
+
if (recovery.concurrency >= recoveryPolicy.recovery_max_concurrency) {
|
|
48877
|
+
if (recovery.queue.length === 0 && recovery.active.length === 0) delete budget.recovery;
|
|
48878
|
+
} else {
|
|
48879
|
+
recovery.concurrency = Math.min(recoveryPolicy.recovery_max_concurrency, recovery.concurrency * 2);
|
|
48880
|
+
recovery.successes = 0;
|
|
48881
|
+
}
|
|
48882
|
+
}
|
|
48883
|
+
} else if (outcome === "failure") {
|
|
48884
|
+
recovery.successes = 0;
|
|
48885
|
+
recovery.concurrency = recoveryPolicy.recovery_initial_concurrency;
|
|
48886
|
+
recovery.nextAt = Math.max(recovery.nextAt, now + fallbackDelayMs(budget.failures ?? 1));
|
|
48887
|
+
}
|
|
48888
|
+
}
|
|
48889
|
+
saveBudget(key, budget);
|
|
48890
|
+
});
|
|
48891
|
+
};
|
|
48892
|
+
assertHyperliquidRecoveryDispatch = (endpoint, permit, requestType) => {
|
|
48893
|
+
const budget = loadBudget(`${PREFIX}${endpoint.replace(/\/$/, "")}`);
|
|
48894
|
+
if (budget.cooldownUntil > Date.now()) throw cooldownError(requestType, budget.cooldownUntil);
|
|
48895
|
+
if (permit && (permit.expiresAt <= Date.now() || budget.recovery && (budget.recovery.generation !== permit.generation || !budget.recovery.active.some((entry) => entry.id === permit.id && entry.expiresAt > Date.now())))) {
|
|
48896
|
+
throw recoveryWaitError(requestType);
|
|
48897
|
+
}
|
|
48898
|
+
if (!permit && budget.recovery) throw recoveryWaitError(requestType);
|
|
48899
|
+
};
|
|
48753
48900
|
cacheTtlMs = (body, options) => {
|
|
48754
48901
|
const requestType = String(body.type);
|
|
48755
48902
|
return (["meta", "spotMeta", "perpDexs"].includes(requestType) ? policy.metadata_ttl_seconds : requestType === "userFees" ? policy.user_fees_ttl_seconds : options.cacheAccountMode && ["userAbstraction", "userDexAbstraction"].includes(requestType) ? policy.account_mode_ttl_seconds : 0) * 1e3;
|
|
@@ -48761,47 +48908,26 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48761
48908
|
return ttl > 0 && existing && Date.now() >= existing.fetchedAtMs && horizon - existing.fetchedAtMs < ttl ? existing : void 0;
|
|
48762
48909
|
};
|
|
48763
48910
|
reserveHyperliquidPublicReads = async (endpoint, bodies, signal, options = {}) => {
|
|
48911
|
+
checkAbort(signal);
|
|
48764
48912
|
const apiUrl = endpoint.replace(/\/$/, "");
|
|
48765
48913
|
const cached2 = /* @__PURE__ */ new Map();
|
|
48766
|
-
const remaining = /* @__PURE__ */ new Map();
|
|
48767
|
-
let weight = 0;
|
|
48768
48914
|
for (const body of bodies) {
|
|
48769
|
-
const key = JSON.stringify(body);
|
|
48770
48915
|
const hit = eligibleCache(apiUrl, body, options);
|
|
48771
|
-
if (hit)
|
|
48772
|
-
cached2.set(key, hit);
|
|
48773
|
-
continue;
|
|
48774
|
-
}
|
|
48775
|
-
remaining.set(key, (remaining.get(key) ?? 0) + 1);
|
|
48776
|
-
weight += weights[String(body.type)] ?? policy.default_request_weight;
|
|
48916
|
+
if (hit) cached2.set(JSON.stringify(body), hit);
|
|
48777
48917
|
}
|
|
48778
|
-
|
|
48779
|
-
const admittedAtMs = Date.now();
|
|
48780
|
-
if (weight) await admit(apiUrl, "bundle", signal, weight, id2, options.cacheValidUntilMs);
|
|
48781
|
-
return { id: id2, closed: false, endpoint: apiUrl, expiresAtMs: admittedAtMs + policy.window_seconds * 1e3, remaining, cached: cached2, cacheValidUntilMs: options.cacheValidUntilMs };
|
|
48918
|
+
return { closed: false, endpoint: apiUrl, cached: cached2, cacheValidUntilMs: options.cacheValidUntilMs };
|
|
48782
48919
|
};
|
|
48783
48920
|
releaseHyperliquidPublicReadReservation = async (reservation) => {
|
|
48784
48921
|
reservation.closed = true;
|
|
48785
|
-
const key = `${PREFIX}${reservation.endpoint}`;
|
|
48786
|
-
await withBudgetLock(key, void 0, () => {
|
|
48787
|
-
const budget = loadBudget(key);
|
|
48788
|
-
const row = budget.reservations.find((entry) => entry.id === reservation.id);
|
|
48789
|
-
if (row) {
|
|
48790
|
-
const unused = [...reservation.remaining].reduce((sum, [body, count4]) => sum + (weights[String(JSON.parse(body).type)] ?? policy.default_request_weight) * count4, 0);
|
|
48791
|
-
row.weight = Math.max(0, row.weight - unused);
|
|
48792
|
-
budget.reservations = budget.reservations.filter((entry) => entry.weight > 0);
|
|
48793
|
-
saveBudget(key, budget);
|
|
48794
|
-
}
|
|
48795
|
-
reservation.remaining.clear();
|
|
48796
|
-
});
|
|
48797
48922
|
};
|
|
48798
48923
|
admitHyperliquidExchangeRequest = async (endpoint, action, signal) => {
|
|
48799
48924
|
const batchLength = Math.max(0, ...[action.orders, action.cancels, action.modifies].filter(Array.isArray).map((value) => value.length));
|
|
48800
48925
|
const weight = weights.exchange + Math.floor(batchLength / runtime_policy_generated_default.exchange.hyperliquid.read_budget.exchange_action_batch_size);
|
|
48801
|
-
|
|
48926
|
+
return admit(endpoint.replace(/\/$/, ""), "exchange", signal, weight);
|
|
48802
48927
|
};
|
|
48803
|
-
recordHyperliquidExchangeResponse = async (endpoint, response) => {
|
|
48928
|
+
recordHyperliquidExchangeResponse = async (endpoint, response, permit) => {
|
|
48804
48929
|
if (response.status === 429) await cooldown(endpoint.replace(/\/$/, ""), response.headers.get("Retry-After"));
|
|
48930
|
+
await finishHyperliquidRecoveryRequest(permit, response.status < 400 ? "success" : "failure");
|
|
48805
48931
|
};
|
|
48806
48932
|
readHyperliquidPublicInfo = async (endpoint, body, options = {}) => {
|
|
48807
48933
|
const apiUrl = endpoint.replace(/\/$/, "");
|
|
@@ -48810,71 +48936,101 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48810
48936
|
const ttlMs = cacheTtlMs(body, cacheOptions);
|
|
48811
48937
|
const key = `${apiUrl}:${JSON.stringify(body)}`;
|
|
48812
48938
|
checkAbort(options.signal);
|
|
48813
|
-
|
|
48814
|
-
|
|
48815
|
-
|
|
48816
|
-
|
|
48817
|
-
|
|
48818
|
-
|
|
48819
|
-
|
|
48820
|
-
|
|
48821
|
-
|
|
48822
|
-
|
|
48823
|
-
|
|
48824
|
-
|
|
48825
|
-
|
|
48826
|
-
|
|
48827
|
-
|
|
48828
|
-
|
|
48829
|
-
|
|
48830
|
-
|
|
48831
|
-
|
|
48832
|
-
|
|
48939
|
+
const transportPolicy = runtime_policy_generated_default.exchange.hyperliquid.http.public_critical;
|
|
48940
|
+
const deadline = Math.min(
|
|
48941
|
+
Date.now() + (transportPolicy.request_timeout_seconds + transportPolicy.pool_timeout_seconds) * 1e3,
|
|
48942
|
+
options.deadlineMs ?? Infinity,
|
|
48943
|
+
options.reservation?.cacheValidUntilMs ?? Infinity
|
|
48944
|
+
);
|
|
48945
|
+
const controller = new AbortController();
|
|
48946
|
+
const signal = controller.signal;
|
|
48947
|
+
const callerAborted = () => controller.abort(abortError2(options.signal));
|
|
48948
|
+
options.signal?.addEventListener("abort", callerAborted, { once: true });
|
|
48949
|
+
let timer;
|
|
48950
|
+
const armDeadline = (until) => {
|
|
48951
|
+
clearTimeout(timer);
|
|
48952
|
+
const timeout = () => controller.abort(new DOMException("Hyperliquid public request timed out.", "TimeoutError"));
|
|
48953
|
+
if (until <= Date.now()) timeout();
|
|
48954
|
+
else timer = setTimeout(timeout, until - Date.now());
|
|
48955
|
+
};
|
|
48956
|
+
armDeadline(deadline);
|
|
48957
|
+
let permit = null;
|
|
48958
|
+
let outcome = "cancelled";
|
|
48833
48959
|
let settled;
|
|
48834
|
-
|
|
48835
|
-
settled = resolve13;
|
|
48836
|
-
}));
|
|
48960
|
+
let acquiring = false;
|
|
48837
48961
|
try {
|
|
48838
|
-
|
|
48839
|
-
|
|
48840
|
-
|
|
48841
|
-
|
|
48842
|
-
|
|
48843
|
-
|
|
48844
|
-
if (
|
|
48845
|
-
|
|
48846
|
-
|
|
48847
|
-
|
|
48848
|
-
|
|
48849
|
-
|
|
48850
|
-
|
|
48851
|
-
|
|
48962
|
+
checkAbort(signal);
|
|
48963
|
+
if (ttlMs) {
|
|
48964
|
+
for (; ; ) {
|
|
48965
|
+
const existing = options.reservation?.cached.get(JSON.stringify(body)) ?? eligibleCache(apiUrl, body, cacheOptions);
|
|
48966
|
+
if (existing) return existing;
|
|
48967
|
+
const running = pending2.get(key);
|
|
48968
|
+
if (!running) break;
|
|
48969
|
+
await new Promise((resolve13, reject) => {
|
|
48970
|
+
const aborted2 = () => {
|
|
48971
|
+
signal.removeEventListener("abort", aborted2);
|
|
48972
|
+
reject(abortError2(signal));
|
|
48973
|
+
};
|
|
48974
|
+
signal.addEventListener("abort", aborted2, { once: true });
|
|
48975
|
+
running.then(() => {
|
|
48976
|
+
signal.removeEventListener("abort", aborted2);
|
|
48977
|
+
resolve13();
|
|
48978
|
+
});
|
|
48979
|
+
});
|
|
48980
|
+
checkAbort(signal);
|
|
48981
|
+
}
|
|
48982
|
+
pending2.set(key, new Promise((resolve13) => {
|
|
48983
|
+
settled = resolve13;
|
|
48984
|
+
}));
|
|
48985
|
+
}
|
|
48986
|
+
if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
|
|
48987
|
+
acquiring = true;
|
|
48988
|
+
permit = await admit(apiUrl, requestType, signal, void 0, deadline);
|
|
48989
|
+
acquiring = false;
|
|
48990
|
+
armDeadline(Math.min(deadline, permit?.expiresAt ?? Infinity));
|
|
48991
|
+
checkAbort(signal);
|
|
48992
|
+
if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
|
|
48993
|
+
assertHyperliquidRecoveryDispatch(apiUrl, permit, requestType);
|
|
48994
|
+
outcome = "failure";
|
|
48995
|
+
let transportAborted;
|
|
48996
|
+
let response;
|
|
48997
|
+
let payload;
|
|
48998
|
+
try {
|
|
48999
|
+
const aborted2 = new Promise((_resolve, reject) => {
|
|
49000
|
+
transportAborted = () => reject(abortError2(signal));
|
|
49001
|
+
signal.addEventListener("abort", transportAborted, { once: true });
|
|
48852
49002
|
});
|
|
48853
|
-
|
|
48854
|
-
|
|
48855
|
-
|
|
48856
|
-
|
|
48857
|
-
|
|
48858
|
-
|
|
48859
|
-
|
|
48860
|
-
|
|
48861
|
-
|
|
48862
|
-
|
|
48863
|
-
|
|
48864
|
-
|
|
48865
|
-
|
|
48866
|
-
|
|
48867
|
-
|
|
48868
|
-
|
|
48869
|
-
|
|
49003
|
+
const transport = (async () => {
|
|
49004
|
+
const received = await fetch(`${apiUrl}/info`, {
|
|
49005
|
+
method: "POST",
|
|
49006
|
+
headers: { "Content-Type": "application/json" },
|
|
49007
|
+
body: JSON.stringify(body),
|
|
49008
|
+
signal
|
|
49009
|
+
});
|
|
49010
|
+
checkAbort(signal);
|
|
49011
|
+
if (received.status === 429) {
|
|
49012
|
+
await cooldown(apiUrl, received.headers.get("Retry-After"));
|
|
49013
|
+
throw new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
|
|
49014
|
+
}
|
|
49015
|
+
const receivedPayload = await received.json().catch((error48) => {
|
|
49016
|
+
if (error48 instanceof SyntaxError) return {};
|
|
49017
|
+
throw error48;
|
|
49018
|
+
});
|
|
49019
|
+
checkAbort(signal);
|
|
49020
|
+
return { response: received, payload: receivedPayload };
|
|
49021
|
+
})();
|
|
49022
|
+
({ response, payload } = await Promise.race([transport, aborted2]));
|
|
49023
|
+
} finally {
|
|
49024
|
+
if (transportAborted) signal.removeEventListener("abort", transportAborted);
|
|
49025
|
+
}
|
|
48870
49026
|
if (!response.ok) {
|
|
48871
49027
|
const detail = sanitizeRuntimeDiagnosticValue(typeof payload?.response === "string" ? payload.response : typeof payload?.detail === "string" ? payload.detail : "");
|
|
48872
|
-
if (response.status === 429) throw new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
|
|
48873
49028
|
throw Object.assign(new Error(`Hyperliquid info request failed (${response.status}) request_type=${requestType}.${detail ? ` ${detail}` : ""}`), {
|
|
48874
49029
|
status: response.status,
|
|
48875
49030
|
requestType
|
|
48876
49031
|
});
|
|
48877
49032
|
}
|
|
49033
|
+
outcome = "success";
|
|
48878
49034
|
const result2 = { payload, fetchedAtMs: Date.now() };
|
|
48879
49035
|
if (ttlMs) {
|
|
48880
49036
|
cache.set(key, result2);
|
|
@@ -48882,14 +49038,26 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48882
49038
|
}
|
|
48883
49039
|
return result2;
|
|
48884
49040
|
} catch (error48) {
|
|
48885
|
-
if (options.signal?.aborted
|
|
49041
|
+
if (options.signal?.aborted) {
|
|
49042
|
+
outcome = "cancelled";
|
|
49043
|
+
throw abortError2(options.signal);
|
|
49044
|
+
}
|
|
49045
|
+
if (acquiring && signal.aborted && signal.reason?.name === "TimeoutError") throw recoveryWaitError(requestType);
|
|
49046
|
+
if (error48 instanceof HyperliquidPublicReadError) throw error48;
|
|
48886
49047
|
if (error48 instanceof TypeError) throw new HyperliquidPublicReadError("public_network_error", "Hyperliquid public request network failure.", requestType);
|
|
48887
49048
|
if (error48 instanceof Error && (error48.name === "TimeoutError" || error48.name === "AbortError")) throw new HyperliquidPublicReadError("public_timeout", "Hyperliquid public request timed out.", requestType);
|
|
48888
49049
|
throw error48;
|
|
48889
49050
|
} finally {
|
|
48890
|
-
|
|
48891
|
-
|
|
48892
|
-
|
|
49051
|
+
clearTimeout(timer);
|
|
49052
|
+
options.signal?.removeEventListener("abort", callerAborted);
|
|
49053
|
+
controller.abort();
|
|
49054
|
+
try {
|
|
49055
|
+
await finishHyperliquidRecoveryRequest(permit, outcome);
|
|
49056
|
+
} finally {
|
|
49057
|
+
if (settled) {
|
|
49058
|
+
pending2.delete(key);
|
|
49059
|
+
settled();
|
|
49060
|
+
}
|
|
48893
49061
|
}
|
|
48894
49062
|
}
|
|
48895
49063
|
};
|
|
@@ -49987,7 +50155,7 @@ var init_network_debug = __esm({
|
|
|
49987
50155
|
});
|
|
49988
50156
|
|
|
49989
50157
|
// lib/runtime/hyperliquid-account-state-adapter.ts
|
|
49990
|
-
var unsupportedUserActiveAssetCache, MAX_UNSUPPORTED_USER_ACTIVE_ASSET_CACHE_KEYS, UNSUPPORTED_USER_ACTIVE_ASSET_STORAGE_KEY, USER_FILLS_CACHE_STORAGE_PREFIX, ACCOUNT_STATE_CACHE_STORAGE_PREFIX,
|
|
50158
|
+
var unsupportedUserActiveAssetCache, MAX_UNSUPPORTED_USER_ACTIVE_ASSET_CACHE_KEYS, UNSUPPORTED_USER_ACTIVE_ASSET_STORAGE_KEY, USER_FILLS_CACHE_STORAGE_PREFIX, ACCOUNT_STATE_CACHE_STORAGE_PREFIX, browserUserFillsCache, browserUserFillsInFlight, HYPERLIQUID_USER_FILLS_PROVIDER_PAGE_CAP, browserAccountStateCache, browserAccountStateInFlight, UNSUPPORTED_USER_ACTIVE_ASSET_DETAIL_PATTERNS, unsupportedUserActiveAssetCacheHydrated, hydrateUnsupportedUserActiveAssetCache, persistUnsupportedUserActiveAssetCache, toPositiveFinite, toFinite, firstFiniteNumber, parseFundingUsdcFromInfoPosition, buildActiveAssetCacheKey, buildUserFillsCacheKey, buildUserFillsStorageKey, buildAccountStateCacheKey, buildAccountStateStorageKey, hasActiveInfoRateLimitCooldown, requireNonNegativeConfigSeconds, requireAccountStateCacheConfig, requireUserFillsCacheConfig, normalizeFillSymbol, buildSymbolFilter, filterFillsBySymbols, readBrowserUserFillsCache, writeBrowserUserFillsCache, cloneBrowserAccountStateResult, withAccountStateEvidence, readBrowserAccountStateCache, writeBrowserAccountStateCache, isRateLimitError, createAbortError, waitForSharedBrowserRequest, waitForSharedBrowserUserFills, getBrowserActiveAssetTypeCandidates, normalizeHyperliquidErrorDetail, isUnsupportedUserActiveAssetError, rememberUnsupportedUserActiveAssetKey, parseInfoPositions, requireFinitePromptMetric, requirePromptClearinghouseState, requirePromptSpotState, normalizePerpDexName, listConfiguredPerpDexs, listPerpDexsForAccountState, prefixHip3PositionCoins, aggregateClearinghouseResponses, hasCompletePerpDexAccountMetrics, normalizeBrowserFillToTradeHistory, isPerpFill, awaitAccountReads, fetchHyperliquidInfoRead, fetchHyperliquidInfoPayload, requireHyperliquidApiUrl, requireWalletAddress, parseInfoPositionSnapshot, fetchBrowserAccountState, fetchBrowserAccountStateUncached, fetchBrowserUserFills, fetchBrowserPositionSnapshot;
|
|
49991
50159
|
var init_hyperliquid_account_state_adapter = __esm({
|
|
49992
50160
|
"lib/runtime/hyperliquid-account-state-adapter.ts"() {
|
|
49993
50161
|
"use strict";
|
|
@@ -50003,20 +50171,17 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50003
50171
|
init_hyperliquid_fee_contract();
|
|
50004
50172
|
init_hyperliquid_market_symbol();
|
|
50005
50173
|
init_network_debug();
|
|
50174
|
+
init_runtime_policy_generated();
|
|
50006
50175
|
unsupportedUserActiveAssetCache = /* @__PURE__ */ new Set();
|
|
50007
50176
|
MAX_UNSUPPORTED_USER_ACTIVE_ASSET_CACHE_KEYS = 512;
|
|
50008
50177
|
UNSUPPORTED_USER_ACTIVE_ASSET_STORAGE_KEY = "vtx:hyperliquid:unsupported-user-active-asset:v1";
|
|
50009
50178
|
USER_FILLS_CACHE_STORAGE_PREFIX = "vtx:hyperliquid:user-fills:v1:";
|
|
50010
50179
|
ACCOUNT_STATE_CACHE_STORAGE_PREFIX = "vtx:hyperliquid:account-state:v1:";
|
|
50011
|
-
INFO_RATE_LIMIT_COOLDOWN_STORAGE_PREFIX = "vtx:hyperliquid:info-rate-limit-cooldown:v1:";
|
|
50012
|
-
INFO_RATE_LIMIT_COOLDOWN_MIN_MS = 5e3;
|
|
50013
|
-
INFO_RATE_LIMIT_COOLDOWN_MAX_MS = 6e4;
|
|
50014
50180
|
browserUserFillsCache = /* @__PURE__ */ new Map();
|
|
50015
50181
|
browserUserFillsInFlight = /* @__PURE__ */ new Map();
|
|
50016
50182
|
HYPERLIQUID_USER_FILLS_PROVIDER_PAGE_CAP = 2e3;
|
|
50017
50183
|
browserAccountStateCache = /* @__PURE__ */ new Map();
|
|
50018
50184
|
browserAccountStateInFlight = /* @__PURE__ */ new Map();
|
|
50019
|
-
browserInfoRateLimitCooldowns = /* @__PURE__ */ new Map();
|
|
50020
50185
|
UNSUPPORTED_USER_ACTIVE_ASSET_DETAIL_PATTERNS = [
|
|
50021
50186
|
/unsupported/i,
|
|
50022
50187
|
/not\s+supported/i,
|
|
@@ -50134,93 +50299,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50134
50299
|
buildAccountStateStorageKey = (cacheKey) => {
|
|
50135
50300
|
return `${ACCOUNT_STATE_CACHE_STORAGE_PREFIX}${cacheKey}`;
|
|
50136
50301
|
};
|
|
50137
|
-
|
|
50138
|
-
return String(apiUrl || "").trim().replace(/\/$/, "").toLowerCase();
|
|
50139
|
-
};
|
|
50140
|
-
normalizeInfoRequestType = (requestType) => {
|
|
50141
|
-
return String(requestType || "").trim() || "info";
|
|
50142
|
-
};
|
|
50143
|
-
buildInfoRateLimitCooldownKey = (apiUrl, requestType) => {
|
|
50144
|
-
return [
|
|
50145
|
-
normalizeInfoRateLimitApiUrl(apiUrl),
|
|
50146
|
-
normalizeInfoRequestType(requestType)
|
|
50147
|
-
].join("::");
|
|
50148
|
-
};
|
|
50149
|
-
buildInfoRateLimitCooldownStorageKey = (cooldownKey) => {
|
|
50150
|
-
return `${INFO_RATE_LIMIT_COOLDOWN_STORAGE_PREFIX}${encodeURIComponent(cooldownKey)}`;
|
|
50151
|
-
};
|
|
50152
|
-
readInfoRateLimitCooldownUntilMs = (apiUrl, requestType, nowMs = Date.now()) => {
|
|
50153
|
-
const cooldownKey = buildInfoRateLimitCooldownKey(apiUrl, requestType);
|
|
50154
|
-
const memoryValue = browserInfoRateLimitCooldowns.get(cooldownKey);
|
|
50155
|
-
if (Number.isFinite(memoryValue)) {
|
|
50156
|
-
if (Number(memoryValue) > nowMs) {
|
|
50157
|
-
return Number(memoryValue);
|
|
50158
|
-
}
|
|
50159
|
-
browserInfoRateLimitCooldowns.delete(cooldownKey);
|
|
50160
|
-
}
|
|
50161
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
50162
|
-
return 0;
|
|
50163
|
-
}
|
|
50164
|
-
try {
|
|
50165
|
-
const storageKey = buildInfoRateLimitCooldownStorageKey(cooldownKey);
|
|
50166
|
-
const rawValue = window.localStorage.getItem(storageKey);
|
|
50167
|
-
if (!rawValue) {
|
|
50168
|
-
return 0;
|
|
50169
|
-
}
|
|
50170
|
-
const parsed = JSON.parse(rawValue);
|
|
50171
|
-
const untilMs = Number(parsed?.untilMs);
|
|
50172
|
-
if (!Number.isFinite(untilMs) || untilMs <= nowMs) {
|
|
50173
|
-
window.localStorage.removeItem(storageKey);
|
|
50174
|
-
return 0;
|
|
50175
|
-
}
|
|
50176
|
-
browserInfoRateLimitCooldowns.set(cooldownKey, untilMs);
|
|
50177
|
-
return untilMs;
|
|
50178
|
-
} catch {
|
|
50179
|
-
return 0;
|
|
50180
|
-
}
|
|
50181
|
-
};
|
|
50182
|
-
hasActiveInfoRateLimitCooldown = (apiUrl, requestTypes, nowMs = Date.now()) => requestTypes.some((requestType) => readInfoRateLimitCooldownUntilMs(apiUrl, requestType, nowMs) > nowMs);
|
|
50183
|
-
writeInfoRateLimitCooldown = (apiUrl, requestType, staleIf429MaxAgeMs, nowMs = Date.now()) => {
|
|
50184
|
-
if (!Number.isFinite(staleIf429MaxAgeMs) || staleIf429MaxAgeMs <= 0) {
|
|
50185
|
-
return;
|
|
50186
|
-
}
|
|
50187
|
-
const cooldownKey = buildInfoRateLimitCooldownKey(apiUrl, requestType);
|
|
50188
|
-
const cooldownMs = Math.max(
|
|
50189
|
-
INFO_RATE_LIMIT_COOLDOWN_MIN_MS,
|
|
50190
|
-
Math.min(INFO_RATE_LIMIT_COOLDOWN_MAX_MS, staleIf429MaxAgeMs)
|
|
50191
|
-
);
|
|
50192
|
-
const untilMs = nowMs + cooldownMs;
|
|
50193
|
-
browserInfoRateLimitCooldowns.set(cooldownKey, untilMs);
|
|
50194
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
50195
|
-
return;
|
|
50196
|
-
}
|
|
50197
|
-
try {
|
|
50198
|
-
window.localStorage.setItem(
|
|
50199
|
-
buildInfoRateLimitCooldownStorageKey(cooldownKey),
|
|
50200
|
-
JSON.stringify({ untilMs })
|
|
50201
|
-
);
|
|
50202
|
-
} catch {
|
|
50203
|
-
}
|
|
50204
|
-
};
|
|
50205
|
-
extractInfoRequestTypeFromRateLimitError = (error48) => {
|
|
50206
|
-
const explicitType = normalizeInfoRequestType(error48?.requestType);
|
|
50207
|
-
if (explicitType !== "info") {
|
|
50208
|
-
return explicitType;
|
|
50209
|
-
}
|
|
50210
|
-
const detail = normalizeHyperliquidErrorDetail(error48);
|
|
50211
|
-
const match = /\brequest_type=([A-Za-z0-9_:-]+)/.exec(detail);
|
|
50212
|
-
return match?.[1] ? normalizeInfoRequestType(match[1]) : null;
|
|
50213
|
-
};
|
|
50214
|
-
recordInfoRateLimitCooldownFromError = (apiUrl, error48, staleIf429MaxAgeMs, nowMs = Date.now()) => {
|
|
50215
|
-
if (!isRateLimitError(error48)) {
|
|
50216
|
-
return;
|
|
50217
|
-
}
|
|
50218
|
-
const requestType = extractInfoRequestTypeFromRateLimitError(error48);
|
|
50219
|
-
if (!requestType) {
|
|
50220
|
-
return;
|
|
50221
|
-
}
|
|
50222
|
-
writeInfoRateLimitCooldown(apiUrl, requestType, staleIf429MaxAgeMs, nowMs);
|
|
50223
|
-
};
|
|
50302
|
+
hasActiveInfoRateLimitCooldown = (apiUrl, _requestTypes, nowMs = Date.now()) => getHyperliquidPublicReadBudget(apiUrl).cooldownUntilMs > nowMs;
|
|
50224
50303
|
requireNonNegativeConfigSeconds = (value, path) => {
|
|
50225
50304
|
const numeric2 = Number(value);
|
|
50226
50305
|
if (!Number.isFinite(numeric2) || numeric2 < 0) {
|
|
@@ -50744,17 +50823,31 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50744
50823
|
}
|
|
50745
50824
|
return true;
|
|
50746
50825
|
};
|
|
50747
|
-
|
|
50826
|
+
awaitAccountReads = async (reads) => {
|
|
50827
|
+
try {
|
|
50828
|
+
return await Promise.all(reads);
|
|
50829
|
+
} catch (error48) {
|
|
50830
|
+
if (error48 instanceof HyperliquidPublicReadError && error48.code === "public_cooldown_active") {
|
|
50831
|
+
const settled = await Promise.allSettled(reads);
|
|
50832
|
+
for (const result2 of settled) {
|
|
50833
|
+
if (result2.status === "rejected" && result2.reason instanceof HyperliquidPublicReadError && result2.reason.code === "public_rate_limited") throw result2.reason;
|
|
50834
|
+
}
|
|
50835
|
+
}
|
|
50836
|
+
throw error48;
|
|
50837
|
+
}
|
|
50838
|
+
};
|
|
50839
|
+
fetchHyperliquidInfoRead = async (apiUrl, body, signal, reservation) => {
|
|
50748
50840
|
const trace = startRuntimeNetworkDebugTrace({ kind: "exchange", label: `hyperliquid_info:${String(body.type)}`, method: "POST", url: `${apiUrl.replace(/\/$/, "")}/info` });
|
|
50749
50841
|
try {
|
|
50750
50842
|
const result2 = await readHyperliquidPublicInfo(apiUrl, body, { signal, reservation });
|
|
50751
50843
|
trace.completeSuccess(200);
|
|
50752
|
-
return result2
|
|
50844
|
+
return result2;
|
|
50753
50845
|
} catch (error48) {
|
|
50754
50846
|
trace.completeError(error48, error48?.status ?? null);
|
|
50755
50847
|
throw error48;
|
|
50756
50848
|
}
|
|
50757
50849
|
};
|
|
50850
|
+
fetchHyperliquidInfoPayload = async (apiUrl, body, signal, reservation) => (await fetchHyperliquidInfoRead(apiUrl, body, signal, reservation)).payload;
|
|
50758
50851
|
requireHyperliquidApiUrl = (config2) => {
|
|
50759
50852
|
const apiUrl = String(config2.client_runtime_exchange_endpoints?.hyperliquid_api_url || "").trim();
|
|
50760
50853
|
if (!apiUrl) {
|
|
@@ -50867,7 +50960,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50867
50960
|
"Browser account state request aborted."
|
|
50868
50961
|
));
|
|
50869
50962
|
} catch (error48) {
|
|
50870
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
50871
50963
|
const staleCache = readBrowserAccountStateCache(cacheKey);
|
|
50872
50964
|
if (!input.forceRefresh && isRateLimitError(error48) && staleCache && Date.now() - staleCache.fetchedAtMs <= staleIf429MaxAgeMs) {
|
|
50873
50965
|
return withAccountStateEvidence(staleCache.result, "stale_if_429", staleCache.fetchedAtMs, staleIf429MaxAgeMs);
|
|
@@ -50927,10 +51019,10 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50927
51019
|
capturedAt: new Date(capturedAtMs).toISOString()
|
|
50928
51020
|
};
|
|
50929
51021
|
})() : Promise.resolve(null);
|
|
50930
|
-
await
|
|
51022
|
+
await awaitAccountReads([userFeesPromise, exactAccountModePromise]);
|
|
50931
51023
|
const metadataByDex = /* @__PURE__ */ new Map();
|
|
50932
51024
|
if (input.includeEffectiveTakerRate === true) {
|
|
50933
|
-
await
|
|
51025
|
+
await awaitAccountReads(["", ...dexNames].map(async (dex) => {
|
|
50934
51026
|
try {
|
|
50935
51027
|
metadataByDex.set(dex, await fetchHyperliquidInfoPayload(apiUrl, { type: "meta", ...dex ? { dex } : {} }, input.signal, reservation));
|
|
50936
51028
|
} catch (error48) {
|
|
@@ -50939,68 +51031,56 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50939
51031
|
}
|
|
50940
51032
|
}));
|
|
50941
51033
|
}
|
|
50942
|
-
const
|
|
50943
|
-
const
|
|
50944
|
-
|
|
50945
|
-
{ type: "clearinghouseState", user: walletAddress },
|
|
50946
|
-
|
|
50947
|
-
|
|
50948
|
-
)
|
|
50949
|
-
|
|
50950
|
-
|
|
50951
|
-
}
|
|
50952
|
-
const dexResponses = await Promise.all(
|
|
50953
|
-
dexNames.map(async (dexName) => {
|
|
50954
|
-
const response = await fetchHyperliquidInfoPayload(
|
|
50955
|
-
apiUrl,
|
|
50956
|
-
{ type: "clearinghouseState", user: walletAddress, dex: dexName },
|
|
50957
|
-
input.signal,
|
|
50958
|
-
reservation
|
|
50959
|
-
);
|
|
51034
|
+
const dynamicPromise = (async () => {
|
|
51035
|
+
const perpsDexes = ["", ...dexNames];
|
|
51036
|
+
const components = [
|
|
51037
|
+
...perpsDexes.map((dex) => ({ dex, body: { type: "clearinghouseState", user: walletAddress, ...dex ? { dex } : {} } })),
|
|
51038
|
+
{ body: { type: "spotClearinghouseState", user: walletAddress } }
|
|
51039
|
+
];
|
|
51040
|
+
const capture = async (component) => {
|
|
51041
|
+
try {
|
|
51042
|
+
const read = await fetchHyperliquidInfoRead(apiUrl, component.body, input.signal, reservation);
|
|
50960
51043
|
if (input.includeEffectiveTakerRate === true) {
|
|
50961
|
-
|
|
51044
|
+
if (component.dex == null) requirePromptSpotState(read.payload);
|
|
51045
|
+
else requirePromptClearinghouseState(read.payload, component.dex || "default");
|
|
50962
51046
|
}
|
|
50963
|
-
|
|
50964
|
-
|
|
50965
|
-
|
|
50966
|
-
|
|
50967
|
-
|
|
50968
|
-
})
|
|
50969
|
-
);
|
|
50970
|
-
const selectedPayload = selectedDex ? dexResponses.find((entry) => entry.dex === selectedDex)?.payload : defaultResponse;
|
|
50971
|
-
if (!selectedPayload) {
|
|
50972
|
-
throw new Error(`Missing selected Hyperliquid clearinghouse state for DEX ${selectedDex}.`);
|
|
50973
|
-
}
|
|
50974
|
-
return {
|
|
50975
|
-
payload: aggregateClearinghouseResponses([
|
|
50976
|
-
defaultResponse,
|
|
50977
|
-
...dexResponses.map((entry) => entry.payload)
|
|
50978
|
-
]),
|
|
50979
|
-
selectedPayload,
|
|
50980
|
-
dexPayloads: [
|
|
50981
|
-
{ dex: "", payload: defaultResponse },
|
|
50982
|
-
...dexResponses.map(({ dex, rawPayload }) => ({ dex, payload: rawPayload }))
|
|
50983
|
-
],
|
|
50984
|
-
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
51047
|
+
component.read = read;
|
|
51048
|
+
} catch (error48) {
|
|
51049
|
+
if (component.dex != null || input.forceRefresh || input.includeEffectiveTakerRate === true) throw error48;
|
|
51050
|
+
component.read = { payload: {}, fetchedAtMs: Date.now() };
|
|
51051
|
+
}
|
|
50985
51052
|
};
|
|
50986
|
-
|
|
50987
|
-
|
|
50988
|
-
|
|
50989
|
-
|
|
50990
|
-
|
|
50991
|
-
|
|
50992
|
-
{
|
|
50993
|
-
|
|
50994
|
-
|
|
50995
|
-
|
|
50996
|
-
|
|
50997
|
-
|
|
50998
|
-
if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
|
|
50999
|
-
throw error48;
|
|
51053
|
+
await awaitAccountReads(components.map(capture));
|
|
51054
|
+
if (input.publicReadDeadlineMs != null && input.includeEffectiveTakerRate === true && input.includeExactAccountMode === true) {
|
|
51055
|
+
const freshness = runtime_policy_generated_default.trading.engine.server_runtime.prompt_rescue;
|
|
51056
|
+
const horizonMs = Math.min(freshness.snapshot_max_age_seconds, freshness.snapshot_component_max_skew_seconds) * 1e3;
|
|
51057
|
+
for (; ; ) {
|
|
51058
|
+
const now = Date.now();
|
|
51059
|
+
const stale = components.filter(({ read }) => now - read.fetchedAtMs > horizonMs);
|
|
51060
|
+
if (!stale.length) break;
|
|
51061
|
+
if (now >= input.publicReadDeadlineMs) {
|
|
51062
|
+
throw new HyperliquidPublicReadError("public_timeout", "Hyperliquid public request timed out.", "clearinghouseState");
|
|
51063
|
+
}
|
|
51064
|
+
await awaitAccountReads(stale.map(capture));
|
|
51000
51065
|
}
|
|
51001
|
-
payload = {};
|
|
51002
51066
|
}
|
|
51003
|
-
|
|
51067
|
+
const perpsReads = components.slice(0, perpsDexes.length).map((component) => ({
|
|
51068
|
+
dex: component.dex,
|
|
51069
|
+
payload: component.read.payload,
|
|
51070
|
+
fetchedAtMs: component.read.fetchedAtMs
|
|
51071
|
+
}));
|
|
51072
|
+
const selectedRead = perpsReads.find(({ dex }) => dex === selectedDex);
|
|
51073
|
+
if (!selectedRead) throw new Error(`Missing selected Hyperliquid clearinghouse state for DEX ${selectedDex}.`);
|
|
51074
|
+
const spotRead = components[perpsDexes.length].read;
|
|
51075
|
+
return {
|
|
51076
|
+
perpsResult: {
|
|
51077
|
+
payload: aggregateClearinghouseResponses(perpsReads.map(({ dex, payload }) => dex ? prefixHip3PositionCoins(payload, dex) : payload)),
|
|
51078
|
+
selectedPayload: selectedDex ? prefixHip3PositionCoins(selectedRead.payload, selectedDex) : selectedRead.payload,
|
|
51079
|
+
dexPayloads: perpsReads.map(({ dex, payload }) => ({ dex, payload })),
|
|
51080
|
+
capturedAt: new Date(Math.min(...perpsReads.map(({ fetchedAtMs }) => fetchedAtMs))).toISOString()
|
|
51081
|
+
},
|
|
51082
|
+
spotResult: { payload: spotRead.payload, capturedAt: new Date(spotRead.fetchedAtMs).toISOString() }
|
|
51083
|
+
};
|
|
51004
51084
|
})();
|
|
51005
51085
|
const activeAssetPromise = input.includeActiveAssetData === false ? Promise.resolve(null) : (async () => {
|
|
51006
51086
|
let lastError = null;
|
|
@@ -51015,7 +51095,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51015
51095
|
return { payload, type: typeName };
|
|
51016
51096
|
} catch (error48) {
|
|
51017
51097
|
lastError = error48;
|
|
51018
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
51019
51098
|
if (isRateLimitError(error48)) throw error48;
|
|
51020
51099
|
if (typeName === "userActiveAssetData" && isUnsupportedUserActiveAssetError(error48)) {
|
|
51021
51100
|
rememberUnsupportedUserActiveAssetKey(activeAssetCacheKey);
|
|
@@ -51024,9 +51103,8 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51024
51103
|
}
|
|
51025
51104
|
throw lastError instanceof Error ? lastError : new Error("Failed to fetch browser active asset data.");
|
|
51026
51105
|
})();
|
|
51027
|
-
const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await
|
|
51028
|
-
|
|
51029
|
-
spotPromise,
|
|
51106
|
+
const [{ perpsResult, spotResult }, activeAssetResult, userFeesResult, exactAccountMode] = await awaitAccountReads([
|
|
51107
|
+
dynamicPromise,
|
|
51030
51108
|
activeAssetPromise,
|
|
51031
51109
|
userFeesPromise,
|
|
51032
51110
|
exactAccountModePromise
|
|
@@ -51050,7 +51128,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51050
51128
|
...parseInfoPositions(perpsResponse).filter((position) => Number(position.size) !== 0).map((position) => position.symbol)
|
|
51051
51129
|
].map(normalizeHyperliquidMarketSymbol).filter(Boolean))].sort();
|
|
51052
51130
|
const feeDexes = [...new Set(feeSymbols.map(getHyperliquidMarketDex))];
|
|
51053
|
-
const metadata = await
|
|
51131
|
+
const metadata = await awaitAccountReads(feeDexes.map(async (dex) => {
|
|
51054
51132
|
try {
|
|
51055
51133
|
const payload = metadataByDex.get(dex) ?? null;
|
|
51056
51134
|
return [dex, payload];
|
|
@@ -51151,7 +51229,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51151
51229
|
...effectiveTakerRates == null ? {} : { effectiveTakerRates },
|
|
51152
51230
|
...exactAccountMode == null || userFeesResult == null ? {} : {
|
|
51153
51231
|
promptRescueEvidence: {
|
|
51154
|
-
capturedAt:
|
|
51232
|
+
capturedAt: new Date(Math.min(Date.parse(perpsResult.capturedAt), Date.parse(spotResult.capturedAt))).toISOString(),
|
|
51155
51233
|
perpsCapturedAt: perpsResult.capturedAt,
|
|
51156
51234
|
spotCapturedAt: spotResult.capturedAt,
|
|
51157
51235
|
feesCapturedAt: userFeesResult.capturedAt,
|
|
@@ -51245,7 +51323,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51245
51323
|
providerRowCount = liveResult.providerRowCount;
|
|
51246
51324
|
fetchedAtMs = liveResult.fetchedAtMs;
|
|
51247
51325
|
} catch (error48) {
|
|
51248
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
51249
51326
|
const staleCache = readBrowserUserFillsCache(cacheKey);
|
|
51250
51327
|
if (isRateLimitError(error48) && !input.forceRefresh) {
|
|
51251
51328
|
evidenceSource = "stale_if_429";
|
|
@@ -83844,6 +83921,7 @@ var init_hyperliquid_client = __esm({
|
|
|
83844
83921
|
init_define_VTX_EXO_POLICY();
|
|
83845
83922
|
init_define_VTX_GROK_POLICY();
|
|
83846
83923
|
init_define_VTX_PI_MODEL_POLICY();
|
|
83924
|
+
init_runtime_policy_generated();
|
|
83847
83925
|
init_hyperliquid_public_read();
|
|
83848
83926
|
init_api2();
|
|
83849
83927
|
init_abort();
|
|
@@ -85514,6 +85592,7 @@ var init_hyperliquid_client = __esm({
|
|
|
85514
85592
|
const serializedPayload = JSON.stringify(input.payload);
|
|
85515
85593
|
const durableMutation = input.durableMutation;
|
|
85516
85594
|
let exchangeDispatched = false;
|
|
85595
|
+
let recoveryPermit = null;
|
|
85517
85596
|
let settlementAttempted = false;
|
|
85518
85597
|
assertFreshPreparedExecutionContext(input.preparedContext);
|
|
85519
85598
|
const captureTimeoutMs = Number(
|
|
@@ -85670,8 +85749,9 @@ var init_hyperliquid_client = __esm({
|
|
|
85670
85749
|
}
|
|
85671
85750
|
}
|
|
85672
85751
|
try {
|
|
85673
|
-
await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal);
|
|
85752
|
+
recoveryPermit = await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal);
|
|
85674
85753
|
assertFreshPreparedExecutionContext(input.preparedContext);
|
|
85754
|
+
assertHyperliquidRecoveryDispatch(apiUrl, recoveryPermit, "exchange");
|
|
85675
85755
|
} catch (preparedContextError) {
|
|
85676
85756
|
await settleDurableMutation("rejected");
|
|
85677
85757
|
if (isAbortLikeError(preparedContextError) || preparedContextError instanceof HyperliquidPublicReadError) throw preparedContextError;
|
|
@@ -85699,16 +85779,44 @@ var init_hyperliquid_client = __esm({
|
|
|
85699
85779
|
}
|
|
85700
85780
|
}
|
|
85701
85781
|
exchangeDispatched = true;
|
|
85702
|
-
const
|
|
85703
|
-
|
|
85704
|
-
|
|
85705
|
-
|
|
85706
|
-
|
|
85707
|
-
|
|
85708
|
-
|
|
85709
|
-
|
|
85710
|
-
|
|
85711
|
-
|
|
85782
|
+
const transportController = new AbortController();
|
|
85783
|
+
const exchangeTimeout = runtime_policy_generated_default.exchange.hyperliquid.http.exchange;
|
|
85784
|
+
const transportTimeoutMs = Math.min(
|
|
85785
|
+
(exchangeTimeout.request_timeout_seconds + exchangeTimeout.pool_timeout_seconds) * 1e3,
|
|
85786
|
+
recoveryPermit ? Math.max(0, recoveryPermit.expiresAt - Date.now()) : Infinity
|
|
85787
|
+
);
|
|
85788
|
+
let transportTimer;
|
|
85789
|
+
let response;
|
|
85790
|
+
let payload;
|
|
85791
|
+
try {
|
|
85792
|
+
const transport = (async () => {
|
|
85793
|
+
const received = await fetch(requestUrl, {
|
|
85794
|
+
method: "POST",
|
|
85795
|
+
headers: { "Content-Type": "application/json" },
|
|
85796
|
+
body: serializedPayload,
|
|
85797
|
+
signal: transportController.signal
|
|
85798
|
+
});
|
|
85799
|
+
if (transportController.signal.aborted) throw transportController.signal.reason;
|
|
85800
|
+
responseStatus = received.status;
|
|
85801
|
+
await recordHyperliquidExchangeResponse(apiUrl, received);
|
|
85802
|
+
const body = await received.json().catch(() => ({}));
|
|
85803
|
+
if (transportController.signal.aborted) throw transportController.signal.reason;
|
|
85804
|
+
return { response: received, payload: body };
|
|
85805
|
+
})();
|
|
85806
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
85807
|
+
transportTimer = globalThis.setTimeout(() => {
|
|
85808
|
+
const error48 = new DOMException("Hyperliquid exchange transport timed out.", "TimeoutError");
|
|
85809
|
+
transportController.abort(error48);
|
|
85810
|
+
reject(error48);
|
|
85811
|
+
}, transportTimeoutMs);
|
|
85812
|
+
});
|
|
85813
|
+
({ response, payload } = await Promise.race([transport, timeout]));
|
|
85814
|
+
} finally {
|
|
85815
|
+
globalThis.clearTimeout(transportTimer);
|
|
85816
|
+
transportController.abort();
|
|
85817
|
+
}
|
|
85818
|
+
await finishHyperliquidRecoveryRequest(recoveryPermit, response.status < 400 ? "success" : "failure").catch(() => void 0);
|
|
85819
|
+
recoveryPermit = null;
|
|
85712
85820
|
if (!response.ok) {
|
|
85713
85821
|
await settleDurableMutation("transport_ambiguous");
|
|
85714
85822
|
throw new RuntimeExecutionError(
|
|
@@ -85773,6 +85881,8 @@ var init_hyperliquid_client = __esm({
|
|
|
85773
85881
|
);
|
|
85774
85882
|
}
|
|
85775
85883
|
throw error48;
|
|
85884
|
+
} finally {
|
|
85885
|
+
await finishHyperliquidRecoveryRequest(recoveryPermit, exchangeDispatched ? "failure" : "cancelled").catch(() => void 0);
|
|
85776
85886
|
}
|
|
85777
85887
|
});
|
|
85778
85888
|
} catch (error48) {
|