@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,1214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema push + incremental migration runner for daemon SQLite database.
|
|
3
|
+
*
|
|
4
|
+
* Creates all 15 tables with indexes, foreign keys, and CHECK constraints
|
|
5
|
+
* using CREATE TABLE IF NOT EXISTS statements. After initial schema creation,
|
|
6
|
+
* runs incremental migrations via runMigrations() for ALTER TABLE changes.
|
|
7
|
+
*
|
|
8
|
+
* v1.4+: DB schema changes MUST use ALTER TABLE incremental migrations (MIG-01~06).
|
|
9
|
+
* DB deletion and recreation is prohibited.
|
|
10
|
+
*
|
|
11
|
+
* v1.4.2: agents table renamed to wallets (v3 migration). DDL uses latest
|
|
12
|
+
* names (wallets, wallet_id). pushSchema records LATEST_SCHEMA_VERSION so
|
|
13
|
+
* migrations are only needed for existing (pre-v3) databases.
|
|
14
|
+
*
|
|
15
|
+
* v1.4.6: Environment model migration:
|
|
16
|
+
* v6a (version 6): Add network column to transactions with backfill from wallets
|
|
17
|
+
* v6b (version 7): Replace wallets.network with environment + default_network (12-step)
|
|
18
|
+
* v8 (version 8): Add network column to policies (12-step)
|
|
19
|
+
*
|
|
20
|
+
* @see docs/25-sqlite-schema.md
|
|
21
|
+
* @see docs/65-migration-strategy.md
|
|
22
|
+
* @see docs/69-db-migration-v6-design.md
|
|
23
|
+
* @see docs/71-policy-engine-network-extension-design.md
|
|
24
|
+
*/
|
|
25
|
+
import { WALLET_STATUSES, CHAIN_TYPES, NETWORK_TYPES, ENVIRONMENT_TYPES, TRANSACTION_STATUSES, TRANSACTION_TYPES, POLICY_TYPES, POLICY_TIERS, NOTIFICATION_LOG_STATUSES, } from '@waiaas/core';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Utility: build CHECK IN clause from SSoT arrays
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const inList = (values) => values.map((v) => `'${v}'`).join(', ');
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// DDL statements for all 15 tables (latest schema: wallets + wallet_id + token_registry + settings + api_keys + telegram_users + wc_sessions + wc_store)
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/**
|
|
34
|
+
* The latest schema version that getCreateTableStatements() represents.
|
|
35
|
+
* pushSchema() records this version for fresh databases so migrations are skipped.
|
|
36
|
+
* Increment this whenever DDL statements are updated to match a new migration.
|
|
37
|
+
*/
|
|
38
|
+
export const LATEST_SCHEMA_VERSION = 16;
|
|
39
|
+
function getCreateTableStatements() {
|
|
40
|
+
return [
|
|
41
|
+
// Table 1: wallets (renamed from agents in v3, environment model in v6b)
|
|
42
|
+
`CREATE TABLE IF NOT EXISTS wallets (
|
|
43
|
+
id TEXT PRIMARY KEY,
|
|
44
|
+
name TEXT NOT NULL,
|
|
45
|
+
chain TEXT NOT NULL CHECK (chain IN (${inList(CHAIN_TYPES)})),
|
|
46
|
+
environment TEXT NOT NULL CHECK (environment IN (${inList(ENVIRONMENT_TYPES)})),
|
|
47
|
+
default_network TEXT CHECK (default_network IS NULL OR default_network IN (${inList(NETWORK_TYPES)})),
|
|
48
|
+
public_key TEXT NOT NULL,
|
|
49
|
+
status TEXT NOT NULL DEFAULT 'CREATING' CHECK (status IN (${inList(WALLET_STATUSES)})),
|
|
50
|
+
owner_address TEXT,
|
|
51
|
+
owner_verified INTEGER NOT NULL DEFAULT 0 CHECK (owner_verified IN (0, 1)),
|
|
52
|
+
created_at INTEGER NOT NULL,
|
|
53
|
+
updated_at INTEGER NOT NULL,
|
|
54
|
+
suspended_at INTEGER,
|
|
55
|
+
suspension_reason TEXT
|
|
56
|
+
)`,
|
|
57
|
+
// Table 2: sessions
|
|
58
|
+
`CREATE TABLE IF NOT EXISTS sessions (
|
|
59
|
+
id TEXT PRIMARY KEY,
|
|
60
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE CASCADE,
|
|
61
|
+
token_hash TEXT NOT NULL,
|
|
62
|
+
expires_at INTEGER NOT NULL,
|
|
63
|
+
constraints TEXT,
|
|
64
|
+
usage_stats TEXT,
|
|
65
|
+
revoked_at INTEGER,
|
|
66
|
+
renewal_count INTEGER NOT NULL DEFAULT 0,
|
|
67
|
+
max_renewals INTEGER NOT NULL DEFAULT 30,
|
|
68
|
+
last_renewed_at INTEGER,
|
|
69
|
+
absolute_expires_at INTEGER NOT NULL,
|
|
70
|
+
created_at INTEGER NOT NULL
|
|
71
|
+
)`,
|
|
72
|
+
// Table 3: transactions
|
|
73
|
+
`CREATE TABLE IF NOT EXISTS transactions (
|
|
74
|
+
id TEXT PRIMARY KEY,
|
|
75
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
|
|
76
|
+
session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
77
|
+
chain TEXT NOT NULL,
|
|
78
|
+
tx_hash TEXT,
|
|
79
|
+
type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
|
|
80
|
+
amount TEXT,
|
|
81
|
+
to_address TEXT,
|
|
82
|
+
token_mint TEXT,
|
|
83
|
+
contract_address TEXT,
|
|
84
|
+
method_signature TEXT,
|
|
85
|
+
spender_address TEXT,
|
|
86
|
+
approved_amount TEXT,
|
|
87
|
+
parent_id TEXT REFERENCES transactions(id) ON DELETE CASCADE,
|
|
88
|
+
batch_index INTEGER,
|
|
89
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
|
|
90
|
+
tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
|
|
91
|
+
queued_at INTEGER,
|
|
92
|
+
executed_at INTEGER,
|
|
93
|
+
created_at INTEGER NOT NULL,
|
|
94
|
+
reserved_amount TEXT,
|
|
95
|
+
amount_usd REAL,
|
|
96
|
+
reserved_amount_usd REAL,
|
|
97
|
+
error TEXT,
|
|
98
|
+
metadata TEXT,
|
|
99
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)}))
|
|
100
|
+
)`,
|
|
101
|
+
// Table 4: policies (network column added in v8)
|
|
102
|
+
`CREATE TABLE IF NOT EXISTS policies (
|
|
103
|
+
id TEXT PRIMARY KEY,
|
|
104
|
+
wallet_id TEXT REFERENCES wallets(id) ON DELETE CASCADE,
|
|
105
|
+
type TEXT NOT NULL CHECK (type IN (${inList(POLICY_TYPES)})),
|
|
106
|
+
rules TEXT NOT NULL,
|
|
107
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
108
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
109
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
|
|
110
|
+
created_at INTEGER NOT NULL,
|
|
111
|
+
updated_at INTEGER NOT NULL
|
|
112
|
+
)`,
|
|
113
|
+
// Table 5: pending_approvals (approval_channel added in v16)
|
|
114
|
+
`CREATE TABLE IF NOT EXISTS pending_approvals (
|
|
115
|
+
id TEXT PRIMARY KEY,
|
|
116
|
+
tx_id TEXT NOT NULL REFERENCES transactions(id) ON DELETE CASCADE,
|
|
117
|
+
required_by INTEGER NOT NULL,
|
|
118
|
+
expires_at INTEGER NOT NULL,
|
|
119
|
+
approved_at INTEGER,
|
|
120
|
+
rejected_at INTEGER,
|
|
121
|
+
owner_signature TEXT,
|
|
122
|
+
approval_channel TEXT DEFAULT 'rest_api',
|
|
123
|
+
created_at INTEGER NOT NULL
|
|
124
|
+
)`,
|
|
125
|
+
// Table 6: audit_log
|
|
126
|
+
`CREATE TABLE IF NOT EXISTS audit_log (
|
|
127
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
128
|
+
timestamp INTEGER NOT NULL,
|
|
129
|
+
event_type TEXT NOT NULL,
|
|
130
|
+
actor TEXT NOT NULL,
|
|
131
|
+
wallet_id TEXT,
|
|
132
|
+
session_id TEXT,
|
|
133
|
+
tx_id TEXT,
|
|
134
|
+
details TEXT NOT NULL,
|
|
135
|
+
severity TEXT NOT NULL DEFAULT 'info' CHECK (severity IN ('info', 'warning', 'critical')),
|
|
136
|
+
ip_address TEXT
|
|
137
|
+
)`,
|
|
138
|
+
// Table 7: key_value_store
|
|
139
|
+
`CREATE TABLE IF NOT EXISTS key_value_store (
|
|
140
|
+
key TEXT PRIMARY KEY,
|
|
141
|
+
value TEXT NOT NULL,
|
|
142
|
+
updated_at INTEGER NOT NULL
|
|
143
|
+
)`,
|
|
144
|
+
// Table 8: notification_logs
|
|
145
|
+
`CREATE TABLE IF NOT EXISTS notification_logs (
|
|
146
|
+
id TEXT PRIMARY KEY,
|
|
147
|
+
event_type TEXT NOT NULL,
|
|
148
|
+
wallet_id TEXT,
|
|
149
|
+
channel TEXT NOT NULL,
|
|
150
|
+
status TEXT NOT NULL CHECK (status IN (${inList(NOTIFICATION_LOG_STATUSES)})),
|
|
151
|
+
error TEXT,
|
|
152
|
+
message TEXT,
|
|
153
|
+
created_at INTEGER NOT NULL
|
|
154
|
+
)`,
|
|
155
|
+
// Table 9: token_registry
|
|
156
|
+
`CREATE TABLE IF NOT EXISTS token_registry (
|
|
157
|
+
id TEXT PRIMARY KEY,
|
|
158
|
+
network TEXT NOT NULL,
|
|
159
|
+
address TEXT NOT NULL,
|
|
160
|
+
symbol TEXT NOT NULL,
|
|
161
|
+
name TEXT NOT NULL,
|
|
162
|
+
decimals INTEGER NOT NULL,
|
|
163
|
+
source TEXT NOT NULL DEFAULT 'custom' CHECK (source IN ('builtin', 'custom')),
|
|
164
|
+
created_at INTEGER NOT NULL
|
|
165
|
+
)`,
|
|
166
|
+
// Table 10: settings
|
|
167
|
+
`CREATE TABLE IF NOT EXISTS settings (
|
|
168
|
+
key TEXT PRIMARY KEY,
|
|
169
|
+
value TEXT NOT NULL,
|
|
170
|
+
encrypted INTEGER NOT NULL DEFAULT 0 CHECK (encrypted IN (0, 1)),
|
|
171
|
+
category TEXT NOT NULL,
|
|
172
|
+
updated_at INTEGER NOT NULL
|
|
173
|
+
)`,
|
|
174
|
+
// Table 11: api_keys (Action Provider API key encrypted storage, v1.5)
|
|
175
|
+
`CREATE TABLE IF NOT EXISTS api_keys (
|
|
176
|
+
provider_name TEXT PRIMARY KEY,
|
|
177
|
+
encrypted_key TEXT NOT NULL,
|
|
178
|
+
created_at INTEGER NOT NULL,
|
|
179
|
+
updated_at INTEGER NOT NULL
|
|
180
|
+
)`,
|
|
181
|
+
// Table 12: schema_version
|
|
182
|
+
`CREATE TABLE IF NOT EXISTS schema_version (
|
|
183
|
+
version INTEGER PRIMARY KEY,
|
|
184
|
+
applied_at INTEGER NOT NULL,
|
|
185
|
+
description TEXT NOT NULL
|
|
186
|
+
)`,
|
|
187
|
+
// Table 13: telegram_users (Telegram Bot user management, v1.6)
|
|
188
|
+
`CREATE TABLE IF NOT EXISTS telegram_users (
|
|
189
|
+
chat_id INTEGER PRIMARY KEY,
|
|
190
|
+
username TEXT,
|
|
191
|
+
role TEXT NOT NULL DEFAULT 'PENDING' CHECK (role IN ('PENDING', 'ADMIN', 'READONLY')),
|
|
192
|
+
registered_at INTEGER NOT NULL,
|
|
193
|
+
approved_at INTEGER
|
|
194
|
+
)`,
|
|
195
|
+
// Table 14: wc_sessions (WalletConnect session metadata, v1.6.1)
|
|
196
|
+
`CREATE TABLE IF NOT EXISTS wc_sessions (
|
|
197
|
+
wallet_id TEXT PRIMARY KEY REFERENCES wallets(id) ON DELETE CASCADE,
|
|
198
|
+
topic TEXT NOT NULL UNIQUE,
|
|
199
|
+
peer_meta TEXT,
|
|
200
|
+
chain_id TEXT NOT NULL,
|
|
201
|
+
owner_address TEXT NOT NULL,
|
|
202
|
+
namespaces TEXT,
|
|
203
|
+
expiry INTEGER NOT NULL,
|
|
204
|
+
created_at INTEGER NOT NULL
|
|
205
|
+
)`,
|
|
206
|
+
// Table 15: wc_store (WalletConnect IKeyValueStorage, v1.6.1)
|
|
207
|
+
`CREATE TABLE IF NOT EXISTS wc_store (
|
|
208
|
+
key TEXT PRIMARY KEY,
|
|
209
|
+
value TEXT NOT NULL
|
|
210
|
+
)`,
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Index creation statements
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
function getCreateIndexStatements() {
|
|
217
|
+
return [
|
|
218
|
+
// wallets indexes (renamed from agents in v3)
|
|
219
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS idx_wallets_public_key ON wallets(public_key)',
|
|
220
|
+
'CREATE INDEX IF NOT EXISTS idx_wallets_status ON wallets(status)',
|
|
221
|
+
'CREATE INDEX IF NOT EXISTS idx_wallets_chain_environment ON wallets(chain, environment)',
|
|
222
|
+
'CREATE INDEX IF NOT EXISTS idx_wallets_owner_address ON wallets(owner_address)',
|
|
223
|
+
// sessions indexes
|
|
224
|
+
'CREATE INDEX IF NOT EXISTS idx_sessions_wallet_id ON sessions(wallet_id)',
|
|
225
|
+
'CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at)',
|
|
226
|
+
'CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash)',
|
|
227
|
+
// transactions indexes
|
|
228
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_wallet_status ON transactions(wallet_id, status)',
|
|
229
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_session_id ON transactions(session_id)',
|
|
230
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS idx_transactions_tx_hash ON transactions(tx_hash)',
|
|
231
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_queued_at ON transactions(queued_at)',
|
|
232
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_created_at ON transactions(created_at)',
|
|
233
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_type ON transactions(type)',
|
|
234
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_contract_address ON transactions(contract_address)',
|
|
235
|
+
'CREATE INDEX IF NOT EXISTS idx_transactions_parent_id ON transactions(parent_id)',
|
|
236
|
+
// policies indexes
|
|
237
|
+
'CREATE INDEX IF NOT EXISTS idx_policies_wallet_enabled ON policies(wallet_id, enabled)',
|
|
238
|
+
'CREATE INDEX IF NOT EXISTS idx_policies_type ON policies(type)',
|
|
239
|
+
'CREATE INDEX IF NOT EXISTS idx_policies_network ON policies(network)',
|
|
240
|
+
// pending_approvals indexes
|
|
241
|
+
'CREATE INDEX IF NOT EXISTS idx_pending_approvals_tx_id ON pending_approvals(tx_id)',
|
|
242
|
+
'CREATE INDEX IF NOT EXISTS idx_pending_approvals_expires_at ON pending_approvals(expires_at)',
|
|
243
|
+
// audit_log indexes
|
|
244
|
+
'CREATE INDEX IF NOT EXISTS idx_audit_log_timestamp ON audit_log(timestamp)',
|
|
245
|
+
'CREATE INDEX IF NOT EXISTS idx_audit_log_event_type ON audit_log(event_type)',
|
|
246
|
+
'CREATE INDEX IF NOT EXISTS idx_audit_log_wallet_id ON audit_log(wallet_id)',
|
|
247
|
+
'CREATE INDEX IF NOT EXISTS idx_audit_log_severity ON audit_log(severity)',
|
|
248
|
+
'CREATE INDEX IF NOT EXISTS idx_audit_log_wallet_timestamp ON audit_log(wallet_id, timestamp)',
|
|
249
|
+
// notification_logs indexes
|
|
250
|
+
'CREATE INDEX IF NOT EXISTS idx_notification_logs_event_type ON notification_logs(event_type)',
|
|
251
|
+
'CREATE INDEX IF NOT EXISTS idx_notification_logs_wallet_id ON notification_logs(wallet_id)',
|
|
252
|
+
'CREATE INDEX IF NOT EXISTS idx_notification_logs_status ON notification_logs(status)',
|
|
253
|
+
'CREATE INDEX IF NOT EXISTS idx_notification_logs_created_at ON notification_logs(created_at)',
|
|
254
|
+
// token_registry indexes
|
|
255
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS idx_token_registry_network_address ON token_registry(network, address)',
|
|
256
|
+
'CREATE INDEX IF NOT EXISTS idx_token_registry_network ON token_registry(network)',
|
|
257
|
+
// settings indexes
|
|
258
|
+
'CREATE INDEX IF NOT EXISTS idx_settings_category ON settings(category)',
|
|
259
|
+
// telegram_users indexes
|
|
260
|
+
'CREATE INDEX IF NOT EXISTS idx_telegram_users_role ON telegram_users(role)',
|
|
261
|
+
// wc_sessions indexes
|
|
262
|
+
'CREATE INDEX IF NOT EXISTS idx_wc_sessions_topic ON wc_sessions(topic)',
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Global migration registry. v1.4 migrations will be added here in subsequent phases.
|
|
267
|
+
* Each migration's version must be unique and greater than 1.
|
|
268
|
+
*/
|
|
269
|
+
export const MIGRATIONS = [];
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
// v2: Expand agents.network CHECK to include EVM networks
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// SQLite cannot ALTER CHECK constraints, so we use 12-step table recreation.
|
|
274
|
+
// This requires PRAGMA foreign_keys=OFF (handled by managesOwnTransaction).
|
|
275
|
+
MIGRATIONS.push({
|
|
276
|
+
version: 2,
|
|
277
|
+
description: 'Expand agents network CHECK to include EVM networks',
|
|
278
|
+
managesOwnTransaction: true,
|
|
279
|
+
up: (sqlite) => {
|
|
280
|
+
// Step 1: Begin transaction (foreign_keys already OFF via runner)
|
|
281
|
+
sqlite.exec('BEGIN');
|
|
282
|
+
try {
|
|
283
|
+
// Step 2: Create new agents table with expanded CHECK (uses SSoT arrays)
|
|
284
|
+
sqlite.exec(`CREATE TABLE agents_new (
|
|
285
|
+
id TEXT PRIMARY KEY,
|
|
286
|
+
name TEXT NOT NULL,
|
|
287
|
+
chain TEXT NOT NULL CHECK (chain IN (${inList(CHAIN_TYPES)})),
|
|
288
|
+
network TEXT NOT NULL CHECK (network IN (${inList(NETWORK_TYPES)})),
|
|
289
|
+
public_key TEXT NOT NULL,
|
|
290
|
+
status TEXT NOT NULL DEFAULT 'CREATING' CHECK (status IN (${inList(WALLET_STATUSES)})),
|
|
291
|
+
owner_address TEXT,
|
|
292
|
+
owner_verified INTEGER NOT NULL DEFAULT 0 CHECK (owner_verified IN (0, 1)),
|
|
293
|
+
created_at INTEGER NOT NULL,
|
|
294
|
+
updated_at INTEGER NOT NULL,
|
|
295
|
+
suspended_at INTEGER,
|
|
296
|
+
suspension_reason TEXT
|
|
297
|
+
)`);
|
|
298
|
+
// Step 3: Copy existing data
|
|
299
|
+
sqlite.exec('INSERT INTO agents_new SELECT * FROM agents');
|
|
300
|
+
// Step 4: Drop old table
|
|
301
|
+
sqlite.exec('DROP TABLE agents');
|
|
302
|
+
// Step 5: Rename new table
|
|
303
|
+
sqlite.exec('ALTER TABLE agents_new RENAME TO agents');
|
|
304
|
+
// Step 6: Recreate indexes
|
|
305
|
+
sqlite.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_agents_public_key ON agents(public_key)');
|
|
306
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status)');
|
|
307
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_agents_chain_network ON agents(chain, network)');
|
|
308
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_agents_owner_address ON agents(owner_address)');
|
|
309
|
+
// Step 7: Commit transaction
|
|
310
|
+
sqlite.exec('COMMIT');
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
sqlite.exec('ROLLBACK');
|
|
314
|
+
throw err;
|
|
315
|
+
}
|
|
316
|
+
// Step 8: Re-enable foreign keys to run integrity check
|
|
317
|
+
sqlite.pragma('foreign_keys = ON');
|
|
318
|
+
// Step 9: Verify FK integrity
|
|
319
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
320
|
+
if (fkErrors.length > 0) {
|
|
321
|
+
throw new Error(`FK integrity check failed after v2 migration: ${JSON.stringify(fkErrors)}`);
|
|
322
|
+
}
|
|
323
|
+
// Note: Runner will also set foreign_keys = ON after we return,
|
|
324
|
+
// but we set it here to run the integrity check with FK enabled.
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
// v3: Rename agents to wallets (table, FK columns, indexes, enum data)
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
// Renames agents table to wallets, agent_id columns to wallet_id in 5 tables,
|
|
331
|
+
// recreates all affected indexes, and updates AGENT_* enum data to WALLET_*.
|
|
332
|
+
// Requires PRAGMA foreign_keys=OFF for table recreation (managesOwnTransaction).
|
|
333
|
+
MIGRATIONS.push({
|
|
334
|
+
version: 3,
|
|
335
|
+
description: 'Rename agents to wallets (table, FK columns, indexes, enum data)',
|
|
336
|
+
managesOwnTransaction: true,
|
|
337
|
+
up: (sqlite) => {
|
|
338
|
+
sqlite.exec('BEGIN');
|
|
339
|
+
try {
|
|
340
|
+
// Step 1: Rename agents table to wallets
|
|
341
|
+
sqlite.exec('ALTER TABLE agents RENAME TO wallets');
|
|
342
|
+
// Step 1b: Drop old agents indexes (ALTER TABLE RENAME doesn't rename indexes)
|
|
343
|
+
sqlite.exec('DROP INDEX IF EXISTS idx_agents_public_key');
|
|
344
|
+
sqlite.exec('DROP INDEX IF EXISTS idx_agents_status');
|
|
345
|
+
sqlite.exec('DROP INDEX IF EXISTS idx_agents_chain_network');
|
|
346
|
+
sqlite.exec('DROP INDEX IF EXISTS idx_agents_owner_address');
|
|
347
|
+
// Step 2: Recreate sessions with wallet_id instead of agent_id
|
|
348
|
+
sqlite.exec(`CREATE TABLE sessions_new (
|
|
349
|
+
id TEXT PRIMARY KEY,
|
|
350
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE CASCADE,
|
|
351
|
+
token_hash TEXT NOT NULL,
|
|
352
|
+
expires_at INTEGER NOT NULL,
|
|
353
|
+
constraints TEXT,
|
|
354
|
+
usage_stats TEXT,
|
|
355
|
+
revoked_at INTEGER,
|
|
356
|
+
renewal_count INTEGER NOT NULL DEFAULT 0,
|
|
357
|
+
max_renewals INTEGER NOT NULL DEFAULT 30,
|
|
358
|
+
last_renewed_at INTEGER,
|
|
359
|
+
absolute_expires_at INTEGER NOT NULL,
|
|
360
|
+
created_at INTEGER NOT NULL
|
|
361
|
+
)`);
|
|
362
|
+
sqlite.exec(`INSERT INTO sessions_new (id, wallet_id, token_hash, expires_at, constraints, usage_stats, revoked_at, renewal_count, max_renewals, last_renewed_at, absolute_expires_at, created_at)
|
|
363
|
+
SELECT id, agent_id, token_hash, expires_at, constraints, usage_stats, revoked_at, renewal_count, max_renewals, last_renewed_at, absolute_expires_at, created_at FROM sessions`);
|
|
364
|
+
sqlite.exec('DROP TABLE sessions');
|
|
365
|
+
sqlite.exec('ALTER TABLE sessions_new RENAME TO sessions');
|
|
366
|
+
// Step 3: Recreate transactions with wallet_id instead of agent_id
|
|
367
|
+
sqlite.exec(`CREATE TABLE transactions_new (
|
|
368
|
+
id TEXT PRIMARY KEY,
|
|
369
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
|
|
370
|
+
session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
371
|
+
chain TEXT NOT NULL,
|
|
372
|
+
tx_hash TEXT,
|
|
373
|
+
type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
|
|
374
|
+
amount TEXT,
|
|
375
|
+
to_address TEXT,
|
|
376
|
+
token_mint TEXT,
|
|
377
|
+
contract_address TEXT,
|
|
378
|
+
method_signature TEXT,
|
|
379
|
+
spender_address TEXT,
|
|
380
|
+
approved_amount TEXT,
|
|
381
|
+
parent_id TEXT REFERENCES transactions_new(id) ON DELETE CASCADE,
|
|
382
|
+
batch_index INTEGER,
|
|
383
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
|
|
384
|
+
tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
|
|
385
|
+
queued_at INTEGER,
|
|
386
|
+
executed_at INTEGER,
|
|
387
|
+
created_at INTEGER NOT NULL,
|
|
388
|
+
reserved_amount TEXT,
|
|
389
|
+
error TEXT,
|
|
390
|
+
metadata TEXT
|
|
391
|
+
)`);
|
|
392
|
+
sqlite.exec(`INSERT INTO transactions_new (id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata)
|
|
393
|
+
SELECT id, agent_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata FROM transactions`);
|
|
394
|
+
sqlite.exec('DROP TABLE transactions');
|
|
395
|
+
sqlite.exec('ALTER TABLE transactions_new RENAME TO transactions');
|
|
396
|
+
// Step 4: Recreate policies with wallet_id instead of agent_id
|
|
397
|
+
sqlite.exec(`CREATE TABLE policies_new (
|
|
398
|
+
id TEXT PRIMARY KEY,
|
|
399
|
+
wallet_id TEXT REFERENCES wallets(id) ON DELETE CASCADE,
|
|
400
|
+
type TEXT NOT NULL CHECK (type IN (${inList(POLICY_TYPES)})),
|
|
401
|
+
rules TEXT NOT NULL,
|
|
402
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
403
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
404
|
+
created_at INTEGER NOT NULL,
|
|
405
|
+
updated_at INTEGER NOT NULL
|
|
406
|
+
)`);
|
|
407
|
+
sqlite.exec(`INSERT INTO policies_new (id, wallet_id, type, rules, priority, enabled, created_at, updated_at)
|
|
408
|
+
SELECT id, agent_id, type, rules, priority, enabled, created_at, updated_at FROM policies`);
|
|
409
|
+
sqlite.exec('DROP TABLE policies');
|
|
410
|
+
sqlite.exec('ALTER TABLE policies_new RENAME TO policies');
|
|
411
|
+
// Step 5: Recreate audit_log with wallet_id instead of agent_id (no FK constraint)
|
|
412
|
+
sqlite.exec(`CREATE TABLE audit_log_new (
|
|
413
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
414
|
+
timestamp INTEGER NOT NULL,
|
|
415
|
+
event_type TEXT NOT NULL,
|
|
416
|
+
actor TEXT NOT NULL,
|
|
417
|
+
wallet_id TEXT,
|
|
418
|
+
session_id TEXT,
|
|
419
|
+
tx_id TEXT,
|
|
420
|
+
details TEXT NOT NULL,
|
|
421
|
+
severity TEXT NOT NULL DEFAULT 'info' CHECK (severity IN ('info', 'warning', 'critical')),
|
|
422
|
+
ip_address TEXT
|
|
423
|
+
)`);
|
|
424
|
+
sqlite.exec(`INSERT INTO audit_log_new (id, timestamp, event_type, actor, wallet_id, session_id, tx_id, details, severity, ip_address)
|
|
425
|
+
SELECT id, timestamp, event_type, actor, agent_id, session_id, tx_id, details, severity, ip_address FROM audit_log`);
|
|
426
|
+
sqlite.exec('DROP TABLE audit_log');
|
|
427
|
+
sqlite.exec('ALTER TABLE audit_log_new RENAME TO audit_log');
|
|
428
|
+
// Step 6: Recreate notification_logs with wallet_id instead of agent_id (no FK constraint)
|
|
429
|
+
sqlite.exec(`CREATE TABLE notification_logs_new (
|
|
430
|
+
id TEXT PRIMARY KEY,
|
|
431
|
+
event_type TEXT NOT NULL,
|
|
432
|
+
wallet_id TEXT,
|
|
433
|
+
channel TEXT NOT NULL,
|
|
434
|
+
status TEXT NOT NULL CHECK (status IN (${inList(NOTIFICATION_LOG_STATUSES)})),
|
|
435
|
+
error TEXT,
|
|
436
|
+
created_at INTEGER NOT NULL
|
|
437
|
+
)`);
|
|
438
|
+
sqlite.exec(`INSERT INTO notification_logs_new (id, event_type, wallet_id, channel, status, error, created_at)
|
|
439
|
+
SELECT id, event_type, agent_id, channel, status, error, created_at FROM notification_logs`);
|
|
440
|
+
sqlite.exec('DROP TABLE notification_logs');
|
|
441
|
+
sqlite.exec('ALTER TABLE notification_logs_new RENAME TO notification_logs');
|
|
442
|
+
// Step 7: Recreate all indexes with wallet naming
|
|
443
|
+
// wallets table indexes
|
|
444
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_wallets_public_key ON wallets(public_key)');
|
|
445
|
+
sqlite.exec('CREATE INDEX idx_wallets_status ON wallets(status)');
|
|
446
|
+
sqlite.exec('CREATE INDEX idx_wallets_chain_network ON wallets(chain, network)');
|
|
447
|
+
sqlite.exec('CREATE INDEX idx_wallets_owner_address ON wallets(owner_address)');
|
|
448
|
+
// sessions indexes (all recreated because table was dropped/recreated)
|
|
449
|
+
sqlite.exec('CREATE INDEX idx_sessions_wallet_id ON sessions(wallet_id)');
|
|
450
|
+
sqlite.exec('CREATE INDEX idx_sessions_expires_at ON sessions(expires_at)');
|
|
451
|
+
sqlite.exec('CREATE INDEX idx_sessions_token_hash ON sessions(token_hash)');
|
|
452
|
+
// transactions indexes (all recreated because table was dropped/recreated)
|
|
453
|
+
sqlite.exec('CREATE INDEX idx_transactions_wallet_status ON transactions(wallet_id, status)');
|
|
454
|
+
sqlite.exec('CREATE INDEX idx_transactions_session_id ON transactions(session_id)');
|
|
455
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash)');
|
|
456
|
+
sqlite.exec('CREATE INDEX idx_transactions_queued_at ON transactions(queued_at)');
|
|
457
|
+
sqlite.exec('CREATE INDEX idx_transactions_created_at ON transactions(created_at)');
|
|
458
|
+
sqlite.exec('CREATE INDEX idx_transactions_type ON transactions(type)');
|
|
459
|
+
sqlite.exec('CREATE INDEX idx_transactions_contract_address ON transactions(contract_address)');
|
|
460
|
+
sqlite.exec('CREATE INDEX idx_transactions_parent_id ON transactions(parent_id)');
|
|
461
|
+
// policies indexes (all recreated because table was dropped/recreated)
|
|
462
|
+
sqlite.exec('CREATE INDEX idx_policies_wallet_enabled ON policies(wallet_id, enabled)');
|
|
463
|
+
sqlite.exec('CREATE INDEX idx_policies_type ON policies(type)');
|
|
464
|
+
// audit_log indexes (all recreated because table was dropped/recreated)
|
|
465
|
+
sqlite.exec('CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp)');
|
|
466
|
+
sqlite.exec('CREATE INDEX idx_audit_log_event_type ON audit_log(event_type)');
|
|
467
|
+
sqlite.exec('CREATE INDEX idx_audit_log_wallet_id ON audit_log(wallet_id)');
|
|
468
|
+
sqlite.exec('CREATE INDEX idx_audit_log_severity ON audit_log(severity)');
|
|
469
|
+
sqlite.exec('CREATE INDEX idx_audit_log_wallet_timestamp ON audit_log(wallet_id, timestamp)');
|
|
470
|
+
// notification_logs indexes (all recreated because table was dropped/recreated)
|
|
471
|
+
sqlite.exec('CREATE INDEX idx_notification_logs_event_type ON notification_logs(event_type)');
|
|
472
|
+
sqlite.exec('CREATE INDEX idx_notification_logs_wallet_id ON notification_logs(wallet_id)');
|
|
473
|
+
sqlite.exec('CREATE INDEX idx_notification_logs_status ON notification_logs(status)');
|
|
474
|
+
sqlite.exec('CREATE INDEX idx_notification_logs_created_at ON notification_logs(created_at)');
|
|
475
|
+
// Step 8: Update audit_log.event_type AGENT_* values to WALLET_*
|
|
476
|
+
sqlite.exec("UPDATE audit_log SET event_type = 'WALLET_CREATED' WHERE event_type = 'AGENT_CREATED'");
|
|
477
|
+
sqlite.exec("UPDATE audit_log SET event_type = 'WALLET_ACTIVATED' WHERE event_type = 'AGENT_ACTIVATED'");
|
|
478
|
+
sqlite.exec("UPDATE audit_log SET event_type = 'WALLET_SUSPENDED' WHERE event_type = 'AGENT_SUSPENDED'");
|
|
479
|
+
sqlite.exec("UPDATE audit_log SET event_type = 'WALLET_TERMINATED' WHERE event_type = 'AGENT_TERMINATED'");
|
|
480
|
+
// Step 9: Update notification_logs.event_type AGENT_SUSPENDED to WALLET_SUSPENDED
|
|
481
|
+
sqlite.exec("UPDATE notification_logs SET event_type = 'WALLET_SUSPENDED' WHERE event_type = 'AGENT_SUSPENDED'");
|
|
482
|
+
sqlite.exec('COMMIT');
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
sqlite.exec('ROLLBACK');
|
|
486
|
+
throw err;
|
|
487
|
+
}
|
|
488
|
+
// Re-enable FK and verify integrity
|
|
489
|
+
sqlite.pragma('foreign_keys = ON');
|
|
490
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
491
|
+
if (fkErrors.length > 0) {
|
|
492
|
+
throw new Error(`FK integrity check failed after v3 migration: ${JSON.stringify(fkErrors)}`);
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
// ---------------------------------------------------------------------------
|
|
497
|
+
// v4: Create token_registry table for EVM token management
|
|
498
|
+
// ---------------------------------------------------------------------------
|
|
499
|
+
MIGRATIONS.push({
|
|
500
|
+
version: 4,
|
|
501
|
+
description: 'Create token_registry table for EVM token management',
|
|
502
|
+
up: (sqlite) => {
|
|
503
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS token_registry (
|
|
504
|
+
id TEXT PRIMARY KEY,
|
|
505
|
+
network TEXT NOT NULL,
|
|
506
|
+
address TEXT NOT NULL,
|
|
507
|
+
symbol TEXT NOT NULL,
|
|
508
|
+
name TEXT NOT NULL,
|
|
509
|
+
decimals INTEGER NOT NULL,
|
|
510
|
+
source TEXT NOT NULL DEFAULT 'custom' CHECK (source IN ('builtin', 'custom')),
|
|
511
|
+
created_at INTEGER NOT NULL
|
|
512
|
+
)`);
|
|
513
|
+
sqlite.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_token_registry_network_address ON token_registry(network, address)');
|
|
514
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_token_registry_network ON token_registry(network)');
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
// ---------------------------------------------------------------------------
|
|
518
|
+
// v5: Create settings table for operational config DB storage
|
|
519
|
+
// ---------------------------------------------------------------------------
|
|
520
|
+
MIGRATIONS.push({
|
|
521
|
+
version: 5,
|
|
522
|
+
description: 'Create settings table for operational config DB storage',
|
|
523
|
+
up: (sqlite) => {
|
|
524
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS settings (
|
|
525
|
+
key TEXT PRIMARY KEY,
|
|
526
|
+
value TEXT NOT NULL,
|
|
527
|
+
encrypted INTEGER NOT NULL DEFAULT 0 CHECK (encrypted IN (0, 1)),
|
|
528
|
+
category TEXT NOT NULL,
|
|
529
|
+
updated_at INTEGER NOT NULL
|
|
530
|
+
)`);
|
|
531
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_settings_category ON settings(category)');
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
// ---------------------------------------------------------------------------
|
|
535
|
+
// v6a: Add network column to transactions with backfill from wallets
|
|
536
|
+
// ---------------------------------------------------------------------------
|
|
537
|
+
// Standard migration (managesOwnTransaction: false). Adds nullable network
|
|
538
|
+
// column to transactions and backfills from wallets.network via FK relationship.
|
|
539
|
+
// Must run BEFORE v6b which removes wallets.network.
|
|
540
|
+
MIGRATIONS.push({
|
|
541
|
+
version: 6,
|
|
542
|
+
description: 'Add network column to transactions with backfill from wallets',
|
|
543
|
+
managesOwnTransaction: false,
|
|
544
|
+
up: (sqlite) => {
|
|
545
|
+
// SQL 1: Add nullable network column
|
|
546
|
+
sqlite.exec('ALTER TABLE transactions ADD COLUMN network TEXT');
|
|
547
|
+
// SQL 2: Backfill from wallets.network via FK relationship
|
|
548
|
+
sqlite.exec(`UPDATE transactions SET network = (
|
|
549
|
+
SELECT w.network FROM wallets w WHERE w.id = transactions.wallet_id
|
|
550
|
+
)`);
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
// ---------------------------------------------------------------------------
|
|
554
|
+
// v6b: Replace wallets.network with environment + default_network (12-step)
|
|
555
|
+
// ---------------------------------------------------------------------------
|
|
556
|
+
// 12-step table recreation. Converts wallets.network to environment + default_network.
|
|
557
|
+
// Recreates FK dependent tables (sessions, transactions, policies, audit_log).
|
|
558
|
+
// Requires PRAGMA foreign_keys=OFF (handled by managesOwnTransaction).
|
|
559
|
+
// @see docs/69-db-migration-v6-design.md section 3
|
|
560
|
+
MIGRATIONS.push({
|
|
561
|
+
version: 7,
|
|
562
|
+
description: 'Replace wallets.network with environment + default_network (12-step recreation)',
|
|
563
|
+
managesOwnTransaction: true,
|
|
564
|
+
up: (sqlite) => {
|
|
565
|
+
// Step 1: Begin transaction
|
|
566
|
+
sqlite.exec('BEGIN');
|
|
567
|
+
try {
|
|
568
|
+
// Step 2: Create wallets_new with environment + default_network
|
|
569
|
+
sqlite.exec(`CREATE TABLE wallets_new (
|
|
570
|
+
id TEXT PRIMARY KEY,
|
|
571
|
+
name TEXT NOT NULL,
|
|
572
|
+
chain TEXT NOT NULL CHECK (chain IN (${inList(CHAIN_TYPES)})),
|
|
573
|
+
environment TEXT NOT NULL CHECK (environment IN (${inList(ENVIRONMENT_TYPES)})),
|
|
574
|
+
default_network TEXT CHECK (default_network IS NULL OR default_network IN (${inList(NETWORK_TYPES)})),
|
|
575
|
+
public_key TEXT NOT NULL,
|
|
576
|
+
status TEXT NOT NULL DEFAULT 'CREATING' CHECK (status IN (${inList(WALLET_STATUSES)})),
|
|
577
|
+
owner_address TEXT,
|
|
578
|
+
owner_verified INTEGER NOT NULL DEFAULT 0 CHECK (owner_verified IN (0, 1)),
|
|
579
|
+
created_at INTEGER NOT NULL,
|
|
580
|
+
updated_at INTEGER NOT NULL,
|
|
581
|
+
suspended_at INTEGER,
|
|
582
|
+
suspension_reason TEXT
|
|
583
|
+
)`);
|
|
584
|
+
// Step 3: Data transformation INSERT with 13 CASE WHEN branches
|
|
585
|
+
// Maps network -> environment using deriveEnvironment() logic (docs/68 section 3.3)
|
|
586
|
+
// Preserves original network as default_network
|
|
587
|
+
sqlite.exec(`INSERT INTO wallets_new (
|
|
588
|
+
id, name, chain, environment, default_network,
|
|
589
|
+
public_key, status, owner_address, owner_verified,
|
|
590
|
+
created_at, updated_at, suspended_at, suspension_reason
|
|
591
|
+
)
|
|
592
|
+
SELECT
|
|
593
|
+
id, name, chain,
|
|
594
|
+
CASE
|
|
595
|
+
WHEN network = 'mainnet' THEN 'mainnet'
|
|
596
|
+
WHEN network = 'devnet' THEN 'testnet'
|
|
597
|
+
WHEN network = 'testnet' THEN 'testnet'
|
|
598
|
+
WHEN network = 'ethereum-mainnet' THEN 'mainnet'
|
|
599
|
+
WHEN network = 'polygon-mainnet' THEN 'mainnet'
|
|
600
|
+
WHEN network = 'arbitrum-mainnet' THEN 'mainnet'
|
|
601
|
+
WHEN network = 'optimism-mainnet' THEN 'mainnet'
|
|
602
|
+
WHEN network = 'base-mainnet' THEN 'mainnet'
|
|
603
|
+
WHEN network = 'ethereum-sepolia' THEN 'testnet'
|
|
604
|
+
WHEN network = 'polygon-amoy' THEN 'testnet'
|
|
605
|
+
WHEN network = 'arbitrum-sepolia' THEN 'testnet'
|
|
606
|
+
WHEN network = 'optimism-sepolia' THEN 'testnet'
|
|
607
|
+
WHEN network = 'base-sepolia' THEN 'testnet'
|
|
608
|
+
ELSE 'testnet'
|
|
609
|
+
END AS environment,
|
|
610
|
+
network AS default_network,
|
|
611
|
+
public_key, status, owner_address, owner_verified,
|
|
612
|
+
created_at, updated_at, suspended_at, suspension_reason
|
|
613
|
+
FROM wallets`);
|
|
614
|
+
// Step 4: Drop old wallets table
|
|
615
|
+
sqlite.exec('DROP TABLE wallets');
|
|
616
|
+
// Step 5: Rename new table
|
|
617
|
+
sqlite.exec('ALTER TABLE wallets_new RENAME TO wallets');
|
|
618
|
+
// Step 6: Recreate wallets indexes
|
|
619
|
+
sqlite.exec('DROP INDEX IF EXISTS idx_wallets_chain_network');
|
|
620
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_wallets_public_key ON wallets(public_key)');
|
|
621
|
+
sqlite.exec('CREATE INDEX idx_wallets_status ON wallets(status)');
|
|
622
|
+
sqlite.exec('CREATE INDEX idx_wallets_chain_environment ON wallets(chain, environment)');
|
|
623
|
+
sqlite.exec('CREATE INDEX idx_wallets_owner_address ON wallets(owner_address)');
|
|
624
|
+
// Step 7: Recreate sessions (FK reconnection, no schema change)
|
|
625
|
+
sqlite.exec(`CREATE TABLE sessions_new (
|
|
626
|
+
id TEXT PRIMARY KEY,
|
|
627
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE CASCADE,
|
|
628
|
+
token_hash TEXT NOT NULL,
|
|
629
|
+
expires_at INTEGER NOT NULL,
|
|
630
|
+
constraints TEXT,
|
|
631
|
+
usage_stats TEXT,
|
|
632
|
+
revoked_at INTEGER,
|
|
633
|
+
renewal_count INTEGER NOT NULL DEFAULT 0,
|
|
634
|
+
max_renewals INTEGER NOT NULL DEFAULT 30,
|
|
635
|
+
last_renewed_at INTEGER,
|
|
636
|
+
absolute_expires_at INTEGER NOT NULL,
|
|
637
|
+
created_at INTEGER NOT NULL
|
|
638
|
+
)`);
|
|
639
|
+
sqlite.exec(`INSERT INTO sessions_new (id, wallet_id, token_hash, expires_at, constraints, usage_stats, revoked_at, renewal_count, max_renewals, last_renewed_at, absolute_expires_at, created_at)
|
|
640
|
+
SELECT id, wallet_id, token_hash, expires_at, constraints, usage_stats, revoked_at, renewal_count, max_renewals, last_renewed_at, absolute_expires_at, created_at FROM sessions`);
|
|
641
|
+
sqlite.exec('DROP TABLE sessions');
|
|
642
|
+
sqlite.exec('ALTER TABLE sessions_new RENAME TO sessions');
|
|
643
|
+
sqlite.exec('CREATE INDEX idx_sessions_wallet_id ON sessions(wallet_id)');
|
|
644
|
+
sqlite.exec('CREATE INDEX idx_sessions_expires_at ON sessions(expires_at)');
|
|
645
|
+
sqlite.exec('CREATE INDEX idx_sessions_token_hash ON sessions(token_hash)');
|
|
646
|
+
// Step 8: Recreate transactions (network column with CHECK, FK reconnection)
|
|
647
|
+
sqlite.exec(`CREATE TABLE transactions_new (
|
|
648
|
+
id TEXT PRIMARY KEY,
|
|
649
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
|
|
650
|
+
session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
651
|
+
chain TEXT NOT NULL,
|
|
652
|
+
tx_hash TEXT,
|
|
653
|
+
type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
|
|
654
|
+
amount TEXT,
|
|
655
|
+
to_address TEXT,
|
|
656
|
+
token_mint TEXT,
|
|
657
|
+
contract_address TEXT,
|
|
658
|
+
method_signature TEXT,
|
|
659
|
+
spender_address TEXT,
|
|
660
|
+
approved_amount TEXT,
|
|
661
|
+
parent_id TEXT REFERENCES transactions_new(id) ON DELETE CASCADE,
|
|
662
|
+
batch_index INTEGER,
|
|
663
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
|
|
664
|
+
tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
|
|
665
|
+
queued_at INTEGER,
|
|
666
|
+
executed_at INTEGER,
|
|
667
|
+
created_at INTEGER NOT NULL,
|
|
668
|
+
reserved_amount TEXT,
|
|
669
|
+
error TEXT,
|
|
670
|
+
metadata TEXT,
|
|
671
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)}))
|
|
672
|
+
)`);
|
|
673
|
+
sqlite.exec(`INSERT INTO transactions_new (id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network)
|
|
674
|
+
SELECT id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network FROM transactions`);
|
|
675
|
+
sqlite.exec('DROP TABLE transactions');
|
|
676
|
+
sqlite.exec('ALTER TABLE transactions_new RENAME TO transactions');
|
|
677
|
+
sqlite.exec('CREATE INDEX idx_transactions_wallet_status ON transactions(wallet_id, status)');
|
|
678
|
+
sqlite.exec('CREATE INDEX idx_transactions_session_id ON transactions(session_id)');
|
|
679
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash)');
|
|
680
|
+
sqlite.exec('CREATE INDEX idx_transactions_queued_at ON transactions(queued_at)');
|
|
681
|
+
sqlite.exec('CREATE INDEX idx_transactions_created_at ON transactions(created_at)');
|
|
682
|
+
sqlite.exec('CREATE INDEX idx_transactions_type ON transactions(type)');
|
|
683
|
+
sqlite.exec('CREATE INDEX idx_transactions_contract_address ON transactions(contract_address)');
|
|
684
|
+
sqlite.exec('CREATE INDEX idx_transactions_parent_id ON transactions(parent_id)');
|
|
685
|
+
// Step 9: Recreate policies (FK reconnection, no schema change -- v8 adds network)
|
|
686
|
+
sqlite.exec(`CREATE TABLE policies_new (
|
|
687
|
+
id TEXT PRIMARY KEY,
|
|
688
|
+
wallet_id TEXT REFERENCES wallets(id) ON DELETE CASCADE,
|
|
689
|
+
type TEXT NOT NULL CHECK (type IN (${inList(POLICY_TYPES)})),
|
|
690
|
+
rules TEXT NOT NULL,
|
|
691
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
692
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
693
|
+
created_at INTEGER NOT NULL,
|
|
694
|
+
updated_at INTEGER NOT NULL
|
|
695
|
+
)`);
|
|
696
|
+
sqlite.exec(`INSERT INTO policies_new (id, wallet_id, type, rules, priority, enabled, created_at, updated_at)
|
|
697
|
+
SELECT id, wallet_id, type, rules, priority, enabled, created_at, updated_at FROM policies`);
|
|
698
|
+
sqlite.exec('DROP TABLE policies');
|
|
699
|
+
sqlite.exec('ALTER TABLE policies_new RENAME TO policies');
|
|
700
|
+
sqlite.exec('CREATE INDEX idx_policies_wallet_enabled ON policies(wallet_id, enabled)');
|
|
701
|
+
sqlite.exec('CREATE INDEX idx_policies_type ON policies(type)');
|
|
702
|
+
// Step 10: Recreate audit_log (consistency with v3 pattern)
|
|
703
|
+
sqlite.exec(`CREATE TABLE audit_log_new (
|
|
704
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
705
|
+
timestamp INTEGER NOT NULL,
|
|
706
|
+
event_type TEXT NOT NULL,
|
|
707
|
+
actor TEXT NOT NULL,
|
|
708
|
+
wallet_id TEXT,
|
|
709
|
+
session_id TEXT,
|
|
710
|
+
tx_id TEXT,
|
|
711
|
+
details TEXT NOT NULL,
|
|
712
|
+
severity TEXT NOT NULL DEFAULT 'info' CHECK (severity IN ('info', 'warning', 'critical')),
|
|
713
|
+
ip_address TEXT
|
|
714
|
+
)`);
|
|
715
|
+
sqlite.exec(`INSERT INTO audit_log_new (id, timestamp, event_type, actor, wallet_id, session_id, tx_id, details, severity, ip_address)
|
|
716
|
+
SELECT id, timestamp, event_type, actor, wallet_id, session_id, tx_id, details, severity, ip_address FROM audit_log`);
|
|
717
|
+
sqlite.exec('DROP TABLE audit_log');
|
|
718
|
+
sqlite.exec('ALTER TABLE audit_log_new RENAME TO audit_log');
|
|
719
|
+
sqlite.exec('CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp)');
|
|
720
|
+
sqlite.exec('CREATE INDEX idx_audit_log_event_type ON audit_log(event_type)');
|
|
721
|
+
sqlite.exec('CREATE INDEX idx_audit_log_wallet_id ON audit_log(wallet_id)');
|
|
722
|
+
sqlite.exec('CREATE INDEX idx_audit_log_severity ON audit_log(severity)');
|
|
723
|
+
sqlite.exec('CREATE INDEX idx_audit_log_wallet_timestamp ON audit_log(wallet_id, timestamp)');
|
|
724
|
+
// Step 11: Commit transaction
|
|
725
|
+
sqlite.exec('COMMIT');
|
|
726
|
+
}
|
|
727
|
+
catch (err) {
|
|
728
|
+
sqlite.exec('ROLLBACK');
|
|
729
|
+
throw err;
|
|
730
|
+
}
|
|
731
|
+
// Step 12: Re-enable foreign keys and verify integrity
|
|
732
|
+
sqlite.pragma('foreign_keys = ON');
|
|
733
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
734
|
+
if (fkErrors.length > 0) {
|
|
735
|
+
throw new Error(`FK integrity violation after v6b: ${JSON.stringify(fkErrors)}`);
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
// ---------------------------------------------------------------------------
|
|
740
|
+
// v8: Add network column to policies (12-step recreation)
|
|
741
|
+
// ---------------------------------------------------------------------------
|
|
742
|
+
// Adds nullable network column and updates type CHECK to include ALLOWED_NETWORKS.
|
|
743
|
+
// Requires 12-step recreation because SQLite cannot ALTER CHECK constraints.
|
|
744
|
+
// @see docs/71-policy-engine-network-extension-design.md section 6
|
|
745
|
+
MIGRATIONS.push({
|
|
746
|
+
version: 8,
|
|
747
|
+
description: 'Add network column to policies and ALLOWED_NETWORKS type support',
|
|
748
|
+
managesOwnTransaction: true,
|
|
749
|
+
up: (sqlite) => {
|
|
750
|
+
// Step 1: Begin transaction
|
|
751
|
+
sqlite.exec('BEGIN');
|
|
752
|
+
try {
|
|
753
|
+
// Step 2: Create policies_new with network column + updated CHECK
|
|
754
|
+
sqlite.exec(`CREATE TABLE policies_new (
|
|
755
|
+
id TEXT PRIMARY KEY,
|
|
756
|
+
wallet_id TEXT REFERENCES wallets(id) ON DELETE CASCADE,
|
|
757
|
+
type TEXT NOT NULL CHECK (type IN (${inList(POLICY_TYPES)})),
|
|
758
|
+
rules TEXT NOT NULL,
|
|
759
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
760
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
761
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
|
|
762
|
+
created_at INTEGER NOT NULL,
|
|
763
|
+
updated_at INTEGER NOT NULL
|
|
764
|
+
)`);
|
|
765
|
+
// Step 3: Copy existing policies with network=NULL
|
|
766
|
+
sqlite.exec(`INSERT INTO policies_new (
|
|
767
|
+
id, wallet_id, type, rules, priority, enabled, network, created_at, updated_at
|
|
768
|
+
)
|
|
769
|
+
SELECT
|
|
770
|
+
id, wallet_id, type, rules, priority, enabled, NULL, created_at, updated_at
|
|
771
|
+
FROM policies`);
|
|
772
|
+
// Step 4: Drop old table
|
|
773
|
+
sqlite.exec('DROP TABLE policies');
|
|
774
|
+
// Step 5: Rename new table
|
|
775
|
+
sqlite.exec('ALTER TABLE policies_new RENAME TO policies');
|
|
776
|
+
// Step 6: Recreate existing indexes
|
|
777
|
+
sqlite.exec('CREATE INDEX idx_policies_wallet_enabled ON policies(wallet_id, enabled)');
|
|
778
|
+
sqlite.exec('CREATE INDEX idx_policies_type ON policies(type)');
|
|
779
|
+
// Step 7: Create new network index
|
|
780
|
+
sqlite.exec('CREATE INDEX idx_policies_network ON policies(network)');
|
|
781
|
+
// Step 8: Commit
|
|
782
|
+
sqlite.exec('COMMIT');
|
|
783
|
+
}
|
|
784
|
+
catch (err) {
|
|
785
|
+
sqlite.exec('ROLLBACK');
|
|
786
|
+
throw err;
|
|
787
|
+
}
|
|
788
|
+
// Step 9: Re-enable foreign keys and verify integrity
|
|
789
|
+
sqlite.pragma('foreign_keys = ON');
|
|
790
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
791
|
+
if (fkErrors.length > 0) {
|
|
792
|
+
throw new Error(`FK integrity violation after v8: ${JSON.stringify(fkErrors)}`);
|
|
793
|
+
}
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
// ---------------------------------------------------------------------------
|
|
797
|
+
// v9: Add SIGNED status and SIGN type to transactions CHECK constraints
|
|
798
|
+
// ---------------------------------------------------------------------------
|
|
799
|
+
// SSoT arrays TRANSACTION_STATUSES/TRANSACTION_TYPES에 새 값이 추가되었으므로
|
|
800
|
+
// transactions 테이블의 CHECK 제약을 갱신해야 한다. SQLite는 ALTER CHECK 불가 -> 12-step 재생성.
|
|
801
|
+
// 이 마이그레이션은 transactions 테이블만 재생성한다 (다른 테이블에 영향 없음).
|
|
802
|
+
MIGRATIONS.push({
|
|
803
|
+
version: 9,
|
|
804
|
+
description: 'Add SIGNED status and SIGN type to transactions CHECK constraints',
|
|
805
|
+
managesOwnTransaction: true,
|
|
806
|
+
up: (sqlite) => {
|
|
807
|
+
// Step 1: Begin transaction
|
|
808
|
+
sqlite.exec('BEGIN');
|
|
809
|
+
try {
|
|
810
|
+
// Step 2: Create transactions_new with updated CHECK constraints
|
|
811
|
+
sqlite.exec(`CREATE TABLE transactions_new (
|
|
812
|
+
id TEXT PRIMARY KEY,
|
|
813
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
|
|
814
|
+
session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
815
|
+
chain TEXT NOT NULL,
|
|
816
|
+
tx_hash TEXT,
|
|
817
|
+
type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
|
|
818
|
+
amount TEXT,
|
|
819
|
+
to_address TEXT,
|
|
820
|
+
token_mint TEXT,
|
|
821
|
+
contract_address TEXT,
|
|
822
|
+
method_signature TEXT,
|
|
823
|
+
spender_address TEXT,
|
|
824
|
+
approved_amount TEXT,
|
|
825
|
+
parent_id TEXT REFERENCES transactions_new(id) ON DELETE CASCADE,
|
|
826
|
+
batch_index INTEGER,
|
|
827
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
|
|
828
|
+
tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
|
|
829
|
+
queued_at INTEGER,
|
|
830
|
+
executed_at INTEGER,
|
|
831
|
+
created_at INTEGER NOT NULL,
|
|
832
|
+
reserved_amount TEXT,
|
|
833
|
+
error TEXT,
|
|
834
|
+
metadata TEXT,
|
|
835
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)}))
|
|
836
|
+
)`);
|
|
837
|
+
// Step 3: Copy existing data
|
|
838
|
+
sqlite.exec(`INSERT INTO transactions_new (id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network)
|
|
839
|
+
SELECT id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network FROM transactions`);
|
|
840
|
+
// Step 4: Drop old table
|
|
841
|
+
sqlite.exec('DROP TABLE transactions');
|
|
842
|
+
// Step 5: Rename new table
|
|
843
|
+
sqlite.exec('ALTER TABLE transactions_new RENAME TO transactions');
|
|
844
|
+
// Step 6: Recreate all 8 existing indexes
|
|
845
|
+
sqlite.exec('CREATE INDEX idx_transactions_wallet_status ON transactions(wallet_id, status)');
|
|
846
|
+
sqlite.exec('CREATE INDEX idx_transactions_session_id ON transactions(session_id)');
|
|
847
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash)');
|
|
848
|
+
sqlite.exec('CREATE INDEX idx_transactions_queued_at ON transactions(queued_at)');
|
|
849
|
+
sqlite.exec('CREATE INDEX idx_transactions_created_at ON transactions(created_at)');
|
|
850
|
+
sqlite.exec('CREATE INDEX idx_transactions_type ON transactions(type)');
|
|
851
|
+
sqlite.exec('CREATE INDEX idx_transactions_contract_address ON transactions(contract_address)');
|
|
852
|
+
sqlite.exec('CREATE INDEX idx_transactions_parent_id ON transactions(parent_id)');
|
|
853
|
+
// Step 7: Commit
|
|
854
|
+
sqlite.exec('COMMIT');
|
|
855
|
+
}
|
|
856
|
+
catch (err) {
|
|
857
|
+
sqlite.exec('ROLLBACK');
|
|
858
|
+
throw err;
|
|
859
|
+
}
|
|
860
|
+
// Step 8: Re-enable foreign keys and verify integrity
|
|
861
|
+
sqlite.pragma('foreign_keys = ON');
|
|
862
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
863
|
+
if (fkErrors.length > 0) {
|
|
864
|
+
throw new Error(`FK integrity violation after v9: ${JSON.stringify(fkErrors)}`);
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
// ---------------------------------------------------------------------------
|
|
869
|
+
// v10: Add message column to notification_logs
|
|
870
|
+
// ---------------------------------------------------------------------------
|
|
871
|
+
// Simple ALTER TABLE ADD COLUMN -- no CHECK constraint changes, no table recreation needed.
|
|
872
|
+
MIGRATIONS.push({
|
|
873
|
+
version: 10,
|
|
874
|
+
description: 'Add message column to notification_logs',
|
|
875
|
+
up: (sqlite) => {
|
|
876
|
+
sqlite.exec('ALTER TABLE notification_logs ADD COLUMN message TEXT');
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
// ---------------------------------------------------------------------------
|
|
880
|
+
// v11: Create api_keys table for Action Provider API key storage
|
|
881
|
+
// ---------------------------------------------------------------------------
|
|
882
|
+
MIGRATIONS.push({
|
|
883
|
+
version: 11,
|
|
884
|
+
description: 'Add api_keys table for Action Provider API key storage',
|
|
885
|
+
up: (sqlite) => {
|
|
886
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS api_keys (
|
|
887
|
+
provider_name TEXT PRIMARY KEY,
|
|
888
|
+
encrypted_key TEXT NOT NULL,
|
|
889
|
+
created_at INTEGER NOT NULL,
|
|
890
|
+
updated_at INTEGER NOT NULL
|
|
891
|
+
)`);
|
|
892
|
+
},
|
|
893
|
+
});
|
|
894
|
+
// ---------------------------------------------------------------------------
|
|
895
|
+
// v12: Add X402_PAYMENT to transactions and X402_ALLOWED_DOMAINS to policies CHECK constraints
|
|
896
|
+
// ---------------------------------------------------------------------------
|
|
897
|
+
// x402 결제 지원을 위해 transactions.type에 X402_PAYMENT,
|
|
898
|
+
// policies.type에 X402_ALLOWED_DOMAINS가 CHECK 제약에 포함되어야 한다.
|
|
899
|
+
// SQLite는 ALTER CHECK 불가 -> transactions와 policies 모두 12-step 재생성.
|
|
900
|
+
MIGRATIONS.push({
|
|
901
|
+
version: 12,
|
|
902
|
+
description: 'Add X402_PAYMENT to transactions and X402_ALLOWED_DOMAINS to policies CHECK constraints',
|
|
903
|
+
managesOwnTransaction: true,
|
|
904
|
+
up: (sqlite) => {
|
|
905
|
+
sqlite.exec('BEGIN');
|
|
906
|
+
try {
|
|
907
|
+
// ── Part 1: transactions 테이블 재생성 ──
|
|
908
|
+
// v9과 동일 DDL. TRANSACTION_TYPES SSoT에 X402_PAYMENT이 이미 포함됨.
|
|
909
|
+
sqlite.exec(`CREATE TABLE transactions_new (
|
|
910
|
+
id TEXT PRIMARY KEY,
|
|
911
|
+
wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
|
|
912
|
+
session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
913
|
+
chain TEXT NOT NULL,
|
|
914
|
+
tx_hash TEXT,
|
|
915
|
+
type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
|
|
916
|
+
amount TEXT,
|
|
917
|
+
to_address TEXT,
|
|
918
|
+
token_mint TEXT,
|
|
919
|
+
contract_address TEXT,
|
|
920
|
+
method_signature TEXT,
|
|
921
|
+
spender_address TEXT,
|
|
922
|
+
approved_amount TEXT,
|
|
923
|
+
parent_id TEXT REFERENCES transactions_new(id) ON DELETE CASCADE,
|
|
924
|
+
batch_index INTEGER,
|
|
925
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
|
|
926
|
+
tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
|
|
927
|
+
queued_at INTEGER,
|
|
928
|
+
executed_at INTEGER,
|
|
929
|
+
created_at INTEGER NOT NULL,
|
|
930
|
+
reserved_amount TEXT,
|
|
931
|
+
error TEXT,
|
|
932
|
+
metadata TEXT,
|
|
933
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)}))
|
|
934
|
+
)`);
|
|
935
|
+
sqlite.exec(`INSERT INTO transactions_new (id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network)
|
|
936
|
+
SELECT id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, error, metadata, network FROM transactions`);
|
|
937
|
+
sqlite.exec('DROP TABLE transactions');
|
|
938
|
+
sqlite.exec('ALTER TABLE transactions_new RENAME TO transactions');
|
|
939
|
+
// Recreate all 8 indexes (same as v9)
|
|
940
|
+
sqlite.exec('CREATE INDEX idx_transactions_wallet_status ON transactions(wallet_id, status)');
|
|
941
|
+
sqlite.exec('CREATE INDEX idx_transactions_session_id ON transactions(session_id)');
|
|
942
|
+
sqlite.exec('CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash)');
|
|
943
|
+
sqlite.exec('CREATE INDEX idx_transactions_queued_at ON transactions(queued_at)');
|
|
944
|
+
sqlite.exec('CREATE INDEX idx_transactions_created_at ON transactions(created_at)');
|
|
945
|
+
sqlite.exec('CREATE INDEX idx_transactions_type ON transactions(type)');
|
|
946
|
+
sqlite.exec('CREATE INDEX idx_transactions_contract_address ON transactions(contract_address)');
|
|
947
|
+
sqlite.exec('CREATE INDEX idx_transactions_parent_id ON transactions(parent_id)');
|
|
948
|
+
// ── Part 2: policies 테이블 재생성 ──
|
|
949
|
+
// v8과 동일 DDL. POLICY_TYPES SSoT에 X402_ALLOWED_DOMAINS가 이미 포함됨.
|
|
950
|
+
sqlite.exec(`CREATE TABLE policies_new (
|
|
951
|
+
id TEXT PRIMARY KEY,
|
|
952
|
+
wallet_id TEXT REFERENCES wallets(id) ON DELETE CASCADE,
|
|
953
|
+
type TEXT NOT NULL CHECK (type IN (${inList(POLICY_TYPES)})),
|
|
954
|
+
rules TEXT NOT NULL,
|
|
955
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
956
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
957
|
+
network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
|
|
958
|
+
created_at INTEGER NOT NULL,
|
|
959
|
+
updated_at INTEGER NOT NULL
|
|
960
|
+
)`);
|
|
961
|
+
sqlite.exec(`INSERT INTO policies_new (id, wallet_id, type, rules, priority, enabled, network, created_at, updated_at)
|
|
962
|
+
SELECT id, wallet_id, type, rules, priority, enabled, network, created_at, updated_at FROM policies`);
|
|
963
|
+
sqlite.exec('DROP TABLE policies');
|
|
964
|
+
sqlite.exec('ALTER TABLE policies_new RENAME TO policies');
|
|
965
|
+
// Recreate 3 indexes (same as v8)
|
|
966
|
+
sqlite.exec('CREATE INDEX idx_policies_wallet_enabled ON policies(wallet_id, enabled)');
|
|
967
|
+
sqlite.exec('CREATE INDEX idx_policies_type ON policies(type)');
|
|
968
|
+
sqlite.exec('CREATE INDEX idx_policies_network ON policies(network)');
|
|
969
|
+
sqlite.exec('COMMIT');
|
|
970
|
+
}
|
|
971
|
+
catch (err) {
|
|
972
|
+
sqlite.exec('ROLLBACK');
|
|
973
|
+
throw err;
|
|
974
|
+
}
|
|
975
|
+
// Re-enable foreign keys and verify integrity
|
|
976
|
+
sqlite.pragma('foreign_keys = ON');
|
|
977
|
+
const fkErrors = sqlite.pragma('foreign_key_check');
|
|
978
|
+
if (fkErrors.length > 0) {
|
|
979
|
+
throw new Error(`FK integrity violation after v12: ${JSON.stringify(fkErrors)}`);
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
// ---------------------------------------------------------------------------
|
|
984
|
+
// v13: Add amount_usd and reserved_amount_usd columns to transactions
|
|
985
|
+
// ---------------------------------------------------------------------------
|
|
986
|
+
// Simple ALTER TABLE ADD COLUMN -- no CHECK constraint changes, no table recreation needed.
|
|
987
|
+
// These nullable REAL columns store USD-denominated amounts for cumulative spending limit evaluation.
|
|
988
|
+
// amount_usd: confirmed USD amount (persists after CONFIRMED), reserved_amount_usd: cleared on release.
|
|
989
|
+
MIGRATIONS.push({
|
|
990
|
+
version: 13,
|
|
991
|
+
description: 'Add amount_usd and reserved_amount_usd columns to transactions',
|
|
992
|
+
up: (sqlite) => {
|
|
993
|
+
sqlite.exec('ALTER TABLE transactions ADD COLUMN amount_usd REAL');
|
|
994
|
+
sqlite.exec('ALTER TABLE transactions ADD COLUMN reserved_amount_usd REAL');
|
|
995
|
+
},
|
|
996
|
+
});
|
|
997
|
+
// ---------------------------------------------------------------------------
|
|
998
|
+
// v14: Migrate kill_switch_state values: NORMAL->ACTIVE, ACTIVATED->SUSPENDED
|
|
999
|
+
// ---------------------------------------------------------------------------
|
|
1000
|
+
// Kill Switch 3-state machine migration.
|
|
1001
|
+
// Old 2-state values (NORMAL, ACTIVATED, RECOVERING) are converted to
|
|
1002
|
+
// new 3-state values (ACTIVE, SUSPENDED, LOCKED).
|
|
1003
|
+
// Simple UPDATE on key_value_store -- no schema changes, no table recreation.
|
|
1004
|
+
MIGRATIONS.push({
|
|
1005
|
+
version: 14,
|
|
1006
|
+
description: 'Migrate kill_switch_state values: NORMAL->ACTIVE, ACTIVATED->SUSPENDED',
|
|
1007
|
+
up: (sqlite) => {
|
|
1008
|
+
const now = Math.floor(Date.now() / 1000);
|
|
1009
|
+
// NORMAL -> ACTIVE
|
|
1010
|
+
sqlite
|
|
1011
|
+
.prepare("UPDATE key_value_store SET value = 'ACTIVE', updated_at = ? WHERE key = 'kill_switch_state' AND value = 'NORMAL'")
|
|
1012
|
+
.run(now);
|
|
1013
|
+
// ACTIVATED -> SUSPENDED
|
|
1014
|
+
sqlite
|
|
1015
|
+
.prepare("UPDATE key_value_store SET value = 'SUSPENDED', updated_at = ? WHERE key = 'kill_switch_state' AND value = 'ACTIVATED'")
|
|
1016
|
+
.run(now);
|
|
1017
|
+
// RECOVERING -> ACTIVE (v0.10 design removed RECOVERING state)
|
|
1018
|
+
sqlite
|
|
1019
|
+
.prepare("UPDATE key_value_store SET value = 'ACTIVE', updated_at = ? WHERE key = 'kill_switch_state' AND value = 'RECOVERING'")
|
|
1020
|
+
.run(now);
|
|
1021
|
+
},
|
|
1022
|
+
});
|
|
1023
|
+
// ---------------------------------------------------------------------------
|
|
1024
|
+
// v15: Create telegram_users table for Telegram Bot user management
|
|
1025
|
+
// ---------------------------------------------------------------------------
|
|
1026
|
+
MIGRATIONS.push({
|
|
1027
|
+
version: 15,
|
|
1028
|
+
description: 'Create telegram_users table for Telegram Bot user management',
|
|
1029
|
+
up: (sqlite) => {
|
|
1030
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS telegram_users (
|
|
1031
|
+
chat_id INTEGER PRIMARY KEY,
|
|
1032
|
+
username TEXT,
|
|
1033
|
+
role TEXT NOT NULL DEFAULT 'PENDING' CHECK (role IN ('PENDING', 'ADMIN', 'READONLY')),
|
|
1034
|
+
registered_at INTEGER NOT NULL,
|
|
1035
|
+
approved_at INTEGER
|
|
1036
|
+
)`);
|
|
1037
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_telegram_users_role ON telegram_users(role)');
|
|
1038
|
+
},
|
|
1039
|
+
});
|
|
1040
|
+
// ---------------------------------------------------------------------------
|
|
1041
|
+
// v16: Add WC infra: wc_sessions table, wc_store table, pending_approvals.approval_channel
|
|
1042
|
+
// ---------------------------------------------------------------------------
|
|
1043
|
+
MIGRATIONS.push({
|
|
1044
|
+
version: 16,
|
|
1045
|
+
description: 'Add WC infra: wc_sessions table, wc_store table, pending_approvals.approval_channel',
|
|
1046
|
+
up: (sqlite) => {
|
|
1047
|
+
// 1. pending_approvals.approval_channel 추가
|
|
1048
|
+
sqlite.exec("ALTER TABLE pending_approvals ADD COLUMN approval_channel TEXT DEFAULT 'rest_api'");
|
|
1049
|
+
// 2. wc_sessions 테이블 생성
|
|
1050
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS wc_sessions (
|
|
1051
|
+
wallet_id TEXT PRIMARY KEY REFERENCES wallets(id) ON DELETE CASCADE,
|
|
1052
|
+
topic TEXT NOT NULL UNIQUE,
|
|
1053
|
+
peer_meta TEXT,
|
|
1054
|
+
chain_id TEXT NOT NULL,
|
|
1055
|
+
owner_address TEXT NOT NULL,
|
|
1056
|
+
namespaces TEXT,
|
|
1057
|
+
expiry INTEGER NOT NULL,
|
|
1058
|
+
created_at INTEGER NOT NULL
|
|
1059
|
+
)`);
|
|
1060
|
+
sqlite.exec('CREATE INDEX IF NOT EXISTS idx_wc_sessions_topic ON wc_sessions(topic)');
|
|
1061
|
+
// 3. wc_store 테이블 생성 (IKeyValueStorage용)
|
|
1062
|
+
sqlite.exec(`CREATE TABLE IF NOT EXISTS wc_store (
|
|
1063
|
+
key TEXT PRIMARY KEY,
|
|
1064
|
+
value TEXT NOT NULL
|
|
1065
|
+
)`);
|
|
1066
|
+
},
|
|
1067
|
+
});
|
|
1068
|
+
/**
|
|
1069
|
+
* Run incremental migrations against the database.
|
|
1070
|
+
*
|
|
1071
|
+
* - Reads the current max version from schema_version table
|
|
1072
|
+
* - Executes each migration with version > current in ascending order
|
|
1073
|
+
* - Each migration runs in its own transaction (BEGIN/COMMIT)
|
|
1074
|
+
* - On failure: ROLLBACK the failed migration, throw error, skip remaining
|
|
1075
|
+
*
|
|
1076
|
+
* @param sqlite - Raw better-sqlite3 database instance.
|
|
1077
|
+
* @param migrations - Migration list to apply. Defaults to global MIGRATIONS array.
|
|
1078
|
+
* @returns Count of applied and skipped migrations.
|
|
1079
|
+
*/
|
|
1080
|
+
export function runMigrations(sqlite, migrations = MIGRATIONS) {
|
|
1081
|
+
// Get current schema version (pushSchema always inserts version 1)
|
|
1082
|
+
const row = sqlite
|
|
1083
|
+
.prepare('SELECT MAX(version) AS max_version FROM schema_version')
|
|
1084
|
+
.get();
|
|
1085
|
+
const currentVersion = row?.max_version ?? 1;
|
|
1086
|
+
// Sort migrations by version ascending to guarantee order
|
|
1087
|
+
const sorted = [...migrations].sort((a, b) => a.version - b.version);
|
|
1088
|
+
let applied = 0;
|
|
1089
|
+
let skipped = 0;
|
|
1090
|
+
for (const migration of sorted) {
|
|
1091
|
+
if (migration.version <= currentVersion) {
|
|
1092
|
+
skipped++;
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
if (migration.managesOwnTransaction) {
|
|
1096
|
+
// Migration manages its own PRAGMA + transaction (e.g. 12-step table recreation)
|
|
1097
|
+
// Disable foreign keys so the migration can DROP/RENAME tables
|
|
1098
|
+
sqlite.pragma('foreign_keys = OFF');
|
|
1099
|
+
try {
|
|
1100
|
+
migration.up(sqlite);
|
|
1101
|
+
// Record successful migration (up() must have committed its own transaction)
|
|
1102
|
+
sqlite
|
|
1103
|
+
.prepare('INSERT INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)')
|
|
1104
|
+
.run(migration.version, Math.floor(Date.now() / 1000), migration.description);
|
|
1105
|
+
applied++;
|
|
1106
|
+
}
|
|
1107
|
+
catch (err) {
|
|
1108
|
+
// Ensure foreign_keys is restored even on failure
|
|
1109
|
+
try {
|
|
1110
|
+
sqlite.pragma('foreign_keys = ON');
|
|
1111
|
+
}
|
|
1112
|
+
catch {
|
|
1113
|
+
/* best effort */
|
|
1114
|
+
}
|
|
1115
|
+
throw new Error(`Migration v${migration.version} (${migration.description}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1116
|
+
}
|
|
1117
|
+
// Re-enable foreign keys after successful migration
|
|
1118
|
+
sqlite.pragma('foreign_keys = ON');
|
|
1119
|
+
}
|
|
1120
|
+
else {
|
|
1121
|
+
// Standard migration: wrap in BEGIN/COMMIT
|
|
1122
|
+
sqlite.exec('BEGIN');
|
|
1123
|
+
try {
|
|
1124
|
+
migration.up(sqlite);
|
|
1125
|
+
// Record successful migration
|
|
1126
|
+
sqlite
|
|
1127
|
+
.prepare('INSERT INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)')
|
|
1128
|
+
.run(migration.version, Math.floor(Date.now() / 1000), migration.description);
|
|
1129
|
+
sqlite.exec('COMMIT');
|
|
1130
|
+
applied++;
|
|
1131
|
+
}
|
|
1132
|
+
catch (err) {
|
|
1133
|
+
sqlite.exec('ROLLBACK');
|
|
1134
|
+
throw new Error(`Migration v${migration.version} (${migration.description}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return { applied, skipped };
|
|
1139
|
+
}
|
|
1140
|
+
// ---------------------------------------------------------------------------
|
|
1141
|
+
// Public API
|
|
1142
|
+
// ---------------------------------------------------------------------------
|
|
1143
|
+
/**
|
|
1144
|
+
* Push the full schema to the database (CREATE TABLE IF NOT EXISTS + indexes).
|
|
1145
|
+
* Then run any pending incremental migrations.
|
|
1146
|
+
* Safe to call on every daemon startup -- idempotent.
|
|
1147
|
+
*
|
|
1148
|
+
* @param sqlite - Raw better-sqlite3 database instance (PRAGMAs must already be applied).
|
|
1149
|
+
*/
|
|
1150
|
+
export function pushSchema(sqlite) {
|
|
1151
|
+
const tables = getCreateTableStatements();
|
|
1152
|
+
const indexes = getCreateIndexStatements();
|
|
1153
|
+
// Step 1: Create tables + record schema version (NO indexes yet)
|
|
1154
|
+
// Indexes reference latest-schema columns (e.g. wallets.environment) that may
|
|
1155
|
+
// not exist in pre-migration databases. Creating indexes before migrations
|
|
1156
|
+
// causes "no such column" errors on existing DBs. (MIGR-01 fix)
|
|
1157
|
+
//
|
|
1158
|
+
// Pre-v3 databases have an `agents` table that gets renamed to `wallets` by
|
|
1159
|
+
// v3 migration. We must skip creating `wallets` if `agents` still exists,
|
|
1160
|
+
// otherwise v3 migration fails with "table already exists". (MIGR-01b fix)
|
|
1161
|
+
const hasAgentsTable = sqlite
|
|
1162
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='agents'")
|
|
1163
|
+
.get() !== undefined;
|
|
1164
|
+
sqlite.exec('BEGIN');
|
|
1165
|
+
try {
|
|
1166
|
+
for (const stmt of tables) {
|
|
1167
|
+
// Skip wallets table creation if agents table exists (v3 migration will handle rename)
|
|
1168
|
+
if (hasAgentsTable && stmt.includes('CREATE TABLE IF NOT EXISTS wallets')) {
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
sqlite.exec(stmt);
|
|
1172
|
+
}
|
|
1173
|
+
// Record schema version 1 if not already recorded (for existing DBs that only had v1)
|
|
1174
|
+
const existing = sqlite
|
|
1175
|
+
.prepare('SELECT version FROM schema_version WHERE version = 1')
|
|
1176
|
+
.get();
|
|
1177
|
+
if (!existing) {
|
|
1178
|
+
// Fresh DB: record all versions up to LATEST_SCHEMA_VERSION so migrations are skipped.
|
|
1179
|
+
// The DDL above already represents the latest schema state.
|
|
1180
|
+
const ts = Math.floor(Date.now() / 1000);
|
|
1181
|
+
sqlite
|
|
1182
|
+
.prepare('INSERT INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)')
|
|
1183
|
+
.run(1, ts, 'Initial schema (15 tables)');
|
|
1184
|
+
// Record all migration versions as already applied (DDL is up-to-date)
|
|
1185
|
+
for (const migration of MIGRATIONS) {
|
|
1186
|
+
sqlite
|
|
1187
|
+
.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)')
|
|
1188
|
+
.run(migration.version, ts, `${migration.description} (via pushSchema)`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
sqlite.exec('COMMIT');
|
|
1192
|
+
}
|
|
1193
|
+
catch (err) {
|
|
1194
|
+
sqlite.exec('ROLLBACK');
|
|
1195
|
+
throw err;
|
|
1196
|
+
}
|
|
1197
|
+
// Step 2: Run incremental migrations (adds/transforms columns in existing DBs)
|
|
1198
|
+
// Fresh DBs have all versions recorded above, so migrations are skipped.
|
|
1199
|
+
runMigrations(sqlite);
|
|
1200
|
+
// Step 3: Create indexes AFTER migrations complete
|
|
1201
|
+
// All columns are now guaranteed to exist (e.g. wallets.environment from v7).
|
|
1202
|
+
sqlite.exec('BEGIN');
|
|
1203
|
+
try {
|
|
1204
|
+
for (const stmt of indexes) {
|
|
1205
|
+
sqlite.exec(stmt);
|
|
1206
|
+
}
|
|
1207
|
+
sqlite.exec('COMMIT');
|
|
1208
|
+
}
|
|
1209
|
+
catch (err) {
|
|
1210
|
+
sqlite.exec('ROLLBACK');
|
|
1211
|
+
throw err;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
//# sourceMappingURL=migrate.js.map
|