@waiaas/daemon 2.0.0-rc.1

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 (480) hide show
  1. package/dist/api/error-hints.d.ts +15 -0
  2. package/dist/api/error-hints.d.ts.map +1 -0
  3. package/dist/api/error-hints.js +71 -0
  4. package/dist/api/error-hints.js.map +1 -0
  5. package/dist/api/index.d.ts +11 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/index.js +14 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/middleware/address-validation.d.ts +38 -0
  10. package/dist/api/middleware/address-validation.d.ts.map +1 -0
  11. package/dist/api/middleware/address-validation.js +134 -0
  12. package/dist/api/middleware/address-validation.js.map +1 -0
  13. package/dist/api/middleware/csp.d.ts +17 -0
  14. package/dist/api/middleware/csp.d.ts.map +1 -0
  15. package/dist/api/middleware/csp.js +31 -0
  16. package/dist/api/middleware/csp.js.map +1 -0
  17. package/dist/api/middleware/error-handler.d.ts +16 -0
  18. package/dist/api/middleware/error-handler.d.ts.map +1 -0
  19. package/dist/api/middleware/error-handler.js +46 -0
  20. package/dist/api/middleware/error-handler.js.map +1 -0
  21. package/dist/api/middleware/host-guard.d.ts +11 -0
  22. package/dist/api/middleware/host-guard.d.ts.map +1 -0
  23. package/dist/api/middleware/host-guard.js +25 -0
  24. package/dist/api/middleware/host-guard.js.map +1 -0
  25. package/dist/api/middleware/index.d.ts +13 -0
  26. package/dist/api/middleware/index.d.ts.map +1 -0
  27. package/dist/api/middleware/index.js +13 -0
  28. package/dist/api/middleware/index.js.map +1 -0
  29. package/dist/api/middleware/kill-switch-guard.d.ts +19 -0
  30. package/dist/api/middleware/kill-switch-guard.d.ts.map +1 -0
  31. package/dist/api/middleware/kill-switch-guard.js +49 -0
  32. package/dist/api/middleware/kill-switch-guard.js.map +1 -0
  33. package/dist/api/middleware/master-auth.d.ts +15 -0
  34. package/dist/api/middleware/master-auth.d.ts.map +1 -0
  35. package/dist/api/middleware/master-auth.js +35 -0
  36. package/dist/api/middleware/master-auth.js.map +1 -0
  37. package/dist/api/middleware/owner-auth.d.ts +30 -0
  38. package/dist/api/middleware/owner-auth.d.ts.map +1 -0
  39. package/dist/api/middleware/owner-auth.js +133 -0
  40. package/dist/api/middleware/owner-auth.js.map +1 -0
  41. package/dist/api/middleware/request-id.d.ts +10 -0
  42. package/dist/api/middleware/request-id.d.ts.map +1 -0
  43. package/dist/api/middleware/request-id.js +18 -0
  44. package/dist/api/middleware/request-id.js.map +1 -0
  45. package/dist/api/middleware/request-logger.d.ts +9 -0
  46. package/dist/api/middleware/request-logger.d.ts.map +1 -0
  47. package/dist/api/middleware/request-logger.js +18 -0
  48. package/dist/api/middleware/request-logger.js.map +1 -0
  49. package/dist/api/middleware/session-auth.d.ts +21 -0
  50. package/dist/api/middleware/session-auth.d.ts.map +1 -0
  51. package/dist/api/middleware/session-auth.js +51 -0
  52. package/dist/api/middleware/session-auth.js.map +1 -0
  53. package/dist/api/middleware/siwe-verify.d.ts +31 -0
  54. package/dist/api/middleware/siwe-verify.d.ts.map +1 -0
  55. package/dist/api/middleware/siwe-verify.js +55 -0
  56. package/dist/api/middleware/siwe-verify.js.map +1 -0
  57. package/dist/api/routes/actions.d.ts +56 -0
  58. package/dist/api/routes/actions.d.ts.map +1 -0
  59. package/dist/api/routes/actions.js +291 -0
  60. package/dist/api/routes/actions.js.map +1 -0
  61. package/dist/api/routes/admin.d.ts +99 -0
  62. package/dist/api/routes/admin.d.ts.map +1 -0
  63. package/dist/api/routes/admin.js +1304 -0
  64. package/dist/api/routes/admin.js.map +1 -0
  65. package/dist/api/routes/display-currency-helper.d.ts +26 -0
  66. package/dist/api/routes/display-currency-helper.d.ts.map +1 -0
  67. package/dist/api/routes/display-currency-helper.js +47 -0
  68. package/dist/api/routes/display-currency-helper.js.map +1 -0
  69. package/dist/api/routes/health.d.ts +14 -0
  70. package/dist/api/routes/health.d.ts.map +1 -0
  71. package/dist/api/routes/health.js +47 -0
  72. package/dist/api/routes/health.js.map +1 -0
  73. package/dist/api/routes/index.d.ts +15 -0
  74. package/dist/api/routes/index.d.ts.map +1 -0
  75. package/dist/api/routes/index.js +15 -0
  76. package/dist/api/routes/index.js.map +1 -0
  77. package/dist/api/routes/mcp.d.ts +30 -0
  78. package/dist/api/routes/mcp.d.ts.map +1 -0
  79. package/dist/api/routes/mcp.js +156 -0
  80. package/dist/api/routes/mcp.js.map +1 -0
  81. package/dist/api/routes/nonce.d.ts +20 -0
  82. package/dist/api/routes/nonce.d.ts.map +1 -0
  83. package/dist/api/routes/nonce.js +48 -0
  84. package/dist/api/routes/nonce.js.map +1 -0
  85. package/dist/api/routes/openapi-schemas.d.ts +2281 -0
  86. package/dist/api/routes/openapi-schemas.d.ts.map +1 -0
  87. package/dist/api/routes/openapi-schemas.js +770 -0
  88. package/dist/api/routes/openapi-schemas.js.map +1 -0
  89. package/dist/api/routes/policies.d.ts +29 -0
  90. package/dist/api/routes/policies.d.ts.map +1 -0
  91. package/dist/api/routes/policies.js +332 -0
  92. package/dist/api/routes/policies.js.map +1 -0
  93. package/dist/api/routes/sessions.d.ts +35 -0
  94. package/dist/api/routes/sessions.d.ts.map +1 -0
  95. package/dist/api/routes/sessions.js +347 -0
  96. package/dist/api/routes/sessions.js.map +1 -0
  97. package/dist/api/routes/skills.d.ts +9 -0
  98. package/dist/api/routes/skills.d.ts.map +1 -0
  99. package/dist/api/routes/skills.js +59 -0
  100. package/dist/api/routes/skills.js.map +1 -0
  101. package/dist/api/routes/tokens.d.ts +25 -0
  102. package/dist/api/routes/tokens.d.ts.map +1 -0
  103. package/dist/api/routes/tokens.js +161 -0
  104. package/dist/api/routes/tokens.js.map +1 -0
  105. package/dist/api/routes/transactions.d.ts +68 -0
  106. package/dist/api/routes/transactions.d.ts.map +1 -0
  107. package/dist/api/routes/transactions.js +576 -0
  108. package/dist/api/routes/transactions.js.map +1 -0
  109. package/dist/api/routes/utils.d.ts +9 -0
  110. package/dist/api/routes/utils.d.ts.map +1 -0
  111. package/dist/api/routes/utils.js +52 -0
  112. package/dist/api/routes/utils.js.map +1 -0
  113. package/dist/api/routes/wallet.d.ts +36 -0
  114. package/dist/api/routes/wallet.d.ts.map +1 -0
  115. package/dist/api/routes/wallet.js +358 -0
  116. package/dist/api/routes/wallet.js.map +1 -0
  117. package/dist/api/routes/wallets.d.ts +43 -0
  118. package/dist/api/routes/wallets.d.ts.map +1 -0
  119. package/dist/api/routes/wallets.js +630 -0
  120. package/dist/api/routes/wallets.js.map +1 -0
  121. package/dist/api/routes/wc.d.ts +46 -0
  122. package/dist/api/routes/wc.d.ts.map +1 -0
  123. package/dist/api/routes/wc.js +354 -0
  124. package/dist/api/routes/wc.js.map +1 -0
  125. package/dist/api/routes/x402.d.ts +61 -0
  126. package/dist/api/routes/x402.d.ts.map +1 -0
  127. package/dist/api/routes/x402.js +493 -0
  128. package/dist/api/routes/x402.js.map +1 -0
  129. package/dist/api/server.d.ts +81 -0
  130. package/dist/api/server.d.ts.map +1 -0
  131. package/dist/api/server.js +406 -0
  132. package/dist/api/server.js.map +1 -0
  133. package/dist/index.d.ts +35 -0
  134. package/dist/index.d.ts.map +1 -0
  135. package/dist/index.js +43 -0
  136. package/dist/index.js.map +1 -0
  137. package/dist/infrastructure/action/action-provider-registry.d.ts +77 -0
  138. package/dist/infrastructure/action/action-provider-registry.d.ts.map +1 -0
  139. package/dist/infrastructure/action/action-provider-registry.js +239 -0
  140. package/dist/infrastructure/action/action-provider-registry.js.map +1 -0
  141. package/dist/infrastructure/action/api-key-store.d.ts +60 -0
  142. package/dist/infrastructure/action/api-key-store.d.ts.map +1 -0
  143. package/dist/infrastructure/action/api-key-store.js +130 -0
  144. package/dist/infrastructure/action/api-key-store.js.map +1 -0
  145. package/dist/infrastructure/action/index.d.ts +10 -0
  146. package/dist/infrastructure/action/index.d.ts.map +1 -0
  147. package/dist/infrastructure/action/index.js +9 -0
  148. package/dist/infrastructure/action/index.js.map +1 -0
  149. package/dist/infrastructure/adapter-pool.d.ts +50 -0
  150. package/dist/infrastructure/adapter-pool.d.ts.map +1 -0
  151. package/dist/infrastructure/adapter-pool.js +110 -0
  152. package/dist/infrastructure/adapter-pool.js.map +1 -0
  153. package/dist/infrastructure/backup/backup-service.d.ts +53 -0
  154. package/dist/infrastructure/backup/backup-service.d.ts.map +1 -0
  155. package/dist/infrastructure/backup/backup-service.js +158 -0
  156. package/dist/infrastructure/backup/backup-service.js.map +1 -0
  157. package/dist/infrastructure/backup/index.d.ts +2 -0
  158. package/dist/infrastructure/backup/index.d.ts.map +1 -0
  159. package/dist/infrastructure/backup/index.js +2 -0
  160. package/dist/infrastructure/backup/index.js.map +1 -0
  161. package/dist/infrastructure/config/index.d.ts +8 -0
  162. package/dist/infrastructure/config/index.d.ts.map +1 -0
  163. package/dist/infrastructure/config/index.js +7 -0
  164. package/dist/infrastructure/config/index.js.map +1 -0
  165. package/dist/infrastructure/config/loader.d.ts +555 -0
  166. package/dist/infrastructure/config/loader.d.ts.map +1 -0
  167. package/dist/infrastructure/config/loader.js +311 -0
  168. package/dist/infrastructure/config/loader.js.map +1 -0
  169. package/dist/infrastructure/database/checks.d.ts +19 -0
  170. package/dist/infrastructure/database/checks.d.ts.map +1 -0
  171. package/dist/infrastructure/database/checks.js +27 -0
  172. package/dist/infrastructure/database/checks.js.map +1 -0
  173. package/dist/infrastructure/database/compatibility.d.ts +36 -0
  174. package/dist/infrastructure/database/compatibility.d.ts.map +1 -0
  175. package/dist/infrastructure/database/compatibility.js +75 -0
  176. package/dist/infrastructure/database/compatibility.js.map +1 -0
  177. package/dist/infrastructure/database/connection.d.ts +36 -0
  178. package/dist/infrastructure/database/connection.d.ts.map +1 -0
  179. package/dist/infrastructure/database/connection.js +47 -0
  180. package/dist/infrastructure/database/connection.js.map +1 -0
  181. package/dist/infrastructure/database/id.d.ts +17 -0
  182. package/dist/infrastructure/database/id.d.ts.map +1 -0
  183. package/dist/infrastructure/database/id.js +20 -0
  184. package/dist/infrastructure/database/id.js.map +1 -0
  185. package/dist/infrastructure/database/index.d.ts +15 -0
  186. package/dist/infrastructure/database/index.d.ts.map +1 -0
  187. package/dist/infrastructure/database/index.js +12 -0
  188. package/dist/infrastructure/database/index.js.map +1 -0
  189. package/dist/infrastructure/database/migrate.d.ts +76 -0
  190. package/dist/infrastructure/database/migrate.d.ts.map +1 -0
  191. package/dist/infrastructure/database/migrate.js +1214 -0
  192. package/dist/infrastructure/database/migrate.js.map +1 -0
  193. package/dist/infrastructure/database/schema.d.ts +2352 -0
  194. package/dist/infrastructure/database/schema.d.ts.map +1 -0
  195. package/dist/infrastructure/database/schema.js +288 -0
  196. package/dist/infrastructure/database/schema.js.map +1 -0
  197. package/dist/infrastructure/jwt/index.d.ts +2 -0
  198. package/dist/infrastructure/jwt/index.d.ts.map +1 -0
  199. package/dist/infrastructure/jwt/index.js +2 -0
  200. package/dist/infrastructure/jwt/index.js.map +1 -0
  201. package/dist/infrastructure/jwt/jwt-secret-manager.d.ts +58 -0
  202. package/dist/infrastructure/jwt/jwt-secret-manager.d.ts.map +1 -0
  203. package/dist/infrastructure/jwt/jwt-secret-manager.js +222 -0
  204. package/dist/infrastructure/jwt/jwt-secret-manager.js.map +1 -0
  205. package/dist/infrastructure/keystore/crypto.d.ts +62 -0
  206. package/dist/infrastructure/keystore/crypto.d.ts.map +1 -0
  207. package/dist/infrastructure/keystore/crypto.js +89 -0
  208. package/dist/infrastructure/keystore/crypto.js.map +1 -0
  209. package/dist/infrastructure/keystore/index.d.ts +4 -0
  210. package/dist/infrastructure/keystore/index.d.ts.map +1 -0
  211. package/dist/infrastructure/keystore/index.js +5 -0
  212. package/dist/infrastructure/keystore/index.js.map +1 -0
  213. package/dist/infrastructure/keystore/keystore.d.ts +115 -0
  214. package/dist/infrastructure/keystore/keystore.d.ts.map +1 -0
  215. package/dist/infrastructure/keystore/keystore.js +327 -0
  216. package/dist/infrastructure/keystore/keystore.js.map +1 -0
  217. package/dist/infrastructure/keystore/memory.d.ts +45 -0
  218. package/dist/infrastructure/keystore/memory.d.ts.map +1 -0
  219. package/dist/infrastructure/keystore/memory.js +105 -0
  220. package/dist/infrastructure/keystore/memory.js.map +1 -0
  221. package/dist/infrastructure/oracle/coingecko-forex.d.ts +35 -0
  222. package/dist/infrastructure/oracle/coingecko-forex.d.ts.map +1 -0
  223. package/dist/infrastructure/oracle/coingecko-forex.js +69 -0
  224. package/dist/infrastructure/oracle/coingecko-forex.js.map +1 -0
  225. package/dist/infrastructure/oracle/coingecko-oracle.d.ts +73 -0
  226. package/dist/infrastructure/oracle/coingecko-oracle.d.ts.map +1 -0
  227. package/dist/infrastructure/oracle/coingecko-oracle.js +199 -0
  228. package/dist/infrastructure/oracle/coingecko-oracle.js.map +1 -0
  229. package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts +32 -0
  230. package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts.map +1 -0
  231. package/dist/infrastructure/oracle/coingecko-platform-ids.js +30 -0
  232. package/dist/infrastructure/oracle/coingecko-platform-ids.js.map +1 -0
  233. package/dist/infrastructure/oracle/forex-currencies.d.ts +36 -0
  234. package/dist/infrastructure/oracle/forex-currencies.d.ts.map +1 -0
  235. package/dist/infrastructure/oracle/forex-currencies.js +71 -0
  236. package/dist/infrastructure/oracle/forex-currencies.js.map +1 -0
  237. package/dist/infrastructure/oracle/forex-rate-service.d.ts +51 -0
  238. package/dist/infrastructure/oracle/forex-rate-service.d.ts.map +1 -0
  239. package/dist/infrastructure/oracle/forex-rate-service.js +149 -0
  240. package/dist/infrastructure/oracle/forex-rate-service.js.map +1 -0
  241. package/dist/infrastructure/oracle/index.d.ts +18 -0
  242. package/dist/infrastructure/oracle/index.d.ts.map +1 -0
  243. package/dist/infrastructure/oracle/index.js +19 -0
  244. package/dist/infrastructure/oracle/index.js.map +1 -0
  245. package/dist/infrastructure/oracle/oracle-chain.d.ts +101 -0
  246. package/dist/infrastructure/oracle/oracle-chain.d.ts.map +1 -0
  247. package/dist/infrastructure/oracle/oracle-chain.js +163 -0
  248. package/dist/infrastructure/oracle/oracle-chain.js.map +1 -0
  249. package/dist/infrastructure/oracle/oracle-errors.d.ts +42 -0
  250. package/dist/infrastructure/oracle/oracle-errors.d.ts.map +1 -0
  251. package/dist/infrastructure/oracle/oracle-errors.js +53 -0
  252. package/dist/infrastructure/oracle/oracle-errors.js.map +1 -0
  253. package/dist/infrastructure/oracle/price-age.d.ts +38 -0
  254. package/dist/infrastructure/oracle/price-age.d.ts.map +1 -0
  255. package/dist/infrastructure/oracle/price-age.js +44 -0
  256. package/dist/infrastructure/oracle/price-age.js.map +1 -0
  257. package/dist/infrastructure/oracle/price-cache.d.ts +99 -0
  258. package/dist/infrastructure/oracle/price-cache.d.ts.map +1 -0
  259. package/dist/infrastructure/oracle/price-cache.js +173 -0
  260. package/dist/infrastructure/oracle/price-cache.js.map +1 -0
  261. package/dist/infrastructure/oracle/pyth-feed-ids.d.ts +31 -0
  262. package/dist/infrastructure/oracle/pyth-feed-ids.d.ts.map +1 -0
  263. package/dist/infrastructure/oracle/pyth-feed-ids.js +44 -0
  264. package/dist/infrastructure/oracle/pyth-feed-ids.js.map +1 -0
  265. package/dist/infrastructure/oracle/pyth-oracle.d.ts +69 -0
  266. package/dist/infrastructure/oracle/pyth-oracle.d.ts.map +1 -0
  267. package/dist/infrastructure/oracle/pyth-oracle.js +149 -0
  268. package/dist/infrastructure/oracle/pyth-oracle.js.map +1 -0
  269. package/dist/infrastructure/settings/hot-reload.d.ts +71 -0
  270. package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -0
  271. package/dist/infrastructure/settings/hot-reload.js +315 -0
  272. package/dist/infrastructure/settings/hot-reload.js.map +1 -0
  273. package/dist/infrastructure/settings/index.d.ts +13 -0
  274. package/dist/infrastructure/settings/index.d.ts.map +1 -0
  275. package/dist/infrastructure/settings/index.js +10 -0
  276. package/dist/infrastructure/settings/index.js.map +1 -0
  277. package/dist/infrastructure/settings/setting-keys.d.ts +28 -0
  278. package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -0
  279. package/dist/infrastructure/settings/setting-keys.js +105 -0
  280. package/dist/infrastructure/settings/setting-keys.js.map +1 -0
  281. package/dist/infrastructure/settings/settings-crypto.d.ts +39 -0
  282. package/dist/infrastructure/settings/settings-crypto.d.ts.map +1 -0
  283. package/dist/infrastructure/settings/settings-crypto.js +73 -0
  284. package/dist/infrastructure/settings/settings-crypto.js.map +1 -0
  285. package/dist/infrastructure/settings/settings-service.d.ts +82 -0
  286. package/dist/infrastructure/settings/settings-service.d.ts.map +1 -0
  287. package/dist/infrastructure/settings/settings-service.js +267 -0
  288. package/dist/infrastructure/settings/settings-service.js.map +1 -0
  289. package/dist/infrastructure/telegram/index.d.ts +6 -0
  290. package/dist/infrastructure/telegram/index.d.ts.map +1 -0
  291. package/dist/infrastructure/telegram/index.js +5 -0
  292. package/dist/infrastructure/telegram/index.js.map +1 -0
  293. package/dist/infrastructure/telegram/telegram-api.d.ts +35 -0
  294. package/dist/infrastructure/telegram/telegram-api.d.ts.map +1 -0
  295. package/dist/infrastructure/telegram/telegram-api.js +82 -0
  296. package/dist/infrastructure/telegram/telegram-api.js.map +1 -0
  297. package/dist/infrastructure/telegram/telegram-auth.d.ts +57 -0
  298. package/dist/infrastructure/telegram/telegram-auth.d.ts.map +1 -0
  299. package/dist/infrastructure/telegram/telegram-auth.js +88 -0
  300. package/dist/infrastructure/telegram/telegram-auth.js.map +1 -0
  301. package/dist/infrastructure/telegram/telegram-bot-service.d.ts +95 -0
  302. package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -0
  303. package/dist/infrastructure/telegram/telegram-bot-service.js +564 -0
  304. package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -0
  305. package/dist/infrastructure/telegram/telegram-keyboard.d.ts +27 -0
  306. package/dist/infrastructure/telegram/telegram-keyboard.d.ts.map +1 -0
  307. package/dist/infrastructure/telegram/telegram-keyboard.js +52 -0
  308. package/dist/infrastructure/telegram/telegram-keyboard.js.map +1 -0
  309. package/dist/infrastructure/telegram/telegram-types.d.ts +43 -0
  310. package/dist/infrastructure/telegram/telegram-types.d.ts.map +1 -0
  311. package/dist/infrastructure/telegram/telegram-types.js +8 -0
  312. package/dist/infrastructure/telegram/telegram-types.js.map +1 -0
  313. package/dist/infrastructure/token-registry/builtin-tokens.d.ts +39 -0
  314. package/dist/infrastructure/token-registry/builtin-tokens.d.ts.map +1 -0
  315. package/dist/infrastructure/token-registry/builtin-tokens.js +135 -0
  316. package/dist/infrastructure/token-registry/builtin-tokens.js.map +1 -0
  317. package/dist/infrastructure/token-registry/index.d.ts +8 -0
  318. package/dist/infrastructure/token-registry/index.d.ts.map +1 -0
  319. package/dist/infrastructure/token-registry/index.js +8 -0
  320. package/dist/infrastructure/token-registry/index.js.map +1 -0
  321. package/dist/infrastructure/token-registry/token-registry-service.d.ts +49 -0
  322. package/dist/infrastructure/token-registry/token-registry-service.d.ts.map +1 -0
  323. package/dist/infrastructure/token-registry/token-registry-service.js +93 -0
  324. package/dist/infrastructure/token-registry/token-registry-service.js.map +1 -0
  325. package/dist/infrastructure/version/index.d.ts +5 -0
  326. package/dist/infrastructure/version/index.d.ts.map +1 -0
  327. package/dist/infrastructure/version/index.js +5 -0
  328. package/dist/infrastructure/version/index.js.map +1 -0
  329. package/dist/infrastructure/version/version-check-service.d.ts +35 -0
  330. package/dist/infrastructure/version/version-check-service.d.ts.map +1 -0
  331. package/dist/infrastructure/version/version-check-service.js +92 -0
  332. package/dist/infrastructure/version/version-check-service.js.map +1 -0
  333. package/dist/lifecycle/daemon.d.ts +103 -0
  334. package/dist/lifecycle/daemon.d.ts.map +1 -0
  335. package/dist/lifecycle/daemon.js +934 -0
  336. package/dist/lifecycle/daemon.js.map +1 -0
  337. package/dist/lifecycle/index.d.ts +9 -0
  338. package/dist/lifecycle/index.d.ts.map +1 -0
  339. package/dist/lifecycle/index.js +9 -0
  340. package/dist/lifecycle/index.js.map +1 -0
  341. package/dist/lifecycle/signal-handler.d.ts +18 -0
  342. package/dist/lifecycle/signal-handler.d.ts.map +1 -0
  343. package/dist/lifecycle/signal-handler.js +37 -0
  344. package/dist/lifecycle/signal-handler.js.map +1 -0
  345. package/dist/lifecycle/workers.d.ts +46 -0
  346. package/dist/lifecycle/workers.d.ts.map +1 -0
  347. package/dist/lifecycle/workers.js +101 -0
  348. package/dist/lifecycle/workers.js.map +1 -0
  349. package/dist/notifications/channels/discord.d.ts +10 -0
  350. package/dist/notifications/channels/discord.d.ts.map +1 -0
  351. package/dist/notifications/channels/discord.js +54 -0
  352. package/dist/notifications/channels/discord.js.map +1 -0
  353. package/dist/notifications/channels/ntfy.d.ts +13 -0
  354. package/dist/notifications/channels/ntfy.d.ts.map +1 -0
  355. package/dist/notifications/channels/ntfy.js +58 -0
  356. package/dist/notifications/channels/ntfy.js.map +1 -0
  357. package/dist/notifications/channels/slack.d.ts +10 -0
  358. package/dist/notifications/channels/slack.d.ts.map +1 -0
  359. package/dist/notifications/channels/slack.js +55 -0
  360. package/dist/notifications/channels/slack.js.map +1 -0
  361. package/dist/notifications/channels/telegram.d.ts +10 -0
  362. package/dist/notifications/channels/telegram.d.ts.map +1 -0
  363. package/dist/notifications/channels/telegram.js +40 -0
  364. package/dist/notifications/channels/telegram.js.map +1 -0
  365. package/dist/notifications/index.d.ts +9 -0
  366. package/dist/notifications/index.d.ts.map +1 -0
  367. package/dist/notifications/index.js +7 -0
  368. package/dist/notifications/index.js.map +1 -0
  369. package/dist/notifications/notification-service.d.ts +75 -0
  370. package/dist/notifications/notification-service.d.ts.map +1 -0
  371. package/dist/notifications/notification-service.js +213 -0
  372. package/dist/notifications/notification-service.js.map +1 -0
  373. package/dist/notifications/templates/message-templates.d.ts +12 -0
  374. package/dist/notifications/templates/message-templates.d.ts.map +1 -0
  375. package/dist/notifications/templates/message-templates.js +22 -0
  376. package/dist/notifications/templates/message-templates.js.map +1 -0
  377. package/dist/pipeline/database-policy-engine.d.ts +286 -0
  378. package/dist/pipeline/database-policy-engine.d.ts.map +1 -0
  379. package/dist/pipeline/database-policy-engine.js +992 -0
  380. package/dist/pipeline/database-policy-engine.js.map +1 -0
  381. package/dist/pipeline/default-policy-engine.d.ts +26 -0
  382. package/dist/pipeline/default-policy-engine.d.ts.map +1 -0
  383. package/dist/pipeline/default-policy-engine.js +25 -0
  384. package/dist/pipeline/default-policy-engine.js.map +1 -0
  385. package/dist/pipeline/index.d.ts +9 -0
  386. package/dist/pipeline/index.d.ts.map +1 -0
  387. package/dist/pipeline/index.js +9 -0
  388. package/dist/pipeline/index.js.map +1 -0
  389. package/dist/pipeline/network-resolver.d.ts +22 -0
  390. package/dist/pipeline/network-resolver.d.ts.map +1 -0
  391. package/dist/pipeline/network-resolver.js +32 -0
  392. package/dist/pipeline/network-resolver.js.map +1 -0
  393. package/dist/pipeline/pipeline.d.ts +72 -0
  394. package/dist/pipeline/pipeline.d.ts.map +1 -0
  395. package/dist/pipeline/pipeline.js +87 -0
  396. package/dist/pipeline/pipeline.js.map +1 -0
  397. package/dist/pipeline/resolve-effective-amount-usd.d.ts +41 -0
  398. package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -0
  399. package/dist/pipeline/resolve-effective-amount-usd.js +208 -0
  400. package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -0
  401. package/dist/pipeline/sign-only.d.ts +99 -0
  402. package/dist/pipeline/sign-only.d.ts.map +1 -0
  403. package/dist/pipeline/sign-only.js +267 -0
  404. package/dist/pipeline/sign-only.js.map +1 -0
  405. package/dist/pipeline/sleep.d.ts +6 -0
  406. package/dist/pipeline/sleep.d.ts.map +1 -0
  407. package/dist/pipeline/sleep.js +8 -0
  408. package/dist/pipeline/sleep.js.map +1 -0
  409. package/dist/pipeline/stages.d.ts +82 -0
  410. package/dist/pipeline/stages.d.ts.map +1 -0
  411. package/dist/pipeline/stages.js +784 -0
  412. package/dist/pipeline/stages.js.map +1 -0
  413. package/dist/services/autostop-rules.d.ts +79 -0
  414. package/dist/services/autostop-rules.d.ts.map +1 -0
  415. package/dist/services/autostop-rules.js +174 -0
  416. package/dist/services/autostop-rules.js.map +1 -0
  417. package/dist/services/autostop-service.d.ts +82 -0
  418. package/dist/services/autostop-service.d.ts.map +1 -0
  419. package/dist/services/autostop-service.js +223 -0
  420. package/dist/services/autostop-service.js.map +1 -0
  421. package/dist/services/kill-switch-service.d.ts +118 -0
  422. package/dist/services/kill-switch-service.d.ts.map +1 -0
  423. package/dist/services/kill-switch-service.js +291 -0
  424. package/dist/services/kill-switch-service.js.map +1 -0
  425. package/dist/services/monitoring/balance-monitor-service.d.ts +65 -0
  426. package/dist/services/monitoring/balance-monitor-service.d.ts.map +1 -0
  427. package/dist/services/monitoring/balance-monitor-service.js +207 -0
  428. package/dist/services/monitoring/balance-monitor-service.js.map +1 -0
  429. package/dist/services/wc-session-service.d.ts +123 -0
  430. package/dist/services/wc-session-service.d.ts.map +1 -0
  431. package/dist/services/wc-session-service.js +363 -0
  432. package/dist/services/wc-session-service.js.map +1 -0
  433. package/dist/services/wc-signing-bridge.d.ts +60 -0
  434. package/dist/services/wc-signing-bridge.d.ts.map +1 -0
  435. package/dist/services/wc-signing-bridge.js +334 -0
  436. package/dist/services/wc-signing-bridge.js.map +1 -0
  437. package/dist/services/wc-storage.d.ts +32 -0
  438. package/dist/services/wc-storage.d.ts.map +1 -0
  439. package/dist/services/wc-storage.js +64 -0
  440. package/dist/services/wc-storage.js.map +1 -0
  441. package/dist/services/x402/payment-signer.d.ts +88 -0
  442. package/dist/services/x402/payment-signer.d.ts.map +1 -0
  443. package/dist/services/x402/payment-signer.js +311 -0
  444. package/dist/services/x402/payment-signer.js.map +1 -0
  445. package/dist/services/x402/ssrf-guard.d.ts +27 -0
  446. package/dist/services/x402/ssrf-guard.d.ts.map +1 -0
  447. package/dist/services/x402/ssrf-guard.js +236 -0
  448. package/dist/services/x402/ssrf-guard.js.map +1 -0
  449. package/dist/services/x402/x402-domain-policy.d.ts +50 -0
  450. package/dist/services/x402/x402-domain-policy.d.ts.map +1 -0
  451. package/dist/services/x402/x402-domain-policy.js +78 -0
  452. package/dist/services/x402/x402-domain-policy.js.map +1 -0
  453. package/dist/services/x402/x402-handler.d.ts +71 -0
  454. package/dist/services/x402/x402-handler.d.ts.map +1 -0
  455. package/dist/services/x402/x402-handler.js +195 -0
  456. package/dist/services/x402/x402-handler.js.map +1 -0
  457. package/dist/services/x402/x402-usd-resolver.d.ts +26 -0
  458. package/dist/services/x402/x402-usd-resolver.d.ts.map +1 -0
  459. package/dist/services/x402/x402-usd-resolver.js +79 -0
  460. package/dist/services/x402/x402-usd-resolver.js.map +1 -0
  461. package/dist/workflow/approval-workflow.d.ts +103 -0
  462. package/dist/workflow/approval-workflow.d.ts.map +1 -0
  463. package/dist/workflow/approval-workflow.js +202 -0
  464. package/dist/workflow/approval-workflow.js.map +1 -0
  465. package/dist/workflow/delay-queue.d.ts +78 -0
  466. package/dist/workflow/delay-queue.d.ts.map +1 -0
  467. package/dist/workflow/delay-queue.js +174 -0
  468. package/dist/workflow/delay-queue.js.map +1 -0
  469. package/dist/workflow/index.d.ts +11 -0
  470. package/dist/workflow/index.d.ts.map +1 -0
  471. package/dist/workflow/index.js +9 -0
  472. package/dist/workflow/index.js.map +1 -0
  473. package/dist/workflow/owner-state.d.ts +97 -0
  474. package/dist/workflow/owner-state.d.ts.map +1 -0
  475. package/dist/workflow/owner-state.js +168 -0
  476. package/dist/workflow/owner-state.js.map +1 -0
  477. package/package.json +71 -0
  478. package/public/admin/assets/index-BPoUSH8W.css +1 -0
  479. package/public/admin/assets/index-CDi1qoXB.js +1 -0
  480. package/public/admin/index.html +13 -0
