@hoox-sh/hoox-shared 1.3.0 → 1.4.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/agent-config-fields.js +2 -0
- package/dist/d1/index.js +4 -2
- package/dist/d1/repository.js +4 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -2
- package/dist/health.js +4 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +209 -80
- package/dist/kill-switch.js +2 -0
- package/dist/kvKeys.d.ts +3 -0
- package/dist/kvKeys.d.ts.map +1 -1
- package/dist/kvKeys.js +3 -0
- package/dist/kvUtils.d.ts +34 -1
- package/dist/kvUtils.d.ts.map +1 -1
- package/dist/kvUtils.js +56 -3
- package/dist/middleware/auth.d.ts +6 -3
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +19 -5
- package/dist/middleware/index.d.ts +3 -2
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +88 -8
- package/dist/middleware/logger.js +4 -2
- package/dist/middleware/validate.d.ts +16 -0
- package/dist/middleware/validate.d.ts.map +1 -1
- package/dist/middleware/validate.js +37 -1
- package/dist/middleware/wait-until.d.ts +32 -0
- package/dist/middleware/wait-until.d.ts.map +1 -0
- package/dist/middleware/wait-until.js +46 -0
- package/dist/queue-handler.d.ts +6 -0
- package/dist/queue-handler.d.ts.map +1 -1
- package/dist/queue-handler.js +51 -20
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +12 -2
- package/dist/schemas/index.d.ts +2 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +58 -13
- package/dist/schemas/registry.d.ts +13 -0
- package/dist/schemas/registry.d.ts.map +1 -1
- package/dist/schemas/registry.js +55 -12
- package/dist/schemas/types.d.ts +5 -0
- package/dist/schemas/types.d.ts.map +1 -1
- package/dist/schemas/validators.d.ts.map +1 -1
- package/dist/schemas/validators.js +3 -1
- package/dist/service-bindings.js +18 -5
- package/dist/stores/service-store.js +1 -1
- package/dist/types.d.ts +22 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -4
- package/dist/wizard/engine.d.ts.map +1 -1
- package/dist/wizard/engine.js +18 -35
- package/dist/wizard/index.js +18 -35
- package/dist/wizard/presets.d.ts.map +1 -1
- package/dist/wizard/presets.js +6 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -269,6 +269,7 @@ var KV_BOT_ENABLED = "bot:enabled";
|
|
|
269
269
|
var KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id";
|
|
270
270
|
var KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution";
|
|
271
271
|
var KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error";
|
|
272
|
+
var KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids";
|
|
272
273
|
var KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled";
|
|
273
274
|
var KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips";
|
|
274
275
|
var KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode";
|
|
@@ -299,6 +300,7 @@ var KVKeys = {
|
|
|
299
300
|
KV_BOT_DEFAULT_CHAT_ID,
|
|
300
301
|
KV_BOT_NOTIFY_ON_EXECUTION,
|
|
301
302
|
KV_BOT_NOTIFY_ON_ERROR,
|
|
303
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
302
304
|
KV_WEBHOOK_IP_CHECK_ENABLED,
|
|
303
305
|
KV_WEBHOOK_ALLOWED_IPS,
|
|
304
306
|
KV_WEBHOOK_QUEUE_MODE,
|
|
@@ -686,8 +688,10 @@ function toError(err, fallback = "Unknown error") {
|
|
|
686
688
|
return err.message;
|
|
687
689
|
if (typeof err === "string")
|
|
688
690
|
return err;
|
|
689
|
-
if (err && typeof err === "object" && "message" in err
|
|
690
|
-
|
|
691
|
+
if (err && typeof err === "object" && "message" in err) {
|
|
692
|
+
const message = err.message;
|
|
693
|
+
if (typeof message === "string")
|
|
694
|
+
return message;
|
|
691
695
|
}
|
|
692
696
|
if (err === null || err === undefined)
|
|
693
697
|
return fallback;
|
|
@@ -1773,14 +1777,16 @@ var TradeActionSchema = z2.enum([
|
|
|
1773
1777
|
"CLOSE_LONG",
|
|
1774
1778
|
"CLOSE_SHORT"
|
|
1775
1779
|
]);
|
|
1780
|
+
var MAX_WEBHOOK_LEVERAGE = 125;
|
|
1781
|
+
var MAX_WEBHOOK_QUANTITY = 1e6;
|
|
1776
1782
|
var WebhookPayloadSchema = z2.object({
|
|
1777
1783
|
exchange: z2.string().min(1),
|
|
1778
1784
|
action: TradeActionSchema,
|
|
1779
1785
|
symbol: z2.string().min(1).max(20),
|
|
1780
|
-
quantity: z2.number().positive().finite(),
|
|
1786
|
+
quantity: z2.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
1781
1787
|
price: z2.number().positive().finite().optional(),
|
|
1782
1788
|
orderType: z2.string().optional(),
|
|
1783
|
-
leverage: z2.number().int().positive().optional(),
|
|
1789
|
+
leverage: z2.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
1784
1790
|
test: z2.boolean().optional()
|
|
1785
1791
|
}).strict();
|
|
1786
1792
|
var TradeQueueMessageSchema = z2.object({
|
|
@@ -1788,9 +1794,9 @@ var TradeQueueMessageSchema = z2.object({
|
|
|
1788
1794
|
exchange: z2.string().min(1).max(64),
|
|
1789
1795
|
action: TradeActionSchema,
|
|
1790
1796
|
symbol: z2.string().min(1).max(32),
|
|
1791
|
-
quantity: z2.number().positive().finite(),
|
|
1797
|
+
quantity: z2.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
1792
1798
|
price: z2.number().positive().finite().optional(),
|
|
1793
|
-
leverage: z2.number().int().positive().max(
|
|
1799
|
+
leverage: z2.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
1794
1800
|
test: z2.boolean().optional(),
|
|
1795
1801
|
idempotencyKey: z2.string().min(1).max(512).optional(),
|
|
1796
1802
|
queuedAt: z2.string().min(1).max(64)
|
|
@@ -1880,6 +1886,53 @@ async function logKvTimestamp(env, prefix = "timestamp") {
|
|
|
1880
1886
|
console.error(`Failed to log timestamp to KV: ${toError(error, "Unknown error")}`);
|
|
1881
1887
|
}
|
|
1882
1888
|
}
|
|
1889
|
+
var KV_BULK_GET_MAX_KEYS = 100;
|
|
1890
|
+
async function tryBulkGetChunk(kv, chunk) {
|
|
1891
|
+
try {
|
|
1892
|
+
const result = await kv.get([...chunk]);
|
|
1893
|
+
if (!(result instanceof Map)) {
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
return chunk.map((key) => result.get(key) ?? null);
|
|
1897
|
+
} catch {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
async function kvGetMany(kv, keys) {
|
|
1902
|
+
if (keys.length === 0)
|
|
1903
|
+
return [];
|
|
1904
|
+
const out = new Array(keys.length);
|
|
1905
|
+
let offset = 0;
|
|
1906
|
+
while (offset < keys.length) {
|
|
1907
|
+
const chunk = keys.slice(offset, offset + KV_BULK_GET_MAX_KEYS);
|
|
1908
|
+
const bulk = await tryBulkGetChunk(kv, chunk);
|
|
1909
|
+
if (bulk === null) {
|
|
1910
|
+
const rest = await Promise.all(keys.slice(offset).map((key) => kv.get(key)));
|
|
1911
|
+
for (let i = 0;i < rest.length; i++) {
|
|
1912
|
+
out[offset + i] = rest[i] ?? null;
|
|
1913
|
+
}
|
|
1914
|
+
return out;
|
|
1915
|
+
}
|
|
1916
|
+
for (let i = 0;i < bulk.length; i++) {
|
|
1917
|
+
out[offset + i] = bulk[i] ?? null;
|
|
1918
|
+
}
|
|
1919
|
+
offset += chunk.length;
|
|
1920
|
+
}
|
|
1921
|
+
return out;
|
|
1922
|
+
}
|
|
1923
|
+
async function kvGetManyAsRecord(kv, keys) {
|
|
1924
|
+
const values = await kvGetMany(kv, keys);
|
|
1925
|
+
const out = {};
|
|
1926
|
+
for (let i = 0;i < keys.length; i++) {
|
|
1927
|
+
out[keys[i]] = values[i] ?? null;
|
|
1928
|
+
}
|
|
1929
|
+
return out;
|
|
1930
|
+
}
|
|
1931
|
+
async function kvPutMany(kv, entries) {
|
|
1932
|
+
if (entries.length === 0)
|
|
1933
|
+
return;
|
|
1934
|
+
await Promise.all(entries.map((entry) => kv.put(entry.key, entry.value, entry.options)));
|
|
1935
|
+
}
|
|
1883
1936
|
function headersToObject(headers) {
|
|
1884
1937
|
const result = {};
|
|
1885
1938
|
if (!headers)
|
|
@@ -1895,29 +1948,60 @@ function headersToObject(headers) {
|
|
|
1895
1948
|
}
|
|
1896
1949
|
|
|
1897
1950
|
// src/queue-handler.ts
|
|
1951
|
+
async function mapPool(items, concurrency, fn) {
|
|
1952
|
+
if (items.length === 0)
|
|
1953
|
+
return;
|
|
1954
|
+
const limit = Math.min(Math.max(1, concurrency), items.length);
|
|
1955
|
+
if (limit === 1) {
|
|
1956
|
+
for (const item of items) {
|
|
1957
|
+
await fn(item);
|
|
1958
|
+
}
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
let nextIndex = 0;
|
|
1962
|
+
async function worker() {
|
|
1963
|
+
while (true) {
|
|
1964
|
+
const i = nextIndex++;
|
|
1965
|
+
if (i >= items.length)
|
|
1966
|
+
return;
|
|
1967
|
+
await fn(items[i]);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
1971
|
+
}
|
|
1898
1972
|
function createQueueHandler(options) {
|
|
1899
|
-
const {
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1973
|
+
const {
|
|
1974
|
+
maxRetries,
|
|
1975
|
+
backoffDelays,
|
|
1976
|
+
onMessage,
|
|
1977
|
+
onRetry,
|
|
1978
|
+
onDLQ,
|
|
1979
|
+
logger,
|
|
1980
|
+
concurrency: concurrencyOpt
|
|
1981
|
+
} = options;
|
|
1982
|
+
const concurrency = typeof concurrencyOpt === "number" && Number.isFinite(concurrencyOpt) && concurrencyOpt >= 1 ? Math.floor(concurrencyOpt) : 1;
|
|
1983
|
+
async function processMessage(msg) {
|
|
1984
|
+
const attemptNumber = msg.attempts || 0;
|
|
1985
|
+
const logId = `[${msg.id}]`;
|
|
1986
|
+
try {
|
|
1987
|
+
logger?.info(`${logId} Processing message (attempt ${attemptNumber + 1})`);
|
|
1988
|
+
await onMessage(msg.body, attemptNumber);
|
|
1989
|
+
logger?.info(`${logId} Message processed successfully`);
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1992
|
+
if (attemptNumber < maxRetries) {
|
|
1993
|
+
const delaySeconds = backoffDelays[attemptNumber] ?? backoffDelays[backoffDelays.length - 1] ?? 0;
|
|
1994
|
+
logger?.info(`${logId} Retrying in ${delaySeconds}s (attempt ${attemptNumber + 2}/${maxRetries + 1})`);
|
|
1995
|
+
await onRetry?.(msg.body, attemptNumber, errorMsg, delaySeconds);
|
|
1996
|
+
msg.retry({ delaySeconds });
|
|
1997
|
+
} else {
|
|
1998
|
+
logger?.error(`${logId} Max retries exceeded (${maxRetries + 1} attempts), moving to DLQ`);
|
|
1999
|
+
await onDLQ?.(msg.body, attemptNumber, errorMsg);
|
|
1919
2000
|
}
|
|
1920
2001
|
}
|
|
2002
|
+
}
|
|
2003
|
+
return async (batch) => {
|
|
2004
|
+
await mapPool(batch.messages, concurrency, processMessage);
|
|
1921
2005
|
};
|
|
1922
2006
|
}
|
|
1923
2007
|
|
|
@@ -1929,12 +2013,24 @@ function timingSafeEqual(a, b) {
|
|
|
1929
2013
|
const len = Math.max(aBuf.length, bBuf.length);
|
|
1930
2014
|
let result = aBuf.length === bBuf.length ? 0 : 1;
|
|
1931
2015
|
for (let i = 0;i < len; i++) {
|
|
1932
|
-
const av =
|
|
1933
|
-
const bv =
|
|
2016
|
+
const av = aBuf[i] ?? 0;
|
|
2017
|
+
const bv = bBuf[i] ?? 0;
|
|
1934
2018
|
result |= av ^ bv;
|
|
1935
2019
|
}
|
|
1936
2020
|
return result === 0;
|
|
1937
2021
|
}
|
|
2022
|
+
async function timingSafeEqualAsync(a, b) {
|
|
2023
|
+
const subtle = globalThis.crypto?.subtle;
|
|
2024
|
+
if (!subtle || typeof subtle.digest !== "function" || typeof subtle.timingSafeEqual !== "function") {
|
|
2025
|
+
return timingSafeEqual(a, b);
|
|
2026
|
+
}
|
|
2027
|
+
const encoder = new TextEncoder;
|
|
2028
|
+
const [providedHash, expectedHash] = await Promise.all([
|
|
2029
|
+
subtle.digest("SHA-256", encoder.encode(a)),
|
|
2030
|
+
subtle.digest("SHA-256", encoder.encode(b))
|
|
2031
|
+
]);
|
|
2032
|
+
return subtle.timingSafeEqual(providedHash, expectedHash);
|
|
2033
|
+
}
|
|
1938
2034
|
function resolveOperatorApiKey(env) {
|
|
1939
2035
|
const preferred = env.OPERATOR_API_KEY;
|
|
1940
2036
|
if (typeof preferred === "string" && preferred.length > 0) {
|
|
@@ -1959,7 +2055,7 @@ async function requireOperatorAuth(request, env) {
|
|
|
1959
2055
|
}
|
|
1960
2056
|
const authHeader = request.headers.get("Authorization");
|
|
1961
2057
|
const expectedHeader = `Bearer ${apiKey}`;
|
|
1962
|
-
if (!authHeader || !
|
|
2058
|
+
if (!authHeader || !await timingSafeEqualAsync(authHeader, expectedHeader)) {
|
|
1963
2059
|
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
1964
2060
|
status: 401,
|
|
1965
2061
|
headers: { "Content-Type": "application/json" }
|
|
@@ -1992,12 +2088,13 @@ function collectInternalAuthKeys(env, keyNames) {
|
|
|
1992
2088
|
return keys;
|
|
1993
2089
|
}
|
|
1994
2090
|
function matchesAnyInternalAuthKey(providedKey, expectedKeys) {
|
|
2091
|
+
let matched = false;
|
|
1995
2092
|
for (const expected of expectedKeys) {
|
|
1996
2093
|
if (timingSafeEqual(providedKey, expected)) {
|
|
1997
|
-
|
|
2094
|
+
matched = true;
|
|
1998
2095
|
}
|
|
1999
2096
|
}
|
|
2000
|
-
return
|
|
2097
|
+
return matched;
|
|
2001
2098
|
}
|
|
2002
2099
|
function internalAuthNotConfiguredResponse(keyNames) {
|
|
2003
2100
|
const label = normalizeKeyNames(keyNames).join(" | ");
|
|
@@ -2560,7 +2657,7 @@ var PRESETS = [
|
|
|
2560
2657
|
"analytics-worker",
|
|
2561
2658
|
"telegram-worker"
|
|
2562
2659
|
],
|
|
2563
|
-
integrations: ["
|
|
2660
|
+
integrations: ["exchange", "telegram"]
|
|
2564
2661
|
},
|
|
2565
2662
|
{
|
|
2566
2663
|
name: "full",
|
|
@@ -2577,15 +2674,7 @@ var PRESETS = [
|
|
|
2577
2674
|
"web3-wallet-worker",
|
|
2578
2675
|
"pyne-worker"
|
|
2579
2676
|
],
|
|
2580
|
-
integrations: [
|
|
2581
|
-
"binance",
|
|
2582
|
-
"bybit",
|
|
2583
|
-
"mexc",
|
|
2584
|
-
"telegram",
|
|
2585
|
-
"openai",
|
|
2586
|
-
"wallet",
|
|
2587
|
-
"pyne"
|
|
2588
|
-
]
|
|
2677
|
+
integrations: ["exchange", "telegram", "openai", "wallet", "pyne"]
|
|
2589
2678
|
}
|
|
2590
2679
|
];
|
|
2591
2680
|
var WORKER_DEPENDENCIES = {
|
|
@@ -2617,30 +2706,12 @@ function resolveDependencies(selected) {
|
|
|
2617
2706
|
}
|
|
2618
2707
|
var INTEGRATIONS = [
|
|
2619
2708
|
{
|
|
2620
|
-
key: "
|
|
2621
|
-
label: "Binance
|
|
2622
|
-
workerName: "trade-worker",
|
|
2623
|
-
secrets: {
|
|
2624
|
-
BINANCE_KEY_BINDING: "Binance API Key",
|
|
2625
|
-
BINANCE_SECRET_BINDING: "Binance API Secret"
|
|
2626
|
-
}
|
|
2627
|
-
},
|
|
2628
|
-
{
|
|
2629
|
-
key: "mexc",
|
|
2630
|
-
label: "MEXC Exchange",
|
|
2631
|
-
workerName: "trade-worker",
|
|
2632
|
-
secrets: {
|
|
2633
|
-
MEXC_KEY_BINDING: "MEXC API Key",
|
|
2634
|
-
MEXC_SECRET_BINDING: "MEXC API Secret"
|
|
2635
|
-
}
|
|
2636
|
-
},
|
|
2637
|
-
{
|
|
2638
|
-
key: "bybit",
|
|
2639
|
-
label: "Bybit Exchange",
|
|
2709
|
+
key: "exchange",
|
|
2710
|
+
label: "Exchange API (Binance / Bybit / MEXC)",
|
|
2640
2711
|
workerName: "trade-worker",
|
|
2641
2712
|
secrets: {
|
|
2642
|
-
|
|
2643
|
-
|
|
2713
|
+
EXCHANGE_KEY_BINDING: "Exchange API Key",
|
|
2714
|
+
EXCHANGE_SECRET_BINDING: "Exchange API Secret"
|
|
2644
2715
|
}
|
|
2645
2716
|
},
|
|
2646
2717
|
{
|
|
@@ -2870,7 +2941,11 @@ class WizardEngine {
|
|
|
2870
2941
|
return { ...this.state };
|
|
2871
2942
|
}
|
|
2872
2943
|
getCurrentStep() {
|
|
2873
|
-
|
|
2944
|
+
const step = STEPS.find((s) => s.id === this.state.step) ?? STEPS[0];
|
|
2945
|
+
if (!step) {
|
|
2946
|
+
throw new Error("Wizard has no steps defined");
|
|
2947
|
+
}
|
|
2948
|
+
return step;
|
|
2874
2949
|
}
|
|
2875
2950
|
getCompletedSteps() {
|
|
2876
2951
|
return [...this.state.completedSteps];
|
|
@@ -2893,8 +2968,11 @@ class WizardEngine {
|
|
|
2893
2968
|
this.state.completedSteps.push(this.state.step);
|
|
2894
2969
|
}
|
|
2895
2970
|
const currentIdx = STEP_ORDER.indexOf(this.state.step);
|
|
2896
|
-
if (currentIdx < STEP_ORDER.length - 1) {
|
|
2897
|
-
|
|
2971
|
+
if (currentIdx >= 0 && currentIdx < STEP_ORDER.length - 1) {
|
|
2972
|
+
const nextStep = STEP_ORDER[currentIdx + 1];
|
|
2973
|
+
if (nextStep !== undefined) {
|
|
2974
|
+
this.state.step = nextStep;
|
|
2975
|
+
}
|
|
2898
2976
|
}
|
|
2899
2977
|
this.state.updatedAt = Date.now();
|
|
2900
2978
|
return [];
|
|
@@ -2905,6 +2983,8 @@ class WizardEngine {
|
|
|
2905
2983
|
const currentIdx = STEP_ORDER.indexOf(this.state.step);
|
|
2906
2984
|
if (currentIdx > 0) {
|
|
2907
2985
|
const previousStep = STEP_ORDER[currentIdx - 1];
|
|
2986
|
+
if (previousStep === undefined)
|
|
2987
|
+
return;
|
|
2908
2988
|
this.state.step = previousStep;
|
|
2909
2989
|
this.state.completedSteps = this.state.completedSteps.filter((s) => s !== this.state.step || STEP_ORDER.indexOf(s) <= STEP_ORDER.indexOf(previousStep));
|
|
2910
2990
|
}
|
|
@@ -3062,9 +3142,12 @@ function deriveCalledBy(manifests) {
|
|
|
3062
3142
|
if (!calledBy[workerName])
|
|
3063
3143
|
calledBy[workerName] = new Set;
|
|
3064
3144
|
for (const svc of manifest.services) {
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3145
|
+
let callers = calledBy[svc.service];
|
|
3146
|
+
if (!callers) {
|
|
3147
|
+
callers = new Set;
|
|
3148
|
+
calledBy[svc.service] = callers;
|
|
3149
|
+
}
|
|
3150
|
+
callers.add(workerName);
|
|
3068
3151
|
}
|
|
3069
3152
|
}
|
|
3070
3153
|
const result = {};
|
|
@@ -3077,6 +3160,7 @@ var manifests = {
|
|
|
3077
3160
|
hoox: {
|
|
3078
3161
|
name: "hoox",
|
|
3079
3162
|
path: "workers/hoox-worker",
|
|
3163
|
+
defaultEnabled: true,
|
|
3080
3164
|
vars: {
|
|
3081
3165
|
WEBHOOK_API_KEY_BINDING: {
|
|
3082
3166
|
type: "secret",
|
|
@@ -3086,7 +3170,11 @@ var manifests = {
|
|
|
3086
3170
|
type: "secret",
|
|
3087
3171
|
description: "Inter-worker auth key"
|
|
3088
3172
|
},
|
|
3089
|
-
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" }
|
|
3173
|
+
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" },
|
|
3174
|
+
TELEGRAM_ALLOWED_CHAT_IDS: {
|
|
3175
|
+
type: "secret",
|
|
3176
|
+
description: "Comma-separated chat IDs for webhook notify (fail-closed when unset); alias AUTHORIZED_CHAT_IDS"
|
|
3177
|
+
}
|
|
3090
3178
|
},
|
|
3091
3179
|
services: [
|
|
3092
3180
|
{
|
|
@@ -3112,7 +3200,8 @@ var manifests = {
|
|
|
3112
3200
|
ai: true,
|
|
3113
3201
|
queues: { producer: ["trade-execution"] },
|
|
3114
3202
|
durableObjects: [
|
|
3115
|
-
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" }
|
|
3203
|
+
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" },
|
|
3204
|
+
{ name: "RATE_LIMITER", className: "RateLimiterStore" }
|
|
3116
3205
|
]
|
|
3117
3206
|
},
|
|
3118
3207
|
middleware: [
|
|
@@ -3127,6 +3216,7 @@ var manifests = {
|
|
|
3127
3216
|
"trade-worker": {
|
|
3128
3217
|
name: "trade-worker",
|
|
3129
3218
|
path: "workers/trade-worker",
|
|
3219
|
+
defaultEnabled: true,
|
|
3130
3220
|
vars: {
|
|
3131
3221
|
INTERNAL_KEY_BINDING: {
|
|
3132
3222
|
type: "secret",
|
|
@@ -3136,15 +3226,22 @@ var manifests = {
|
|
|
3136
3226
|
type: "secret",
|
|
3137
3227
|
description: "Telegram outbound auth"
|
|
3138
3228
|
},
|
|
3139
|
-
|
|
3140
|
-
|
|
3229
|
+
EXCHANGE_KEY_BINDING: {
|
|
3230
|
+
type: "secret",
|
|
3231
|
+
description: "Unified exchange API key (Binance / Bybit / MEXC)"
|
|
3232
|
+
},
|
|
3233
|
+
EXCHANGE_SECRET_BINDING: {
|
|
3234
|
+
type: "secret",
|
|
3235
|
+
description: "Unified exchange API secret"
|
|
3236
|
+
},
|
|
3237
|
+
EXCHANGE_TESTNET_KEY_BINDING: {
|
|
3141
3238
|
type: "secret",
|
|
3142
|
-
description: "
|
|
3239
|
+
description: "Optional unified testnet API key"
|
|
3143
3240
|
},
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3241
|
+
EXCHANGE_TESTNET_SECRET_BINDING: {
|
|
3242
|
+
type: "secret",
|
|
3243
|
+
description: "Optional unified testnet API secret"
|
|
3244
|
+
}
|
|
3148
3245
|
},
|
|
3149
3246
|
services: [
|
|
3150
3247
|
{
|
|
@@ -3186,6 +3283,7 @@ var manifests = {
|
|
|
3186
3283
|
"telegram-worker": {
|
|
3187
3284
|
name: "telegram-worker",
|
|
3188
3285
|
path: "workers/telegram-worker",
|
|
3286
|
+
defaultEnabled: true,
|
|
3189
3287
|
vars: {
|
|
3190
3288
|
INTERNAL_KEY_BINDING: {
|
|
3191
3289
|
type: "secret",
|
|
@@ -3199,6 +3297,10 @@ var manifests = {
|
|
|
3199
3297
|
TELEGRAM_SECRET_TOKEN: {
|
|
3200
3298
|
type: "secret",
|
|
3201
3299
|
description: "Webhook verification token"
|
|
3300
|
+
},
|
|
3301
|
+
AUTHORIZED_CHAT_IDS: {
|
|
3302
|
+
type: "secret",
|
|
3303
|
+
description: "Comma-separated chat IDs; inbound webhook fail-closed when unset; outbound /alert allowlist"
|
|
3202
3304
|
}
|
|
3203
3305
|
},
|
|
3204
3306
|
services: [],
|
|
@@ -3219,6 +3321,7 @@ var manifests = {
|
|
|
3219
3321
|
"d1-worker": {
|
|
3220
3322
|
name: "d1-worker",
|
|
3221
3323
|
path: "workers/d1-worker",
|
|
3324
|
+
defaultEnabled: true,
|
|
3222
3325
|
vars: {
|
|
3223
3326
|
INTERNAL_KEY_BINDING: {
|
|
3224
3327
|
type: "secret",
|
|
@@ -3241,6 +3344,7 @@ var manifests = {
|
|
|
3241
3344
|
"web3-wallet-worker": {
|
|
3242
3345
|
name: "web3-wallet-worker",
|
|
3243
3346
|
path: "workers/web3-wallet-worker",
|
|
3347
|
+
defaultEnabled: false,
|
|
3244
3348
|
vars: {
|
|
3245
3349
|
WALLET_PK_SECRET: { type: "secret", description: "Wallet private key" },
|
|
3246
3350
|
WALLET_MNEMONIC_SECRET: {
|
|
@@ -3261,6 +3365,7 @@ var manifests = {
|
|
|
3261
3365
|
"agent-worker": {
|
|
3262
3366
|
name: "agent-worker",
|
|
3263
3367
|
path: "workers/agent-worker",
|
|
3368
|
+
defaultEnabled: true,
|
|
3264
3369
|
vars: {
|
|
3265
3370
|
AGENT_INTERNAL_KEY: { type: "secret", description: "Agent worker auth" },
|
|
3266
3371
|
INTERNAL_KEY_BINDING: {
|
|
@@ -3297,6 +3402,7 @@ var manifests = {
|
|
|
3297
3402
|
"email-worker": {
|
|
3298
3403
|
name: "email-worker",
|
|
3299
3404
|
path: "workers/email-worker",
|
|
3405
|
+
defaultEnabled: false,
|
|
3300
3406
|
vars: {
|
|
3301
3407
|
INTERNAL_KEY_BINDING: {
|
|
3302
3408
|
type: "secret",
|
|
@@ -3334,6 +3440,7 @@ var manifests = {
|
|
|
3334
3440
|
"analytics-worker": {
|
|
3335
3441
|
name: "analytics-worker",
|
|
3336
3442
|
path: "workers/analytics-worker",
|
|
3443
|
+
defaultEnabled: true,
|
|
3337
3444
|
vars: {
|
|
3338
3445
|
CLOUDFLARE_API_TOKEN: {
|
|
3339
3446
|
type: "secret",
|
|
@@ -3353,6 +3460,7 @@ var manifests = {
|
|
|
3353
3460
|
"report-worker": {
|
|
3354
3461
|
name: "report-worker",
|
|
3355
3462
|
path: "workers/report-worker",
|
|
3463
|
+
defaultEnabled: false,
|
|
3356
3464
|
vars: {
|
|
3357
3465
|
CF_API_TOKEN_BINDING: {
|
|
3358
3466
|
type: "secret",
|
|
@@ -3387,6 +3495,7 @@ var manifests = {
|
|
|
3387
3495
|
"pyne-worker": {
|
|
3388
3496
|
name: "pyne-worker",
|
|
3389
3497
|
path: "workers/pyne-worker",
|
|
3498
|
+
defaultEnabled: true,
|
|
3390
3499
|
vars: {
|
|
3391
3500
|
API_KEY: {
|
|
3392
3501
|
type: "secret",
|
|
@@ -3424,6 +3533,7 @@ var manifests = {
|
|
|
3424
3533
|
dashboard: {
|
|
3425
3534
|
name: "dashboard",
|
|
3426
3535
|
path: "workers/dashboard",
|
|
3536
|
+
defaultEnabled: true,
|
|
3427
3537
|
vars: {
|
|
3428
3538
|
DASHBOARD_USER: {
|
|
3429
3539
|
type: "secret",
|
|
@@ -3466,6 +3576,17 @@ var manifests = {
|
|
|
3466
3576
|
var CALLED_BY = deriveCalledBy(manifests);
|
|
3467
3577
|
var WORKER_MANIFESTS = manifests;
|
|
3468
3578
|
var WORKER_NAMES = Object.keys(manifests).sort();
|
|
3579
|
+
var WORKER_CATALOG = WORKER_NAMES.map((name) => {
|
|
3580
|
+
const m = manifests[name];
|
|
3581
|
+
return {
|
|
3582
|
+
name: m.name,
|
|
3583
|
+
path: m.path,
|
|
3584
|
+
defaultEnabled: m.defaultEnabled
|
|
3585
|
+
};
|
|
3586
|
+
});
|
|
3587
|
+
function getWorkerDefaultEnabled(name) {
|
|
3588
|
+
return manifests[name]?.defaultEnabled;
|
|
3589
|
+
}
|
|
3469
3590
|
|
|
3470
3591
|
// src/schemas/validators.ts
|
|
3471
3592
|
import { parse } from "jsonc-parser";
|
|
@@ -3505,7 +3626,7 @@ function validateWranglerJsonc(workerName, manifest, jsoncContent) {
|
|
|
3505
3626
|
}
|
|
3506
3627
|
}
|
|
3507
3628
|
for (const [name, def] of Object.entries(manifest.vars)) {
|
|
3508
|
-
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") {
|
|
3629
|
+
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") {
|
|
3509
3630
|
errors.push({
|
|
3510
3631
|
worker: workerName,
|
|
3511
3632
|
severity: "warning",
|
|
@@ -3622,6 +3743,8 @@ function generateWranglerJsonc(manifest) {
|
|
|
3622
3743
|
parts.push(` "vars": {`);
|
|
3623
3744
|
for (const [i, name] of varKeys.entries()) {
|
|
3624
3745
|
const def = manifest.vars[name];
|
|
3746
|
+
if (!def)
|
|
3747
|
+
continue;
|
|
3625
3748
|
const comma = i < varKeys.length - 1 ? "," : "";
|
|
3626
3749
|
const val = def.type === "secret" ? "__SECRET__" : JSON.stringify(def.default ?? "");
|
|
3627
3750
|
parts.push(` "${name}": ${val}${comma}`);
|
|
@@ -3841,7 +3964,7 @@ function getBackoffDelay(retryCount) {
|
|
|
3841
3964
|
if (retryCount <= 0)
|
|
3842
3965
|
return 0;
|
|
3843
3966
|
const index = Math.min(retryCount - 1, BACKOFF_SEQUENCE.length - 1);
|
|
3844
|
-
return BACKOFF_SEQUENCE[index];
|
|
3967
|
+
return BACKOFF_SEQUENCE[index] ?? 0;
|
|
3845
3968
|
}
|
|
3846
3969
|
var useServiceStore = create2()(immer2((set, get) => ({
|
|
3847
3970
|
...initialState2,
|
|
@@ -4290,7 +4413,10 @@ export {
|
|
|
4290
4413
|
logKvTimestamp,
|
|
4291
4414
|
loadDashboardManifestsFromRoot,
|
|
4292
4415
|
loadDashboardKvManifestFromRoot,
|
|
4416
|
+
kvPutMany,
|
|
4293
4417
|
kvManifestFromDashboardManifests,
|
|
4418
|
+
kvGetManyAsRecord,
|
|
4419
|
+
kvGetMany,
|
|
4294
4420
|
isWithinHooxHome,
|
|
4295
4421
|
isUnixModeGroupOrWorldAccessible,
|
|
4296
4422
|
isTruthyKillSwitchFlag,
|
|
@@ -4305,6 +4431,7 @@ export {
|
|
|
4305
4431
|
healthCheck,
|
|
4306
4432
|
headersToObject,
|
|
4307
4433
|
hasOperatorClientCredentials,
|
|
4434
|
+
getWorkerDefaultEnabled,
|
|
4308
4435
|
getTuiEntryCandidates,
|
|
4309
4436
|
getRememberedMonorepoRoot,
|
|
4310
4437
|
getRememberedMonorepoPath,
|
|
@@ -4367,6 +4494,7 @@ export {
|
|
|
4367
4494
|
WORKER_NAMES,
|
|
4368
4495
|
WORKER_MANIFESTS,
|
|
4369
4496
|
WORKER_DEPENDENCIES,
|
|
4497
|
+
WORKER_CATALOG,
|
|
4370
4498
|
WIZARD_STATE_PATH,
|
|
4371
4499
|
WALLET_EXECUTE_AUTH_KEY_FIELDS,
|
|
4372
4500
|
TradeSignalSchema,
|
|
@@ -4381,6 +4509,7 @@ export {
|
|
|
4381
4509
|
PositionSchema,
|
|
4382
4510
|
PRESETS,
|
|
4383
4511
|
LogLevelColor,
|
|
4512
|
+
KV_BULK_GET_MAX_KEYS,
|
|
4384
4513
|
KVKeys,
|
|
4385
4514
|
KILL_SWITCH_KEYS,
|
|
4386
4515
|
KILL_SWITCH_ACTIVE_PREFIX,
|
package/dist/kill-switch.js
CHANGED
|
@@ -26,6 +26,7 @@ var KV_BOT_ENABLED = "bot:enabled";
|
|
|
26
26
|
var KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id";
|
|
27
27
|
var KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution";
|
|
28
28
|
var KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error";
|
|
29
|
+
var KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids";
|
|
29
30
|
var KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled";
|
|
30
31
|
var KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips";
|
|
31
32
|
var KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode";
|
|
@@ -56,6 +57,7 @@ var KVKeys = {
|
|
|
56
57
|
KV_BOT_DEFAULT_CHAT_ID,
|
|
57
58
|
KV_BOT_NOTIFY_ON_EXECUTION,
|
|
58
59
|
KV_BOT_NOTIFY_ON_ERROR,
|
|
60
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
59
61
|
KV_WEBHOOK_IP_CHECK_ENABLED,
|
|
60
62
|
KV_WEBHOOK_ALLOWED_IPS,
|
|
61
63
|
KV_WEBHOOK_QUEUE_MODE,
|
package/dist/kvKeys.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare const KV_BOT_ENABLED = "bot:enabled";
|
|
|
25
25
|
export declare const KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id";
|
|
26
26
|
export declare const KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution";
|
|
27
27
|
export declare const KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error";
|
|
28
|
+
/** JSON array of string|number — gateway notify chatId allowlist (fail-closed). */
|
|
29
|
+
export declare const KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids";
|
|
28
30
|
export declare const KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled";
|
|
29
31
|
export declare const KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips";
|
|
30
32
|
export declare const KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode";
|
|
@@ -55,6 +57,7 @@ export declare const KVKeys: {
|
|
|
55
57
|
KV_BOT_DEFAULT_CHAT_ID: string;
|
|
56
58
|
KV_BOT_NOTIFY_ON_EXECUTION: string;
|
|
57
59
|
KV_BOT_NOTIFY_ON_ERROR: string;
|
|
60
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS: string;
|
|
58
61
|
KV_WEBHOOK_IP_CHECK_ENABLED: string;
|
|
59
62
|
KV_WEBHOOK_ALLOWED_IPS: string;
|
|
60
63
|
KV_WEBHOOK_QUEUE_MODE: string;
|
package/dist/kvKeys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kvKeys.d.ts","sourceRoot":"","sources":["../src/kvKeys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAClE,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,mCAAmC,qCACZ,CAAC;AACrC,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AACxD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAGhD,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAC5C,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"kvKeys.d.ts","sourceRoot":"","sources":["../src/kvKeys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAClE,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,mCAAmC,qCACZ,CAAC;AACrC,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AACxD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAGhD,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAC5C,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,mFAAmF;AACnF,eAAO,MAAM,4BAA4B,8BAA8B,CAAC;AAGxE,eAAO,MAAM,2BAA2B,yCACA,CAAC;AACzC,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AACxE,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAG1D,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAClD,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAC9D,eAAO,MAAM,4BAA4B,8BAA8B,CAAC;AAGxE,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAGtD,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAG5E,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AAGpE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAKpD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BlB,CAAC"}
|
package/dist/kvKeys.js
CHANGED
|
@@ -26,6 +26,7 @@ var KV_BOT_ENABLED = "bot:enabled";
|
|
|
26
26
|
var KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id";
|
|
27
27
|
var KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution";
|
|
28
28
|
var KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error";
|
|
29
|
+
var KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids";
|
|
29
30
|
var KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled";
|
|
30
31
|
var KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips";
|
|
31
32
|
var KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode";
|
|
@@ -56,6 +57,7 @@ var KVKeys = {
|
|
|
56
57
|
KV_BOT_DEFAULT_CHAT_ID,
|
|
57
58
|
KV_BOT_NOTIFY_ON_EXECUTION,
|
|
58
59
|
KV_BOT_NOTIFY_ON_ERROR,
|
|
60
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
59
61
|
KV_WEBHOOK_IP_CHECK_ENABLED,
|
|
60
62
|
KV_WEBHOOK_ALLOWED_IPS,
|
|
61
63
|
KV_WEBHOOK_QUEUE_MODE,
|
|
@@ -89,6 +91,7 @@ export {
|
|
|
89
91
|
KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT,
|
|
90
92
|
KV_TRADE_KILL_SWITCH,
|
|
91
93
|
KV_TRADE_DEFAULT_LEVERAGE,
|
|
94
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
92
95
|
KV_HOUSEKEEPING_LAST_CHECK,
|
|
93
96
|
KV_HEALTH_CHECK,
|
|
94
97
|
KV_GLOBAL_KILL_SWITCH,
|