@vtxmacro/cli 2026.9.54 → 2026.9.56
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 +23 -1
- package/bin/vtx-service-launcher.js +22 -0
- package/bin/vtx.js +397 -245
- 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.56",
|
|
20
20
|
codex_package_name: "@openai/codex",
|
|
21
21
|
codex_version: "0.155.0",
|
|
22
22
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -296,6 +296,28 @@ var runtime_policy_generated_default = {
|
|
|
296
296
|
apiWallets: 20
|
|
297
297
|
},
|
|
298
298
|
exchange_action_batch_size: 40
|
|
299
|
+
},
|
|
300
|
+
public_recovery: {
|
|
301
|
+
fallback_initial_seconds: 2,
|
|
302
|
+
fallback_max_seconds: 60,
|
|
303
|
+
permit_lease_seconds: 60,
|
|
304
|
+
recovery_initial_concurrency: 1,
|
|
305
|
+
recovery_max_concurrency: 8,
|
|
306
|
+
recovery_successes_per_step: 4,
|
|
307
|
+
recovery_min_spacing_ms: 100,
|
|
308
|
+
queue_poll_ms: 50,
|
|
309
|
+
recovery_queue_wait_seconds: 10,
|
|
310
|
+
recovery_quiet_seconds: 30
|
|
311
|
+
},
|
|
312
|
+
http: {
|
|
313
|
+
exchange: {
|
|
314
|
+
request_timeout_seconds: 10,
|
|
315
|
+
pool_timeout_seconds: 10
|
|
316
|
+
},
|
|
317
|
+
public_critical: {
|
|
318
|
+
request_timeout_seconds: 10,
|
|
319
|
+
pool_timeout_seconds: 5
|
|
320
|
+
}
|
|
299
321
|
}
|
|
300
322
|
}
|
|
301
323
|
}
|
|
@@ -179,6 +179,28 @@ var runtime_policy_generated_default = {
|
|
|
179
179
|
apiWallets: 20
|
|
180
180
|
},
|
|
181
181
|
exchange_action_batch_size: 40
|
|
182
|
+
},
|
|
183
|
+
public_recovery: {
|
|
184
|
+
fallback_initial_seconds: 2,
|
|
185
|
+
fallback_max_seconds: 60,
|
|
186
|
+
permit_lease_seconds: 60,
|
|
187
|
+
recovery_initial_concurrency: 1,
|
|
188
|
+
recovery_max_concurrency: 8,
|
|
189
|
+
recovery_successes_per_step: 4,
|
|
190
|
+
recovery_min_spacing_ms: 100,
|
|
191
|
+
queue_poll_ms: 50,
|
|
192
|
+
recovery_queue_wait_seconds: 10,
|
|
193
|
+
recovery_quiet_seconds: 30
|
|
194
|
+
},
|
|
195
|
+
http: {
|
|
196
|
+
exchange: {
|
|
197
|
+
request_timeout_seconds: 10,
|
|
198
|
+
pool_timeout_seconds: 10
|
|
199
|
+
},
|
|
200
|
+
public_critical: {
|
|
201
|
+
request_timeout_seconds: 10,
|
|
202
|
+
pool_timeout_seconds: 5
|
|
203
|
+
}
|
|
182
204
|
}
|
|
183
205
|
}
|
|
184
206
|
}
|
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.56",
|
|
81
81
|
codex_package_name: "@openai/codex",
|
|
82
82
|
codex_version: "0.155.0",
|
|
83
83
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -20637,6 +20637,28 @@ var init_runtime_policy_generated = __esm({
|
|
|
20637
20637
|
apiWallets: 20
|
|
20638
20638
|
},
|
|
20639
20639
|
exchange_action_batch_size: 40
|
|
20640
|
+
},
|
|
20641
|
+
public_recovery: {
|
|
20642
|
+
fallback_initial_seconds: 2,
|
|
20643
|
+
fallback_max_seconds: 60,
|
|
20644
|
+
permit_lease_seconds: 60,
|
|
20645
|
+
recovery_initial_concurrency: 1,
|
|
20646
|
+
recovery_max_concurrency: 8,
|
|
20647
|
+
recovery_successes_per_step: 4,
|
|
20648
|
+
recovery_min_spacing_ms: 100,
|
|
20649
|
+
queue_poll_ms: 50,
|
|
20650
|
+
recovery_queue_wait_seconds: 10,
|
|
20651
|
+
recovery_quiet_seconds: 30
|
|
20652
|
+
},
|
|
20653
|
+
http: {
|
|
20654
|
+
exchange: {
|
|
20655
|
+
request_timeout_seconds: 10,
|
|
20656
|
+
pool_timeout_seconds: 10
|
|
20657
|
+
},
|
|
20658
|
+
public_critical: {
|
|
20659
|
+
request_timeout_seconds: 10,
|
|
20660
|
+
pool_timeout_seconds: 5
|
|
20661
|
+
}
|
|
20640
20662
|
}
|
|
20641
20663
|
}
|
|
20642
20664
|
}
|
|
@@ -21519,7 +21541,8 @@ var init_mcp_client = __esm({
|
|
|
21519
21541
|
this.#initialized = true;
|
|
21520
21542
|
}
|
|
21521
21543
|
async callTool(name, argumentsValue, options = {}) {
|
|
21522
|
-
const
|
|
21544
|
+
const timingObserver = name === "inference.job.claim" ? options.onClaimTiming : name === "inference.host.heartbeat" ? options.onHostHeartbeatTiming : void 0;
|
|
21545
|
+
const timing = timingObserver ? new ClaimTiming() : void 0;
|
|
21523
21546
|
let outcome = "failure";
|
|
21524
21547
|
try {
|
|
21525
21548
|
if (!this.#initialized) {
|
|
@@ -21598,7 +21621,7 @@ var init_mcp_client = __esm({
|
|
|
21598
21621
|
if (timing) {
|
|
21599
21622
|
const receipt = Object.freeze({ ...timing.finish(outcome), transport_route: this.#transport.route });
|
|
21600
21623
|
try {
|
|
21601
|
-
void Promise.resolve(
|
|
21624
|
+
void Promise.resolve(timingObserver?.(receipt)).catch(() => void 0);
|
|
21602
21625
|
} catch {
|
|
21603
21626
|
}
|
|
21604
21627
|
}
|
|
@@ -32615,6 +32638,39 @@ var init_runner = __esm({
|
|
|
32615
32638
|
};
|
|
32616
32639
|
const hostHeartbeatAbort = new AbortController();
|
|
32617
32640
|
stopHostHeartbeatLoop = () => hostHeartbeatAbort.abort();
|
|
32641
|
+
const backgroundHostHeartbeat = async (advertisementGeneration, allowOfflineProjection, deadlineAtMs) => {
|
|
32642
|
+
const startedAt = performance.now();
|
|
32643
|
+
let clientTiming;
|
|
32644
|
+
try {
|
|
32645
|
+
await hostHeartbeat("healthy", {
|
|
32646
|
+
signal: hostHeartbeatAbort.signal,
|
|
32647
|
+
// A liveness request must not inherit the general MCP timeout,
|
|
32648
|
+
// which can exceed the server's host-staleness window. Generation
|
|
32649
|
+
// recovery shares this deadline with its first attempt.
|
|
32650
|
+
timeoutMs: settings.hostHeartbeatMs,
|
|
32651
|
+
deadlineAtMs,
|
|
32652
|
+
onHostHeartbeatTiming: (timing) => {
|
|
32653
|
+
clientTiming = timing;
|
|
32654
|
+
}
|
|
32655
|
+
}, false, allowOfflineProjection, 0, advertisementGeneration);
|
|
32656
|
+
} catch (error48) {
|
|
32657
|
+
if (!hostHeartbeatAbort.signal.aborted && !drainRequested) {
|
|
32658
|
+
emitDiagnostic("host_heartbeat_request_failed", {
|
|
32659
|
+
elapsed_ms: Math.max(0, Math.round(performance.now() - startedAt)),
|
|
32660
|
+
request_timeout_ms: settings.hostHeartbeatMs,
|
|
32661
|
+
advertisement_generation: advertisementGeneration,
|
|
32662
|
+
failure_code: safeFailureCode(
|
|
32663
|
+
error48 instanceof ExternalInferenceMcpError ? error48.code : "",
|
|
32664
|
+
"heartbeat_failed"
|
|
32665
|
+
),
|
|
32666
|
+
http_status_code: error48 instanceof ExternalInferenceMcpError ? error48.httpStatusCode : null,
|
|
32667
|
+
retry_after_ms: error48 instanceof ExternalInferenceMcpError ? error48.retryAfterMs : null,
|
|
32668
|
+
...clientTiming ? { client_timing: clientTiming } : {}
|
|
32669
|
+
});
|
|
32670
|
+
}
|
|
32671
|
+
throw error48;
|
|
32672
|
+
}
|
|
32673
|
+
};
|
|
32618
32674
|
let nextHostHeartbeatAt = now() + settings.hostHeartbeatMs;
|
|
32619
32675
|
hostHeartbeatLoop = (async () => {
|
|
32620
32676
|
while (!drainRequested && !hostHeartbeatAbort.signal.aborted) {
|
|
@@ -32643,19 +32699,16 @@ var init_runner = __esm({
|
|
|
32643
32699
|
}
|
|
32644
32700
|
}
|
|
32645
32701
|
if (drainRequested || hostHeartbeatAbort.signal.aborted) return;
|
|
32646
|
-
const
|
|
32702
|
+
const heartbeatDeadlineAtMs = Date.now() + settings.hostHeartbeatMs;
|
|
32647
32703
|
const attemptedAdvertisementGeneration = receipt.advertisement_generation;
|
|
32648
32704
|
try {
|
|
32649
|
-
await
|
|
32650
|
-
|
|
32651
|
-
{ signal: hostHeartbeatAbort.signal },
|
|
32652
|
-
false,
|
|
32705
|
+
await backgroundHostHeartbeat(
|
|
32706
|
+
attemptedAdvertisementGeneration,
|
|
32653
32707
|
// The server evaluates advertisement expiry when it receives
|
|
32654
32708
|
// the heartbeat. A request sent just before expiry can therefore
|
|
32655
32709
|
// truthfully return offline; the advertisement loop owns repair.
|
|
32656
32710
|
true,
|
|
32657
|
-
|
|
32658
|
-
attemptedAdvertisementGeneration
|
|
32711
|
+
heartbeatDeadlineAtMs
|
|
32659
32712
|
);
|
|
32660
32713
|
} catch (error48) {
|
|
32661
32714
|
if (hostHeartbeatAbort.signal.aborted || drainRequested) return;
|
|
@@ -32664,13 +32717,10 @@ var init_runner = __esm({
|
|
|
32664
32717
|
const recoveryAdvertisementGeneration = receipt.advertisement_generation > attemptedAdvertisementGeneration ? receipt.advertisement_generation : errorCode === "generation_stale" && pendingAdvertisement && pendingAdvertisement.advertisement_generation === attemptedAdvertisementGeneration + 1 ? pendingAdvertisement.advertisement_generation : null;
|
|
32665
32718
|
if (errorCode === "generation_stale" && recoveryAdvertisementGeneration !== null) {
|
|
32666
32719
|
try {
|
|
32667
|
-
await
|
|
32668
|
-
|
|
32669
|
-
{ signal: hostHeartbeatAbort.signal },
|
|
32670
|
-
false,
|
|
32720
|
+
await backgroundHostHeartbeat(
|
|
32721
|
+
recoveryAdvertisementGeneration,
|
|
32671
32722
|
false,
|
|
32672
|
-
|
|
32673
|
-
recoveryAdvertisementGeneration
|
|
32723
|
+
heartbeatDeadlineAtMs
|
|
32674
32724
|
);
|
|
32675
32725
|
if (receipt.advertisement_generation < recoveryAdvertisementGeneration) {
|
|
32676
32726
|
await mutateReceipt((current) => current.advertisement_generation >= recoveryAdvertisementGeneration ? current : {
|
|
@@ -42647,6 +42697,28 @@ var init_runtime_policy_generated2 = __esm({
|
|
|
42647
42697
|
apiWallets: 20
|
|
42648
42698
|
},
|
|
42649
42699
|
exchange_action_batch_size: 40
|
|
42700
|
+
},
|
|
42701
|
+
public_recovery: {
|
|
42702
|
+
fallback_initial_seconds: 2,
|
|
42703
|
+
fallback_max_seconds: 60,
|
|
42704
|
+
permit_lease_seconds: 60,
|
|
42705
|
+
recovery_initial_concurrency: 1,
|
|
42706
|
+
recovery_max_concurrency: 8,
|
|
42707
|
+
recovery_successes_per_step: 4,
|
|
42708
|
+
recovery_min_spacing_ms: 100,
|
|
42709
|
+
queue_poll_ms: 50,
|
|
42710
|
+
recovery_queue_wait_seconds: 10,
|
|
42711
|
+
recovery_quiet_seconds: 30
|
|
42712
|
+
},
|
|
42713
|
+
http: {
|
|
42714
|
+
exchange: {
|
|
42715
|
+
request_timeout_seconds: 10,
|
|
42716
|
+
pool_timeout_seconds: 10
|
|
42717
|
+
},
|
|
42718
|
+
public_critical: {
|
|
42719
|
+
request_timeout_seconds: 10,
|
|
42720
|
+
pool_timeout_seconds: 5
|
|
42721
|
+
}
|
|
42650
42722
|
}
|
|
42651
42723
|
}
|
|
42652
42724
|
}
|
|
@@ -48588,7 +48660,7 @@ var init_runtime_redaction = __esm({
|
|
|
48588
48660
|
});
|
|
48589
48661
|
|
|
48590
48662
|
// lib/runtime/hyperliquid-public-read.ts
|
|
48591
|
-
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;
|
|
48663
|
+
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;
|
|
48592
48664
|
var init_hyperliquid_public_read = __esm({
|
|
48593
48665
|
"lib/runtime/hyperliquid-public-read.ts"() {
|
|
48594
48666
|
"use strict";
|
|
@@ -48599,6 +48671,7 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48599
48671
|
init_runtime_policy_generated();
|
|
48600
48672
|
policy = runtime_policy_generated_default.exchange.hyperliquid.client_public_read_budget;
|
|
48601
48673
|
weights = runtime_policy_generated_default.exchange.hyperliquid.read_budget.weights;
|
|
48674
|
+
recoveryPolicy = runtime_policy_generated_default.exchange.hyperliquid.public_recovery;
|
|
48602
48675
|
budgets = /* @__PURE__ */ new Map();
|
|
48603
48676
|
unpersistedBudgets = /* @__PURE__ */ new Set();
|
|
48604
48677
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -48656,7 +48729,15 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48656
48729
|
withBudgetLock = async (key, signal, work) => {
|
|
48657
48730
|
checkAbort(signal);
|
|
48658
48731
|
if (typeof navigator !== "undefined" && navigator.locks?.request) {
|
|
48659
|
-
|
|
48732
|
+
const result2 = await navigator.locks.request(key, { ...signal ? { signal } : {} }, () => {
|
|
48733
|
+
try {
|
|
48734
|
+
return { ok: true, value: work() };
|
|
48735
|
+
} catch (error48) {
|
|
48736
|
+
return { ok: false, error: error48 };
|
|
48737
|
+
}
|
|
48738
|
+
});
|
|
48739
|
+
if (!result2.ok) throw result2.error;
|
|
48740
|
+
return result2.value;
|
|
48660
48741
|
}
|
|
48661
48742
|
return work();
|
|
48662
48743
|
};
|
|
@@ -48673,6 +48754,15 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48673
48754
|
this.name = "HyperliquidPublicReadError";
|
|
48674
48755
|
}
|
|
48675
48756
|
};
|
|
48757
|
+
getHyperliquidPublicReadBudget = (endpoint) => {
|
|
48758
|
+
const budget = loadBudget(`${PREFIX}${endpoint.replace(/\/$/, "")}`);
|
|
48759
|
+
return {
|
|
48760
|
+
usedWeight: budget.reservations.filter((r) => r.at > Date.now() - policy.window_seconds * 1e3).reduce((sum, r) => sum + r.weight, 0),
|
|
48761
|
+
maxWeight: policy.max_weight,
|
|
48762
|
+
windowSeconds: policy.window_seconds,
|
|
48763
|
+
cooldownUntilMs: budget.cooldownUntil
|
|
48764
|
+
};
|
|
48765
|
+
};
|
|
48676
48766
|
cooldownError = (requestType, until) => new HyperliquidPublicReadError(
|
|
48677
48767
|
"public_cooldown_active",
|
|
48678
48768
|
"Hyperliquid public request cooldown is active.",
|
|
@@ -48680,48 +48770,129 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48680
48770
|
void 0,
|
|
48681
48771
|
Math.max(0, until - Date.now())
|
|
48682
48772
|
);
|
|
48683
|
-
|
|
48773
|
+
recoveryWaitError = (requestType) => new HyperliquidPublicReadError(
|
|
48774
|
+
"public_recovery_wait",
|
|
48775
|
+
"Hyperliquid provider recovery could not dispatch before the request deadline.",
|
|
48776
|
+
requestType
|
|
48777
|
+
);
|
|
48778
|
+
fallbackDelayMs = (failures) => Math.min(
|
|
48779
|
+
recoveryPolicy.fallback_max_seconds * 1e3,
|
|
48780
|
+
recoveryPolicy.fallback_initial_seconds * 1e3 * 2 ** Math.min(30, Math.max(0, failures - 1)) * (0.5 + Math.random())
|
|
48781
|
+
);
|
|
48782
|
+
admit = async (apiUrl, requestType, signal, weightOverride, deadlineMs) => {
|
|
48684
48783
|
const key = `${PREFIX}${apiUrl}`;
|
|
48685
|
-
const weight =
|
|
48686
|
-
|
|
48687
|
-
|
|
48688
|
-
|
|
48689
|
-
|
|
48690
|
-
|
|
48691
|
-
|
|
48692
|
-
|
|
48693
|
-
|
|
48694
|
-
|
|
48695
|
-
|
|
48696
|
-
|
|
48697
|
-
|
|
48784
|
+
const weight = weightOverride ?? weights[requestType] ?? policy.default_request_weight;
|
|
48785
|
+
const ticket = crypto.randomUUID();
|
|
48786
|
+
const deadline = Math.min(deadlineMs ?? Infinity, Date.now() + recoveryPolicy.recovery_queue_wait_seconds * 1e3);
|
|
48787
|
+
let admitted = false;
|
|
48788
|
+
try {
|
|
48789
|
+
for (; ; ) {
|
|
48790
|
+
checkAbort(signal);
|
|
48791
|
+
if (deadlineMs != null && Date.now() >= deadlineMs) throw recoveryWaitError(requestType);
|
|
48792
|
+
const result2 = await withBudgetLock(key, signal, () => {
|
|
48793
|
+
const now = Date.now();
|
|
48794
|
+
const budget = loadBudget(key);
|
|
48795
|
+
if (budget.cooldownUntil > now) throw cooldownError(requestType, budget.cooldownUntil);
|
|
48796
|
+
const recovery = budget.recovery;
|
|
48797
|
+
let permit = null;
|
|
48798
|
+
if (recovery) {
|
|
48799
|
+
recovery.active = recovery.active.filter((entry) => entry.expiresAt > now);
|
|
48800
|
+
recovery.queue = recovery.queue.filter((entry) => entry.expiresAt > now);
|
|
48801
|
+
if (now >= deadline) throw recoveryWaitError(requestType);
|
|
48802
|
+
if (!recovery.queue.some((entry) => entry.id === ticket)) recovery.queue.push({ id: ticket, expiresAt: deadline });
|
|
48803
|
+
if (recovery.queue[0]?.id !== ticket || recovery.active.length >= recovery.concurrency || recovery.nextAt > now) {
|
|
48804
|
+
saveBudget(key, budget);
|
|
48805
|
+
return { ready: false, permit: null };
|
|
48806
|
+
}
|
|
48807
|
+
recovery.queue.shift();
|
|
48808
|
+
const expiresAt = now + recoveryPolicy.permit_lease_seconds * 1e3;
|
|
48809
|
+
recovery.active.push({ id: ticket, expiresAt });
|
|
48810
|
+
recovery.nextAt = now + recoveryPolicy.recovery_min_spacing_ms;
|
|
48811
|
+
permit = { endpoint: apiUrl, id: ticket, generation: recovery.generation, expiresAt };
|
|
48812
|
+
}
|
|
48813
|
+
budget.reservations = budget.reservations.filter((entry) => entry.at > now - policy.window_seconds * 1e3);
|
|
48814
|
+
budget.reservations.push({ at: now, weight });
|
|
48698
48815
|
saveBudget(key, budget);
|
|
48699
|
-
return {
|
|
48816
|
+
return { ready: true, permit };
|
|
48817
|
+
});
|
|
48818
|
+
if (result2.ready) {
|
|
48819
|
+
admitted = true;
|
|
48820
|
+
return result2.permit;
|
|
48700
48821
|
}
|
|
48701
|
-
|
|
48702
|
-
|
|
48703
|
-
|
|
48822
|
+
await wait(Math.min(recoveryPolicy.queue_poll_ms, Math.max(1, deadline - Date.now())), signal);
|
|
48823
|
+
}
|
|
48824
|
+
} finally {
|
|
48825
|
+
if (!admitted) await withBudgetLock(key, void 0, () => {
|
|
48826
|
+
const budget = loadBudget(key);
|
|
48827
|
+
if (budget.recovery) {
|
|
48828
|
+
budget.recovery.queue = budget.recovery.queue.filter((entry) => entry.id !== ticket);
|
|
48829
|
+
saveBudget(key, budget);
|
|
48704
48830
|
}
|
|
48705
|
-
throw new Error("Invalid Hyperliquid public read budget.");
|
|
48706
48831
|
});
|
|
48707
|
-
if (!delay2) return;
|
|
48708
|
-
if (bundleWeight != null || deadlineMs != null && Date.now() + delay2 >= deadlineMs) {
|
|
48709
|
-
throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid local public request allowance is exhausted.", requestType, void 0, delay2, weight, usedWeight, policy.max_weight);
|
|
48710
|
-
}
|
|
48711
|
-
await wait(delay2, signal);
|
|
48712
48832
|
}
|
|
48713
48833
|
};
|
|
48714
48834
|
cooldown = async (apiUrl, retryAfter) => {
|
|
48715
48835
|
const key = `${PREFIX}${apiUrl}`;
|
|
48716
48836
|
await withBudgetLock(key, void 0, () => {
|
|
48717
48837
|
const now = Date.now();
|
|
48718
|
-
const seconds = retryAfter == null ? NaN : Number(retryAfter);
|
|
48719
|
-
const providerUntil = Number.isFinite(seconds) ? now + seconds * 1e3 : Date.parse(retryAfter ?? "");
|
|
48720
48838
|
const budget = loadBudget(key);
|
|
48721
|
-
budget.
|
|
48839
|
+
if (!budget.recovery && now - (budget.lastFailure ?? 0) >= recoveryPolicy.recovery_quiet_seconds * 1e3) budget.failures = 0;
|
|
48840
|
+
budget.failures = (budget.failures ?? 0) + 1;
|
|
48841
|
+
const trimmed = retryAfter?.trim() ?? "";
|
|
48842
|
+
const seconds = trimmed !== "" ? Number(trimmed) : NaN;
|
|
48843
|
+
const providerUntil = Number.isFinite(seconds) && seconds >= 0 ? now + seconds * 1e3 : trimmed && !Number.isFinite(seconds) ? Date.parse(trimmed) : NaN;
|
|
48844
|
+
const until = Number.isFinite(providerUntil) ? Math.max(now, Number(providerUntil)) : now + fallbackDelayMs(budget.failures);
|
|
48845
|
+
budget.cooldownUntil = Math.max(budget.cooldownUntil, until);
|
|
48846
|
+
budget.lastFailure = now;
|
|
48847
|
+
budget.recovery = {
|
|
48848
|
+
generation: crypto.randomUUID(),
|
|
48849
|
+
concurrency: recoveryPolicy.recovery_initial_concurrency,
|
|
48850
|
+
successes: 0,
|
|
48851
|
+
nextAt: budget.cooldownUntil,
|
|
48852
|
+
queue: budget.recovery?.queue ?? [],
|
|
48853
|
+
active: []
|
|
48854
|
+
};
|
|
48722
48855
|
saveBudget(key, budget);
|
|
48723
48856
|
});
|
|
48724
48857
|
};
|
|
48858
|
+
finishHyperliquidRecoveryRequest = async (permit, outcome) => {
|
|
48859
|
+
if (!permit) return;
|
|
48860
|
+
const key = `${PREFIX}${permit.endpoint}`;
|
|
48861
|
+
await withBudgetLock(key, void 0, () => {
|
|
48862
|
+
const budget = loadBudget(key);
|
|
48863
|
+
const recovery = budget.recovery;
|
|
48864
|
+
if (!recovery || recovery.generation !== permit.generation) return;
|
|
48865
|
+
const now = Date.now();
|
|
48866
|
+
const member = recovery.active.find((entry) => entry.id === permit.id);
|
|
48867
|
+
recovery.active = recovery.active.filter((entry) => entry.id !== permit.id);
|
|
48868
|
+
if (member && member.expiresAt > now) {
|
|
48869
|
+
if (outcome === "success") {
|
|
48870
|
+
recovery.successes += 1;
|
|
48871
|
+
if (recovery.successes >= recoveryPolicy.recovery_successes_per_step) {
|
|
48872
|
+
if (recovery.concurrency >= recoveryPolicy.recovery_max_concurrency) {
|
|
48873
|
+
if (recovery.queue.length === 0 && recovery.active.length === 0) delete budget.recovery;
|
|
48874
|
+
} else {
|
|
48875
|
+
recovery.concurrency = Math.min(recoveryPolicy.recovery_max_concurrency, recovery.concurrency * 2);
|
|
48876
|
+
recovery.successes = 0;
|
|
48877
|
+
}
|
|
48878
|
+
}
|
|
48879
|
+
} else if (outcome === "failure") {
|
|
48880
|
+
recovery.successes = 0;
|
|
48881
|
+
recovery.concurrency = recoveryPolicy.recovery_initial_concurrency;
|
|
48882
|
+
recovery.nextAt = Math.max(recovery.nextAt, now + fallbackDelayMs(budget.failures ?? 1));
|
|
48883
|
+
}
|
|
48884
|
+
}
|
|
48885
|
+
saveBudget(key, budget);
|
|
48886
|
+
});
|
|
48887
|
+
};
|
|
48888
|
+
assertHyperliquidRecoveryDispatch = (endpoint, permit, requestType) => {
|
|
48889
|
+
const budget = loadBudget(`${PREFIX}${endpoint.replace(/\/$/, "")}`);
|
|
48890
|
+
if (budget.cooldownUntil > Date.now()) throw cooldownError(requestType, budget.cooldownUntil);
|
|
48891
|
+
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())))) {
|
|
48892
|
+
throw recoveryWaitError(requestType);
|
|
48893
|
+
}
|
|
48894
|
+
if (!permit && budget.recovery) throw recoveryWaitError(requestType);
|
|
48895
|
+
};
|
|
48725
48896
|
cacheTtlMs = (body, options) => {
|
|
48726
48897
|
const requestType = String(body.type);
|
|
48727
48898
|
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;
|
|
@@ -48733,47 +48904,26 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48733
48904
|
return ttl > 0 && existing && Date.now() >= existing.fetchedAtMs && horizon - existing.fetchedAtMs < ttl ? existing : void 0;
|
|
48734
48905
|
};
|
|
48735
48906
|
reserveHyperliquidPublicReads = async (endpoint, bodies, signal, options = {}) => {
|
|
48907
|
+
checkAbort(signal);
|
|
48736
48908
|
const apiUrl = endpoint.replace(/\/$/, "");
|
|
48737
48909
|
const cached2 = /* @__PURE__ */ new Map();
|
|
48738
|
-
const remaining = /* @__PURE__ */ new Map();
|
|
48739
|
-
let weight = 0;
|
|
48740
48910
|
for (const body of bodies) {
|
|
48741
|
-
const key = JSON.stringify(body);
|
|
48742
48911
|
const hit = eligibleCache(apiUrl, body, options);
|
|
48743
|
-
if (hit)
|
|
48744
|
-
cached2.set(key, hit);
|
|
48745
|
-
continue;
|
|
48746
|
-
}
|
|
48747
|
-
remaining.set(key, (remaining.get(key) ?? 0) + 1);
|
|
48748
|
-
weight += weights[String(body.type)] ?? policy.default_request_weight;
|
|
48912
|
+
if (hit) cached2.set(JSON.stringify(body), hit);
|
|
48749
48913
|
}
|
|
48750
|
-
|
|
48751
|
-
const admittedAtMs = Date.now();
|
|
48752
|
-
if (weight) await admit(apiUrl, "bundle", signal, weight, id2, options.cacheValidUntilMs);
|
|
48753
|
-
return { id: id2, closed: false, endpoint: apiUrl, expiresAtMs: admittedAtMs + policy.window_seconds * 1e3, remaining, cached: cached2, cacheValidUntilMs: options.cacheValidUntilMs };
|
|
48914
|
+
return { closed: false, endpoint: apiUrl, cached: cached2, cacheValidUntilMs: options.cacheValidUntilMs };
|
|
48754
48915
|
};
|
|
48755
48916
|
releaseHyperliquidPublicReadReservation = async (reservation) => {
|
|
48756
48917
|
reservation.closed = true;
|
|
48757
|
-
const key = `${PREFIX}${reservation.endpoint}`;
|
|
48758
|
-
await withBudgetLock(key, void 0, () => {
|
|
48759
|
-
const budget = loadBudget(key);
|
|
48760
|
-
const row = budget.reservations.find((entry) => entry.id === reservation.id);
|
|
48761
|
-
if (row) {
|
|
48762
|
-
const unused = [...reservation.remaining].reduce((sum, [body, count4]) => sum + (weights[String(JSON.parse(body).type)] ?? policy.default_request_weight) * count4, 0);
|
|
48763
|
-
row.weight = Math.max(0, row.weight - unused);
|
|
48764
|
-
budget.reservations = budget.reservations.filter((entry) => entry.weight > 0);
|
|
48765
|
-
saveBudget(key, budget);
|
|
48766
|
-
}
|
|
48767
|
-
reservation.remaining.clear();
|
|
48768
|
-
});
|
|
48769
48918
|
};
|
|
48770
48919
|
admitHyperliquidExchangeRequest = async (endpoint, action, signal) => {
|
|
48771
48920
|
const batchLength = Math.max(0, ...[action.orders, action.cancels, action.modifies].filter(Array.isArray).map((value) => value.length));
|
|
48772
48921
|
const weight = weights.exchange + Math.floor(batchLength / runtime_policy_generated_default.exchange.hyperliquid.read_budget.exchange_action_batch_size);
|
|
48773
|
-
|
|
48922
|
+
return admit(endpoint.replace(/\/$/, ""), "exchange", signal, weight);
|
|
48774
48923
|
};
|
|
48775
|
-
recordHyperliquidExchangeResponse = async (endpoint, response) => {
|
|
48924
|
+
recordHyperliquidExchangeResponse = async (endpoint, response, permit) => {
|
|
48776
48925
|
if (response.status === 429) await cooldown(endpoint.replace(/\/$/, ""), response.headers.get("Retry-After"));
|
|
48926
|
+
await finishHyperliquidRecoveryRequest(permit, response.status < 400 ? "success" : "failure");
|
|
48777
48927
|
};
|
|
48778
48928
|
readHyperliquidPublicInfo = async (endpoint, body, options = {}) => {
|
|
48779
48929
|
const apiUrl = endpoint.replace(/\/$/, "");
|
|
@@ -48782,71 +48932,101 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48782
48932
|
const ttlMs = cacheTtlMs(body, cacheOptions);
|
|
48783
48933
|
const key = `${apiUrl}:${JSON.stringify(body)}`;
|
|
48784
48934
|
checkAbort(options.signal);
|
|
48785
|
-
|
|
48786
|
-
|
|
48787
|
-
|
|
48788
|
-
|
|
48789
|
-
|
|
48790
|
-
|
|
48791
|
-
|
|
48792
|
-
|
|
48793
|
-
|
|
48794
|
-
|
|
48795
|
-
|
|
48796
|
-
|
|
48797
|
-
|
|
48798
|
-
|
|
48799
|
-
|
|
48800
|
-
|
|
48801
|
-
|
|
48802
|
-
|
|
48803
|
-
|
|
48804
|
-
|
|
48935
|
+
const transportPolicy = runtime_policy_generated_default.exchange.hyperliquid.http.public_critical;
|
|
48936
|
+
const deadline = Math.min(
|
|
48937
|
+
Date.now() + (transportPolicy.request_timeout_seconds + transportPolicy.pool_timeout_seconds) * 1e3,
|
|
48938
|
+
options.deadlineMs ?? Infinity,
|
|
48939
|
+
options.reservation?.cacheValidUntilMs ?? Infinity
|
|
48940
|
+
);
|
|
48941
|
+
const controller = new AbortController();
|
|
48942
|
+
const signal = controller.signal;
|
|
48943
|
+
const callerAborted = () => controller.abort(abortError2(options.signal));
|
|
48944
|
+
options.signal?.addEventListener("abort", callerAborted, { once: true });
|
|
48945
|
+
let timer;
|
|
48946
|
+
const armDeadline = (until) => {
|
|
48947
|
+
clearTimeout(timer);
|
|
48948
|
+
const timeout = () => controller.abort(new DOMException("Hyperliquid public request timed out.", "TimeoutError"));
|
|
48949
|
+
if (until <= Date.now()) timeout();
|
|
48950
|
+
else timer = setTimeout(timeout, until - Date.now());
|
|
48951
|
+
};
|
|
48952
|
+
armDeadline(deadline);
|
|
48953
|
+
let permit = null;
|
|
48954
|
+
let outcome = "cancelled";
|
|
48805
48955
|
let settled;
|
|
48806
|
-
|
|
48807
|
-
settled = resolve13;
|
|
48808
|
-
}));
|
|
48956
|
+
let acquiring = false;
|
|
48809
48957
|
try {
|
|
48810
|
-
|
|
48811
|
-
|
|
48812
|
-
|
|
48813
|
-
|
|
48814
|
-
|
|
48815
|
-
|
|
48816
|
-
if (
|
|
48817
|
-
|
|
48818
|
-
|
|
48819
|
-
|
|
48820
|
-
|
|
48821
|
-
|
|
48822
|
-
|
|
48823
|
-
|
|
48958
|
+
checkAbort(signal);
|
|
48959
|
+
if (ttlMs) {
|
|
48960
|
+
for (; ; ) {
|
|
48961
|
+
const existing = options.reservation?.cached.get(JSON.stringify(body)) ?? eligibleCache(apiUrl, body, cacheOptions);
|
|
48962
|
+
if (existing) return existing;
|
|
48963
|
+
const running = pending2.get(key);
|
|
48964
|
+
if (!running) break;
|
|
48965
|
+
await new Promise((resolve13, reject) => {
|
|
48966
|
+
const aborted2 = () => {
|
|
48967
|
+
signal.removeEventListener("abort", aborted2);
|
|
48968
|
+
reject(abortError2(signal));
|
|
48969
|
+
};
|
|
48970
|
+
signal.addEventListener("abort", aborted2, { once: true });
|
|
48971
|
+
running.then(() => {
|
|
48972
|
+
signal.removeEventListener("abort", aborted2);
|
|
48973
|
+
resolve13();
|
|
48974
|
+
});
|
|
48975
|
+
});
|
|
48976
|
+
checkAbort(signal);
|
|
48977
|
+
}
|
|
48978
|
+
pending2.set(key, new Promise((resolve13) => {
|
|
48979
|
+
settled = resolve13;
|
|
48980
|
+
}));
|
|
48981
|
+
}
|
|
48982
|
+
if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
|
|
48983
|
+
acquiring = true;
|
|
48984
|
+
permit = await admit(apiUrl, requestType, signal, void 0, deadline);
|
|
48985
|
+
acquiring = false;
|
|
48986
|
+
armDeadline(Math.min(deadline, permit?.expiresAt ?? Infinity));
|
|
48987
|
+
checkAbort(signal);
|
|
48988
|
+
if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
|
|
48989
|
+
assertHyperliquidRecoveryDispatch(apiUrl, permit, requestType);
|
|
48990
|
+
outcome = "failure";
|
|
48991
|
+
let transportAborted;
|
|
48992
|
+
let response;
|
|
48993
|
+
let payload;
|
|
48994
|
+
try {
|
|
48995
|
+
const aborted2 = new Promise((_resolve, reject) => {
|
|
48996
|
+
transportAborted = () => reject(abortError2(signal));
|
|
48997
|
+
signal.addEventListener("abort", transportAborted, { once: true });
|
|
48824
48998
|
});
|
|
48825
|
-
|
|
48826
|
-
|
|
48827
|
-
|
|
48828
|
-
|
|
48829
|
-
|
|
48830
|
-
|
|
48831
|
-
|
|
48832
|
-
|
|
48833
|
-
|
|
48834
|
-
|
|
48835
|
-
|
|
48836
|
-
|
|
48837
|
-
|
|
48838
|
-
|
|
48839
|
-
|
|
48840
|
-
|
|
48841
|
-
|
|
48999
|
+
const transport = (async () => {
|
|
49000
|
+
const received = await fetch(`${apiUrl}/info`, {
|
|
49001
|
+
method: "POST",
|
|
49002
|
+
headers: { "Content-Type": "application/json" },
|
|
49003
|
+
body: JSON.stringify(body),
|
|
49004
|
+
signal
|
|
49005
|
+
});
|
|
49006
|
+
checkAbort(signal);
|
|
49007
|
+
if (received.status === 429) {
|
|
49008
|
+
await cooldown(apiUrl, received.headers.get("Retry-After"));
|
|
49009
|
+
throw new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
|
|
49010
|
+
}
|
|
49011
|
+
const receivedPayload = await received.json().catch((error48) => {
|
|
49012
|
+
if (error48 instanceof SyntaxError) return {};
|
|
49013
|
+
throw error48;
|
|
49014
|
+
});
|
|
49015
|
+
checkAbort(signal);
|
|
49016
|
+
return { response: received, payload: receivedPayload };
|
|
49017
|
+
})();
|
|
49018
|
+
({ response, payload } = await Promise.race([transport, aborted2]));
|
|
49019
|
+
} finally {
|
|
49020
|
+
if (transportAborted) signal.removeEventListener("abort", transportAborted);
|
|
49021
|
+
}
|
|
48842
49022
|
if (!response.ok) {
|
|
48843
49023
|
const detail = sanitizeRuntimeDiagnosticValue(typeof payload?.response === "string" ? payload.response : typeof payload?.detail === "string" ? payload.detail : "");
|
|
48844
|
-
if (response.status === 429) throw new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
|
|
48845
49024
|
throw Object.assign(new Error(`Hyperliquid info request failed (${response.status}) request_type=${requestType}.${detail ? ` ${detail}` : ""}`), {
|
|
48846
49025
|
status: response.status,
|
|
48847
49026
|
requestType
|
|
48848
49027
|
});
|
|
48849
49028
|
}
|
|
49029
|
+
outcome = "success";
|
|
48850
49030
|
const result2 = { payload, fetchedAtMs: Date.now() };
|
|
48851
49031
|
if (ttlMs) {
|
|
48852
49032
|
cache.set(key, result2);
|
|
@@ -48854,14 +49034,26 @@ var init_hyperliquid_public_read = __esm({
|
|
|
48854
49034
|
}
|
|
48855
49035
|
return result2;
|
|
48856
49036
|
} catch (error48) {
|
|
48857
|
-
if (options.signal?.aborted
|
|
49037
|
+
if (options.signal?.aborted) {
|
|
49038
|
+
outcome = "cancelled";
|
|
49039
|
+
throw abortError2(options.signal);
|
|
49040
|
+
}
|
|
49041
|
+
if (acquiring && signal.aborted && signal.reason?.name === "TimeoutError") throw recoveryWaitError(requestType);
|
|
49042
|
+
if (error48 instanceof HyperliquidPublicReadError) throw error48;
|
|
48858
49043
|
if (error48 instanceof TypeError) throw new HyperliquidPublicReadError("public_network_error", "Hyperliquid public request network failure.", requestType);
|
|
48859
49044
|
if (error48 instanceof Error && (error48.name === "TimeoutError" || error48.name === "AbortError")) throw new HyperliquidPublicReadError("public_timeout", "Hyperliquid public request timed out.", requestType);
|
|
48860
49045
|
throw error48;
|
|
48861
49046
|
} finally {
|
|
48862
|
-
|
|
48863
|
-
|
|
48864
|
-
|
|
49047
|
+
clearTimeout(timer);
|
|
49048
|
+
options.signal?.removeEventListener("abort", callerAborted);
|
|
49049
|
+
controller.abort();
|
|
49050
|
+
try {
|
|
49051
|
+
await finishHyperliquidRecoveryRequest(permit, outcome);
|
|
49052
|
+
} finally {
|
|
49053
|
+
if (settled) {
|
|
49054
|
+
pending2.delete(key);
|
|
49055
|
+
settled();
|
|
49056
|
+
}
|
|
48865
49057
|
}
|
|
48866
49058
|
}
|
|
48867
49059
|
};
|
|
@@ -49839,6 +50031,8 @@ var init_network_debug = __esm({
|
|
|
49839
50031
|
kind: input.kind,
|
|
49840
50032
|
label: input.label,
|
|
49841
50033
|
transport: "browser",
|
|
50034
|
+
providerTransport: input.kind === "provider" ? input.providerTransport ?? "direct" : null,
|
|
50035
|
+
actualRelayPath: input.kind === "provider" && input.providerTransport === "server_relay" ? "/llm/native-provider-relay" : null,
|
|
49842
50036
|
method: (input.method || "POST").toUpperCase(),
|
|
49843
50037
|
targetProtocol,
|
|
49844
50038
|
targetHost,
|
|
@@ -49957,7 +50151,7 @@ var init_network_debug = __esm({
|
|
|
49957
50151
|
});
|
|
49958
50152
|
|
|
49959
50153
|
// lib/runtime/hyperliquid-account-state-adapter.ts
|
|
49960
|
-
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,
|
|
50154
|
+
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, fetchHyperliquidInfoPayload, requireHyperliquidApiUrl, requireWalletAddress, parseInfoPositionSnapshot, fetchBrowserAccountState, fetchBrowserAccountStateUncached, fetchBrowserUserFills, fetchBrowserPositionSnapshot;
|
|
49961
50155
|
var init_hyperliquid_account_state_adapter = __esm({
|
|
49962
50156
|
"lib/runtime/hyperliquid-account-state-adapter.ts"() {
|
|
49963
50157
|
"use strict";
|
|
@@ -49978,15 +50172,11 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
49978
50172
|
UNSUPPORTED_USER_ACTIVE_ASSET_STORAGE_KEY = "vtx:hyperliquid:unsupported-user-active-asset:v1";
|
|
49979
50173
|
USER_FILLS_CACHE_STORAGE_PREFIX = "vtx:hyperliquid:user-fills:v1:";
|
|
49980
50174
|
ACCOUNT_STATE_CACHE_STORAGE_PREFIX = "vtx:hyperliquid:account-state:v1:";
|
|
49981
|
-
INFO_RATE_LIMIT_COOLDOWN_STORAGE_PREFIX = "vtx:hyperliquid:info-rate-limit-cooldown:v1:";
|
|
49982
|
-
INFO_RATE_LIMIT_COOLDOWN_MIN_MS = 5e3;
|
|
49983
|
-
INFO_RATE_LIMIT_COOLDOWN_MAX_MS = 6e4;
|
|
49984
50175
|
browserUserFillsCache = /* @__PURE__ */ new Map();
|
|
49985
50176
|
browserUserFillsInFlight = /* @__PURE__ */ new Map();
|
|
49986
50177
|
HYPERLIQUID_USER_FILLS_PROVIDER_PAGE_CAP = 2e3;
|
|
49987
50178
|
browserAccountStateCache = /* @__PURE__ */ new Map();
|
|
49988
50179
|
browserAccountStateInFlight = /* @__PURE__ */ new Map();
|
|
49989
|
-
browserInfoRateLimitCooldowns = /* @__PURE__ */ new Map();
|
|
49990
50180
|
UNSUPPORTED_USER_ACTIVE_ASSET_DETAIL_PATTERNS = [
|
|
49991
50181
|
/unsupported/i,
|
|
49992
50182
|
/not\s+supported/i,
|
|
@@ -50104,93 +50294,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50104
50294
|
buildAccountStateStorageKey = (cacheKey) => {
|
|
50105
50295
|
return `${ACCOUNT_STATE_CACHE_STORAGE_PREFIX}${cacheKey}`;
|
|
50106
50296
|
};
|
|
50107
|
-
|
|
50108
|
-
return String(apiUrl || "").trim().replace(/\/$/, "").toLowerCase();
|
|
50109
|
-
};
|
|
50110
|
-
normalizeInfoRequestType = (requestType) => {
|
|
50111
|
-
return String(requestType || "").trim() || "info";
|
|
50112
|
-
};
|
|
50113
|
-
buildInfoRateLimitCooldownKey = (apiUrl, requestType) => {
|
|
50114
|
-
return [
|
|
50115
|
-
normalizeInfoRateLimitApiUrl(apiUrl),
|
|
50116
|
-
normalizeInfoRequestType(requestType)
|
|
50117
|
-
].join("::");
|
|
50118
|
-
};
|
|
50119
|
-
buildInfoRateLimitCooldownStorageKey = (cooldownKey) => {
|
|
50120
|
-
return `${INFO_RATE_LIMIT_COOLDOWN_STORAGE_PREFIX}${encodeURIComponent(cooldownKey)}`;
|
|
50121
|
-
};
|
|
50122
|
-
readInfoRateLimitCooldownUntilMs = (apiUrl, requestType, nowMs = Date.now()) => {
|
|
50123
|
-
const cooldownKey = buildInfoRateLimitCooldownKey(apiUrl, requestType);
|
|
50124
|
-
const memoryValue = browserInfoRateLimitCooldowns.get(cooldownKey);
|
|
50125
|
-
if (Number.isFinite(memoryValue)) {
|
|
50126
|
-
if (Number(memoryValue) > nowMs) {
|
|
50127
|
-
return Number(memoryValue);
|
|
50128
|
-
}
|
|
50129
|
-
browserInfoRateLimitCooldowns.delete(cooldownKey);
|
|
50130
|
-
}
|
|
50131
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
50132
|
-
return 0;
|
|
50133
|
-
}
|
|
50134
|
-
try {
|
|
50135
|
-
const storageKey = buildInfoRateLimitCooldownStorageKey(cooldownKey);
|
|
50136
|
-
const rawValue = window.localStorage.getItem(storageKey);
|
|
50137
|
-
if (!rawValue) {
|
|
50138
|
-
return 0;
|
|
50139
|
-
}
|
|
50140
|
-
const parsed = JSON.parse(rawValue);
|
|
50141
|
-
const untilMs = Number(parsed?.untilMs);
|
|
50142
|
-
if (!Number.isFinite(untilMs) || untilMs <= nowMs) {
|
|
50143
|
-
window.localStorage.removeItem(storageKey);
|
|
50144
|
-
return 0;
|
|
50145
|
-
}
|
|
50146
|
-
browserInfoRateLimitCooldowns.set(cooldownKey, untilMs);
|
|
50147
|
-
return untilMs;
|
|
50148
|
-
} catch {
|
|
50149
|
-
return 0;
|
|
50150
|
-
}
|
|
50151
|
-
};
|
|
50152
|
-
hasActiveInfoRateLimitCooldown = (apiUrl, requestTypes, nowMs = Date.now()) => requestTypes.some((requestType) => readInfoRateLimitCooldownUntilMs(apiUrl, requestType, nowMs) > nowMs);
|
|
50153
|
-
writeInfoRateLimitCooldown = (apiUrl, requestType, staleIf429MaxAgeMs, nowMs = Date.now()) => {
|
|
50154
|
-
if (!Number.isFinite(staleIf429MaxAgeMs) || staleIf429MaxAgeMs <= 0) {
|
|
50155
|
-
return;
|
|
50156
|
-
}
|
|
50157
|
-
const cooldownKey = buildInfoRateLimitCooldownKey(apiUrl, requestType);
|
|
50158
|
-
const cooldownMs = Math.max(
|
|
50159
|
-
INFO_RATE_LIMIT_COOLDOWN_MIN_MS,
|
|
50160
|
-
Math.min(INFO_RATE_LIMIT_COOLDOWN_MAX_MS, staleIf429MaxAgeMs)
|
|
50161
|
-
);
|
|
50162
|
-
const untilMs = nowMs + cooldownMs;
|
|
50163
|
-
browserInfoRateLimitCooldowns.set(cooldownKey, untilMs);
|
|
50164
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
50165
|
-
return;
|
|
50166
|
-
}
|
|
50167
|
-
try {
|
|
50168
|
-
window.localStorage.setItem(
|
|
50169
|
-
buildInfoRateLimitCooldownStorageKey(cooldownKey),
|
|
50170
|
-
JSON.stringify({ untilMs })
|
|
50171
|
-
);
|
|
50172
|
-
} catch {
|
|
50173
|
-
}
|
|
50174
|
-
};
|
|
50175
|
-
extractInfoRequestTypeFromRateLimitError = (error48) => {
|
|
50176
|
-
const explicitType = normalizeInfoRequestType(error48?.requestType);
|
|
50177
|
-
if (explicitType !== "info") {
|
|
50178
|
-
return explicitType;
|
|
50179
|
-
}
|
|
50180
|
-
const detail = normalizeHyperliquidErrorDetail(error48);
|
|
50181
|
-
const match = /\brequest_type=([A-Za-z0-9_:-]+)/.exec(detail);
|
|
50182
|
-
return match?.[1] ? normalizeInfoRequestType(match[1]) : null;
|
|
50183
|
-
};
|
|
50184
|
-
recordInfoRateLimitCooldownFromError = (apiUrl, error48, staleIf429MaxAgeMs, nowMs = Date.now()) => {
|
|
50185
|
-
if (!isRateLimitError(error48)) {
|
|
50186
|
-
return;
|
|
50187
|
-
}
|
|
50188
|
-
const requestType = extractInfoRequestTypeFromRateLimitError(error48);
|
|
50189
|
-
if (!requestType) {
|
|
50190
|
-
return;
|
|
50191
|
-
}
|
|
50192
|
-
writeInfoRateLimitCooldown(apiUrl, requestType, staleIf429MaxAgeMs, nowMs);
|
|
50193
|
-
};
|
|
50297
|
+
hasActiveInfoRateLimitCooldown = (apiUrl, _requestTypes, nowMs = Date.now()) => getHyperliquidPublicReadBudget(apiUrl).cooldownUntilMs > nowMs;
|
|
50194
50298
|
requireNonNegativeConfigSeconds = (value, path) => {
|
|
50195
50299
|
const numeric2 = Number(value);
|
|
50196
50300
|
if (!Number.isFinite(numeric2) || numeric2 < 0) {
|
|
@@ -50714,6 +50818,19 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50714
50818
|
}
|
|
50715
50819
|
return true;
|
|
50716
50820
|
};
|
|
50821
|
+
awaitAccountReads = async (reads) => {
|
|
50822
|
+
try {
|
|
50823
|
+
return await Promise.all(reads);
|
|
50824
|
+
} catch (error48) {
|
|
50825
|
+
if (error48 instanceof HyperliquidPublicReadError && error48.code === "public_cooldown_active") {
|
|
50826
|
+
const settled = await Promise.allSettled(reads);
|
|
50827
|
+
for (const result2 of settled) {
|
|
50828
|
+
if (result2.status === "rejected" && result2.reason instanceof HyperliquidPublicReadError && result2.reason.code === "public_rate_limited") throw result2.reason;
|
|
50829
|
+
}
|
|
50830
|
+
}
|
|
50831
|
+
throw error48;
|
|
50832
|
+
}
|
|
50833
|
+
};
|
|
50717
50834
|
fetchHyperliquidInfoPayload = async (apiUrl, body, signal, reservation) => {
|
|
50718
50835
|
const trace = startRuntimeNetworkDebugTrace({ kind: "exchange", label: `hyperliquid_info:${String(body.type)}`, method: "POST", url: `${apiUrl.replace(/\/$/, "")}/info` });
|
|
50719
50836
|
try {
|
|
@@ -50837,7 +50954,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50837
50954
|
"Browser account state request aborted."
|
|
50838
50955
|
));
|
|
50839
50956
|
} catch (error48) {
|
|
50840
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
50841
50957
|
const staleCache = readBrowserAccountStateCache(cacheKey);
|
|
50842
50958
|
if (!input.forceRefresh && isRateLimitError(error48) && staleCache && Date.now() - staleCache.fetchedAtMs <= staleIf429MaxAgeMs) {
|
|
50843
50959
|
return withAccountStateEvidence(staleCache.result, "stale_if_429", staleCache.fetchedAtMs, staleIf429MaxAgeMs);
|
|
@@ -50897,10 +51013,10 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50897
51013
|
capturedAt: new Date(capturedAtMs).toISOString()
|
|
50898
51014
|
};
|
|
50899
51015
|
})() : Promise.resolve(null);
|
|
50900
|
-
await
|
|
51016
|
+
await awaitAccountReads([userFeesPromise, exactAccountModePromise]);
|
|
50901
51017
|
const metadataByDex = /* @__PURE__ */ new Map();
|
|
50902
51018
|
if (input.includeEffectiveTakerRate === true) {
|
|
50903
|
-
await
|
|
51019
|
+
await awaitAccountReads(["", ...dexNames].map(async (dex) => {
|
|
50904
51020
|
try {
|
|
50905
51021
|
metadataByDex.set(dex, await fetchHyperliquidInfoPayload(apiUrl, { type: "meta", ...dex ? { dex } : {} }, input.signal, reservation));
|
|
50906
51022
|
} catch (error48) {
|
|
@@ -50919,7 +51035,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50919
51035
|
if (input.includeEffectiveTakerRate === true) {
|
|
50920
51036
|
requirePromptClearinghouseState(defaultResponse, "default");
|
|
50921
51037
|
}
|
|
50922
|
-
const dexResponses = await
|
|
51038
|
+
const dexResponses = await awaitAccountReads(
|
|
50923
51039
|
dexNames.map(async (dexName) => {
|
|
50924
51040
|
const response = await fetchHyperliquidInfoPayload(
|
|
50925
51041
|
apiUrl,
|
|
@@ -50964,7 +51080,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50964
51080
|
reservation
|
|
50965
51081
|
);
|
|
50966
51082
|
} catch (error48) {
|
|
50967
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
50968
51083
|
if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
|
|
50969
51084
|
throw error48;
|
|
50970
51085
|
}
|
|
@@ -50985,7 +51100,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50985
51100
|
return { payload, type: typeName };
|
|
50986
51101
|
} catch (error48) {
|
|
50987
51102
|
lastError = error48;
|
|
50988
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
50989
51103
|
if (isRateLimitError(error48)) throw error48;
|
|
50990
51104
|
if (typeName === "userActiveAssetData" && isUnsupportedUserActiveAssetError(error48)) {
|
|
50991
51105
|
rememberUnsupportedUserActiveAssetKey(activeAssetCacheKey);
|
|
@@ -50994,7 +51108,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
50994
51108
|
}
|
|
50995
51109
|
throw lastError instanceof Error ? lastError : new Error("Failed to fetch browser active asset data.");
|
|
50996
51110
|
})();
|
|
50997
|
-
const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await
|
|
51111
|
+
const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await awaitAccountReads([
|
|
50998
51112
|
perpsPromise,
|
|
50999
51113
|
spotPromise,
|
|
51000
51114
|
activeAssetPromise,
|
|
@@ -51020,7 +51134,7 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51020
51134
|
...parseInfoPositions(perpsResponse).filter((position) => Number(position.size) !== 0).map((position) => position.symbol)
|
|
51021
51135
|
].map(normalizeHyperliquidMarketSymbol).filter(Boolean))].sort();
|
|
51022
51136
|
const feeDexes = [...new Set(feeSymbols.map(getHyperliquidMarketDex))];
|
|
51023
|
-
const metadata = await
|
|
51137
|
+
const metadata = await awaitAccountReads(feeDexes.map(async (dex) => {
|
|
51024
51138
|
try {
|
|
51025
51139
|
const payload = metadataByDex.get(dex) ?? null;
|
|
51026
51140
|
return [dex, payload];
|
|
@@ -51215,7 +51329,6 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
51215
51329
|
providerRowCount = liveResult.providerRowCount;
|
|
51216
51330
|
fetchedAtMs = liveResult.fetchedAtMs;
|
|
51217
51331
|
} catch (error48) {
|
|
51218
|
-
recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
|
|
51219
51332
|
const staleCache = readBrowserUserFillsCache(cacheKey);
|
|
51220
51333
|
if (isRateLimitError(error48) && !input.forceRefresh) {
|
|
51221
51334
|
evidenceSource = "stale_if_429";
|
|
@@ -83814,6 +83927,7 @@ var init_hyperliquid_client = __esm({
|
|
|
83814
83927
|
init_define_VTX_EXO_POLICY();
|
|
83815
83928
|
init_define_VTX_GROK_POLICY();
|
|
83816
83929
|
init_define_VTX_PI_MODEL_POLICY();
|
|
83930
|
+
init_runtime_policy_generated();
|
|
83817
83931
|
init_hyperliquid_public_read();
|
|
83818
83932
|
init_api2();
|
|
83819
83933
|
init_abort();
|
|
@@ -85484,6 +85598,7 @@ var init_hyperliquid_client = __esm({
|
|
|
85484
85598
|
const serializedPayload = JSON.stringify(input.payload);
|
|
85485
85599
|
const durableMutation = input.durableMutation;
|
|
85486
85600
|
let exchangeDispatched = false;
|
|
85601
|
+
let recoveryPermit = null;
|
|
85487
85602
|
let settlementAttempted = false;
|
|
85488
85603
|
assertFreshPreparedExecutionContext(input.preparedContext);
|
|
85489
85604
|
const captureTimeoutMs = Number(
|
|
@@ -85640,8 +85755,9 @@ var init_hyperliquid_client = __esm({
|
|
|
85640
85755
|
}
|
|
85641
85756
|
}
|
|
85642
85757
|
try {
|
|
85643
|
-
await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal);
|
|
85758
|
+
recoveryPermit = await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal);
|
|
85644
85759
|
assertFreshPreparedExecutionContext(input.preparedContext);
|
|
85760
|
+
assertHyperliquidRecoveryDispatch(apiUrl, recoveryPermit, "exchange");
|
|
85645
85761
|
} catch (preparedContextError) {
|
|
85646
85762
|
await settleDurableMutation("rejected");
|
|
85647
85763
|
if (isAbortLikeError(preparedContextError) || preparedContextError instanceof HyperliquidPublicReadError) throw preparedContextError;
|
|
@@ -85669,16 +85785,44 @@ var init_hyperliquid_client = __esm({
|
|
|
85669
85785
|
}
|
|
85670
85786
|
}
|
|
85671
85787
|
exchangeDispatched = true;
|
|
85672
|
-
const
|
|
85673
|
-
|
|
85674
|
-
|
|
85675
|
-
|
|
85676
|
-
|
|
85677
|
-
|
|
85678
|
-
|
|
85679
|
-
|
|
85680
|
-
|
|
85681
|
-
|
|
85788
|
+
const transportController = new AbortController();
|
|
85789
|
+
const exchangeTimeout = runtime_policy_generated_default.exchange.hyperliquid.http.exchange;
|
|
85790
|
+
const transportTimeoutMs = Math.min(
|
|
85791
|
+
(exchangeTimeout.request_timeout_seconds + exchangeTimeout.pool_timeout_seconds) * 1e3,
|
|
85792
|
+
recoveryPermit ? Math.max(0, recoveryPermit.expiresAt - Date.now()) : Infinity
|
|
85793
|
+
);
|
|
85794
|
+
let transportTimer;
|
|
85795
|
+
let response;
|
|
85796
|
+
let payload;
|
|
85797
|
+
try {
|
|
85798
|
+
const transport = (async () => {
|
|
85799
|
+
const received = await fetch(requestUrl, {
|
|
85800
|
+
method: "POST",
|
|
85801
|
+
headers: { "Content-Type": "application/json" },
|
|
85802
|
+
body: serializedPayload,
|
|
85803
|
+
signal: transportController.signal
|
|
85804
|
+
});
|
|
85805
|
+
if (transportController.signal.aborted) throw transportController.signal.reason;
|
|
85806
|
+
responseStatus = received.status;
|
|
85807
|
+
await recordHyperliquidExchangeResponse(apiUrl, received);
|
|
85808
|
+
const body = await received.json().catch(() => ({}));
|
|
85809
|
+
if (transportController.signal.aborted) throw transportController.signal.reason;
|
|
85810
|
+
return { response: received, payload: body };
|
|
85811
|
+
})();
|
|
85812
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
85813
|
+
transportTimer = globalThis.setTimeout(() => {
|
|
85814
|
+
const error48 = new DOMException("Hyperliquid exchange transport timed out.", "TimeoutError");
|
|
85815
|
+
transportController.abort(error48);
|
|
85816
|
+
reject(error48);
|
|
85817
|
+
}, transportTimeoutMs);
|
|
85818
|
+
});
|
|
85819
|
+
({ response, payload } = await Promise.race([transport, timeout]));
|
|
85820
|
+
} finally {
|
|
85821
|
+
globalThis.clearTimeout(transportTimer);
|
|
85822
|
+
transportController.abort();
|
|
85823
|
+
}
|
|
85824
|
+
await finishHyperliquidRecoveryRequest(recoveryPermit, response.status < 400 ? "success" : "failure").catch(() => void 0);
|
|
85825
|
+
recoveryPermit = null;
|
|
85682
85826
|
if (!response.ok) {
|
|
85683
85827
|
await settleDurableMutation("transport_ambiguous");
|
|
85684
85828
|
throw new RuntimeExecutionError(
|
|
@@ -85743,6 +85887,8 @@ var init_hyperliquid_client = __esm({
|
|
|
85743
85887
|
);
|
|
85744
85888
|
}
|
|
85745
85889
|
throw error48;
|
|
85890
|
+
} finally {
|
|
85891
|
+
await finishHyperliquidRecoveryRequest(recoveryPermit, exchangeDispatched ? "failure" : "cancelled").catch(() => void 0);
|
|
85746
85892
|
}
|
|
85747
85893
|
});
|
|
85748
85894
|
} catch (error48) {
|
|
@@ -92451,13 +92597,14 @@ var init_constraint_contract = __esm({
|
|
|
92451
92597
|
});
|
|
92452
92598
|
|
|
92453
92599
|
// lib/runtime/provider-observability.ts
|
|
92454
|
-
var record4, identifier, count3, normalizeProviderDiagnostics;
|
|
92600
|
+
var MAX_DIAGNOSTIC_LIST_ITEMS, record4, identifier, count3, normalizeProviderDiagnostics;
|
|
92455
92601
|
var init_provider_observability = __esm({
|
|
92456
92602
|
"lib/runtime/provider-observability.ts"() {
|
|
92457
92603
|
"use strict";
|
|
92458
92604
|
init_define_VTX_EXO_POLICY();
|
|
92459
92605
|
init_define_VTX_GROK_POLICY();
|
|
92460
92606
|
init_define_VTX_PI_MODEL_POLICY();
|
|
92607
|
+
MAX_DIAGNOSTIC_LIST_ITEMS = 16;
|
|
92461
92608
|
record4 = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
92462
92609
|
identifier = (v) => typeof v === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,255}$/.test(v) ? v : void 0;
|
|
92463
92610
|
count3 = (v) => {
|
|
@@ -92479,7 +92626,7 @@ var init_provider_observability = __esm({
|
|
|
92479
92626
|
result2.quota_project_source = "provider_quota_subject";
|
|
92480
92627
|
}
|
|
92481
92628
|
if (Array.isArray(raw.quota_violations)) {
|
|
92482
|
-
const violations = raw.quota_violations.slice(0,
|
|
92629
|
+
const violations = raw.quota_violations.slice(0, MAX_DIAGNOSTIC_LIST_ITEMS).map((item) => {
|
|
92483
92630
|
const v = record4(item);
|
|
92484
92631
|
const out = {};
|
|
92485
92632
|
const metric = identifier(v.metric), id2 = identifier(v.id), value2 = count3(v.value);
|
|
@@ -92493,6 +92640,11 @@ var init_provider_observability = __esm({
|
|
|
92493
92640
|
}).filter((v) => Object.keys(v).length > 0);
|
|
92494
92641
|
if (violations.length) result2.quota_violations = violations;
|
|
92495
92642
|
}
|
|
92643
|
+
const outputValidation = record4(raw.output_validation);
|
|
92644
|
+
if (Array.isArray(outputValidation.expected_symbols)) {
|
|
92645
|
+
const symbols = outputValidation.expected_symbols.slice(0, MAX_DIAGNOSTIC_LIST_ITEMS).map(identifier).filter((symbol2) => symbol2 !== void 0);
|
|
92646
|
+
if (symbols.length) result2.output_validation = { expected_symbols: [...new Set(symbols)] };
|
|
92647
|
+
}
|
|
92496
92648
|
return result2;
|
|
92497
92649
|
};
|
|
92498
92650
|
}
|