@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,934 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DaemonLifecycle - orchestrates daemon startup (6 steps) and shutdown (10 steps).
|
|
3
|
+
*
|
|
4
|
+
* Startup sequence (doc 28 section 2):
|
|
5
|
+
* 1. Environment validation + config + flock (5s timeout, fail-fast)
|
|
6
|
+
* 2. Database initialization (30s timeout, fail-fast)
|
|
7
|
+
* 3. Keystore unlock (30s timeout, fail-fast)
|
|
8
|
+
* 4. Adapter initialization (10s, fail-soft)
|
|
9
|
+
* 4c-6. WalletConnect service (fail-soft)
|
|
10
|
+
* 5. HTTP server start (5s, fail-fast)
|
|
11
|
+
* 6. Background workers + PID (no timeout, fail-soft)
|
|
12
|
+
*
|
|
13
|
+
* Shutdown sequence (doc 28 section 3):
|
|
14
|
+
* 1. Set isShuttingDown, start force timer, log signal
|
|
15
|
+
* 2-4. HTTP server close
|
|
16
|
+
* 5. In-flight signing -- STUB (Phase 50-04)
|
|
17
|
+
* 6. Pending queue persistence -- STUB (Phase 50-04)
|
|
18
|
+
* 6a. Stop TelegramBot, WcSessionService, AutoStop, BalanceMonitor
|
|
19
|
+
* 6b. Remove all EventBus listeners
|
|
20
|
+
* 7. workers.stopAll()
|
|
21
|
+
* 8. WAL checkpoint(TRUNCATE)
|
|
22
|
+
* 9. keyStore.lockAll()
|
|
23
|
+
* 10. sqlite.close(), unlink PID, close lockFd, process.exit(0)
|
|
24
|
+
*
|
|
25
|
+
* @see docs/28-daemon-lifecycle-cli.md
|
|
26
|
+
*/
|
|
27
|
+
import { writeFileSync, unlinkSync, existsSync, mkdirSync } from 'node:fs';
|
|
28
|
+
import { join, dirname } from 'node:path';
|
|
29
|
+
import { WAIaaSError, getDefaultNetwork, EventBus } from '@waiaas/core';
|
|
30
|
+
import { KillSwitchService } from '../services/kill-switch-service.js';
|
|
31
|
+
import { AutoStopService } from '../services/autostop-service.js';
|
|
32
|
+
import { resolveRpcUrl } from '../infrastructure/adapter-pool.js';
|
|
33
|
+
import { createDatabase, pushSchema, checkSchemaCompatibility } from '../infrastructure/database/index.js';
|
|
34
|
+
import { loadConfig } from '../infrastructure/config/index.js';
|
|
35
|
+
import { BackgroundWorkers } from './workers.js';
|
|
36
|
+
import { DelayQueue } from '../workflow/delay-queue.js';
|
|
37
|
+
import { ApprovalWorkflow } from '../workflow/approval-workflow.js';
|
|
38
|
+
import { DatabasePolicyEngine } from '../pipeline/database-policy-engine.js';
|
|
39
|
+
import { JwtSecretManager } from '../infrastructure/jwt/index.js';
|
|
40
|
+
import argon2 from 'argon2';
|
|
41
|
+
let _lockfile = null;
|
|
42
|
+
async function getLockfile() {
|
|
43
|
+
if (_lockfile)
|
|
44
|
+
return _lockfile;
|
|
45
|
+
// proper-lockfile is CJS; use dynamic import
|
|
46
|
+
_lockfile = (await import('proper-lockfile'));
|
|
47
|
+
return _lockfile;
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Timeout utility
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/**
|
|
53
|
+
* Race a promise against a timeout. Rejects with WAIaaSError on timeout.
|
|
54
|
+
*/
|
|
55
|
+
function withTimeout(promise, ms, errorCode) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const timer = setTimeout(() => {
|
|
58
|
+
reject(new WAIaaSError('SYSTEM_LOCKED', {
|
|
59
|
+
message: `${errorCode}: Timeout after ${ms}ms`,
|
|
60
|
+
}));
|
|
61
|
+
}, ms);
|
|
62
|
+
promise.then((value) => {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
resolve(value);
|
|
65
|
+
}, (err) => {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
reject(err);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Export for testing
|
|
72
|
+
export { withTimeout };
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// DaemonLifecycle
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
export class DaemonLifecycle {
|
|
77
|
+
_isShuttingDown = false;
|
|
78
|
+
sqlite = null;
|
|
79
|
+
_db = null;
|
|
80
|
+
keyStore = null;
|
|
81
|
+
masterPassword = '';
|
|
82
|
+
adapterPool = null;
|
|
83
|
+
httpServer = null;
|
|
84
|
+
workers = null;
|
|
85
|
+
releaseLock = null;
|
|
86
|
+
pidPath = '';
|
|
87
|
+
_config = null;
|
|
88
|
+
forceTimer = null;
|
|
89
|
+
delayQueue = null;
|
|
90
|
+
approvalWorkflow = null;
|
|
91
|
+
jwtSecretManager = null;
|
|
92
|
+
masterPasswordHash = '';
|
|
93
|
+
notificationService = null;
|
|
94
|
+
_settingsService = null;
|
|
95
|
+
priceOracle;
|
|
96
|
+
actionProviderRegistry = null;
|
|
97
|
+
apiKeyStore = null;
|
|
98
|
+
forexRateService = null;
|
|
99
|
+
eventBus = new EventBus();
|
|
100
|
+
killSwitchService = null;
|
|
101
|
+
autoStopService = null;
|
|
102
|
+
balanceMonitorService = null;
|
|
103
|
+
telegramBotService = null;
|
|
104
|
+
telegramBotRef = { current: null };
|
|
105
|
+
wcSessionService = null;
|
|
106
|
+
wcServiceRef = { current: null };
|
|
107
|
+
wcSigningBridge = null;
|
|
108
|
+
_versionCheckService = null;
|
|
109
|
+
/** Whether shutdown has been initiated. */
|
|
110
|
+
get isShuttingDown() {
|
|
111
|
+
return this._isShuttingDown;
|
|
112
|
+
}
|
|
113
|
+
/** Current config (available after start). */
|
|
114
|
+
get config() {
|
|
115
|
+
return this._config;
|
|
116
|
+
}
|
|
117
|
+
/** Drizzle database instance (available after start, used by route handlers). */
|
|
118
|
+
get db() {
|
|
119
|
+
return this._db;
|
|
120
|
+
}
|
|
121
|
+
/** SettingsService instance (available after Step 2, used by route handlers). */
|
|
122
|
+
get settingsService() {
|
|
123
|
+
return this._settingsService;
|
|
124
|
+
}
|
|
125
|
+
/** VersionCheckService instance (available after Step 6, used by Health endpoint). */
|
|
126
|
+
get versionCheckService() {
|
|
127
|
+
return this._versionCheckService;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 6-step startup sequence with per-step timeouts and 90s overall cap.
|
|
131
|
+
*/
|
|
132
|
+
async start(dataDir, masterPassword) {
|
|
133
|
+
// Wrap everything in a 90-second overall timeout
|
|
134
|
+
await withTimeout(this._startInternal(dataDir, masterPassword), 90_000, 'STARTUP_TIMEOUT');
|
|
135
|
+
}
|
|
136
|
+
async _startInternal(dataDir, masterPassword) {
|
|
137
|
+
// Store master password for route handlers
|
|
138
|
+
this.masterPassword = masterPassword;
|
|
139
|
+
// ------------------------------------------------------------------
|
|
140
|
+
// Step 1: Environment validation + config + flock (5s, fail-fast)
|
|
141
|
+
// ------------------------------------------------------------------
|
|
142
|
+
await withTimeout((async () => {
|
|
143
|
+
// Ensure data directory exists
|
|
144
|
+
if (!existsSync(dataDir)) {
|
|
145
|
+
mkdirSync(dataDir, { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
// Load config
|
|
148
|
+
this._config = loadConfig(dataDir);
|
|
149
|
+
// Acquire daemon lock (flock-like via proper-lockfile)
|
|
150
|
+
await this.acquireDaemonLock(dataDir);
|
|
151
|
+
console.log('Step 1: Config loaded, daemon lock acquired');
|
|
152
|
+
})(), 5_000, 'STEP1_CONFIG_LOCK');
|
|
153
|
+
// ------------------------------------------------------------------
|
|
154
|
+
// Step 2: Database initialization (30s, fail-fast)
|
|
155
|
+
// ------------------------------------------------------------------
|
|
156
|
+
await withTimeout((async () => {
|
|
157
|
+
const dbPath = join(dataDir, this._config.database.path);
|
|
158
|
+
// Ensure DB directory exists
|
|
159
|
+
const dbDir = dirname(dbPath);
|
|
160
|
+
if (!existsSync(dbDir)) {
|
|
161
|
+
mkdirSync(dbDir, { recursive: true });
|
|
162
|
+
}
|
|
163
|
+
const { sqlite, db } = createDatabase(dbPath);
|
|
164
|
+
this.sqlite = sqlite;
|
|
165
|
+
this._db = db;
|
|
166
|
+
// Check schema compatibility before migration
|
|
167
|
+
const compatibility = checkSchemaCompatibility(sqlite);
|
|
168
|
+
if (compatibility.action === 'reject') {
|
|
169
|
+
console.error(`Step 2: Schema incompatible -- ${compatibility.message}`);
|
|
170
|
+
throw new WAIaaSError('SCHEMA_INCOMPATIBLE', {
|
|
171
|
+
message: compatibility.message,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (compatibility.action === 'migrate') {
|
|
175
|
+
console.log('Step 2: Schema migration needed, applying...');
|
|
176
|
+
}
|
|
177
|
+
// Create all tables + run migrations (idempotent)
|
|
178
|
+
pushSchema(sqlite);
|
|
179
|
+
// Auto-import config.toml operational settings into DB (first boot only)
|
|
180
|
+
const { SettingsService } = await import('../infrastructure/settings/index.js');
|
|
181
|
+
this._settingsService = new SettingsService({
|
|
182
|
+
db: this._db,
|
|
183
|
+
config: this._config,
|
|
184
|
+
masterPassword,
|
|
185
|
+
});
|
|
186
|
+
const importResult = this._settingsService.importFromConfig();
|
|
187
|
+
if (importResult.imported > 0) {
|
|
188
|
+
console.log(`Step 2: Settings imported from config.toml (${importResult.imported} keys)`);
|
|
189
|
+
}
|
|
190
|
+
console.log('Step 2: Database initialized');
|
|
191
|
+
})(), 30_000, 'STEP2_DATABASE');
|
|
192
|
+
// ------------------------------------------------------------------
|
|
193
|
+
// Step 3: Keystore unlock (30s, fail-fast)
|
|
194
|
+
// ------------------------------------------------------------------
|
|
195
|
+
await withTimeout((async () => {
|
|
196
|
+
// Dynamic import to avoid circular dependency issues
|
|
197
|
+
const { LocalKeyStore: KeyStoreCls } = await import('../infrastructure/keystore/index.js');
|
|
198
|
+
const keystoreDir = join(dataDir, 'keystore');
|
|
199
|
+
if (!existsSync(keystoreDir)) {
|
|
200
|
+
mkdirSync(keystoreDir, { recursive: true });
|
|
201
|
+
}
|
|
202
|
+
this.keyStore = new KeyStoreCls(keystoreDir);
|
|
203
|
+
// v1.1: just verify keystore infrastructure is accessible
|
|
204
|
+
// Full key decryption happens when agents are accessed
|
|
205
|
+
if (masterPassword) {
|
|
206
|
+
console.log('Step 3: Keystore infrastructure verified (master password provided)');
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
console.log('Step 3: Keystore infrastructure verified (no master password)');
|
|
210
|
+
}
|
|
211
|
+
})(), 30_000, 'STEP3_KEYSTORE');
|
|
212
|
+
// ------------------------------------------------------------------
|
|
213
|
+
// Step 4: Adapter pool initialization (10s, fail-soft)
|
|
214
|
+
// ------------------------------------------------------------------
|
|
215
|
+
try {
|
|
216
|
+
await withTimeout((async () => {
|
|
217
|
+
const { AdapterPool } = await import('../infrastructure/adapter-pool.js');
|
|
218
|
+
this.adapterPool = new AdapterPool();
|
|
219
|
+
console.log('Step 4: AdapterPool created (lazy init)');
|
|
220
|
+
})(), 10_000, 'STEP4_ADAPTER');
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
// fail-soft: log warning but continue (daemon runs without chain adapter)
|
|
224
|
+
console.warn('Step 4 (fail-soft): AdapterPool init warning:', err);
|
|
225
|
+
this.adapterPool = null;
|
|
226
|
+
}
|
|
227
|
+
// ------------------------------------------------------------------
|
|
228
|
+
// Step 4b: Create workflow instances (DelayQueue + ApprovalWorkflow)
|
|
229
|
+
// ------------------------------------------------------------------
|
|
230
|
+
if (this._db && this.sqlite && this._config) {
|
|
231
|
+
this.delayQueue = new DelayQueue({ db: this._db, sqlite: this.sqlite });
|
|
232
|
+
this.approvalWorkflow = new ApprovalWorkflow({
|
|
233
|
+
db: this._db,
|
|
234
|
+
sqlite: this.sqlite,
|
|
235
|
+
config: {
|
|
236
|
+
policy_defaults_approval_timeout: this._config.security.policy_defaults_approval_timeout,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
console.log('Step 4b: Workflow instances created (DelayQueue + ApprovalWorkflow)');
|
|
240
|
+
}
|
|
241
|
+
// ------------------------------------------------------------------
|
|
242
|
+
// Step 4c: JWT Secret Manager + master password hash
|
|
243
|
+
// ------------------------------------------------------------------
|
|
244
|
+
if (this._db) {
|
|
245
|
+
this.jwtSecretManager = new JwtSecretManager(this._db);
|
|
246
|
+
await this.jwtSecretManager.initialize();
|
|
247
|
+
this.masterPasswordHash = await argon2.hash(masterPassword, {
|
|
248
|
+
type: argon2.argon2id,
|
|
249
|
+
memoryCost: 19456,
|
|
250
|
+
timeCost: 2,
|
|
251
|
+
parallelism: 1,
|
|
252
|
+
});
|
|
253
|
+
console.log('Step 4c: JWT secret manager initialized, master password hashed');
|
|
254
|
+
}
|
|
255
|
+
// ------------------------------------------------------------------
|
|
256
|
+
// Step 4c-2: KillSwitchService initialization
|
|
257
|
+
// ------------------------------------------------------------------
|
|
258
|
+
if (this.sqlite) {
|
|
259
|
+
this.killSwitchService = new KillSwitchService({
|
|
260
|
+
sqlite: this.sqlite,
|
|
261
|
+
// notificationService will be set after Step 4d
|
|
262
|
+
eventBus: this.eventBus,
|
|
263
|
+
});
|
|
264
|
+
this.killSwitchService.ensureInitialized();
|
|
265
|
+
console.log('Step 4c-2: KillSwitchService initialized');
|
|
266
|
+
}
|
|
267
|
+
// ------------------------------------------------------------------
|
|
268
|
+
// Step 4d: Notification Service initialization (fail-soft)
|
|
269
|
+
// ------------------------------------------------------------------
|
|
270
|
+
try {
|
|
271
|
+
if (this._config.notifications.enabled) {
|
|
272
|
+
const { NotificationService, TelegramChannel, DiscordChannel, NtfyChannel, SlackChannel } = await import('../notifications/index.js');
|
|
273
|
+
this.notificationService = new NotificationService({
|
|
274
|
+
db: this._db ?? undefined,
|
|
275
|
+
config: {
|
|
276
|
+
locale: (this._config.notifications.locale ?? 'en'),
|
|
277
|
+
rateLimitRpm: this._config.notifications.rate_limit_rpm ?? 20,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
// Initialize configured channels from config
|
|
281
|
+
const notifConfig = this._config.notifications;
|
|
282
|
+
if (notifConfig.telegram_bot_token && notifConfig.telegram_chat_id) {
|
|
283
|
+
const telegram = new TelegramChannel();
|
|
284
|
+
await telegram.initialize({
|
|
285
|
+
telegram_bot_token: notifConfig.telegram_bot_token,
|
|
286
|
+
telegram_chat_id: notifConfig.telegram_chat_id,
|
|
287
|
+
});
|
|
288
|
+
this.notificationService.addChannel(telegram);
|
|
289
|
+
}
|
|
290
|
+
if (notifConfig.discord_webhook_url) {
|
|
291
|
+
const discord = new DiscordChannel();
|
|
292
|
+
await discord.initialize({
|
|
293
|
+
discord_webhook_url: notifConfig.discord_webhook_url,
|
|
294
|
+
});
|
|
295
|
+
this.notificationService.addChannel(discord);
|
|
296
|
+
}
|
|
297
|
+
if (notifConfig.ntfy_topic) {
|
|
298
|
+
const ntfy = new NtfyChannel();
|
|
299
|
+
await ntfy.initialize({
|
|
300
|
+
ntfy_server: notifConfig.ntfy_server,
|
|
301
|
+
ntfy_topic: notifConfig.ntfy_topic,
|
|
302
|
+
});
|
|
303
|
+
this.notificationService.addChannel(ntfy);
|
|
304
|
+
}
|
|
305
|
+
if (notifConfig.slack_webhook_url) {
|
|
306
|
+
const slack = new SlackChannel();
|
|
307
|
+
await slack.initialize({
|
|
308
|
+
slack_webhook_url: notifConfig.slack_webhook_url,
|
|
309
|
+
});
|
|
310
|
+
this.notificationService.addChannel(slack);
|
|
311
|
+
}
|
|
312
|
+
const channelNames = this.notificationService.getChannelNames();
|
|
313
|
+
console.log(`Step 4d: NotificationService initialized (${channelNames.length} channels: ${channelNames.join(', ') || 'none'})`);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
console.log('Step 4d: Notifications disabled');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
console.warn('Step 4d (fail-soft): NotificationService init warning:', err);
|
|
321
|
+
this.notificationService = null;
|
|
322
|
+
}
|
|
323
|
+
// Wire NotificationService to KillSwitchService (created before Step 4d)
|
|
324
|
+
if (this.killSwitchService && this.notificationService) {
|
|
325
|
+
// Re-create with notification service attached
|
|
326
|
+
this.killSwitchService = new KillSwitchService({
|
|
327
|
+
sqlite: this.sqlite,
|
|
328
|
+
notificationService: this.notificationService,
|
|
329
|
+
eventBus: this.eventBus,
|
|
330
|
+
});
|
|
331
|
+
this.killSwitchService.ensureInitialized();
|
|
332
|
+
}
|
|
333
|
+
// ------------------------------------------------------------------
|
|
334
|
+
// Step 4c-3: AutoStop Engine (fail-soft)
|
|
335
|
+
// ------------------------------------------------------------------
|
|
336
|
+
try {
|
|
337
|
+
if (this.sqlite && this.killSwitchService && this._settingsService) {
|
|
338
|
+
const autoStopConfig = {
|
|
339
|
+
consecutiveFailuresThreshold: parseInt(this._settingsService.get('autostop.consecutive_failures_threshold'), 10),
|
|
340
|
+
unusualActivityThreshold: parseInt(this._settingsService.get('autostop.unusual_activity_threshold'), 10),
|
|
341
|
+
unusualActivityWindowSec: parseInt(this._settingsService.get('autostop.unusual_activity_window_sec'), 10),
|
|
342
|
+
idleTimeoutSec: parseInt(this._settingsService.get('autostop.idle_timeout_sec'), 10),
|
|
343
|
+
idleCheckIntervalSec: parseInt(this._settingsService.get('autostop.idle_check_interval_sec'), 10),
|
|
344
|
+
enabled: this._settingsService.get('autostop.enabled') === 'true',
|
|
345
|
+
};
|
|
346
|
+
this.autoStopService = new AutoStopService({
|
|
347
|
+
sqlite: this.sqlite,
|
|
348
|
+
eventBus: this.eventBus,
|
|
349
|
+
killSwitchService: this.killSwitchService,
|
|
350
|
+
notificationService: this.notificationService ?? undefined,
|
|
351
|
+
config: autoStopConfig,
|
|
352
|
+
});
|
|
353
|
+
if (autoStopConfig.enabled) {
|
|
354
|
+
this.autoStopService.start();
|
|
355
|
+
console.log('Step 4c-3: AutoStop engine started');
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
console.log('Step 4c-3: AutoStop engine disabled');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
console.warn('Step 4c-3 (fail-soft): AutoStop engine init warning:', err);
|
|
364
|
+
this.autoStopService = null;
|
|
365
|
+
}
|
|
366
|
+
// ------------------------------------------------------------------
|
|
367
|
+
// Step 4c-4: BalanceMonitorService initialization (fail-soft)
|
|
368
|
+
// ------------------------------------------------------------------
|
|
369
|
+
try {
|
|
370
|
+
if (this.sqlite && this.adapterPool && this._config && this._settingsService) {
|
|
371
|
+
const { BalanceMonitorService: BalanceMonitorCls } = await import('../services/monitoring/balance-monitor-service.js');
|
|
372
|
+
const monitorConfig = {
|
|
373
|
+
checkIntervalSec: parseInt(this._settingsService.get('monitoring.check_interval_sec'), 10),
|
|
374
|
+
lowBalanceThresholdSol: parseFloat(this._settingsService.get('monitoring.low_balance_threshold_sol')),
|
|
375
|
+
lowBalanceThresholdEth: parseFloat(this._settingsService.get('monitoring.low_balance_threshold_eth')),
|
|
376
|
+
cooldownHours: parseInt(this._settingsService.get('monitoring.cooldown_hours'), 10),
|
|
377
|
+
enabled: this._settingsService.get('monitoring.enabled') === 'true',
|
|
378
|
+
};
|
|
379
|
+
this.balanceMonitorService = new BalanceMonitorCls({
|
|
380
|
+
sqlite: this.sqlite,
|
|
381
|
+
adapterPool: this.adapterPool,
|
|
382
|
+
config: this._config,
|
|
383
|
+
notificationService: this.notificationService ?? undefined,
|
|
384
|
+
monitorConfig,
|
|
385
|
+
});
|
|
386
|
+
if (monitorConfig.enabled) {
|
|
387
|
+
this.balanceMonitorService.start();
|
|
388
|
+
console.log('Step 4c-4: Balance monitor started');
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
console.log('Step 4c-4: Balance monitor disabled');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch (err) {
|
|
396
|
+
console.warn('Step 4c-4 (fail-soft): Balance monitor init warning:', err);
|
|
397
|
+
this.balanceMonitorService = null;
|
|
398
|
+
}
|
|
399
|
+
// ------------------------------------------------------------------
|
|
400
|
+
// Step 4c-5: TelegramBotService initialization (fail-soft)
|
|
401
|
+
// ------------------------------------------------------------------
|
|
402
|
+
try {
|
|
403
|
+
// Read telegram settings from SettingsService (falls back to config.toml)
|
|
404
|
+
const ss = this._settingsService;
|
|
405
|
+
const botEnabled = ss ? ss.get('telegram.enabled') === 'true' : this._config.telegram.enabled;
|
|
406
|
+
// Token priority: telegram.bot_token > notifications.telegram_bot_token > config.toml
|
|
407
|
+
const botToken = (ss ? (ss.get('telegram.bot_token') || ss.get('notifications.telegram_bot_token')) : null)
|
|
408
|
+
|| this._config.telegram.bot_token;
|
|
409
|
+
if (botEnabled && botToken) {
|
|
410
|
+
const { TelegramBotService, TelegramApi } = await import('../infrastructure/telegram/index.js');
|
|
411
|
+
const telegramApi = new TelegramApi(botToken);
|
|
412
|
+
const telegramLocale = ((ss ? ss.get('telegram.locale') : null)
|
|
413
|
+
|| this._config.telegram.locale
|
|
414
|
+
|| this._config.notifications.locale
|
|
415
|
+
|| 'en');
|
|
416
|
+
this.telegramBotService = new TelegramBotService({
|
|
417
|
+
sqlite: this.sqlite,
|
|
418
|
+
api: telegramApi,
|
|
419
|
+
locale: telegramLocale,
|
|
420
|
+
killSwitchService: this.killSwitchService ?? undefined,
|
|
421
|
+
notificationService: this.notificationService ?? undefined,
|
|
422
|
+
settingsService: this._settingsService ?? undefined,
|
|
423
|
+
});
|
|
424
|
+
this.telegramBotService.start();
|
|
425
|
+
this.telegramBotRef.current = this.telegramBotService;
|
|
426
|
+
console.log('Step 4c-5: Telegram Bot started');
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
console.log('Step 4c-5: Telegram Bot disabled');
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch (err) {
|
|
433
|
+
console.warn('Step 4c-5 (fail-soft): Telegram Bot init warning:', err);
|
|
434
|
+
this.telegramBotService = null;
|
|
435
|
+
this.telegramBotRef.current = null;
|
|
436
|
+
}
|
|
437
|
+
// ------------------------------------------------------------------
|
|
438
|
+
// Step 4c-6: WalletConnect service initialization (fail-soft)
|
|
439
|
+
// ------------------------------------------------------------------
|
|
440
|
+
try {
|
|
441
|
+
const wcProjectId = this._settingsService?.get('walletconnect.project_id');
|
|
442
|
+
if (wcProjectId) {
|
|
443
|
+
const { WcSessionService } = await import('../services/wc-session-service.js');
|
|
444
|
+
this.wcSessionService = new WcSessionService({
|
|
445
|
+
sqlite: this.sqlite,
|
|
446
|
+
settingsService: this._settingsService,
|
|
447
|
+
});
|
|
448
|
+
await this.wcSessionService.initialize();
|
|
449
|
+
this.wcServiceRef.current = this.wcSessionService;
|
|
450
|
+
console.log('Step 4c-6: WalletConnect service initialized');
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
console.log('Step 4c-6: WalletConnect disabled (no project_id)');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
catch (err) {
|
|
457
|
+
console.warn('Step 4c-6 (fail-soft): WalletConnect init warning:', err);
|
|
458
|
+
this.wcSessionService = null;
|
|
459
|
+
this.wcServiceRef.current = null;
|
|
460
|
+
}
|
|
461
|
+
// ------------------------------------------------------------------
|
|
462
|
+
// Step 4c-7: WcSigningBridge (fail-soft, requires WcSessionService + ApprovalWorkflow)
|
|
463
|
+
// ------------------------------------------------------------------
|
|
464
|
+
try {
|
|
465
|
+
if (this.wcSessionService && this.approvalWorkflow && this.sqlite) {
|
|
466
|
+
const { WcSigningBridge } = await import('../services/wc-signing-bridge.js');
|
|
467
|
+
this.wcSigningBridge = new WcSigningBridge({
|
|
468
|
+
wcServiceRef: this.wcServiceRef,
|
|
469
|
+
approvalWorkflow: this.approvalWorkflow,
|
|
470
|
+
sqlite: this.sqlite,
|
|
471
|
+
notificationService: this.notificationService ?? undefined,
|
|
472
|
+
eventBus: this.eventBus,
|
|
473
|
+
});
|
|
474
|
+
console.log('Step 4c-7: WcSigningBridge initialized');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
catch (err) {
|
|
478
|
+
console.warn('Step 4c-7 (fail-soft): WcSigningBridge init warning:', err);
|
|
479
|
+
this.wcSigningBridge = null;
|
|
480
|
+
}
|
|
481
|
+
// ------------------------------------------------------------------
|
|
482
|
+
// Step 4e: Price Oracle (fail-soft)
|
|
483
|
+
// ------------------------------------------------------------------
|
|
484
|
+
try {
|
|
485
|
+
const { InMemoryPriceCache, PythOracle, CoinGeckoOracle, OracleChain } = await import('../infrastructure/oracle/index.js');
|
|
486
|
+
const priceCache = new InMemoryPriceCache();
|
|
487
|
+
const pythOracle = new PythOracle();
|
|
488
|
+
const coingeckoApiKey = this._settingsService?.get('oracle.coingecko_api_key');
|
|
489
|
+
const coingeckoOracle = coingeckoApiKey
|
|
490
|
+
? new CoinGeckoOracle(coingeckoApiKey)
|
|
491
|
+
: undefined;
|
|
492
|
+
const thresholdStr = this._settingsService?.get('oracle.cross_validation_threshold');
|
|
493
|
+
const crossValidationThreshold = thresholdStr ? Number(thresholdStr) : 5;
|
|
494
|
+
this.priceOracle = new OracleChain({
|
|
495
|
+
primary: pythOracle,
|
|
496
|
+
fallback: coingeckoOracle,
|
|
497
|
+
cache: priceCache,
|
|
498
|
+
crossValidationThreshold,
|
|
499
|
+
});
|
|
500
|
+
console.log(`Step 4e: PriceOracle initialized (Pyth primary${coingeckoOracle ? ' + CoinGecko fallback' : ''})`);
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
console.warn('Step 4e (fail-soft): PriceOracle init warning:', err);
|
|
504
|
+
this.priceOracle = undefined;
|
|
505
|
+
}
|
|
506
|
+
// ------------------------------------------------------------------
|
|
507
|
+
// Step 4e-2: ForexRateService (fail-soft)
|
|
508
|
+
// ------------------------------------------------------------------
|
|
509
|
+
try {
|
|
510
|
+
const { CoinGeckoForexProvider, ForexRateService, InMemoryPriceCache } = await import('../infrastructure/oracle/index.js');
|
|
511
|
+
const forexCache = new InMemoryPriceCache(30 * 60 * 1000, // TTL: 30 minutes
|
|
512
|
+
2 * 60 * 60 * 1000, // staleMax: 2 hours
|
|
513
|
+
64);
|
|
514
|
+
const coingeckoApiKey = this._settingsService?.get('oracle.coingecko_api_key') ?? '';
|
|
515
|
+
const forexProvider = new CoinGeckoForexProvider(coingeckoApiKey);
|
|
516
|
+
this.forexRateService = new ForexRateService({ forexProvider, cache: forexCache });
|
|
517
|
+
console.log('Step 4e-2: ForexRateService initialized (30min cache)');
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
console.warn('Step 4e-2 (fail-soft): ForexRateService init warning:', err);
|
|
521
|
+
this.forexRateService = null;
|
|
522
|
+
}
|
|
523
|
+
// ------------------------------------------------------------------
|
|
524
|
+
// Step 4f: ActionProviderRegistry + ApiKeyStore (fail-soft)
|
|
525
|
+
// ------------------------------------------------------------------
|
|
526
|
+
try {
|
|
527
|
+
const { ActionProviderRegistry, ApiKeyStore } = await import('../infrastructure/action/index.js');
|
|
528
|
+
this.apiKeyStore = new ApiKeyStore(this._db, masterPassword);
|
|
529
|
+
this.actionProviderRegistry = new ActionProviderRegistry();
|
|
530
|
+
// Load plugins from ~/.waiaas/actions/ (if exists)
|
|
531
|
+
const actionsDir = join(dataDir, 'actions');
|
|
532
|
+
if (existsSync(actionsDir)) {
|
|
533
|
+
const result = await this.actionProviderRegistry.loadPlugins(actionsDir);
|
|
534
|
+
console.log(`Step 4f: ActionProviderRegistry initialized (${result.loaded.length} plugins loaded, ${result.failed.length} failed)`);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
console.log('Step 4f: ActionProviderRegistry initialized (no plugins directory)');
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (err) {
|
|
541
|
+
console.warn('Step 4f (fail-soft): ActionProviderRegistry init warning:', err);
|
|
542
|
+
}
|
|
543
|
+
// ------------------------------------------------------------------
|
|
544
|
+
// Step 4g: VersionCheckService (create before Step 5 for Health endpoint)
|
|
545
|
+
// ------------------------------------------------------------------
|
|
546
|
+
if (this.sqlite && this._config.daemon.update_check) {
|
|
547
|
+
const { VersionCheckService } = await import('../infrastructure/version/index.js');
|
|
548
|
+
this._versionCheckService = new VersionCheckService(this.sqlite);
|
|
549
|
+
console.log('Step 4g: VersionCheckService created');
|
|
550
|
+
}
|
|
551
|
+
// ------------------------------------------------------------------
|
|
552
|
+
// Step 5: HTTP server start (5s, fail-fast)
|
|
553
|
+
// ------------------------------------------------------------------
|
|
554
|
+
await withTimeout((async () => {
|
|
555
|
+
const { createApp } = await import('../api/index.js');
|
|
556
|
+
const { serve } = await import('@hono/node-server');
|
|
557
|
+
const { HotReloadOrchestrator } = await import('../infrastructure/settings/index.js');
|
|
558
|
+
const hotReloader = new HotReloadOrchestrator({
|
|
559
|
+
settingsService: this._settingsService,
|
|
560
|
+
notificationService: this.notificationService,
|
|
561
|
+
adapterPool: this.adapterPool,
|
|
562
|
+
autoStopService: this.autoStopService,
|
|
563
|
+
balanceMonitorService: this.balanceMonitorService,
|
|
564
|
+
wcServiceRef: this.wcServiceRef,
|
|
565
|
+
sqlite: this.sqlite,
|
|
566
|
+
telegramBotRef: this.telegramBotRef,
|
|
567
|
+
killSwitchService: this.killSwitchService,
|
|
568
|
+
});
|
|
569
|
+
const app = createApp({
|
|
570
|
+
db: this._db,
|
|
571
|
+
sqlite: this.sqlite ?? undefined,
|
|
572
|
+
keyStore: this.keyStore,
|
|
573
|
+
masterPassword: this.masterPassword,
|
|
574
|
+
masterPasswordHash: this.masterPasswordHash || undefined,
|
|
575
|
+
config: this._config,
|
|
576
|
+
adapterPool: this.adapterPool,
|
|
577
|
+
policyEngine: new DatabasePolicyEngine(this._db, this.sqlite ?? undefined, this._settingsService ?? undefined),
|
|
578
|
+
jwtSecretManager: this.jwtSecretManager ?? undefined,
|
|
579
|
+
delayQueue: this.delayQueue ?? undefined,
|
|
580
|
+
approvalWorkflow: this.approvalWorkflow ?? undefined,
|
|
581
|
+
notificationService: this.notificationService ?? undefined,
|
|
582
|
+
settingsService: this._settingsService ?? undefined,
|
|
583
|
+
priceOracle: this.priceOracle,
|
|
584
|
+
actionProviderRegistry: this.actionProviderRegistry ?? undefined,
|
|
585
|
+
apiKeyStore: this.apiKeyStore ?? undefined,
|
|
586
|
+
onSettingsChanged: (changedKeys) => {
|
|
587
|
+
void hotReloader.handleChangedKeys(changedKeys);
|
|
588
|
+
},
|
|
589
|
+
dataDir,
|
|
590
|
+
forexRateService: this.forexRateService ?? undefined,
|
|
591
|
+
eventBus: this.eventBus,
|
|
592
|
+
killSwitchService: this.killSwitchService ?? undefined,
|
|
593
|
+
wcServiceRef: this.wcServiceRef,
|
|
594
|
+
wcSigningBridge: this.wcSigningBridge ?? undefined,
|
|
595
|
+
versionCheckService: this._versionCheckService,
|
|
596
|
+
});
|
|
597
|
+
this.httpServer = serve({
|
|
598
|
+
fetch: app.fetch,
|
|
599
|
+
hostname: this._config.daemon.hostname,
|
|
600
|
+
port: this._config.daemon.port,
|
|
601
|
+
});
|
|
602
|
+
console.log(`Step 5: HTTP server listening on ${this._config.daemon.hostname}:${this._config.daemon.port}`);
|
|
603
|
+
})(), 5_000, 'STEP5_HTTP_SERVER');
|
|
604
|
+
// ------------------------------------------------------------------
|
|
605
|
+
// Step 6: Background workers + PID (no timeout, fail-soft)
|
|
606
|
+
// ------------------------------------------------------------------
|
|
607
|
+
try {
|
|
608
|
+
this.workers = new BackgroundWorkers();
|
|
609
|
+
// Register WAL checkpoint worker (default: 5 min = 300s)
|
|
610
|
+
const walInterval = this._config.database.wal_checkpoint_interval * 1000;
|
|
611
|
+
this.workers.register('wal-checkpoint', {
|
|
612
|
+
interval: walInterval,
|
|
613
|
+
handler: () => {
|
|
614
|
+
if (this.sqlite && !this._isShuttingDown) {
|
|
615
|
+
this.sqlite.pragma('wal_checkpoint(PASSIVE)');
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
// Register session cleanup worker (1 min = 60s)
|
|
620
|
+
this.workers.register('session-cleanup', {
|
|
621
|
+
interval: 60_000,
|
|
622
|
+
handler: () => {
|
|
623
|
+
if (this.sqlite && !this._isShuttingDown) {
|
|
624
|
+
// Notify expired sessions before deletion (fire-and-forget)
|
|
625
|
+
if (this.notificationService) {
|
|
626
|
+
try {
|
|
627
|
+
const expired = this.sqlite.prepare("SELECT id, wallet_id FROM sessions WHERE expires_at < unixepoch() AND revoked_at IS NULL").all();
|
|
628
|
+
for (const session of expired) {
|
|
629
|
+
void this.notificationService.notify('SESSION_EXPIRED', session.wallet_id, {
|
|
630
|
+
sessionId: session.id,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
// Fire-and-forget: never block cleanup
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
this.sqlite.exec("DELETE FROM sessions WHERE expires_at < unixepoch() AND revoked_at IS NULL");
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
});
|
|
642
|
+
// Register delay-expired worker (every 5s: check for expired DELAY transactions)
|
|
643
|
+
if (this.delayQueue) {
|
|
644
|
+
this.workers.register('delay-expired', {
|
|
645
|
+
interval: 5_000,
|
|
646
|
+
handler: () => {
|
|
647
|
+
if (this._isShuttingDown)
|
|
648
|
+
return;
|
|
649
|
+
const now = Math.floor(Date.now() / 1000);
|
|
650
|
+
const expired = this.delayQueue.processExpired(now);
|
|
651
|
+
for (const tx of expired) {
|
|
652
|
+
void this.executeFromStage5(tx.txId, tx.walletId);
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
// Register approval-expired worker (every 30s: expire timed-out approvals)
|
|
658
|
+
if (this.approvalWorkflow) {
|
|
659
|
+
this.workers.register('approval-expired', {
|
|
660
|
+
interval: 30_000,
|
|
661
|
+
handler: () => {
|
|
662
|
+
if (this._isShuttingDown)
|
|
663
|
+
return;
|
|
664
|
+
const now = Math.floor(Date.now() / 1000);
|
|
665
|
+
this.approvalWorkflow.processExpiredApprovals(now);
|
|
666
|
+
},
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
// Register version-check worker (uses instance created in Step 4g)
|
|
670
|
+
if (this._versionCheckService) {
|
|
671
|
+
const versionCheckInterval = this._config.daemon.update_check_interval * 1000;
|
|
672
|
+
this.workers.register('version-check', {
|
|
673
|
+
interval: versionCheckInterval,
|
|
674
|
+
runImmediately: true,
|
|
675
|
+
handler: async () => { await this._versionCheckService.check(); },
|
|
676
|
+
});
|
|
677
|
+
console.log('Step 6: Version check worker registered');
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
console.log('Step 6: Version check disabled');
|
|
681
|
+
}
|
|
682
|
+
this.workers.startAll();
|
|
683
|
+
// Write PID file
|
|
684
|
+
this.pidPath = join(dataDir, this._config.daemon.pid_file);
|
|
685
|
+
writeFileSync(this.pidPath, String(process.pid), 'utf-8');
|
|
686
|
+
console.log(`Step 6: Workers started, PID file written`);
|
|
687
|
+
console.log(`WAIaaS daemon ready (PID: ${process.pid})`);
|
|
688
|
+
}
|
|
689
|
+
catch (err) {
|
|
690
|
+
console.warn('Step 6 (fail-soft): Worker/PID warning:', err);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* 10-step graceful shutdown cascade.
|
|
695
|
+
*/
|
|
696
|
+
async shutdown(signal) {
|
|
697
|
+
// Guard against double shutdown
|
|
698
|
+
if (this._isShuttingDown)
|
|
699
|
+
return;
|
|
700
|
+
this._isShuttingDown = true;
|
|
701
|
+
console.log(`Shutdown initiated by ${signal}`);
|
|
702
|
+
// Start force-exit timer (configurable, default 30s)
|
|
703
|
+
const timeout = this._config?.daemon.shutdown_timeout ?? 30;
|
|
704
|
+
this.forceTimer = setTimeout(() => {
|
|
705
|
+
console.error('Force exit: shutdown timeout exceeded');
|
|
706
|
+
process.exit(1);
|
|
707
|
+
}, timeout * 1000);
|
|
708
|
+
this.forceTimer.unref(); // don't prevent exit
|
|
709
|
+
try {
|
|
710
|
+
// Steps 1: Set flag + log (done above)
|
|
711
|
+
// Steps 2-4: HTTP server close
|
|
712
|
+
if (this.httpServer) {
|
|
713
|
+
this.httpServer.close();
|
|
714
|
+
console.log('Steps 2-4: HTTP server closed');
|
|
715
|
+
}
|
|
716
|
+
// Steps 5: In-flight signing -- STUB (Phase 50-04)
|
|
717
|
+
// Steps 6: Pending queue persistence -- STUB (Phase 50-04)
|
|
718
|
+
// Disconnect all chain adapters
|
|
719
|
+
if (this.adapterPool) {
|
|
720
|
+
try {
|
|
721
|
+
await this.adapterPool.disconnectAll();
|
|
722
|
+
console.log('Adapter pool disconnected');
|
|
723
|
+
}
|
|
724
|
+
catch (err) {
|
|
725
|
+
console.warn('Adapter pool disconnect warning:', err);
|
|
726
|
+
}
|
|
727
|
+
this.adapterPool = null;
|
|
728
|
+
}
|
|
729
|
+
// Stop AutoStop engine (before EventBus cleanup)
|
|
730
|
+
if (this.autoStopService) {
|
|
731
|
+
this.autoStopService.stop();
|
|
732
|
+
this.autoStopService = null;
|
|
733
|
+
}
|
|
734
|
+
// Stop BalanceMonitorService (before EventBus cleanup)
|
|
735
|
+
if (this.balanceMonitorService) {
|
|
736
|
+
this.balanceMonitorService.stop();
|
|
737
|
+
this.balanceMonitorService = null;
|
|
738
|
+
}
|
|
739
|
+
// Stop TelegramBotService (before EventBus cleanup)
|
|
740
|
+
if (this.telegramBotService) {
|
|
741
|
+
this.telegramBotService.stop();
|
|
742
|
+
this.telegramBotService = null;
|
|
743
|
+
this.telegramBotRef.current = null;
|
|
744
|
+
}
|
|
745
|
+
// Stop WcSessionService (before EventBus cleanup)
|
|
746
|
+
if (this.wcSessionService) {
|
|
747
|
+
try {
|
|
748
|
+
await this.wcSessionService.shutdown();
|
|
749
|
+
}
|
|
750
|
+
catch (err) {
|
|
751
|
+
console.warn('WcSessionService shutdown warning:', err);
|
|
752
|
+
}
|
|
753
|
+
this.wcSessionService = null;
|
|
754
|
+
this.wcServiceRef.current = null;
|
|
755
|
+
}
|
|
756
|
+
// Step 6b: Remove all EventBus listeners
|
|
757
|
+
this.eventBus.removeAllListeners();
|
|
758
|
+
// Step 7: Stop background workers
|
|
759
|
+
if (this.workers) {
|
|
760
|
+
await this.workers.stopAll();
|
|
761
|
+
console.log('Step 7: Workers stopped');
|
|
762
|
+
}
|
|
763
|
+
// Step 8: WAL checkpoint(TRUNCATE)
|
|
764
|
+
if (this.sqlite) {
|
|
765
|
+
try {
|
|
766
|
+
this.sqlite.pragma('wal_checkpoint(TRUNCATE)');
|
|
767
|
+
console.log('Step 8: WAL checkpoint complete');
|
|
768
|
+
}
|
|
769
|
+
catch (err) {
|
|
770
|
+
console.warn('Step 8: WAL checkpoint warning:', err);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// Step 9: Keystore lock (sodium_memzero all guarded buffers)
|
|
774
|
+
if (this.keyStore) {
|
|
775
|
+
this.keyStore.lockAll();
|
|
776
|
+
console.log('Step 9: Keystore locked');
|
|
777
|
+
}
|
|
778
|
+
// Clear master password and hash from memory
|
|
779
|
+
this.masterPassword = '';
|
|
780
|
+
this.masterPasswordHash = '';
|
|
781
|
+
// Step 10: Close DB, unlink PID, release lock
|
|
782
|
+
if (this.sqlite) {
|
|
783
|
+
try {
|
|
784
|
+
this.sqlite.close();
|
|
785
|
+
console.log('Step 10: Database closed');
|
|
786
|
+
}
|
|
787
|
+
catch (err) {
|
|
788
|
+
console.warn('Step 10: DB close warning:', err);
|
|
789
|
+
}
|
|
790
|
+
this.sqlite = null;
|
|
791
|
+
this._db = null;
|
|
792
|
+
}
|
|
793
|
+
// Delete PID file
|
|
794
|
+
if (this.pidPath) {
|
|
795
|
+
try {
|
|
796
|
+
unlinkSync(this.pidPath);
|
|
797
|
+
}
|
|
798
|
+
catch {
|
|
799
|
+
// Ignore if already deleted
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
// Release daemon lock
|
|
803
|
+
if (this.releaseLock) {
|
|
804
|
+
try {
|
|
805
|
+
await this.releaseLock();
|
|
806
|
+
}
|
|
807
|
+
catch {
|
|
808
|
+
// Ignore lock release errors during shutdown
|
|
809
|
+
}
|
|
810
|
+
this.releaseLock = null;
|
|
811
|
+
}
|
|
812
|
+
// Cancel force timer
|
|
813
|
+
if (this.forceTimer) {
|
|
814
|
+
clearTimeout(this.forceTimer);
|
|
815
|
+
this.forceTimer = null;
|
|
816
|
+
}
|
|
817
|
+
console.log('Shutdown complete');
|
|
818
|
+
}
|
|
819
|
+
catch (err) {
|
|
820
|
+
console.error('Shutdown error:', err);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Re-enter the pipeline at stage5 for a delay-expired transaction.
|
|
825
|
+
*
|
|
826
|
+
* Called by the delay-expired BackgroundWorker when processExpired()
|
|
827
|
+
* returns transactions whose cooldown has elapsed.
|
|
828
|
+
*
|
|
829
|
+
* @param txId - Transaction ID to execute
|
|
830
|
+
* @param walletId - Wallet that owns the transaction
|
|
831
|
+
*/
|
|
832
|
+
async executeFromStage5(txId, walletId) {
|
|
833
|
+
try {
|
|
834
|
+
if (!this._db || !this.adapterPool || !this.keyStore || !this._config) {
|
|
835
|
+
console.warn(`executeFromStage5(${txId}): missing deps, skipping`);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
// Import stages and schema
|
|
839
|
+
const { stage5Execute, stage6Confirm } = await import('../pipeline/stages.js');
|
|
840
|
+
const { wallets, transactions } = await import('../infrastructure/database/schema.js');
|
|
841
|
+
const { eq } = await import('drizzle-orm');
|
|
842
|
+
// Look up wallet from DB
|
|
843
|
+
const wallet = this._db.select().from(wallets).where(eq(wallets.id, walletId)).get();
|
|
844
|
+
if (!wallet) {
|
|
845
|
+
console.warn(`executeFromStage5(${txId}): wallet ${walletId} not found`);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
// Look up transaction to get request data
|
|
849
|
+
const tx = this._db.select().from(transactions).where(eq(transactions.id, txId)).get();
|
|
850
|
+
if (!tx) {
|
|
851
|
+
console.warn(`executeFromStage5(${txId}): transaction not found`);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
// Use network recorded at Stage 1 (NOT re-resolve -- wallet.defaultNetwork may have changed)
|
|
855
|
+
const resolvedNetwork = tx.network
|
|
856
|
+
?? getDefaultNetwork(wallet.chain, wallet.environment);
|
|
857
|
+
// Resolve adapter from pool using recorded network
|
|
858
|
+
const rpcUrl = resolveRpcUrl(this._config.rpc, wallet.chain, resolvedNetwork);
|
|
859
|
+
const adapter = await this.adapterPool.resolve(wallet.chain, resolvedNetwork, rpcUrl);
|
|
860
|
+
// Construct minimal PipelineContext for stages 5-6
|
|
861
|
+
const ctx = {
|
|
862
|
+
db: this._db,
|
|
863
|
+
adapter,
|
|
864
|
+
keyStore: this.keyStore,
|
|
865
|
+
policyEngine: null, // Not needed for stages 5-6
|
|
866
|
+
masterPassword: this.masterPassword,
|
|
867
|
+
walletId,
|
|
868
|
+
wallet: {
|
|
869
|
+
publicKey: wallet.publicKey,
|
|
870
|
+
chain: wallet.chain,
|
|
871
|
+
environment: wallet.environment,
|
|
872
|
+
defaultNetwork: wallet.defaultNetwork ?? null,
|
|
873
|
+
},
|
|
874
|
+
resolvedNetwork,
|
|
875
|
+
request: {
|
|
876
|
+
to: tx.toAddress ?? '',
|
|
877
|
+
amount: tx.amount ?? '0',
|
|
878
|
+
memo: undefined,
|
|
879
|
+
},
|
|
880
|
+
txId,
|
|
881
|
+
eventBus: this.eventBus,
|
|
882
|
+
};
|
|
883
|
+
await stage5Execute(ctx);
|
|
884
|
+
await stage6Confirm(ctx);
|
|
885
|
+
}
|
|
886
|
+
catch (error) {
|
|
887
|
+
// Mark as FAILED if stages 5-6 throw
|
|
888
|
+
try {
|
|
889
|
+
if (this._db) {
|
|
890
|
+
const { transactions } = await import('../infrastructure/database/schema.js');
|
|
891
|
+
const { eq } = await import('drizzle-orm');
|
|
892
|
+
const errorMessage = error instanceof Error ? error.message : 'Pipeline re-entry failed';
|
|
893
|
+
this._db
|
|
894
|
+
.update(transactions)
|
|
895
|
+
.set({ status: 'FAILED', error: errorMessage })
|
|
896
|
+
.where(eq(transactions.id, txId))
|
|
897
|
+
.run();
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
catch {
|
|
901
|
+
// Swallow DB update errors in background
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Acquire an exclusive daemon lock to prevent multiple instances.
|
|
907
|
+
* Uses proper-lockfile for cross-platform support.
|
|
908
|
+
*/
|
|
909
|
+
async acquireDaemonLock(dataDir) {
|
|
910
|
+
const lockPath = join(dataDir, 'daemon.lock');
|
|
911
|
+
// Ensure the lock file exists (proper-lockfile requires it)
|
|
912
|
+
if (!existsSync(lockPath)) {
|
|
913
|
+
writeFileSync(lockPath, '', 'utf-8');
|
|
914
|
+
}
|
|
915
|
+
try {
|
|
916
|
+
const lockfile = await getLockfile();
|
|
917
|
+
this.releaseLock = await lockfile.lock(lockPath, {
|
|
918
|
+
stale: 10_000, // Consider lock stale after 10s without update
|
|
919
|
+
update: 5_000, // Update lock mtime every 5s
|
|
920
|
+
retries: 0, // No retries -- fail immediately if locked
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
catch (err) {
|
|
924
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
925
|
+
if (errMsg.includes('already being held') || errMsg.includes('ELOCKED')) {
|
|
926
|
+
throw new WAIaaSError('SYSTEM_LOCKED', {
|
|
927
|
+
message: 'Another WAIaaS daemon is already running (daemon.lock is held)',
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
throw err;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
//# sourceMappingURL=daemon.js.map
|