@hoox-sh/hoox-cli 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +101 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14691,7 +14691,7 @@ var init_zod = __esm(() => {
|
|
|
14691
14691
|
});
|
|
14692
14692
|
|
|
14693
14693
|
// ../shared/src/types.ts
|
|
14694
|
-
var TradeActionSchema, WebhookPayloadSchema, TradeQueueMessageSchema, TradeSignalSchema, PositionSchema, BalanceSchema;
|
|
14694
|
+
var TradeActionSchema, MAX_WEBHOOK_LEVERAGE = 125, MAX_WEBHOOK_QUANTITY = 1e6, WebhookPayloadSchema, TradeQueueMessageSchema, TradeSignalSchema, PositionSchema, BalanceSchema;
|
|
14695
14695
|
var init_types = __esm(() => {
|
|
14696
14696
|
init_zod();
|
|
14697
14697
|
TradeActionSchema = exports_external.enum([
|
|
@@ -14704,10 +14704,10 @@ var init_types = __esm(() => {
|
|
|
14704
14704
|
exchange: exports_external.string().min(1),
|
|
14705
14705
|
action: TradeActionSchema,
|
|
14706
14706
|
symbol: exports_external.string().min(1).max(20),
|
|
14707
|
-
quantity: exports_external.number().positive().finite(),
|
|
14707
|
+
quantity: exports_external.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
14708
14708
|
price: exports_external.number().positive().finite().optional(),
|
|
14709
14709
|
orderType: exports_external.string().optional(),
|
|
14710
|
-
leverage: exports_external.number().int().positive().optional(),
|
|
14710
|
+
leverage: exports_external.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
14711
14711
|
test: exports_external.boolean().optional()
|
|
14712
14712
|
}).strict();
|
|
14713
14713
|
TradeQueueMessageSchema = exports_external.object({
|
|
@@ -14715,9 +14715,9 @@ var init_types = __esm(() => {
|
|
|
14715
14715
|
exchange: exports_external.string().min(1).max(64),
|
|
14716
14716
|
action: TradeActionSchema,
|
|
14717
14717
|
symbol: exports_external.string().min(1).max(32),
|
|
14718
|
-
quantity: exports_external.number().positive().finite(),
|
|
14718
|
+
quantity: exports_external.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
14719
14719
|
price: exports_external.number().positive().finite().optional(),
|
|
14720
|
-
leverage: exports_external.number().int().positive().max(
|
|
14720
|
+
leverage: exports_external.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
14721
14721
|
test: exports_external.boolean().optional(),
|
|
14722
14722
|
idempotencyKey: exports_external.string().min(1).max(512).optional(),
|
|
14723
14723
|
queuedAt: exports_external.string().min(1).max(64)
|
|
@@ -14754,7 +14754,7 @@ var init_types = __esm(() => {
|
|
|
14754
14754
|
});
|
|
14755
14755
|
|
|
14756
14756
|
// ../shared/src/kvKeys.ts
|
|
14757
|
-
var KV_TRADE_DEFAULT_LEVERAGE = "trade:default_leverage", KV_TRADE_MAX_POSITION_SIZE = "trade:max_position_size", KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT = "trade:max_daily_drawdown_percent", KV_TRADE_TRAILING_STOP_PERCENT = "trade:trailing_stop_percent", KV_TRADE_KILL_SWITCH = "trade:kill_switch", KV_TRADE_ROUTING = "trade:routing", KV_BOT_ENABLED = "bot:enabled", KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id", KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution", KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error", KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled", KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips", KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode", KV_EMAIL_SCAN_SUBJECT = "email:scan_subject", KV_EMAIL_USE_IMAP = "email:use_imap", KV_EMAIL_COIN_PATTERN = "email:coin_pattern", KV_EMAIL_ACTION_PATTERN = "email:action_pattern", KV_EMAIL_QUANTITY_MULTIPLIER = "email:quantity_multiplier", KV_AGENT_CONFIG = "agent:config", KV_AGENT_OPENAI_KEY = "agent:openai_key", KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key", KV_AGENT_GOOGLE_KEY = "agent:google_key", KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary", KV_GLOBAL_KILL_SWITCH = "global:kill_switch", KV_HEALTH_CHECK = "health_check", KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check", QUEUE_MODE_FAILOVER = "queue_failover", QUEUE_MODE_EVERYWHERE = "queue_everywhere", QUEUE_MODE_DISABLED = "queue_disabled", KVKeys;
|
|
14757
|
+
var KV_TRADE_DEFAULT_LEVERAGE = "trade:default_leverage", KV_TRADE_MAX_POSITION_SIZE = "trade:max_position_size", KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT = "trade:max_daily_drawdown_percent", KV_TRADE_TRAILING_STOP_PERCENT = "trade:trailing_stop_percent", KV_TRADE_KILL_SWITCH = "trade:kill_switch", KV_TRADE_ROUTING = "trade:routing", KV_BOT_ENABLED = "bot:enabled", KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id", KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution", KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error", KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids", KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled", KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips", KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode", KV_EMAIL_SCAN_SUBJECT = "email:scan_subject", KV_EMAIL_USE_IMAP = "email:use_imap", KV_EMAIL_COIN_PATTERN = "email:coin_pattern", KV_EMAIL_ACTION_PATTERN = "email:action_pattern", KV_EMAIL_QUANTITY_MULTIPLIER = "email:quantity_multiplier", KV_AGENT_CONFIG = "agent:config", KV_AGENT_OPENAI_KEY = "agent:openai_key", KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key", KV_AGENT_GOOGLE_KEY = "agent:google_key", KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary", KV_GLOBAL_KILL_SWITCH = "global:kill_switch", KV_HEALTH_CHECK = "health_check", KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check", QUEUE_MODE_FAILOVER = "queue_failover", QUEUE_MODE_EVERYWHERE = "queue_everywhere", QUEUE_MODE_DISABLED = "queue_disabled", KVKeys;
|
|
14758
14758
|
var init_kvKeys = __esm(() => {
|
|
14759
14759
|
KVKeys = {
|
|
14760
14760
|
KV_TRADE_DEFAULT_LEVERAGE,
|
|
@@ -14767,6 +14767,7 @@ var init_kvKeys = __esm(() => {
|
|
|
14767
14767
|
KV_BOT_DEFAULT_CHAT_ID,
|
|
14768
14768
|
KV_BOT_NOTIFY_ON_EXECUTION,
|
|
14769
14769
|
KV_BOT_NOTIFY_ON_ERROR,
|
|
14770
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
14770
14771
|
KV_WEBHOOK_IP_CHECK_ENABLED,
|
|
14771
14772
|
KV_WEBHOOK_ALLOWED_IPS,
|
|
14772
14773
|
KV_WEBHOOK_QUEUE_MODE,
|
|
@@ -15107,10 +15108,38 @@ async function logKvTimestamp(env, prefix = "timestamp") {
|
|
|
15107
15108
|
console.error(`Failed to log timestamp to KV: ${toError(error51, "Unknown error")}`);
|
|
15108
15109
|
}
|
|
15109
15110
|
}
|
|
15111
|
+
async function tryBulkGetChunk(kv, chunk) {
|
|
15112
|
+
try {
|
|
15113
|
+
const result = await kv.get([...chunk]);
|
|
15114
|
+
if (!(result instanceof Map)) {
|
|
15115
|
+
return null;
|
|
15116
|
+
}
|
|
15117
|
+
return chunk.map((key) => result.get(key) ?? null);
|
|
15118
|
+
} catch {
|
|
15119
|
+
return null;
|
|
15120
|
+
}
|
|
15121
|
+
}
|
|
15110
15122
|
async function kvGetMany(kv, keys) {
|
|
15111
15123
|
if (keys.length === 0)
|
|
15112
15124
|
return [];
|
|
15113
|
-
|
|
15125
|
+
const out = new Array(keys.length);
|
|
15126
|
+
let offset = 0;
|
|
15127
|
+
while (offset < keys.length) {
|
|
15128
|
+
const chunk = keys.slice(offset, offset + KV_BULK_GET_MAX_KEYS);
|
|
15129
|
+
const bulk = await tryBulkGetChunk(kv, chunk);
|
|
15130
|
+
if (bulk === null) {
|
|
15131
|
+
const rest = await Promise.all(keys.slice(offset).map((key) => kv.get(key)));
|
|
15132
|
+
for (let i = 0;i < rest.length; i++) {
|
|
15133
|
+
out[offset + i] = rest[i] ?? null;
|
|
15134
|
+
}
|
|
15135
|
+
return out;
|
|
15136
|
+
}
|
|
15137
|
+
for (let i = 0;i < bulk.length; i++) {
|
|
15138
|
+
out[offset + i] = bulk[i] ?? null;
|
|
15139
|
+
}
|
|
15140
|
+
offset += chunk.length;
|
|
15141
|
+
}
|
|
15142
|
+
return out;
|
|
15114
15143
|
}
|
|
15115
15144
|
async function kvGetManyAsRecord(kv, keys) {
|
|
15116
15145
|
const values = await kvGetMany(kv, keys);
|
|
@@ -15138,6 +15167,7 @@ function headersToObject(headers) {
|
|
|
15138
15167
|
}
|
|
15139
15168
|
return result;
|
|
15140
15169
|
}
|
|
15170
|
+
var KV_BULK_GET_MAX_KEYS = 100;
|
|
15141
15171
|
var init_kvUtils = __esm(() => {
|
|
15142
15172
|
init_errors3();
|
|
15143
15173
|
});
|
|
@@ -15187,29 +15217,60 @@ var init_health = __esm(() => {
|
|
|
15187
15217
|
});
|
|
15188
15218
|
|
|
15189
15219
|
// ../shared/src/queue-handler.ts
|
|
15220
|
+
async function mapPool(items, concurrency, fn) {
|
|
15221
|
+
if (items.length === 0)
|
|
15222
|
+
return;
|
|
15223
|
+
const limit = Math.min(Math.max(1, concurrency), items.length);
|
|
15224
|
+
if (limit === 1) {
|
|
15225
|
+
for (const item of items) {
|
|
15226
|
+
await fn(item);
|
|
15227
|
+
}
|
|
15228
|
+
return;
|
|
15229
|
+
}
|
|
15230
|
+
let nextIndex = 0;
|
|
15231
|
+
async function worker() {
|
|
15232
|
+
while (true) {
|
|
15233
|
+
const i = nextIndex++;
|
|
15234
|
+
if (i >= items.length)
|
|
15235
|
+
return;
|
|
15236
|
+
await fn(items[i]);
|
|
15237
|
+
}
|
|
15238
|
+
}
|
|
15239
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
15240
|
+
}
|
|
15190
15241
|
function createQueueHandler(options) {
|
|
15191
|
-
const {
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15242
|
+
const {
|
|
15243
|
+
maxRetries,
|
|
15244
|
+
backoffDelays,
|
|
15245
|
+
onMessage,
|
|
15246
|
+
onRetry,
|
|
15247
|
+
onDLQ,
|
|
15248
|
+
logger,
|
|
15249
|
+
concurrency: concurrencyOpt
|
|
15250
|
+
} = options;
|
|
15251
|
+
const concurrency = typeof concurrencyOpt === "number" && Number.isFinite(concurrencyOpt) && concurrencyOpt >= 1 ? Math.floor(concurrencyOpt) : 1;
|
|
15252
|
+
async function processMessage(msg) {
|
|
15253
|
+
const attemptNumber = msg.attempts || 0;
|
|
15254
|
+
const logId = `[${msg.id}]`;
|
|
15255
|
+
try {
|
|
15256
|
+
logger?.info(`${logId} Processing message (attempt ${attemptNumber + 1})`);
|
|
15257
|
+
await onMessage(msg.body, attemptNumber);
|
|
15258
|
+
logger?.info(`${logId} Message processed successfully`);
|
|
15259
|
+
} catch (error51) {
|
|
15260
|
+
const errorMsg = error51 instanceof Error ? error51.message : String(error51);
|
|
15261
|
+
if (attemptNumber < maxRetries) {
|
|
15262
|
+
const delaySeconds = backoffDelays[attemptNumber] ?? backoffDelays[backoffDelays.length - 1] ?? 0;
|
|
15263
|
+
logger?.info(`${logId} Retrying in ${delaySeconds}s (attempt ${attemptNumber + 2}/${maxRetries + 1})`);
|
|
15264
|
+
await onRetry?.(msg.body, attemptNumber, errorMsg, delaySeconds);
|
|
15265
|
+
msg.retry({ delaySeconds });
|
|
15266
|
+
} else {
|
|
15267
|
+
logger?.error(`${logId} Max retries exceeded (${maxRetries + 1} attempts), moving to DLQ`);
|
|
15268
|
+
await onDLQ?.(msg.body, attemptNumber, errorMsg);
|
|
15211
15269
|
}
|
|
15212
15270
|
}
|
|
15271
|
+
}
|
|
15272
|
+
return async (batch) => {
|
|
15273
|
+
await mapPool(batch.messages, concurrency, processMessage);
|
|
15213
15274
|
};
|
|
15214
15275
|
}
|
|
15215
15276
|
|
|
@@ -17609,7 +17670,11 @@ var init_registry = __esm(() => {
|
|
|
17609
17670
|
type: "secret",
|
|
17610
17671
|
description: "Inter-worker auth key"
|
|
17611
17672
|
},
|
|
17612
|
-
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" }
|
|
17673
|
+
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" },
|
|
17674
|
+
TELEGRAM_ALLOWED_CHAT_IDS: {
|
|
17675
|
+
type: "secret",
|
|
17676
|
+
description: "Comma-separated chat IDs for webhook notify (fail-closed when unset); alias AUTHORIZED_CHAT_IDS"
|
|
17677
|
+
}
|
|
17613
17678
|
},
|
|
17614
17679
|
services: [
|
|
17615
17680
|
{
|
|
@@ -17635,7 +17700,8 @@ var init_registry = __esm(() => {
|
|
|
17635
17700
|
ai: true,
|
|
17636
17701
|
queues: { producer: ["trade-execution"] },
|
|
17637
17702
|
durableObjects: [
|
|
17638
|
-
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" }
|
|
17703
|
+
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" },
|
|
17704
|
+
{ name: "RATE_LIMITER", className: "RateLimiterStore" }
|
|
17639
17705
|
]
|
|
17640
17706
|
},
|
|
17641
17707
|
middleware: [
|
|
@@ -17731,6 +17797,10 @@ var init_registry = __esm(() => {
|
|
|
17731
17797
|
TELEGRAM_SECRET_TOKEN: {
|
|
17732
17798
|
type: "secret",
|
|
17733
17799
|
description: "Webhook verification token"
|
|
17800
|
+
},
|
|
17801
|
+
AUTHORIZED_CHAT_IDS: {
|
|
17802
|
+
type: "secret",
|
|
17803
|
+
description: "Comma-separated chat IDs; inbound webhook fail-closed when unset; outbound /alert allowlist"
|
|
17734
17804
|
}
|
|
17735
17805
|
},
|
|
17736
17806
|
services: [],
|
|
@@ -19653,7 +19723,7 @@ function validateWranglerJsonc(workerName, manifest, jsoncContent) {
|
|
|
19653
19723
|
}
|
|
19654
19724
|
}
|
|
19655
19725
|
for (const [name, def] of Object.entries(manifest.vars)) {
|
|
19656
|
-
if (def.type === "secret" && !name.endsWith("_BINDING") && !name.endsWith("_SECRET") && !name.startsWith("CLOUDFLARE_") && name !== "TELEGRAM_SECRET_TOKEN" && name !== "MAILGUN_API_KEY" && name !== "EMAIL_SCAN_SUBJECT" && name !== "DASHBOARD_USER" && name !== "DASHBOARD_PASS" && name !== "SESSION_SECRET" && name !== "AGENT_INTERNAL_KEY") {
|
|
19726
|
+
if (def.type === "secret" && !name.endsWith("_BINDING") && !name.endsWith("_SECRET") && !name.startsWith("CLOUDFLARE_") && name !== "TELEGRAM_SECRET_TOKEN" && name !== "TELEGRAM_ALLOWED_CHAT_IDS" && name !== "AUTHORIZED_CHAT_IDS" && name !== "MAILGUN_API_KEY" && name !== "EMAIL_SCAN_SUBJECT" && name !== "DASHBOARD_USER" && name !== "DASHBOARD_PASS" && name !== "SESSION_SECRET" && name !== "AGENT_INTERNAL_KEY") {
|
|
19657
19727
|
errors3.push({
|
|
19658
19728
|
worker: workerName,
|
|
19659
19729
|
severity: "warning",
|
|
@@ -22351,6 +22421,7 @@ __export(exports_src, {
|
|
|
22351
22421
|
PositionSchema: () => PositionSchema,
|
|
22352
22422
|
PRESETS: () => PRESETS,
|
|
22353
22423
|
LogLevelColor: () => LogLevelColor,
|
|
22424
|
+
KV_BULK_GET_MAX_KEYS: () => KV_BULK_GET_MAX_KEYS,
|
|
22354
22425
|
KVKeys: () => KVKeys,
|
|
22355
22426
|
KILL_SWITCH_KEYS: () => KILL_SWITCH_KEYS,
|
|
22356
22427
|
KILL_SWITCH_ACTIVE_PREFIX: () => KILL_SWITCH_ACTIVE_PREFIX,
|