@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.
Files changed (55) hide show
  1. package/dist/agent-config-fields.js +2 -0
  2. package/dist/d1/index.js +4 -2
  3. package/dist/d1/repository.js +4 -2
  4. package/dist/errors.d.ts.map +1 -1
  5. package/dist/errors.js +4 -2
  6. package/dist/health.js +4 -2
  7. package/dist/index.d.ts +3 -3
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +209 -80
  10. package/dist/kill-switch.js +2 -0
  11. package/dist/kvKeys.d.ts +3 -0
  12. package/dist/kvKeys.d.ts.map +1 -1
  13. package/dist/kvKeys.js +3 -0
  14. package/dist/kvUtils.d.ts +34 -1
  15. package/dist/kvUtils.d.ts.map +1 -1
  16. package/dist/kvUtils.js +56 -3
  17. package/dist/middleware/auth.d.ts +6 -3
  18. package/dist/middleware/auth.d.ts.map +1 -1
  19. package/dist/middleware/auth.js +19 -5
  20. package/dist/middleware/index.d.ts +3 -2
  21. package/dist/middleware/index.d.ts.map +1 -1
  22. package/dist/middleware/index.js +88 -8
  23. package/dist/middleware/logger.js +4 -2
  24. package/dist/middleware/validate.d.ts +16 -0
  25. package/dist/middleware/validate.d.ts.map +1 -1
  26. package/dist/middleware/validate.js +37 -1
  27. package/dist/middleware/wait-until.d.ts +32 -0
  28. package/dist/middleware/wait-until.d.ts.map +1 -0
  29. package/dist/middleware/wait-until.js +46 -0
  30. package/dist/queue-handler.d.ts +6 -0
  31. package/dist/queue-handler.d.ts.map +1 -1
  32. package/dist/queue-handler.js +51 -20
  33. package/dist/router.d.ts.map +1 -1
  34. package/dist/router.js +12 -2
  35. package/dist/schemas/index.d.ts +2 -1
  36. package/dist/schemas/index.d.ts.map +1 -1
  37. package/dist/schemas/index.js +58 -13
  38. package/dist/schemas/registry.d.ts +13 -0
  39. package/dist/schemas/registry.d.ts.map +1 -1
  40. package/dist/schemas/registry.js +55 -12
  41. package/dist/schemas/types.d.ts +5 -0
  42. package/dist/schemas/types.d.ts.map +1 -1
  43. package/dist/schemas/validators.d.ts.map +1 -1
  44. package/dist/schemas/validators.js +3 -1
  45. package/dist/service-bindings.js +18 -5
  46. package/dist/stores/service-store.js +1 -1
  47. package/dist/types.d.ts +22 -4
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js +8 -4
  50. package/dist/wizard/engine.d.ts.map +1 -1
  51. package/dist/wizard/engine.js +18 -35
  52. package/dist/wizard/index.js +18 -35
  53. package/dist/wizard/presets.d.ts.map +1 -1
  54. package/dist/wizard/presets.js +6 -32
  55. 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 && typeof err.message === "string") {
690
- return err.message;
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(125).optional(),
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 { maxRetries, backoffDelays, onMessage, onRetry, onDLQ, logger } = options;
1900
- return async (batch) => {
1901
- for (const msg of batch.messages) {
1902
- const attemptNumber = msg.attempts || 0;
1903
- const logId = `[${msg.id}]`;
1904
- try {
1905
- logger?.info(`${logId} Processing message (attempt ${attemptNumber + 1})`);
1906
- await onMessage(msg.body, attemptNumber);
1907
- logger?.info(`${logId} Message processed successfully`);
1908
- } catch (error) {
1909
- const errorMsg = error instanceof Error ? error.message : String(error);
1910
- if (attemptNumber < maxRetries) {
1911
- const delaySeconds = backoffDelays[attemptNumber] ?? backoffDelays[backoffDelays.length - 1];
1912
- logger?.info(`${logId} Retrying in ${delaySeconds}s (attempt ${attemptNumber + 2}/${maxRetries + 1})`);
1913
- await onRetry?.(msg.body, attemptNumber, errorMsg, delaySeconds);
1914
- msg.retry({ delaySeconds });
1915
- } else {
1916
- logger?.error(`${logId} Max retries exceeded (${maxRetries + 1} attempts), moving to DLQ`);
1917
- await onDLQ?.(msg.body, attemptNumber, errorMsg);
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 = i < aBuf.length ? aBuf[i] : 0;
1933
- const bv = i < bBuf.length ? bBuf[i] : 0;
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 || !timingSafeEqual(authHeader, expectedHeader)) {
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
- return true;
2094
+ matched = true;
1998
2095
  }
1999
2096
  }
2000
- return false;
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: ["binance", "telegram"]
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: "binance",
2621
- label: "Binance Exchange",
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
- BYBIT_KEY_BINDING: "Bybit API Key",
2643
- BYBIT_SECRET_BINDING: "Bybit API Secret"
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
- return STEPS.find((s) => s.id === this.state.step) ?? STEPS[0];
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
- this.state.step = STEP_ORDER[currentIdx + 1];
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
- if (!calledBy[svc.service])
3066
- calledBy[svc.service] = new Set;
3067
- calledBy[svc.service].add(workerName);
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
- BINANCE_KEY_BINDING: { type: "secret", description: "Binance API key" },
3140
- BINANCE_SECRET_BINDING: {
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: "Binance API secret"
3239
+ description: "Optional unified testnet API key"
3143
3240
  },
3144
- MEXC_KEY_BINDING: { type: "secret", description: "MEXC API key" },
3145
- MEXC_SECRET_BINDING: { type: "secret", description: "MEXC API secret" },
3146
- BYBIT_KEY_BINDING: { type: "secret", description: "Bybit API key" },
3147
- BYBIT_SECRET_BINDING: { type: "secret", description: "Bybit API secret" }
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,
@@ -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;
@@ -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;AAG5D,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BlB,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,