@@ -0,0 +1,1304 @@
1
+ /**
2
+ * Admin route handlers: 22 daemon administration endpoints.
3
+ *
4
+ * GET /admin/status - Daemon health/uptime/version (masterAuth)
5
+ * POST /admin/kill-switch - Activate kill switch (masterAuth)
6
+ * GET /admin/kill-switch - Get kill switch state (public)
7
+ * POST /admin/recover - Deactivate kill switch (masterAuth)
8
+ * POST /admin/shutdown - Graceful daemon shutdown (masterAuth)
9
+ * POST /admin/rotate-secret - Rotate JWT secret (masterAuth)
10
+ * GET /admin/notifications/status - Notification channel status (masterAuth)
11
+ * POST /admin/notifications/test - Send test notification (masterAuth)
12
+ * GET /admin/notifications/log - Query notification logs (masterAuth)
13
+ * GET /admin/settings - Get all settings (masterAuth)
14
+ * PUT /admin/settings - Update settings (masterAuth)
15
+ * POST /admin/settings/test-rpc - Test RPC connectivity (masterAuth)
16
+ * GET /admin/oracle-status - Oracle cache/source/cross-validation status (masterAuth)
17
+ * GET /admin/api-keys - List Action Provider API key status (masterAuth)
18
+ * PUT /admin/api-keys/:provider - Set or update API key (masterAuth)
19
+ * DELETE /admin/api-keys/:provider - Delete API key (masterAuth)
20
+ * GET /admin/forex/rates - Forex exchange rates for display currency (masterAuth)
21
+ * GET /admin/telegram-users - List Telegram bot users (masterAuth)
22
+ * PUT /admin/telegram-users/:chatId - Update Telegram user role (masterAuth)
23
+ * DELETE /admin/telegram-users/:chatId - Delete Telegram user (masterAuth)
24
+ *
25
+ * @see docs/37-rest-api-complete-spec.md
26
+ * @see docs/36-killswitch-evm-freeze.md
27
+ */
28
+ import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
29
+ import { sql, desc, eq, and, count as drizzleCount } from 'drizzle-orm';
30
+ import { WAIaaSError, getDefaultNetwork } from '@waiaas/core';
31
+ import { CurrencyCodeSchema, formatRatePreview } from '@waiaas/core';
32
+ import { wallets, sessions, notificationLogs, policies, transactions } from '../../infrastructure/database/schema.js';
33
+ import { getSettingDefinition } from '../../infrastructure/settings/index.js';
34
+ import { resolveRpcUrl } from '../../infrastructure/adapter-pool.js';
35
+ import { AdminStatusResponseSchema, KillSwitchResponseSchema, KillSwitchActivateResponseSchema, KillSwitchEscalateResponseSchema, RecoverResponseSchema, KillSwitchRecoverRequestSchema, ShutdownResponseSchema, RotateSecretResponseSchema, NotificationStatusResponseSchema, NotificationTestRequestSchema, NotificationTestResponseSchema, NotificationLogResponseSchema, SettingsResponseSchema, SettingsUpdateRequestSchema, SettingsUpdateResponseSchema, TestRpcRequestSchema, TestRpcResponseSchema, OracleStatusResponseSchema, buildErrorResponses, openApiValidationHook, } from './openapi-schemas.js';
36
+ // ---------------------------------------------------------------------------
37
+ // Route definitions
38
+ // ---------------------------------------------------------------------------
39
+ const statusRoute = createRoute({
40
+ method: 'get',
41
+ path: '/admin/status',
42
+ tags: ['Admin'],
43
+ summary: 'Get daemon status',
44
+ responses: {
45
+ 200: {
46
+ description: 'Daemon status',
47
+ content: { 'application/json': { schema: AdminStatusResponseSchema } },
48
+ },
49
+ },
50
+ });
51
+ const activateKillSwitchRoute = createRoute({
52
+ method: 'post',
53
+ path: '/admin/kill-switch',
54
+ tags: ['Admin'],
55
+ summary: 'Activate kill switch',
56
+ responses: {
57
+ 200: {
58
+ description: 'Kill switch activated',
59
+ content: { 'application/json': { schema: KillSwitchActivateResponseSchema } },
60
+ },
61
+ ...buildErrorResponses(['KILL_SWITCH_ACTIVE']),
62
+ },
63
+ });
64
+ const getKillSwitchRoute = createRoute({
65
+ method: 'get',
66
+ path: '/admin/kill-switch',
67
+ tags: ['Admin'],
68
+ summary: 'Get kill switch state',
69
+ responses: {
70
+ 200: {
71
+ description: 'Kill switch state',
72
+ content: { 'application/json': { schema: KillSwitchResponseSchema } },
73
+ },
74
+ },
75
+ });
76
+ const escalateKillSwitchRoute = createRoute({
77
+ method: 'post',
78
+ path: '/admin/kill-switch/escalate',
79
+ tags: ['Admin'],
80
+ summary: 'Escalate kill switch to LOCKED',
81
+ responses: {
82
+ 200: {
83
+ description: 'Kill switch escalated to LOCKED',
84
+ content: { 'application/json': { schema: KillSwitchEscalateResponseSchema } },
85
+ },
86
+ ...buildErrorResponses(['INVALID_STATE_TRANSITION']),
87
+ },
88
+ });
89
+ const recoverRoute = createRoute({
90
+ method: 'post',
91
+ path: '/admin/recover',
92
+ tags: ['Admin'],
93
+ summary: 'Recover from kill switch (dual-auth)',
94
+ request: {
95
+ body: {
96
+ content: { 'application/json': { schema: KillSwitchRecoverRequestSchema } },
97
+ required: false,
98
+ },
99
+ },
100
+ responses: {
101
+ 200: {
102
+ description: 'Kill switch deactivated',
103
+ content: { 'application/json': { schema: RecoverResponseSchema } },
104
+ },
105
+ ...buildErrorResponses(['KILL_SWITCH_NOT_ACTIVE', 'INVALID_STATE_TRANSITION', 'INVALID_SIGNATURE']),
106
+ },
107
+ });
108
+ const shutdownRoute = createRoute({
109
+ method: 'post',
110
+ path: '/admin/shutdown',
111
+ tags: ['Admin'],
112
+ summary: 'Initiate graceful shutdown',
113
+ responses: {
114
+ 200: {
115
+ description: 'Shutdown initiated',
116
+ content: { 'application/json': { schema: ShutdownResponseSchema } },
117
+ },
118
+ },
119
+ });
120
+ const rotateSecretRoute = createRoute({
121
+ method: 'post',
122
+ path: '/admin/rotate-secret',
123
+ tags: ['Admin'],
124
+ summary: 'Rotate JWT secret',
125
+ responses: {
126
+ 200: {
127
+ description: 'JWT secret rotated',
128
+ content: { 'application/json': { schema: RotateSecretResponseSchema } },
129
+ },
130
+ ...buildErrorResponses(['ROTATION_TOO_RECENT']),
131
+ },
132
+ });
133
+ const notificationsStatusRoute = createRoute({
134
+ method: 'get',
135
+ path: '/admin/notifications/status',
136
+ tags: ['Admin'],
137
+ summary: 'Get notification channel status',
138
+ responses: {
139
+ 200: {
140
+ description: 'Notification channel status (no credentials)',
141
+ content: { 'application/json': { schema: NotificationStatusResponseSchema } },
142
+ },
143
+ },
144
+ });
145
+ const notificationsTestRoute = createRoute({
146
+ method: 'post',
147
+ path: '/admin/notifications/test',
148
+ tags: ['Admin'],
149
+ summary: 'Send test notification',
150
+ request: {
151
+ body: {
152
+ content: { 'application/json': { schema: NotificationTestRequestSchema } },
153
+ required: false,
154
+ },
155
+ },
156
+ responses: {
157
+ 200: {
158
+ description: 'Test notification results',
159
+ content: { 'application/json': { schema: NotificationTestResponseSchema } },
160
+ },
161
+ },
162
+ });
163
+ const notificationLogQuerySchema = z.object({
164
+ page: z.string().optional().default('1'),
165
+ pageSize: z.string().optional().default('20'),
166
+ channel: z.string().optional(),
167
+ status: z.string().optional(),
168
+ });
169
+ const notificationsLogRoute = createRoute({
170
+ method: 'get',
171
+ path: '/admin/notifications/log',
172
+ tags: ['Admin'],
173
+ summary: 'Query notification delivery logs',
174
+ request: {
175
+ query: notificationLogQuerySchema,
176
+ },
177
+ responses: {
178
+ 200: {
179
+ description: 'Paginated notification logs',
180
+ content: { 'application/json': { schema: NotificationLogResponseSchema } },
181
+ },
182
+ },
183
+ });
184
+ // ---------------------------------------------------------------------------
185
+ // Settings route definitions
186
+ // ---------------------------------------------------------------------------
187
+ const settingsGetRoute = createRoute({
188
+ method: 'get',
189
+ path: '/admin/settings',
190
+ tags: ['Admin'],
191
+ summary: 'Get all settings grouped by category',
192
+ responses: {
193
+ 200: {
194
+ description: 'All settings with credentials masked as boolean',
195
+ content: { 'application/json': { schema: SettingsResponseSchema } },
196
+ },
197
+ },
198
+ });
199
+ const settingsPutRoute = createRoute({
200
+ method: 'put',
201
+ path: '/admin/settings',
202
+ tags: ['Admin'],
203
+ summary: 'Update settings',
204
+ request: {
205
+ body: {
206
+ content: { 'application/json': { schema: SettingsUpdateRequestSchema } },
207
+ required: true,
208
+ },
209
+ },
210
+ responses: {
211
+ 200: {
212
+ description: 'Updated settings',
213
+ content: { 'application/json': { schema: SettingsUpdateResponseSchema } },
214
+ },
215
+ ...buildErrorResponses(['ACTION_VALIDATION_FAILED']),
216
+ },
217
+ });
218
+ const testRpcRoute = createRoute({
219
+ method: 'post',
220
+ path: '/admin/settings/test-rpc',
221
+ tags: ['Admin'],
222
+ summary: 'Test RPC endpoint connectivity',
223
+ request: {
224
+ body: {
225
+ content: { 'application/json': { schema: TestRpcRequestSchema } },
226
+ required: true,
227
+ },
228
+ },
229
+ responses: {
230
+ 200: {
231
+ description: 'RPC connectivity test result',
232
+ content: { 'application/json': { schema: TestRpcResponseSchema } },
233
+ },
234
+ },
235
+ });
236
+ // ---------------------------------------------------------------------------
237
+ // Oracle status route definition
238
+ // ---------------------------------------------------------------------------
239
+ const oracleStatusRoute = createRoute({
240
+ method: 'get',
241
+ path: '/admin/oracle-status',
242
+ tags: ['Admin'],
243
+ summary: 'Get oracle cache statistics and source status',
244
+ responses: {
245
+ 200: {
246
+ description: 'Oracle status',
247
+ content: { 'application/json': { schema: OracleStatusResponseSchema } },
248
+ },
249
+ },
250
+ });
251
+ // ---------------------------------------------------------------------------
252
+ // API Keys route definitions
253
+ // ---------------------------------------------------------------------------
254
+ const apiKeysListResponseSchema = z.object({
255
+ keys: z.array(z.object({
256
+ providerName: z.string(),
257
+ hasKey: z.boolean(),
258
+ maskedKey: z.string().nullable(),
259
+ requiresApiKey: z.boolean(),
260
+ updatedAt: z.string().nullable(),
261
+ })),
262
+ });
263
+ const apiKeysListRoute = createRoute({
264
+ method: 'get',
265
+ path: '/admin/api-keys',
266
+ tags: ['Admin'],
267
+ summary: 'List Action Provider API key status',
268
+ responses: {
269
+ 200: {
270
+ description: 'API key status per provider',
271
+ content: { 'application/json': { schema: apiKeysListResponseSchema } },
272
+ },
273
+ },
274
+ });
275
+ const apiKeyPutRoute = createRoute({
276
+ method: 'put',
277
+ path: '/admin/api-keys/{provider}',
278
+ tags: ['Admin'],
279
+ summary: 'Set or update Action Provider API key',
280
+ request: {
281
+ params: z.object({ provider: z.string() }),
282
+ body: {
283
+ content: {
284
+ 'application/json': {
285
+ schema: z.object({ apiKey: z.string().min(1) }),
286
+ },
287
+ },
288
+ required: true,
289
+ },
290
+ },
291
+ responses: {
292
+ 200: {
293
+ description: 'API key saved',
294
+ content: {
295
+ 'application/json': {
296
+ schema: z.object({
297
+ success: z.boolean(),
298
+ providerName: z.string(),
299
+ }),
300
+ },
301
+ },
302
+ },
303
+ },
304
+ });
305
+ const apiKeyDeleteRoute = createRoute({
306
+ method: 'delete',
307
+ path: '/admin/api-keys/{provider}',
308
+ tags: ['Admin'],
309
+ summary: 'Delete Action Provider API key',
310
+ request: {
311
+ params: z.object({ provider: z.string() }),
312
+ },
313
+ responses: {
314
+ 200: {
315
+ description: 'API key deleted',
316
+ content: {
317
+ 'application/json': {
318
+ schema: z.object({ success: z.boolean() }),
319
+ },
320
+ },
321
+ },
322
+ ...buildErrorResponses(['ACTION_NOT_FOUND']),
323
+ },
324
+ });
325
+ // ---------------------------------------------------------------------------
326
+ // Forex rates route definitions
327
+ // ---------------------------------------------------------------------------
328
+ const forexRatesQuerySchema = z.object({
329
+ currencies: z.string().optional().openapi({
330
+ description: 'Comma-separated currency codes (e.g. KRW,JPY,EUR). If omitted, returns empty.',
331
+ }),
332
+ });
333
+ const forexRatesRoute = createRoute({
334
+ method: 'get',
335
+ path: '/admin/forex/rates',
336
+ tags: ['Admin'],
337
+ summary: 'Get forex exchange rates for display currencies',
338
+ request: {
339
+ query: forexRatesQuerySchema,
340
+ },
341
+ responses: {
342
+ 200: {
343
+ description: 'Forex rates with preview strings',
344
+ content: {
345
+ 'application/json': {
346
+ schema: z.object({
347
+ rates: z.record(z.string(), z.object({
348
+ rate: z.number(),
349
+ preview: z.string(),
350
+ })),
351
+ }),
352
+ },
353
+ },
354
+ },
355
+ },
356
+ });
357
+ // ---------------------------------------------------------------------------
358
+ // Admin wallet route definitions
359
+ // ---------------------------------------------------------------------------
360
+ const adminWalletTransactionsRoute = createRoute({
361
+ method: 'get',
362
+ path: '/admin/wallets/{id}/transactions',
363
+ tags: ['Admin'],
364
+ summary: 'Get wallet transactions',
365
+ request: {
366
+ params: z.object({ id: z.string().uuid() }),
367
+ query: z.object({
368
+ limit: z.coerce.number().int().min(1).max(100).default(20).optional(),
369
+ }),
370
+ },
371
+ responses: {
372
+ 200: {
373
+ description: 'Wallet transaction list',
374
+ content: {
375
+ 'application/json': {
376
+ schema: z.object({
377
+ items: z.array(z.object({
378
+ id: z.string(),
379
+ type: z.string(),
380
+ status: z.string(),
381
+ toAddress: z.string().nullable(),
382
+ amount: z.string().nullable(),
383
+ network: z.string().nullable(),
384
+ txHash: z.string().nullable(),
385
+ createdAt: z.number().nullable(),
386
+ })),
387
+ total: z.number().int(),
388
+ }),
389
+ },
390
+ },
391
+ },
392
+ ...buildErrorResponses(['WALLET_NOT_FOUND']),
393
+ },
394
+ });
395
+ const adminWalletBalanceRoute = createRoute({
396
+ method: 'get',
397
+ path: '/admin/wallets/{id}/balance',
398
+ tags: ['Admin'],
399
+ summary: 'Get wallet balance (native + tokens)',
400
+ request: {
401
+ params: z.object({ id: z.string().uuid() }),
402
+ },
403
+ responses: {
404
+ 200: {
405
+ description: 'Wallet balance',
406
+ content: {
407
+ 'application/json': {
408
+ schema: z.object({
409
+ native: z
410
+ .object({
411
+ balance: z.string(),
412
+ symbol: z.string(),
413
+ network: z.string(),
414
+ })
415
+ .nullable(),
416
+ tokens: z.array(z.object({
417
+ symbol: z.string(),
418
+ balance: z.string(),
419
+ address: z.string(),
420
+ })),
421
+ error: z.string().optional(),
422
+ }),
423
+ },
424
+ },
425
+ },
426
+ ...buildErrorResponses(['WALLET_NOT_FOUND']),
427
+ },
428
+ });
429
+ // ---------------------------------------------------------------------------
430
+ // Telegram Users route definitions
431
+ // ---------------------------------------------------------------------------
432
+ const TelegramUserSchema = z.object({
433
+ chat_id: z.number(),
434
+ username: z.string().nullable(),
435
+ role: z.enum(['PENDING', 'ADMIN', 'READONLY']),
436
+ registered_at: z.number(),
437
+ approved_at: z.number().nullable(),
438
+ });
439
+ const telegramUsersListRoute = createRoute({
440
+ method: 'get',
441
+ path: '/admin/telegram-users',
442
+ tags: ['Admin'],
443
+ summary: 'List Telegram bot users',
444
+ responses: {
445
+ 200: {
446
+ description: 'Telegram users list',
447
+ content: {
448
+ 'application/json': {
449
+ schema: z.object({
450
+ users: z.array(TelegramUserSchema),
451
+ total: z.number(),
452
+ }),
453
+ },
454
+ },
455
+ },
456
+ },
457
+ });
458
+ const telegramUserUpdateRoute = createRoute({
459
+ method: 'put',
460
+ path: '/admin/telegram-users/{chatId}',
461
+ tags: ['Admin'],
462
+ summary: 'Update Telegram user role',
463
+ request: {
464
+ params: z.object({ chatId: z.coerce.number() }),
465
+ body: {
466
+ content: {
467
+ 'application/json': {
468
+ schema: z.object({
469
+ role: z.enum(['ADMIN', 'READONLY']),
470
+ }),
471
+ },
472
+ },
473
+ required: true,
474
+ },
475
+ },
476
+ responses: {
477
+ 200: {
478
+ description: 'User role updated',
479
+ content: {
480
+ 'application/json': {
481
+ schema: z.object({
482
+ success: z.boolean(),
483
+ chat_id: z.number(),
484
+ role: z.enum(['ADMIN', 'READONLY']),
485
+ }),
486
+ },
487
+ },
488
+ },
489
+ ...buildErrorResponses(['WALLET_NOT_FOUND']),
490
+ },
491
+ });
492
+ const telegramUserDeleteRoute = createRoute({
493
+ method: 'delete',
494
+ path: '/admin/telegram-users/{chatId}',
495
+ tags: ['Admin'],
496
+ summary: 'Delete Telegram user',
497
+ request: {
498
+ params: z.object({ chatId: z.coerce.number() }),
499
+ },
500
+ responses: {
501
+ 200: {
502
+ description: 'User deleted',
503
+ content: {
504
+ 'application/json': {
505
+ schema: z.object({ success: z.boolean() }),
506
+ },
507
+ },
508
+ },
509
+ ...buildErrorResponses(['WALLET_NOT_FOUND']),
510
+ },
511
+ });
512
+ // ---------------------------------------------------------------------------
513
+ // Route factory
514
+ // ---------------------------------------------------------------------------
515
+ /**
516
+ * Create admin route sub-router.
517
+ *
518
+ * GET /admin/status - Daemon health info (masterAuth)
519
+ * POST /admin/kill-switch - Activate kill switch (masterAuth)
520
+ * GET /admin/kill-switch - Get kill switch state (public)
521
+ * POST /admin/recover - Deactivate kill switch (masterAuth)
522
+ * POST /admin/shutdown - Graceful shutdown (masterAuth)
523
+ * POST /admin/rotate-secret - Rotate JWT secret (masterAuth)
524
+ * GET /admin/notifications/status - Notification channel status (masterAuth)
525
+ * POST /admin/notifications/test - Send test notification (masterAuth)
526
+ * GET /admin/notifications/log - Query notification logs (masterAuth)
527
+ * GET /admin/settings - Get all settings (masterAuth)
528
+ * PUT /admin/settings - Update settings (masterAuth)
529
+ * POST /admin/settings/test-rpc - Test RPC connectivity (masterAuth)
530
+ * GET /admin/oracle-status - Oracle cache/source/cross-validation status (masterAuth)
531
+ * GET /admin/api-keys - List Action Provider API key status (masterAuth)
532
+ * PUT /admin/api-keys/:provider - Set or update API key (masterAuth)
533
+ * DELETE /admin/api-keys/:provider - Delete API key (masterAuth)
534
+ * GET /admin/forex/rates - Forex exchange rates (masterAuth)
535
+ * GET /admin/wallets/:id/balance - Wallet native+token balance (masterAuth)
536
+ * GET /admin/wallets/:id/transactions - Wallet transaction history (masterAuth)
537
+ * GET /admin/telegram-users - List Telegram bot users (masterAuth)
538
+ * PUT /admin/telegram-users/:chatId - Update Telegram user role (masterAuth)
539
+ * DELETE /admin/telegram-users/:chatId - Delete Telegram user (masterAuth)
540
+ */
541
+ export function adminRoutes(deps) {
542
+ const router = new OpenAPIHono({ defaultHook: openApiValidationHook });
543
+ // ---------------------------------------------------------------------------
544
+ // GET /admin/status
545
+ // ---------------------------------------------------------------------------
546
+ router.openapi(statusRoute, async (c) => {
547
+ const nowSec = Math.floor(Date.now() / 1000);
548
+ const uptime = nowSec - deps.startTime;
549
+ // Count wallets
550
+ const walletCountResult = deps.db
551
+ .select({ count: sql `count(*)` })
552
+ .from(wallets)
553
+ .get();
554
+ const walletCount = walletCountResult?.count ?? 0;
555
+ // Count active sessions (not expired, not revoked)
556
+ // Use raw SQL with integer comparison (expiresAt is stored as epoch seconds)
557
+ const activeSessionResult = deps.db
558
+ .select({ count: sql `count(*)` })
559
+ .from(sessions)
560
+ .where(sql `${sessions.revokedAt} IS NULL AND ${sessions.expiresAt} > ${nowSec}`)
561
+ .get();
562
+ const activeSessionCount = activeSessionResult?.count ?? 0;
563
+ // Count policies
564
+ const policyCountResult = deps.db
565
+ .select({ count: sql `count(*)` })
566
+ .from(policies)
567
+ .get();
568
+ const policyCount = policyCountResult?.count ?? 0;
569
+ // Count recent transactions (24h) -- created_at stored as epoch seconds in integer column
570
+ const cutoffSec = nowSec - 86400;
571
+ const recentTxCountResult = deps.db
572
+ .select({ count: sql `count(*)` })
573
+ .from(transactions)
574
+ .where(sql `${transactions.createdAt} > ${cutoffSec}`)
575
+ .get();
576
+ const recentTxCount = recentTxCountResult?.count ?? 0;
577
+ // Count failed transactions (24h)
578
+ const failedTxCountResult = deps.db
579
+ .select({ count: sql `count(*)` })
580
+ .from(transactions)
581
+ .where(sql `${transactions.status} = 'FAILED' AND ${transactions.createdAt} > ${cutoffSec}`)
582
+ .get();
583
+ const failedTxCount = failedTxCountResult?.count ?? 0;
584
+ // Recent 5 transactions with wallet name
585
+ const recentTxRows = deps.db
586
+ .select({
587
+ id: transactions.id,
588
+ walletId: transactions.walletId,
589
+ walletName: wallets.name,
590
+ type: transactions.type,
591
+ status: transactions.status,
592
+ toAddress: transactions.toAddress,
593
+ amount: transactions.amount,
594
+ amountUsd: transactions.amountUsd,
595
+ network: transactions.network,
596
+ createdAt: transactions.createdAt,
597
+ })
598
+ .from(transactions)
599
+ .leftJoin(wallets, eq(transactions.walletId, wallets.id))
600
+ .orderBy(desc(transactions.createdAt))
601
+ .limit(5)
602
+ .all();
603
+ const recentTransactions = recentTxRows.map((tx) => ({
604
+ id: tx.id,
605
+ walletId: tx.walletId,
606
+ walletName: tx.walletName ?? null,
607
+ type: tx.type,
608
+ status: tx.status,
609
+ toAddress: tx.toAddress ?? null,
610
+ amount: tx.amount ?? null,
611
+ amountUsd: tx.amountUsd ?? null,
612
+ network: tx.network ?? null,
613
+ createdAt: tx.createdAt instanceof Date
614
+ ? Math.floor(tx.createdAt.getTime() / 1000)
615
+ : (typeof tx.createdAt === 'number' ? tx.createdAt : null),
616
+ }));
617
+ const ksState = deps.killSwitchService
618
+ ? deps.killSwitchService.getState()
619
+ : deps.getKillSwitchState();
620
+ return c.json({
621
+ status: 'running',
622
+ version: deps.version,
623
+ uptime,
624
+ walletCount,
625
+ activeSessionCount,
626
+ killSwitchState: ksState.state,
627
+ adminTimeout: deps.adminTimeout,
628
+ timestamp: nowSec,
629
+ policyCount,
630
+ recentTxCount,
631
+ failedTxCount,
632
+ recentTransactions,
633
+ }, 200);
634
+ });
635
+ // ---------------------------------------------------------------------------
636
+ // POST /admin/kill-switch
637
+ // ---------------------------------------------------------------------------
638
+ router.openapi(activateKillSwitchRoute, async (c) => {
639
+ if (deps.killSwitchService) {
640
+ const result = deps.killSwitchService.activateWithCascade('master');
641
+ if (!result.success) {
642
+ throw new WAIaaSError('KILL_SWITCH_ACTIVE', {
643
+ message: result.error ?? 'Kill switch is already active',
644
+ });
645
+ }
646
+ const state = deps.killSwitchService.getState();
647
+ return c.json({
648
+ state: 'SUSPENDED',
649
+ activatedAt: state.activatedAt ?? Math.floor(Date.now() / 1000),
650
+ }, 200);
651
+ }
652
+ // Legacy fallback (no KillSwitchService)
653
+ const ksState = deps.getKillSwitchState();
654
+ if (ksState.state !== 'ACTIVE' && ksState.state !== 'NORMAL') {
655
+ throw new WAIaaSError('KILL_SWITCH_ACTIVE', {
656
+ message: 'Kill switch is already activated',
657
+ });
658
+ }
659
+ const nowSec = Math.floor(Date.now() / 1000);
660
+ deps.setKillSwitchState('SUSPENDED', 'master');
661
+ return c.json({
662
+ state: 'SUSPENDED',
663
+ activatedAt: nowSec,
664
+ }, 200);
665
+ });
666
+ // ---------------------------------------------------------------------------
667
+ // GET /admin/kill-switch
668
+ // ---------------------------------------------------------------------------
669
+ router.openapi(getKillSwitchRoute, async (c) => {
670
+ if (deps.killSwitchService) {
671
+ const ksState = deps.killSwitchService.getState();
672
+ return c.json({
673
+ state: ksState.state,
674
+ activatedAt: ksState.activatedAt,
675
+ activatedBy: ksState.activatedBy,
676
+ }, 200);
677
+ }
678
+ const ksState = deps.getKillSwitchState();
679
+ return c.json({
680
+ state: ksState.state,
681
+ activatedAt: ksState.activatedAt,
682
+ activatedBy: ksState.activatedBy,
683
+ }, 200);
684
+ });
685
+ // ---------------------------------------------------------------------------
686
+ // POST /admin/kill-switch/escalate
687
+ // ---------------------------------------------------------------------------
688
+ router.openapi(escalateKillSwitchRoute, async (c) => {
689
+ if (deps.killSwitchService) {
690
+ const result = deps.killSwitchService.escalateWithCascade('master');
691
+ if (!result.success) {
692
+ throw new WAIaaSError('INVALID_STATE_TRANSITION', {
693
+ message: result.error ?? 'Cannot escalate kill switch',
694
+ });
695
+ }
696
+ const state = deps.killSwitchService.getState();
697
+ return c.json({
698
+ state: 'LOCKED',
699
+ escalatedAt: state.activatedAt ?? Math.floor(Date.now() / 1000),
700
+ }, 200);
701
+ }
702
+ throw new WAIaaSError('INVALID_STATE_TRANSITION', {
703
+ message: 'Kill switch service not available',
704
+ });
705
+ });
706
+ // ---------------------------------------------------------------------------
707
+ // POST /admin/recover (dual-auth recovery)
708
+ // ---------------------------------------------------------------------------
709
+ router.openapi(recoverRoute, async (c) => {
710
+ if (deps.killSwitchService) {
711
+ const currentState = deps.killSwitchService.getState();
712
+ if (currentState.state === 'ACTIVE') {
713
+ throw new WAIaaSError('KILL_SWITCH_NOT_ACTIVE', {
714
+ message: 'Kill switch is not active, nothing to recover',
715
+ });
716
+ }
717
+ // Check if any wallet has an owner registered (dual-auth requirement)
718
+ const body = await c.req.json().catch(() => ({}));
719
+ // Check if any wallet has owner_address set
720
+ const walletsWithOwner = deps.db
721
+ .select({ ownerAddress: wallets.ownerAddress })
722
+ .from(wallets)
723
+ .where(sql `${wallets.ownerAddress} IS NOT NULL`)
724
+ .all();
725
+ const hasOwners = walletsWithOwner.length > 0;
726
+ if (hasOwners) {
727
+ // Dual-auth: owner signature required
728
+ if (!body.ownerSignature || !body.ownerAddress || !body.message) {
729
+ throw new WAIaaSError('INVALID_SIGNATURE', {
730
+ message: 'Owner signature required for recovery (dual-auth). Provide ownerSignature, ownerAddress, chain, and message.',
731
+ });
732
+ }
733
+ // Verify owner address matches a registered wallet owner
734
+ const matchingWallet = walletsWithOwner.find((w) => w.ownerAddress === body.ownerAddress);
735
+ if (!matchingWallet) {
736
+ throw new WAIaaSError('INVALID_SIGNATURE', {
737
+ message: 'Owner address does not match any registered wallet owner',
738
+ });
739
+ }
740
+ // Note: Full signature verification (SIWS/SIWE) is done by ownerAuth
741
+ // middleware in production. For the recover endpoint, the masterAuth
742
+ // middleware handles the master password part, and we verify owner
743
+ // identity by matching ownerAddress to a registered wallet.
744
+ }
745
+ // If no owners registered: master-only recovery (skip owner verification)
746
+ // LOCKED recovery: additional wait time (5 seconds)
747
+ if (currentState.state === 'LOCKED') {
748
+ await new Promise((resolve) => setTimeout(resolve, 5000));
749
+ const success = deps.killSwitchService.recoverFromLocked();
750
+ if (!success) {
751
+ throw new WAIaaSError('INVALID_STATE_TRANSITION', {
752
+ message: 'Failed to recover from LOCKED state (concurrent state change)',
753
+ });
754
+ }
755
+ }
756
+ else {
757
+ // SUSPENDED recovery
758
+ const success = deps.killSwitchService.recoverFromSuspended();
759
+ if (!success) {
760
+ throw new WAIaaSError('INVALID_STATE_TRANSITION', {
761
+ message: 'Failed to recover from SUSPENDED state (concurrent state change)',
762
+ });
763
+ }
764
+ }
765
+ const nowSec = Math.floor(Date.now() / 1000);
766
+ // Send recovery notification
767
+ if (deps.notificationService) {
768
+ void deps.notificationService.notify('KILL_SWITCH_RECOVERED', 'system', {});
769
+ }
770
+ return c.json({
771
+ state: 'ACTIVE',
772
+ recoveredAt: nowSec,
773
+ }, 200);
774
+ }
775
+ // Legacy fallback
776
+ const ksState = deps.getKillSwitchState();
777
+ if (ksState.state === 'NORMAL' || ksState.state === 'ACTIVE') {
778
+ throw new WAIaaSError('KILL_SWITCH_NOT_ACTIVE', {
779
+ message: 'Kill switch is not active, nothing to recover',
780
+ });
781
+ }
782
+ deps.setKillSwitchState('ACTIVE');
783
+ const nowSec = Math.floor(Date.now() / 1000);
784
+ return c.json({
785
+ state: 'ACTIVE',
786
+ recoveredAt: nowSec,
787
+ }, 200);
788
+ });
789
+ // ---------------------------------------------------------------------------
790
+ // POST /admin/shutdown
791
+ // ---------------------------------------------------------------------------
792
+ router.openapi(shutdownRoute, async (c) => {
793
+ if (deps.requestShutdown) {
794
+ deps.requestShutdown();
795
+ }
796
+ return c.json({
797
+ message: 'Shutdown initiated',
798
+ }, 200);
799
+ });
800
+ // ---------------------------------------------------------------------------
801
+ // POST /admin/rotate-secret
802
+ // ---------------------------------------------------------------------------
803
+ router.openapi(rotateSecretRoute, async (c) => {
804
+ if (!deps.jwtSecretManager) {
805
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
806
+ message: 'JWT secret manager not available',
807
+ });
808
+ }
809
+ await deps.jwtSecretManager.rotateSecret();
810
+ const nowSec = Math.floor(Date.now() / 1000);
811
+ return c.json({
812
+ rotatedAt: nowSec,
813
+ message: 'JWT secret rotated. Old tokens valid for 5 minutes.',
814
+ }, 200);
815
+ });
816
+ // ---------------------------------------------------------------------------
817
+ // GET /admin/notifications/status
818
+ // ---------------------------------------------------------------------------
819
+ router.openapi(notificationsStatusRoute, async (c) => {
820
+ const notifConfig = deps.notificationConfig;
821
+ const svc = deps.notificationService;
822
+ const channelNames = svc ? svc.getChannelNames() : [];
823
+ const channels = [
824
+ {
825
+ name: 'telegram',
826
+ enabled: !!(notifConfig?.telegram_bot_token &&
827
+ notifConfig?.telegram_chat_id &&
828
+ channelNames.includes('telegram')),
829
+ },
830
+ {
831
+ name: 'discord',
832
+ enabled: !!(notifConfig?.discord_webhook_url &&
833
+ channelNames.includes('discord')),
834
+ },
835
+ {
836
+ name: 'ntfy',
837
+ enabled: !!(notifConfig?.ntfy_topic &&
838
+ channelNames.includes('ntfy')),
839
+ },
840
+ {
841
+ name: 'slack',
842
+ enabled: !!(notifConfig?.slack_webhook_url &&
843
+ channelNames.includes('slack')),
844
+ },
845
+ ];
846
+ return c.json({
847
+ enabled: notifConfig?.enabled ?? false,
848
+ channels,
849
+ }, 200);
850
+ });
851
+ // ---------------------------------------------------------------------------
852
+ // POST /admin/notifications/test
853
+ // ---------------------------------------------------------------------------
854
+ router.openapi(notificationsTestRoute, async (c) => {
855
+ const svc = deps.notificationService;
856
+ if (!svc) {
857
+ return c.json({ results: [] }, 200);
858
+ }
859
+ const body = await c.req.json().catch(() => ({}));
860
+ const allChannels = svc.getChannels();
861
+ const targetChannels = body.channel
862
+ ? allChannels.filter((ch) => ch.name === body.channel)
863
+ : allChannels;
864
+ const testPayload = {
865
+ eventType: 'TX_CONFIRMED',
866
+ walletId: 'admin-test',
867
+ message: '[Test] WAIaaS notification test',
868
+ timestamp: Math.floor(Date.now() / 1000),
869
+ };
870
+ const results = [];
871
+ for (const ch of targetChannels) {
872
+ try {
873
+ await ch.send(testPayload);
874
+ results.push({ channel: ch.name, success: true });
875
+ }
876
+ catch (err) {
877
+ results.push({
878
+ channel: ch.name,
879
+ success: false,
880
+ error: err instanceof Error ? err.message : String(err),
881
+ });
882
+ }
883
+ }
884
+ return c.json({ results }, 200);
885
+ });
886
+ // ---------------------------------------------------------------------------
887
+ // GET /admin/notifications/log
888
+ // ---------------------------------------------------------------------------
889
+ router.openapi(notificationsLogRoute, async (c) => {
890
+ const query = c.req.valid('query');
891
+ const page = Math.max(1, parseInt(query.page ?? '1', 10) || 1);
892
+ const pageSize = Math.min(100, Math.max(1, parseInt(query.pageSize ?? '20', 10) || 20));
893
+ const offset = (page - 1) * pageSize;
894
+ // Build where conditions
895
+ const conditions = [];
896
+ if (query.channel) {
897
+ conditions.push(eq(notificationLogs.channel, query.channel));
898
+ }
899
+ if (query.status) {
900
+ conditions.push(eq(notificationLogs.status, query.status));
901
+ }
902
+ const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
903
+ // Query total count
904
+ const totalResult = deps.db
905
+ .select({ count: drizzleCount() })
906
+ .from(notificationLogs)
907
+ .where(whereClause)
908
+ .get();
909
+ const total = totalResult?.count ?? 0;
910
+ // Query logs with pagination
911
+ const rows = deps.db
912
+ .select()
913
+ .from(notificationLogs)
914
+ .where(whereClause)
915
+ .orderBy(desc(notificationLogs.createdAt))
916
+ .limit(pageSize)
917
+ .offset(offset)
918
+ .all();
919
+ const logs = rows.map((row) => ({
920
+ id: row.id,
921
+ eventType: row.eventType,
922
+ walletId: row.walletId ?? null,
923
+ channel: row.channel,
924
+ status: row.status,
925
+ error: row.error ?? null,
926
+ message: row.message ?? null,
927
+ createdAt: row.createdAt instanceof Date
928
+ ? Math.floor(row.createdAt.getTime() / 1000)
929
+ : (typeof row.createdAt === 'number' ? row.createdAt : 0),
930
+ }));
931
+ return c.json({ logs, total, page, pageSize }, 200);
932
+ });
933
+ // ---------------------------------------------------------------------------
934
+ // GET /admin/settings
935
+ // ---------------------------------------------------------------------------
936
+ router.openapi(settingsGetRoute, async (c) => {
937
+ if (!deps.settingsService) {
938
+ return c.json({
939
+ notifications: {},
940
+ rpc: {},
941
+ security: {},
942
+ daemon: {},
943
+ walletconnect: {},
944
+ oracle: {},
945
+ display: {},
946
+ }, 200);
947
+ }
948
+ const masked = deps.settingsService.getAllMasked();
949
+ return c.json({
950
+ notifications: masked.notifications ?? {},
951
+ rpc: masked.rpc ?? {},
952
+ security: masked.security ?? {},
953
+ daemon: masked.daemon ?? {},
954
+ walletconnect: masked.walletconnect ?? {},
955
+ oracle: masked.oracle ?? {},
956
+ display: masked.display ?? {},
957
+ }, 200);
958
+ });
959
+ // ---------------------------------------------------------------------------
960
+ // PUT /admin/settings
961
+ // ---------------------------------------------------------------------------
962
+ router.openapi(settingsPutRoute, async (c) => {
963
+ const body = c.req.valid('json');
964
+ const entries = body.settings;
965
+ // Validate all keys exist in SETTING_DEFINITIONS
966
+ for (const entry of entries) {
967
+ const def = getSettingDefinition(entry.key);
968
+ if (!def) {
969
+ throw new WAIaaSError('ACTION_VALIDATION_FAILED', {
970
+ message: `Unknown setting key: ${entry.key}`,
971
+ });
972
+ }
973
+ }
974
+ if (!deps.settingsService) {
975
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
976
+ message: 'Settings service not available',
977
+ });
978
+ }
979
+ // Persist all values
980
+ deps.settingsService.setMany(entries);
981
+ // Notify hot-reload callback if provided
982
+ if (deps.onSettingsChanged) {
983
+ deps.onSettingsChanged(entries.map((e) => e.key));
984
+ }
985
+ const masked = deps.settingsService.getAllMasked();
986
+ return c.json({
987
+ updated: entries.length,
988
+ settings: {
989
+ notifications: masked.notifications ?? {},
990
+ rpc: masked.rpc ?? {},
991
+ security: masked.security ?? {},
992
+ daemon: masked.daemon ?? {},
993
+ walletconnect: masked.walletconnect ?? {},
994
+ oracle: masked.oracle ?? {},
995
+ display: masked.display ?? {},
996
+ },
997
+ }, 200);
998
+ });
999
+ // ---------------------------------------------------------------------------
1000
+ // POST /admin/settings/test-rpc
1001
+ // ---------------------------------------------------------------------------
1002
+ router.openapi(testRpcRoute, async (c) => {
1003
+ const body = c.req.valid('json');
1004
+ const { url, chain } = body;
1005
+ const rpcMethod = chain === 'solana' ? 'getBlockHeight' : 'eth_blockNumber';
1006
+ const rpcBody = JSON.stringify({
1007
+ jsonrpc: '2.0',
1008
+ method: rpcMethod,
1009
+ params: [],
1010
+ id: 1,
1011
+ });
1012
+ const startMs = performance.now();
1013
+ try {
1014
+ const response = await fetch(url, {
1015
+ method: 'POST',
1016
+ headers: { 'Content-Type': 'application/json' },
1017
+ body: rpcBody,
1018
+ signal: AbortSignal.timeout(5000),
1019
+ });
1020
+ const latencyMs = Math.round(performance.now() - startMs);
1021
+ const result = (await response.json());
1022
+ if (result.error) {
1023
+ return c.json({
1024
+ success: false,
1025
+ latencyMs,
1026
+ error: result.error.message ?? 'RPC error',
1027
+ }, 200);
1028
+ }
1029
+ // Parse block number from result
1030
+ let blockNumber;
1031
+ if (chain === 'solana') {
1032
+ blockNumber = typeof result.result === 'number' ? result.result : undefined;
1033
+ }
1034
+ else {
1035
+ // eth_blockNumber returns hex string
1036
+ blockNumber =
1037
+ typeof result.result === 'string'
1038
+ ? parseInt(result.result, 16)
1039
+ : undefined;
1040
+ }
1041
+ return c.json({
1042
+ success: true,
1043
+ latencyMs,
1044
+ blockNumber,
1045
+ }, 200);
1046
+ }
1047
+ catch (err) {
1048
+ const latencyMs = Math.round(performance.now() - startMs);
1049
+ const errorMessage = err instanceof Error ? err.message : String(err);
1050
+ return c.json({
1051
+ success: false,
1052
+ latencyMs,
1053
+ error: errorMessage,
1054
+ }, 200);
1055
+ }
1056
+ });
1057
+ // ---------------------------------------------------------------------------
1058
+ // GET /admin/oracle-status
1059
+ // ---------------------------------------------------------------------------
1060
+ router.openapi(oracleStatusRoute, async (c) => {
1061
+ const stats = deps.priceOracle?.getCacheStats() ?? { hits: 0, misses: 0, staleHits: 0, size: 0, evictions: 0 };
1062
+ return c.json({
1063
+ cache: stats,
1064
+ sources: {
1065
+ pyth: {
1066
+ available: !!deps.priceOracle,
1067
+ baseUrl: 'https://hermes.pyth.network',
1068
+ },
1069
+ coingecko: {
1070
+ available: deps.oracleConfig?.coingeckoApiKeyConfigured ?? false,
1071
+ apiKeyConfigured: deps.oracleConfig?.coingeckoApiKeyConfigured ?? false,
1072
+ },
1073
+ },
1074
+ crossValidation: {
1075
+ enabled: deps.oracleConfig?.coingeckoApiKeyConfigured ?? false,
1076
+ threshold: deps.oracleConfig?.crossValidationThreshold ?? 5,
1077
+ },
1078
+ }, 200);
1079
+ });
1080
+ // ---------------------------------------------------------------------------
1081
+ // GET /admin/api-keys
1082
+ // ---------------------------------------------------------------------------
1083
+ router.openapi(apiKeysListRoute, async (c) => {
1084
+ const registry = deps.actionProviderRegistry;
1085
+ const store = deps.apiKeyStore;
1086
+ if (!registry) {
1087
+ return c.json({ keys: [] }, 200);
1088
+ }
1089
+ const providers = registry.listProviders();
1090
+ const storedKeys = store ? store.listAll() : [];
1091
+ const storedMap = new Map(storedKeys.map((k) => [k.providerName, k]));
1092
+ const keys = providers.map((p) => {
1093
+ const stored = storedMap.get(p.name);
1094
+ return {
1095
+ providerName: p.name,
1096
+ hasKey: stored?.hasKey ?? false,
1097
+ maskedKey: stored?.maskedKey ?? null,
1098
+ requiresApiKey: p.requiresApiKey ?? false,
1099
+ updatedAt: stored?.updatedAt
1100
+ ? stored.updatedAt.toISOString()
1101
+ : null,
1102
+ };
1103
+ });
1104
+ return c.json({ keys }, 200);
1105
+ });
1106
+ // ---------------------------------------------------------------------------
1107
+ // PUT /admin/api-keys/:provider
1108
+ // ---------------------------------------------------------------------------
1109
+ router.openapi(apiKeyPutRoute, async (c) => {
1110
+ const { provider } = c.req.valid('param');
1111
+ const body = c.req.valid('json');
1112
+ if (!deps.apiKeyStore) {
1113
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
1114
+ message: 'API key store not available',
1115
+ });
1116
+ }
1117
+ deps.apiKeyStore.set(provider, body.apiKey);
1118
+ return c.json({ success: true, providerName: provider }, 200);
1119
+ });
1120
+ // ---------------------------------------------------------------------------
1121
+ // DELETE /admin/api-keys/:provider
1122
+ // ---------------------------------------------------------------------------
1123
+ router.openapi(apiKeyDeleteRoute, async (c) => {
1124
+ const { provider } = c.req.valid('param');
1125
+ if (!deps.apiKeyStore) {
1126
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
1127
+ message: 'API key store not available',
1128
+ });
1129
+ }
1130
+ const deleted = deps.apiKeyStore.delete(provider);
1131
+ if (!deleted) {
1132
+ throw new WAIaaSError('ACTION_NOT_FOUND', {
1133
+ message: `No API key found for provider '${provider}'`,
1134
+ details: { providerName: provider },
1135
+ });
1136
+ }
1137
+ return c.json({ success: true }, 200);
1138
+ });
1139
+ // ---------------------------------------------------------------------------
1140
+ // GET /admin/forex/rates
1141
+ // ---------------------------------------------------------------------------
1142
+ router.openapi(forexRatesRoute, async (c) => {
1143
+ const { currencies: currenciesParam } = c.req.valid('query');
1144
+ const rates = {};
1145
+ if (!currenciesParam || !deps.forexRateService) {
1146
+ return c.json({ rates }, 200);
1147
+ }
1148
+ // Parse comma-separated currency codes, validate each
1149
+ const codes = currenciesParam
1150
+ .split(',')
1151
+ .map((s) => s.trim().toUpperCase())
1152
+ .filter((s) => CurrencyCodeSchema.safeParse(s).success);
1153
+ if (codes.length === 0) {
1154
+ return c.json({ rates }, 200);
1155
+ }
1156
+ const rateMap = await deps.forexRateService.getRates(codes);
1157
+ for (const [code, forexRate] of rateMap) {
1158
+ rates[code] = {
1159
+ rate: forexRate.rate,
1160
+ preview: formatRatePreview(forexRate.rate, code),
1161
+ };
1162
+ }
1163
+ return c.json({ rates }, 200);
1164
+ });
1165
+ // ---------------------------------------------------------------------------
1166
+ // GET /admin/wallets/:id/transactions
1167
+ // ---------------------------------------------------------------------------
1168
+ router.openapi(adminWalletTransactionsRoute, async (c) => {
1169
+ const { id } = c.req.valid('param');
1170
+ const query = c.req.valid('query');
1171
+ const limit = query.limit ?? 20;
1172
+ // Verify wallet exists
1173
+ const wallet = deps.db.select().from(wallets).where(eq(wallets.id, id)).get();
1174
+ if (!wallet) {
1175
+ throw new WAIaaSError('WALLET_NOT_FOUND');
1176
+ }
1177
+ // Query transactions for this wallet
1178
+ const rows = deps.db
1179
+ .select()
1180
+ .from(transactions)
1181
+ .where(eq(transactions.walletId, id))
1182
+ .orderBy(desc(transactions.createdAt))
1183
+ .limit(limit)
1184
+ .all();
1185
+ // Total count
1186
+ const totalResult = deps.db
1187
+ .select({ count: sql `count(*)` })
1188
+ .from(transactions)
1189
+ .where(eq(transactions.walletId, id))
1190
+ .get();
1191
+ const total = totalResult?.count ?? 0;
1192
+ const items = rows.map((tx) => ({
1193
+ id: tx.id,
1194
+ type: tx.type,
1195
+ status: tx.status,
1196
+ toAddress: tx.toAddress ?? null,
1197
+ amount: tx.amount ?? null,
1198
+ amountUsd: tx.amountUsd ?? null,
1199
+ network: tx.network ?? null,
1200
+ txHash: tx.txHash ?? null,
1201
+ createdAt: tx.createdAt instanceof Date
1202
+ ? Math.floor(tx.createdAt.getTime() / 1000)
1203
+ : (typeof tx.createdAt === 'number' ? tx.createdAt : null),
1204
+ }));
1205
+ return c.json({ items, total }, 200);
1206
+ });
1207
+ // ---------------------------------------------------------------------------
1208
+ // GET /admin/wallets/:id/balance
1209
+ // ---------------------------------------------------------------------------
1210
+ router.openapi(adminWalletBalanceRoute, async (c) => {
1211
+ const { id } = c.req.valid('param');
1212
+ // Verify wallet exists
1213
+ const wallet = deps.db.select().from(wallets).where(eq(wallets.id, id)).get();
1214
+ if (!wallet) {
1215
+ throw new WAIaaSError('WALLET_NOT_FOUND');
1216
+ }
1217
+ // If no adapter pool, return null balance
1218
+ if (!deps.adapterPool) {
1219
+ return c.json({ native: null, tokens: [] }, 200);
1220
+ }
1221
+ try {
1222
+ const network = (wallet.defaultNetwork
1223
+ ?? getDefaultNetwork(wallet.chain, wallet.environment));
1224
+ const rpcUrl = resolveRpcUrl(deps.daemonConfig.rpc, wallet.chain, network);
1225
+ const adapter = await deps.adapterPool.resolve(wallet.chain, network, rpcUrl);
1226
+ // Get native balance
1227
+ const balanceInfo = await adapter.getBalance(wallet.publicKey);
1228
+ const nativeBalance = (Number(balanceInfo.balance) / 10 ** balanceInfo.decimals).toString();
1229
+ // Get token assets
1230
+ const assets = await adapter.getAssets(wallet.publicKey);
1231
+ const tokens = assets
1232
+ .filter((a) => !a.isNative)
1233
+ .map((a) => ({
1234
+ symbol: a.symbol,
1235
+ balance: (Number(a.balance) / 10 ** a.decimals).toString(),
1236
+ address: a.mint,
1237
+ }));
1238
+ return c.json({
1239
+ native: { balance: nativeBalance, symbol: balanceInfo.symbol, network },
1240
+ tokens,
1241
+ }, 200);
1242
+ }
1243
+ catch (err) {
1244
+ const errorMessage = err instanceof Error ? err.message : String(err);
1245
+ return c.json({ native: null, tokens: [], error: errorMessage }, 200);
1246
+ }
1247
+ });
1248
+ // ---------------------------------------------------------------------------
1249
+ // GET /admin/telegram-users
1250
+ // ---------------------------------------------------------------------------
1251
+ router.openapi(telegramUsersListRoute, async (c) => {
1252
+ if (!deps.sqlite) {
1253
+ return c.json({ users: [], total: 0 }, 200);
1254
+ }
1255
+ const rows = deps.sqlite
1256
+ .prepare('SELECT chat_id, username, role, registered_at, approved_at FROM telegram_users ORDER BY registered_at DESC')
1257
+ .all();
1258
+ return c.json({ users: rows, total: rows.length }, 200);
1259
+ });
1260
+ // ---------------------------------------------------------------------------
1261
+ // PUT /admin/telegram-users/:chatId
1262
+ // ---------------------------------------------------------------------------
1263
+ router.openapi(telegramUserUpdateRoute, async (c) => {
1264
+ if (!deps.sqlite) {
1265
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
1266
+ message: 'SQLite not available',
1267
+ });
1268
+ }
1269
+ const { chatId } = c.req.valid('param');
1270
+ const body = c.req.valid('json');
1271
+ const now = Math.floor(Date.now() / 1000);
1272
+ const result = deps.sqlite
1273
+ .prepare('UPDATE telegram_users SET role = ?, approved_at = ? WHERE chat_id = ?')
1274
+ .run(body.role, now, chatId);
1275
+ if (result.changes === 0) {
1276
+ throw new WAIaaSError('WALLET_NOT_FOUND', {
1277
+ message: `Telegram user not found: ${chatId}`,
1278
+ });
1279
+ }
1280
+ return c.json({ success: true, chat_id: chatId, role: body.role }, 200);
1281
+ });
1282
+ // ---------------------------------------------------------------------------
1283
+ // DELETE /admin/telegram-users/:chatId
1284
+ // ---------------------------------------------------------------------------
1285
+ router.openapi(telegramUserDeleteRoute, async (c) => {
1286
+ if (!deps.sqlite) {
1287
+ throw new WAIaaSError('ADAPTER_NOT_AVAILABLE', {
1288
+ message: 'SQLite not available',
1289
+ });
1290
+ }
1291
+ const { chatId } = c.req.valid('param');
1292
+ const result = deps.sqlite
1293
+ .prepare('DELETE FROM telegram_users WHERE chat_id = ?')
1294
+ .run(chatId);
1295
+ if (result.changes === 0) {
1296
+ throw new WAIaaSError('WALLET_NOT_FOUND', {
1297
+ message: `Telegram user not found: ${chatId}`,
1298
+ });
1299
+ }
1300
+ return c.json({ success: true }, 200);
1301
+ });
1302
+ return router;
1303
+ }
1304
+ //# sourceMappingURL=admin.js.map