@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.
- package/dist/api/error-hints.d.ts +15 -0
- package/dist/api/error-hints.d.ts.map +1 -0
- package/dist/api/error-hints.js +71 -0
- package/dist/api/error-hints.js.map +1 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +14 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/middleware/address-validation.d.ts +38 -0
- package/dist/api/middleware/address-validation.d.ts.map +1 -0
- package/dist/api/middleware/address-validation.js +134 -0
- package/dist/api/middleware/address-validation.js.map +1 -0
- package/dist/api/middleware/csp.d.ts +17 -0
- package/dist/api/middleware/csp.d.ts.map +1 -0
- package/dist/api/middleware/csp.js +31 -0
- package/dist/api/middleware/csp.js.map +1 -0
- package/dist/api/middleware/error-handler.d.ts +16 -0
- package/dist/api/middleware/error-handler.d.ts.map +1 -0
- package/dist/api/middleware/error-handler.js +46 -0
- package/dist/api/middleware/error-handler.js.map +1 -0
- package/dist/api/middleware/host-guard.d.ts +11 -0
- package/dist/api/middleware/host-guard.d.ts.map +1 -0
- package/dist/api/middleware/host-guard.js +25 -0
- package/dist/api/middleware/host-guard.js.map +1 -0
- package/dist/api/middleware/index.d.ts +13 -0
- package/dist/api/middleware/index.d.ts.map +1 -0
- package/dist/api/middleware/index.js +13 -0
- package/dist/api/middleware/index.js.map +1 -0
- package/dist/api/middleware/kill-switch-guard.d.ts +19 -0
- package/dist/api/middleware/kill-switch-guard.d.ts.map +1 -0
- package/dist/api/middleware/kill-switch-guard.js +49 -0
- package/dist/api/middleware/kill-switch-guard.js.map +1 -0
- package/dist/api/middleware/master-auth.d.ts +15 -0
- package/dist/api/middleware/master-auth.d.ts.map +1 -0
- package/dist/api/middleware/master-auth.js +35 -0
- package/dist/api/middleware/master-auth.js.map +1 -0
- package/dist/api/middleware/owner-auth.d.ts +30 -0
- package/dist/api/middleware/owner-auth.d.ts.map +1 -0
- package/dist/api/middleware/owner-auth.js +133 -0
- package/dist/api/middleware/owner-auth.js.map +1 -0
- package/dist/api/middleware/request-id.d.ts +10 -0
- package/dist/api/middleware/request-id.d.ts.map +1 -0
- package/dist/api/middleware/request-id.js +18 -0
- package/dist/api/middleware/request-id.js.map +1 -0
- package/dist/api/middleware/request-logger.d.ts +9 -0
- package/dist/api/middleware/request-logger.d.ts.map +1 -0
- package/dist/api/middleware/request-logger.js +18 -0
- package/dist/api/middleware/request-logger.js.map +1 -0
- package/dist/api/middleware/session-auth.d.ts +21 -0
- package/dist/api/middleware/session-auth.d.ts.map +1 -0
- package/dist/api/middleware/session-auth.js +51 -0
- package/dist/api/middleware/session-auth.js.map +1 -0
- package/dist/api/middleware/siwe-verify.d.ts +31 -0
- package/dist/api/middleware/siwe-verify.d.ts.map +1 -0
- package/dist/api/middleware/siwe-verify.js +55 -0
- package/dist/api/middleware/siwe-verify.js.map +1 -0
- package/dist/api/routes/actions.d.ts +56 -0
- package/dist/api/routes/actions.d.ts.map +1 -0
- package/dist/api/routes/actions.js +291 -0
- package/dist/api/routes/actions.js.map +1 -0
- package/dist/api/routes/admin.d.ts +99 -0
- package/dist/api/routes/admin.d.ts.map +1 -0
- package/dist/api/routes/admin.js +1304 -0
- package/dist/api/routes/admin.js.map +1 -0
- package/dist/api/routes/display-currency-helper.d.ts +26 -0
- package/dist/api/routes/display-currency-helper.d.ts.map +1 -0
- package/dist/api/routes/display-currency-helper.js +47 -0
- package/dist/api/routes/display-currency-helper.js.map +1 -0
- package/dist/api/routes/health.d.ts +14 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +47 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/index.d.ts +15 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/index.js +15 -0
- package/dist/api/routes/index.js.map +1 -0
- package/dist/api/routes/mcp.d.ts +30 -0
- package/dist/api/routes/mcp.d.ts.map +1 -0
- package/dist/api/routes/mcp.js +156 -0
- package/dist/api/routes/mcp.js.map +1 -0
- package/dist/api/routes/nonce.d.ts +20 -0
- package/dist/api/routes/nonce.d.ts.map +1 -0
- package/dist/api/routes/nonce.js +48 -0
- package/dist/api/routes/nonce.js.map +1 -0
- package/dist/api/routes/openapi-schemas.d.ts +2281 -0
- package/dist/api/routes/openapi-schemas.d.ts.map +1 -0
- package/dist/api/routes/openapi-schemas.js +770 -0
- package/dist/api/routes/openapi-schemas.js.map +1 -0
- package/dist/api/routes/policies.d.ts +29 -0
- package/dist/api/routes/policies.d.ts.map +1 -0
- package/dist/api/routes/policies.js +332 -0
- package/dist/api/routes/policies.js.map +1 -0
- package/dist/api/routes/sessions.d.ts +35 -0
- package/dist/api/routes/sessions.d.ts.map +1 -0
- package/dist/api/routes/sessions.js +347 -0
- package/dist/api/routes/sessions.js.map +1 -0
- package/dist/api/routes/skills.d.ts +9 -0
- package/dist/api/routes/skills.d.ts.map +1 -0
- package/dist/api/routes/skills.js +59 -0
- package/dist/api/routes/skills.js.map +1 -0
- package/dist/api/routes/tokens.d.ts +25 -0
- package/dist/api/routes/tokens.d.ts.map +1 -0
- package/dist/api/routes/tokens.js +161 -0
- package/dist/api/routes/tokens.js.map +1 -0
- package/dist/api/routes/transactions.d.ts +68 -0
- package/dist/api/routes/transactions.d.ts.map +1 -0
- package/dist/api/routes/transactions.js +576 -0
- package/dist/api/routes/transactions.js.map +1 -0
- package/dist/api/routes/utils.d.ts +9 -0
- package/dist/api/routes/utils.d.ts.map +1 -0
- package/dist/api/routes/utils.js +52 -0
- package/dist/api/routes/utils.js.map +1 -0
- package/dist/api/routes/wallet.d.ts +36 -0
- package/dist/api/routes/wallet.d.ts.map +1 -0
- package/dist/api/routes/wallet.js +358 -0
- package/dist/api/routes/wallet.js.map +1 -0
- package/dist/api/routes/wallets.d.ts +43 -0
- package/dist/api/routes/wallets.d.ts.map +1 -0
- package/dist/api/routes/wallets.js +630 -0
- package/dist/api/routes/wallets.js.map +1 -0
- package/dist/api/routes/wc.d.ts +46 -0
- package/dist/api/routes/wc.d.ts.map +1 -0
- package/dist/api/routes/wc.js +354 -0
- package/dist/api/routes/wc.js.map +1 -0
- package/dist/api/routes/x402.d.ts +61 -0
- package/dist/api/routes/x402.d.ts.map +1 -0
- package/dist/api/routes/x402.js +493 -0
- package/dist/api/routes/x402.js.map +1 -0
- package/dist/api/server.d.ts +81 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +406 -0
- package/dist/api/server.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/action/action-provider-registry.d.ts +77 -0
- package/dist/infrastructure/action/action-provider-registry.d.ts.map +1 -0
- package/dist/infrastructure/action/action-provider-registry.js +239 -0
- package/dist/infrastructure/action/action-provider-registry.js.map +1 -0
- package/dist/infrastructure/action/api-key-store.d.ts +60 -0
- package/dist/infrastructure/action/api-key-store.d.ts.map +1 -0
- package/dist/infrastructure/action/api-key-store.js +130 -0
- package/dist/infrastructure/action/api-key-store.js.map +1 -0
- package/dist/infrastructure/action/index.d.ts +10 -0
- package/dist/infrastructure/action/index.d.ts.map +1 -0
- package/dist/infrastructure/action/index.js +9 -0
- package/dist/infrastructure/action/index.js.map +1 -0
- package/dist/infrastructure/adapter-pool.d.ts +50 -0
- package/dist/infrastructure/adapter-pool.d.ts.map +1 -0
- package/dist/infrastructure/adapter-pool.js +110 -0
- package/dist/infrastructure/adapter-pool.js.map +1 -0
- package/dist/infrastructure/backup/backup-service.d.ts +53 -0
- package/dist/infrastructure/backup/backup-service.d.ts.map +1 -0
- package/dist/infrastructure/backup/backup-service.js +158 -0
- package/dist/infrastructure/backup/backup-service.js.map +1 -0
- package/dist/infrastructure/backup/index.d.ts +2 -0
- package/dist/infrastructure/backup/index.d.ts.map +1 -0
- package/dist/infrastructure/backup/index.js +2 -0
- package/dist/infrastructure/backup/index.js.map +1 -0
- package/dist/infrastructure/config/index.d.ts +8 -0
- package/dist/infrastructure/config/index.d.ts.map +1 -0
- package/dist/infrastructure/config/index.js +7 -0
- package/dist/infrastructure/config/index.js.map +1 -0
- package/dist/infrastructure/config/loader.d.ts +555 -0
- package/dist/infrastructure/config/loader.d.ts.map +1 -0
- package/dist/infrastructure/config/loader.js +311 -0
- package/dist/infrastructure/config/loader.js.map +1 -0
- package/dist/infrastructure/database/checks.d.ts +19 -0
- package/dist/infrastructure/database/checks.d.ts.map +1 -0
- package/dist/infrastructure/database/checks.js +27 -0
- package/dist/infrastructure/database/checks.js.map +1 -0
- package/dist/infrastructure/database/compatibility.d.ts +36 -0
- package/dist/infrastructure/database/compatibility.d.ts.map +1 -0
- package/dist/infrastructure/database/compatibility.js +75 -0
- package/dist/infrastructure/database/compatibility.js.map +1 -0
- package/dist/infrastructure/database/connection.d.ts +36 -0
- package/dist/infrastructure/database/connection.d.ts.map +1 -0
- package/dist/infrastructure/database/connection.js +47 -0
- package/dist/infrastructure/database/connection.js.map +1 -0
- package/dist/infrastructure/database/id.d.ts +17 -0
- package/dist/infrastructure/database/id.d.ts.map +1 -0
- package/dist/infrastructure/database/id.js +20 -0
- package/dist/infrastructure/database/id.js.map +1 -0
- package/dist/infrastructure/database/index.d.ts +15 -0
- package/dist/infrastructure/database/index.d.ts.map +1 -0
- package/dist/infrastructure/database/index.js +12 -0
- package/dist/infrastructure/database/index.js.map +1 -0
- package/dist/infrastructure/database/migrate.d.ts +76 -0
- package/dist/infrastructure/database/migrate.d.ts.map +1 -0
- package/dist/infrastructure/database/migrate.js +1214 -0
- package/dist/infrastructure/database/migrate.js.map +1 -0
- package/dist/infrastructure/database/schema.d.ts +2352 -0
- package/dist/infrastructure/database/schema.d.ts.map +1 -0
- package/dist/infrastructure/database/schema.js +288 -0
- package/dist/infrastructure/database/schema.js.map +1 -0
- package/dist/infrastructure/jwt/index.d.ts +2 -0
- package/dist/infrastructure/jwt/index.d.ts.map +1 -0
- package/dist/infrastructure/jwt/index.js +2 -0
- package/dist/infrastructure/jwt/index.js.map +1 -0
- package/dist/infrastructure/jwt/jwt-secret-manager.d.ts +58 -0
- package/dist/infrastructure/jwt/jwt-secret-manager.d.ts.map +1 -0
- package/dist/infrastructure/jwt/jwt-secret-manager.js +222 -0
- package/dist/infrastructure/jwt/jwt-secret-manager.js.map +1 -0
- package/dist/infrastructure/keystore/crypto.d.ts +62 -0
- package/dist/infrastructure/keystore/crypto.d.ts.map +1 -0
- package/dist/infrastructure/keystore/crypto.js +89 -0
- package/dist/infrastructure/keystore/crypto.js.map +1 -0
- package/dist/infrastructure/keystore/index.d.ts +4 -0
- package/dist/infrastructure/keystore/index.d.ts.map +1 -0
- package/dist/infrastructure/keystore/index.js +5 -0
- package/dist/infrastructure/keystore/index.js.map +1 -0
- package/dist/infrastructure/keystore/keystore.d.ts +115 -0
- package/dist/infrastructure/keystore/keystore.d.ts.map +1 -0
- package/dist/infrastructure/keystore/keystore.js +327 -0
- package/dist/infrastructure/keystore/keystore.js.map +1 -0
- package/dist/infrastructure/keystore/memory.d.ts +45 -0
- package/dist/infrastructure/keystore/memory.d.ts.map +1 -0
- package/dist/infrastructure/keystore/memory.js +105 -0
- package/dist/infrastructure/keystore/memory.js.map +1 -0
- package/dist/infrastructure/oracle/coingecko-forex.d.ts +35 -0
- package/dist/infrastructure/oracle/coingecko-forex.d.ts.map +1 -0
- package/dist/infrastructure/oracle/coingecko-forex.js +69 -0
- package/dist/infrastructure/oracle/coingecko-forex.js.map +1 -0
- package/dist/infrastructure/oracle/coingecko-oracle.d.ts +73 -0
- package/dist/infrastructure/oracle/coingecko-oracle.d.ts.map +1 -0
- package/dist/infrastructure/oracle/coingecko-oracle.js +199 -0
- package/dist/infrastructure/oracle/coingecko-oracle.js.map +1 -0
- package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts +32 -0
- package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts.map +1 -0
- package/dist/infrastructure/oracle/coingecko-platform-ids.js +30 -0
- package/dist/infrastructure/oracle/coingecko-platform-ids.js.map +1 -0
- package/dist/infrastructure/oracle/forex-currencies.d.ts +36 -0
- package/dist/infrastructure/oracle/forex-currencies.d.ts.map +1 -0
- package/dist/infrastructure/oracle/forex-currencies.js +71 -0
- package/dist/infrastructure/oracle/forex-currencies.js.map +1 -0
- package/dist/infrastructure/oracle/forex-rate-service.d.ts +51 -0
- package/dist/infrastructure/oracle/forex-rate-service.d.ts.map +1 -0
- package/dist/infrastructure/oracle/forex-rate-service.js +149 -0
- package/dist/infrastructure/oracle/forex-rate-service.js.map +1 -0
- package/dist/infrastructure/oracle/index.d.ts +18 -0
- package/dist/infrastructure/oracle/index.d.ts.map +1 -0
- package/dist/infrastructure/oracle/index.js +19 -0
- package/dist/infrastructure/oracle/index.js.map +1 -0
- package/dist/infrastructure/oracle/oracle-chain.d.ts +101 -0
- package/dist/infrastructure/oracle/oracle-chain.d.ts.map +1 -0
- package/dist/infrastructure/oracle/oracle-chain.js +163 -0
- package/dist/infrastructure/oracle/oracle-chain.js.map +1 -0
- package/dist/infrastructure/oracle/oracle-errors.d.ts +42 -0
- package/dist/infrastructure/oracle/oracle-errors.d.ts.map +1 -0
- package/dist/infrastructure/oracle/oracle-errors.js +53 -0
- package/dist/infrastructure/oracle/oracle-errors.js.map +1 -0
- package/dist/infrastructure/oracle/price-age.d.ts +38 -0
- package/dist/infrastructure/oracle/price-age.d.ts.map +1 -0
- package/dist/infrastructure/oracle/price-age.js +44 -0
- package/dist/infrastructure/oracle/price-age.js.map +1 -0
- package/dist/infrastructure/oracle/price-cache.d.ts +99 -0
- package/dist/infrastructure/oracle/price-cache.d.ts.map +1 -0
- package/dist/infrastructure/oracle/price-cache.js +173 -0
- package/dist/infrastructure/oracle/price-cache.js.map +1 -0
- package/dist/infrastructure/oracle/pyth-feed-ids.d.ts +31 -0
- package/dist/infrastructure/oracle/pyth-feed-ids.d.ts.map +1 -0
- package/dist/infrastructure/oracle/pyth-feed-ids.js +44 -0
- package/dist/infrastructure/oracle/pyth-feed-ids.js.map +1 -0
- package/dist/infrastructure/oracle/pyth-oracle.d.ts +69 -0
- package/dist/infrastructure/oracle/pyth-oracle.d.ts.map +1 -0
- package/dist/infrastructure/oracle/pyth-oracle.js +149 -0
- package/dist/infrastructure/oracle/pyth-oracle.js.map +1 -0
- package/dist/infrastructure/settings/hot-reload.d.ts +71 -0
- package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -0
- package/dist/infrastructure/settings/hot-reload.js +315 -0
- package/dist/infrastructure/settings/hot-reload.js.map +1 -0
- package/dist/infrastructure/settings/index.d.ts +13 -0
- package/dist/infrastructure/settings/index.d.ts.map +1 -0
- package/dist/infrastructure/settings/index.js +10 -0
- package/dist/infrastructure/settings/index.js.map +1 -0
- package/dist/infrastructure/settings/setting-keys.d.ts +28 -0
- package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -0
- package/dist/infrastructure/settings/setting-keys.js +105 -0
- package/dist/infrastructure/settings/setting-keys.js.map +1 -0
- package/dist/infrastructure/settings/settings-crypto.d.ts +39 -0
- package/dist/infrastructure/settings/settings-crypto.d.ts.map +1 -0
- package/dist/infrastructure/settings/settings-crypto.js +73 -0
- package/dist/infrastructure/settings/settings-crypto.js.map +1 -0
- package/dist/infrastructure/settings/settings-service.d.ts +82 -0
- package/dist/infrastructure/settings/settings-service.d.ts.map +1 -0
- package/dist/infrastructure/settings/settings-service.js +267 -0
- package/dist/infrastructure/settings/settings-service.js.map +1 -0
- package/dist/infrastructure/telegram/index.d.ts +6 -0
- package/dist/infrastructure/telegram/index.d.ts.map +1 -0
- package/dist/infrastructure/telegram/index.js +5 -0
- package/dist/infrastructure/telegram/index.js.map +1 -0
- package/dist/infrastructure/telegram/telegram-api.d.ts +35 -0
- package/dist/infrastructure/telegram/telegram-api.d.ts.map +1 -0
- package/dist/infrastructure/telegram/telegram-api.js +82 -0
- package/dist/infrastructure/telegram/telegram-api.js.map +1 -0
- package/dist/infrastructure/telegram/telegram-auth.d.ts +57 -0
- package/dist/infrastructure/telegram/telegram-auth.d.ts.map +1 -0
- package/dist/infrastructure/telegram/telegram-auth.js +88 -0
- package/dist/infrastructure/telegram/telegram-auth.js.map +1 -0
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts +95 -0
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -0
- package/dist/infrastructure/telegram/telegram-bot-service.js +564 -0
- package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -0
- package/dist/infrastructure/telegram/telegram-keyboard.d.ts +27 -0
- package/dist/infrastructure/telegram/telegram-keyboard.d.ts.map +1 -0
- package/dist/infrastructure/telegram/telegram-keyboard.js +52 -0
- package/dist/infrastructure/telegram/telegram-keyboard.js.map +1 -0
- package/dist/infrastructure/telegram/telegram-types.d.ts +43 -0
- package/dist/infrastructure/telegram/telegram-types.d.ts.map +1 -0
- package/dist/infrastructure/telegram/telegram-types.js +8 -0
- package/dist/infrastructure/telegram/telegram-types.js.map +1 -0
- package/dist/infrastructure/token-registry/builtin-tokens.d.ts +39 -0
- package/dist/infrastructure/token-registry/builtin-tokens.d.ts.map +1 -0
- package/dist/infrastructure/token-registry/builtin-tokens.js +135 -0
- package/dist/infrastructure/token-registry/builtin-tokens.js.map +1 -0
- package/dist/infrastructure/token-registry/index.d.ts +8 -0
- package/dist/infrastructure/token-registry/index.d.ts.map +1 -0
- package/dist/infrastructure/token-registry/index.js +8 -0
- package/dist/infrastructure/token-registry/index.js.map +1 -0
- package/dist/infrastructure/token-registry/token-registry-service.d.ts +49 -0
- package/dist/infrastructure/token-registry/token-registry-service.d.ts.map +1 -0
- package/dist/infrastructure/token-registry/token-registry-service.js +93 -0
- package/dist/infrastructure/token-registry/token-registry-service.js.map +1 -0
- package/dist/infrastructure/version/index.d.ts +5 -0
- package/dist/infrastructure/version/index.d.ts.map +1 -0
- package/dist/infrastructure/version/index.js +5 -0
- package/dist/infrastructure/version/index.js.map +1 -0
- package/dist/infrastructure/version/version-check-service.d.ts +35 -0
- package/dist/infrastructure/version/version-check-service.d.ts.map +1 -0
- package/dist/infrastructure/version/version-check-service.js +92 -0
- package/dist/infrastructure/version/version-check-service.js.map +1 -0
- package/dist/lifecycle/daemon.d.ts +103 -0
- package/dist/lifecycle/daemon.d.ts.map +1 -0
- package/dist/lifecycle/daemon.js +934 -0
- package/dist/lifecycle/daemon.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/signal-handler.d.ts +18 -0
- package/dist/lifecycle/signal-handler.d.ts.map +1 -0
- package/dist/lifecycle/signal-handler.js +37 -0
- package/dist/lifecycle/signal-handler.js.map +1 -0
- package/dist/lifecycle/workers.d.ts +46 -0
- package/dist/lifecycle/workers.d.ts.map +1 -0
- package/dist/lifecycle/workers.js +101 -0
- package/dist/lifecycle/workers.js.map +1 -0
- package/dist/notifications/channels/discord.d.ts +10 -0
- package/dist/notifications/channels/discord.d.ts.map +1 -0
- package/dist/notifications/channels/discord.js +54 -0
- package/dist/notifications/channels/discord.js.map +1 -0
- package/dist/notifications/channels/ntfy.d.ts +13 -0
- package/dist/notifications/channels/ntfy.d.ts.map +1 -0
- package/dist/notifications/channels/ntfy.js +58 -0
- package/dist/notifications/channels/ntfy.js.map +1 -0
- package/dist/notifications/channels/slack.d.ts +10 -0
- package/dist/notifications/channels/slack.d.ts.map +1 -0
- package/dist/notifications/channels/slack.js +55 -0
- package/dist/notifications/channels/slack.js.map +1 -0
- package/dist/notifications/channels/telegram.d.ts +10 -0
- package/dist/notifications/channels/telegram.d.ts.map +1 -0
- package/dist/notifications/channels/telegram.js +40 -0
- package/dist/notifications/channels/telegram.js.map +1 -0
- package/dist/notifications/index.d.ts +9 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/notification-service.d.ts +75 -0
- package/dist/notifications/notification-service.d.ts.map +1 -0
- package/dist/notifications/notification-service.js +213 -0
- package/dist/notifications/notification-service.js.map +1 -0
- package/dist/notifications/templates/message-templates.d.ts +12 -0
- package/dist/notifications/templates/message-templates.d.ts.map +1 -0
- package/dist/notifications/templates/message-templates.js +22 -0
- package/dist/notifications/templates/message-templates.js.map +1 -0
- package/dist/pipeline/database-policy-engine.d.ts +286 -0
- package/dist/pipeline/database-policy-engine.d.ts.map +1 -0
- package/dist/pipeline/database-policy-engine.js +992 -0
- package/dist/pipeline/database-policy-engine.js.map +1 -0
- package/dist/pipeline/default-policy-engine.d.ts +26 -0
- package/dist/pipeline/default-policy-engine.d.ts.map +1 -0
- package/dist/pipeline/default-policy-engine.js +25 -0
- package/dist/pipeline/default-policy-engine.js.map +1 -0
- package/dist/pipeline/index.d.ts +9 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +9 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/network-resolver.d.ts +22 -0
- package/dist/pipeline/network-resolver.d.ts.map +1 -0
- package/dist/pipeline/network-resolver.js +32 -0
- package/dist/pipeline/network-resolver.js.map +1 -0
- package/dist/pipeline/pipeline.d.ts +72 -0
- package/dist/pipeline/pipeline.d.ts.map +1 -0
- package/dist/pipeline/pipeline.js +87 -0
- package/dist/pipeline/pipeline.js.map +1 -0
- package/dist/pipeline/resolve-effective-amount-usd.d.ts +41 -0
- package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -0
- package/dist/pipeline/resolve-effective-amount-usd.js +208 -0
- package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -0
- package/dist/pipeline/sign-only.d.ts +99 -0
- package/dist/pipeline/sign-only.d.ts.map +1 -0
- package/dist/pipeline/sign-only.js +267 -0
- package/dist/pipeline/sign-only.js.map +1 -0
- package/dist/pipeline/sleep.d.ts +6 -0
- package/dist/pipeline/sleep.d.ts.map +1 -0
- package/dist/pipeline/sleep.js +8 -0
- package/dist/pipeline/sleep.js.map +1 -0
- package/dist/pipeline/stages.d.ts +82 -0
- package/dist/pipeline/stages.d.ts.map +1 -0
- package/dist/pipeline/stages.js +784 -0
- package/dist/pipeline/stages.js.map +1 -0
- package/dist/services/autostop-rules.d.ts +79 -0
- package/dist/services/autostop-rules.d.ts.map +1 -0
- package/dist/services/autostop-rules.js +174 -0
- package/dist/services/autostop-rules.js.map +1 -0
- package/dist/services/autostop-service.d.ts +82 -0
- package/dist/services/autostop-service.d.ts.map +1 -0
- package/dist/services/autostop-service.js +223 -0
- package/dist/services/autostop-service.js.map +1 -0
- package/dist/services/kill-switch-service.d.ts +118 -0
- package/dist/services/kill-switch-service.d.ts.map +1 -0
- package/dist/services/kill-switch-service.js +291 -0
- package/dist/services/kill-switch-service.js.map +1 -0
- package/dist/services/monitoring/balance-monitor-service.d.ts +65 -0
- package/dist/services/monitoring/balance-monitor-service.d.ts.map +1 -0
- package/dist/services/monitoring/balance-monitor-service.js +207 -0
- package/dist/services/monitoring/balance-monitor-service.js.map +1 -0
- package/dist/services/wc-session-service.d.ts +123 -0
- package/dist/services/wc-session-service.d.ts.map +1 -0
- package/dist/services/wc-session-service.js +363 -0
- package/dist/services/wc-session-service.js.map +1 -0
- package/dist/services/wc-signing-bridge.d.ts +60 -0
- package/dist/services/wc-signing-bridge.d.ts.map +1 -0
- package/dist/services/wc-signing-bridge.js +334 -0
- package/dist/services/wc-signing-bridge.js.map +1 -0
- package/dist/services/wc-storage.d.ts +32 -0
- package/dist/services/wc-storage.d.ts.map +1 -0
- package/dist/services/wc-storage.js +64 -0
- package/dist/services/wc-storage.js.map +1 -0
- package/dist/services/x402/payment-signer.d.ts +88 -0
- package/dist/services/x402/payment-signer.d.ts.map +1 -0
- package/dist/services/x402/payment-signer.js +311 -0
- package/dist/services/x402/payment-signer.js.map +1 -0
- package/dist/services/x402/ssrf-guard.d.ts +27 -0
- package/dist/services/x402/ssrf-guard.d.ts.map +1 -0
- package/dist/services/x402/ssrf-guard.js +236 -0
- package/dist/services/x402/ssrf-guard.js.map +1 -0
- package/dist/services/x402/x402-domain-policy.d.ts +50 -0
- package/dist/services/x402/x402-domain-policy.d.ts.map +1 -0
- package/dist/services/x402/x402-domain-policy.js +78 -0
- package/dist/services/x402/x402-domain-policy.js.map +1 -0
- package/dist/services/x402/x402-handler.d.ts +71 -0
- package/dist/services/x402/x402-handler.d.ts.map +1 -0
- package/dist/services/x402/x402-handler.js +195 -0
- package/dist/services/x402/x402-handler.js.map +1 -0
- package/dist/services/x402/x402-usd-resolver.d.ts +26 -0
- package/dist/services/x402/x402-usd-resolver.d.ts.map +1 -0
- package/dist/services/x402/x402-usd-resolver.js +79 -0
- package/dist/services/x402/x402-usd-resolver.js.map +1 -0
- package/dist/workflow/approval-workflow.d.ts +103 -0
- package/dist/workflow/approval-workflow.d.ts.map +1 -0
- package/dist/workflow/approval-workflow.js +202 -0
- package/dist/workflow/approval-workflow.js.map +1 -0
- package/dist/workflow/delay-queue.d.ts +78 -0
- package/dist/workflow/delay-queue.d.ts.map +1 -0
- package/dist/workflow/delay-queue.js +174 -0
- package/dist/workflow/delay-queue.js.map +1 -0
- package/dist/workflow/index.d.ts +11 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +9 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/owner-state.d.ts +97 -0
- package/dist/workflow/owner-state.d.ts.map +1 -0
- package/dist/workflow/owner-state.js +168 -0
- package/dist/workflow/owner-state.js.map +1 -0
- package/package.json +71 -0
- package/public/admin/assets/index-BPoUSH8W.css +1 -0
- package/public/admin/assets/index-CDi1qoXB.js +1 -0
- 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
|