@elizaos/agent 0.25.8 → 2.0.0-alpha.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) hide show
  1. package/LICENSE +1 -1
  2. package/package.json +994 -34
  3. package/packages/agent/src/actions/emote.d.ts +14 -0
  4. package/packages/agent/src/actions/emote.d.ts.map +1 -0
  5. package/packages/agent/src/actions/emote.js +91 -0
  6. package/packages/agent/src/actions/restart.d.ts +19 -0
  7. package/packages/agent/src/actions/restart.d.ts.map +1 -0
  8. package/packages/agent/src/actions/restart.js +86 -0
  9. package/packages/agent/src/actions/send-message.d.ts +3 -0
  10. package/packages/agent/src/actions/send-message.d.ts.map +1 -0
  11. package/packages/agent/src/actions/send-message.js +144 -0
  12. package/packages/agent/src/actions/stream-control.d.ts +15 -0
  13. package/packages/agent/src/actions/stream-control.d.ts.map +1 -0
  14. package/packages/agent/src/actions/stream-control.js +357 -0
  15. package/packages/agent/src/actions/switch-stream-source.d.ts +16 -0
  16. package/packages/agent/src/actions/switch-stream-source.d.ts.map +1 -0
  17. package/packages/agent/src/actions/switch-stream-source.js +94 -0
  18. package/packages/agent/src/actions/terminal.d.ts +14 -0
  19. package/packages/agent/src/actions/terminal.d.ts.map +1 -0
  20. package/packages/agent/src/actions/terminal.js +154 -0
  21. package/packages/agent/src/api/agent-admin-routes.d.ts +38 -0
  22. package/packages/agent/src/api/agent-admin-routes.d.ts.map +1 -0
  23. package/packages/agent/src/api/agent-admin-routes.js +93 -0
  24. package/packages/agent/src/api/agent-lifecycle-routes.d.ts +16 -0
  25. package/packages/agent/src/api/agent-lifecycle-routes.d.ts.map +1 -0
  26. package/packages/agent/src/api/agent-lifecycle-routes.js +80 -0
  27. package/packages/agent/src/api/agent-model.d.ts +12 -0
  28. package/packages/agent/src/api/agent-model.d.ts.map +1 -0
  29. package/packages/agent/src/api/agent-model.js +123 -0
  30. package/packages/agent/src/api/agent-transfer-routes.d.ts +16 -0
  31. package/packages/agent/src/api/agent-transfer-routes.d.ts.map +1 -0
  32. package/packages/agent/src/api/agent-transfer-routes.js +124 -0
  33. package/packages/agent/src/api/apps-routes.d.ts +19 -0
  34. package/packages/agent/src/api/apps-routes.d.ts.map +1 -0
  35. package/packages/agent/src/api/apps-routes.js +128 -0
  36. package/packages/agent/src/api/auth-routes.d.ts +11 -0
  37. package/packages/agent/src/api/auth-routes.d.ts.map +1 -0
  38. package/packages/agent/src/api/auth-routes.js +54 -0
  39. package/packages/agent/src/api/bsc-trade.d.ts +34 -0
  40. package/packages/agent/src/api/bsc-trade.d.ts.map +1 -0
  41. package/packages/agent/src/api/bsc-trade.js +567 -0
  42. package/packages/agent/src/api/bug-report-routes.d.ts +7 -0
  43. package/packages/agent/src/api/bug-report-routes.d.ts.map +1 -0
  44. package/packages/agent/src/api/bug-report-routes.js +124 -0
  45. package/packages/agent/src/api/character-routes.d.ts +50 -0
  46. package/packages/agent/src/api/character-routes.d.ts.map +1 -0
  47. package/packages/agent/src/api/character-routes.js +302 -0
  48. package/packages/agent/src/api/cloud-billing-routes.d.ts +14 -0
  49. package/packages/agent/src/api/cloud-billing-routes.d.ts.map +1 -0
  50. package/packages/agent/src/api/cloud-billing-routes.js +400 -0
  51. package/packages/agent/src/api/cloud-compat-routes.d.ts +15 -0
  52. package/packages/agent/src/api/cloud-compat-routes.d.ts.map +1 -0
  53. package/packages/agent/src/api/cloud-compat-routes.js +131 -0
  54. package/packages/agent/src/api/cloud-routes.d.ts +62 -0
  55. package/packages/agent/src/api/cloud-routes.d.ts.map +1 -0
  56. package/packages/agent/src/api/cloud-routes.js +339 -0
  57. package/packages/agent/src/api/cloud-status-routes.d.ts +15 -0
  58. package/packages/agent/src/api/cloud-status-routes.d.ts.map +1 -0
  59. package/packages/agent/src/api/cloud-status-routes.js +165 -0
  60. package/packages/agent/src/api/compat-utils.d.ts +49 -0
  61. package/packages/agent/src/api/compat-utils.d.ts.map +1 -0
  62. package/packages/agent/src/api/compat-utils.js +126 -0
  63. package/packages/agent/src/api/connector-health.d.ts +34 -0
  64. package/packages/agent/src/api/connector-health.d.ts.map +1 -0
  65. package/packages/agent/src/api/connector-health.js +109 -0
  66. package/packages/agent/src/api/coordinator-wiring.d.ts +46 -0
  67. package/packages/agent/src/api/coordinator-wiring.d.ts.map +1 -0
  68. package/packages/agent/src/api/coordinator-wiring.js +101 -0
  69. package/packages/agent/src/api/credit-detection.d.ts +9 -0
  70. package/packages/agent/src/api/credit-detection.d.ts.map +1 -0
  71. package/packages/agent/src/api/credit-detection.js +41 -0
  72. package/packages/agent/src/api/database.d.ts +33 -0
  73. package/packages/agent/src/api/database.d.ts.map +1 -0
  74. package/packages/agent/src/api/database.js +1019 -0
  75. package/packages/agent/src/api/diagnostics-routes.d.ts +46 -0
  76. package/packages/agent/src/api/diagnostics-routes.d.ts.map +1 -0
  77. package/packages/agent/src/api/diagnostics-routes.js +241 -0
  78. package/packages/agent/src/api/drop-service.d.ts +26 -0
  79. package/packages/agent/src/api/drop-service.d.ts.map +1 -0
  80. package/packages/agent/src/api/drop-service.js +134 -0
  81. package/packages/agent/src/api/early-logs.d.ts +29 -0
  82. package/packages/agent/src/api/early-logs.d.ts.map +1 -0
  83. package/packages/agent/src/api/early-logs.js +96 -0
  84. package/packages/agent/src/api/http-helpers.d.ts +50 -0
  85. package/packages/agent/src/api/http-helpers.d.ts.map +1 -0
  86. package/packages/agent/src/api/http-helpers.js +145 -0
  87. package/packages/agent/src/api/index.d.ts +61 -0
  88. package/packages/agent/src/api/index.d.ts.map +1 -0
  89. package/packages/agent/src/api/index.js +59 -0
  90. package/packages/agent/src/api/knowledge-routes.d.ts +23 -0
  91. package/packages/agent/src/api/knowledge-routes.d.ts.map +1 -0
  92. package/packages/agent/src/api/knowledge-routes.js +931 -0
  93. package/packages/agent/src/api/knowledge-service-loader.d.ts +51 -0
  94. package/packages/agent/src/api/knowledge-service-loader.d.ts.map +1 -0
  95. package/packages/agent/src/api/knowledge-service-loader.js +34 -0
  96. package/packages/agent/src/api/memory-bounds.d.ts +51 -0
  97. package/packages/agent/src/api/memory-bounds.d.ts.map +1 -0
  98. package/packages/agent/src/api/memory-bounds.js +81 -0
  99. package/packages/agent/src/api/memory-routes.d.ts +9 -0
  100. package/packages/agent/src/api/memory-routes.d.ts.map +1 -0
  101. package/packages/agent/src/api/memory-routes.js +241 -0
  102. package/packages/agent/src/api/merkle-tree.d.ts +90 -0
  103. package/packages/agent/src/api/merkle-tree.d.ts.map +1 -0
  104. package/packages/agent/src/api/merkle-tree.js +174 -0
  105. package/packages/agent/src/api/models-routes.d.ts +14 -0
  106. package/packages/agent/src/api/models-routes.d.ts.map +1 -0
  107. package/packages/agent/src/api/models-routes.js +37 -0
  108. package/packages/agent/src/api/nfa-routes.d.ts +5 -0
  109. package/packages/agent/src/api/nfa-routes.d.ts.map +1 -0
  110. package/packages/agent/src/api/nfa-routes.js +125 -0
  111. package/packages/agent/src/api/og-tracker.d.ts +28 -0
  112. package/packages/agent/src/api/og-tracker.d.ts.map +1 -0
  113. package/packages/agent/src/api/og-tracker.js +60 -0
  114. package/packages/agent/src/api/parse-action-block.d.ts +36 -0
  115. package/packages/agent/src/api/parse-action-block.d.ts.map +1 -0
  116. package/packages/agent/src/api/parse-action-block.js +110 -0
  117. package/packages/agent/src/api/permissions-routes.d.ts +32 -0
  118. package/packages/agent/src/api/permissions-routes.d.ts.map +1 -0
  119. package/packages/agent/src/api/permissions-routes.js +149 -0
  120. package/packages/agent/src/api/plugin-validation.d.ts +86 -0
  121. package/packages/agent/src/api/plugin-validation.d.ts.map +1 -0
  122. package/packages/agent/src/api/plugin-validation.js +259 -0
  123. package/packages/agent/src/api/provider-switch-config.d.ts +37 -0
  124. package/packages/agent/src/api/provider-switch-config.d.ts.map +1 -0
  125. package/packages/agent/src/api/provider-switch-config.js +317 -0
  126. package/packages/agent/src/api/registry-routes.d.ts +26 -0
  127. package/packages/agent/src/api/registry-routes.d.ts.map +1 -0
  128. package/packages/agent/src/api/registry-routes.js +90 -0
  129. package/packages/agent/src/api/registry-service.d.ts +77 -0
  130. package/packages/agent/src/api/registry-service.d.ts.map +1 -0
  131. package/packages/agent/src/api/registry-service.js +190 -0
  132. package/packages/agent/src/api/route-helpers.d.ts +16 -0
  133. package/packages/agent/src/api/route-helpers.d.ts.map +1 -0
  134. package/packages/agent/src/api/route-helpers.js +1 -0
  135. package/packages/agent/src/api/sandbox-routes.d.ts +12 -0
  136. package/packages/agent/src/api/sandbox-routes.d.ts.map +1 -0
  137. package/packages/agent/src/api/sandbox-routes.js +1334 -0
  138. package/packages/agent/src/api/server.d.ts +418 -0
  139. package/packages/agent/src/api/server.d.ts.map +1 -0
  140. package/packages/agent/src/api/server.js +13614 -0
  141. package/packages/agent/src/api/signal-routes.d.ts +39 -0
  142. package/packages/agent/src/api/signal-routes.d.ts.map +1 -0
  143. package/packages/agent/src/api/signal-routes.js +168 -0
  144. package/packages/agent/src/api/stream-persistence.d.ts +64 -0
  145. package/packages/agent/src/api/stream-persistence.d.ts.map +1 -0
  146. package/packages/agent/src/api/stream-persistence.js +231 -0
  147. package/packages/agent/src/api/stream-route-state.d.ts +50 -0
  148. package/packages/agent/src/api/stream-route-state.d.ts.map +1 -0
  149. package/packages/agent/src/api/stream-route-state.js +1 -0
  150. package/packages/agent/src/api/stream-routes.d.ts +45 -0
  151. package/packages/agent/src/api/stream-routes.d.ts.map +1 -0
  152. package/packages/agent/src/api/stream-routes.js +809 -0
  153. package/packages/agent/src/api/stream-voice-routes.d.ts +36 -0
  154. package/packages/agent/src/api/stream-voice-routes.d.ts.map +1 -0
  155. package/packages/agent/src/api/stream-voice-routes.js +133 -0
  156. package/packages/agent/src/api/streaming-text.d.ts +9 -0
  157. package/packages/agent/src/api/streaming-text.d.ts.map +1 -0
  158. package/packages/agent/src/api/streaming-text.js +85 -0
  159. package/packages/agent/src/api/streaming-types.d.ts +30 -0
  160. package/packages/agent/src/api/streaming-types.d.ts.map +1 -0
  161. package/packages/agent/src/api/streaming-types.js +1 -0
  162. package/packages/agent/src/api/subscription-routes.d.ts +20 -0
  163. package/packages/agent/src/api/subscription-routes.d.ts.map +1 -0
  164. package/packages/agent/src/api/subscription-routes.js +191 -0
  165. package/packages/agent/src/api/terminal-run-limits.d.ts +5 -0
  166. package/packages/agent/src/api/terminal-run-limits.d.ts.map +1 -0
  167. package/packages/agent/src/api/terminal-run-limits.js +22 -0
  168. package/packages/agent/src/api/training-backend-check.d.ts +8 -0
  169. package/packages/agent/src/api/training-backend-check.d.ts.map +1 -0
  170. package/packages/agent/src/api/training-backend-check.js +28 -0
  171. package/packages/agent/src/api/training-routes.d.ts +44 -0
  172. package/packages/agent/src/api/training-routes.d.ts.map +1 -0
  173. package/packages/agent/src/api/training-routes.js +195 -0
  174. package/packages/agent/src/api/training-service-like.d.ts +38 -0
  175. package/packages/agent/src/api/training-service-like.d.ts.map +1 -0
  176. package/packages/agent/src/api/training-service-like.js +1 -0
  177. package/packages/agent/src/api/trajectory-routes.d.ts +17 -0
  178. package/packages/agent/src/api/trajectory-routes.d.ts.map +1 -0
  179. package/packages/agent/src/api/trajectory-routes.js +405 -0
  180. package/packages/agent/src/api/trigger-routes.d.ts +72 -0
  181. package/packages/agent/src/api/trigger-routes.d.ts.map +1 -0
  182. package/packages/agent/src/api/trigger-routes.js +268 -0
  183. package/packages/agent/src/api/twitter-verify.d.ts +25 -0
  184. package/packages/agent/src/api/twitter-verify.d.ts.map +1 -0
  185. package/packages/agent/src/api/twitter-verify.js +168 -0
  186. package/packages/agent/src/api/tx-service.d.ts +47 -0
  187. package/packages/agent/src/api/tx-service.d.ts.map +1 -0
  188. package/packages/agent/src/api/tx-service.js +156 -0
  189. package/packages/agent/src/api/wallet-dex-prices.d.ts +43 -0
  190. package/packages/agent/src/api/wallet-dex-prices.d.ts.map +1 -0
  191. package/packages/agent/src/api/wallet-dex-prices.js +149 -0
  192. package/packages/agent/src/api/wallet-evm-balance.d.ts +65 -0
  193. package/packages/agent/src/api/wallet-evm-balance.d.ts.map +1 -0
  194. package/packages/agent/src/api/wallet-evm-balance.js +663 -0
  195. package/packages/agent/src/api/wallet-routes.d.ts +33 -0
  196. package/packages/agent/src/api/wallet-routes.d.ts.map +1 -0
  197. package/packages/agent/src/api/wallet-routes.js +292 -0
  198. package/packages/agent/src/api/wallet-rpc.d.ts +61 -0
  199. package/packages/agent/src/api/wallet-rpc.d.ts.map +1 -0
  200. package/packages/agent/src/api/wallet-rpc.js +367 -0
  201. package/packages/agent/src/api/wallet-trading-profile.d.ts +51 -0
  202. package/packages/agent/src/api/wallet-trading-profile.d.ts.map +1 -0
  203. package/packages/agent/src/api/wallet-trading-profile.js +547 -0
  204. package/packages/agent/src/api/wallet.d.ts +31 -0
  205. package/packages/agent/src/api/wallet.d.ts.map +1 -0
  206. package/packages/agent/src/api/wallet.js +513 -0
  207. package/packages/agent/src/api/whatsapp-routes.d.ts +39 -0
  208. package/packages/agent/src/api/whatsapp-routes.d.ts.map +1 -0
  209. package/packages/agent/src/api/whatsapp-routes.js +182 -0
  210. package/packages/agent/src/api/zip-utils.d.ts +8 -0
  211. package/packages/agent/src/api/zip-utils.d.ts.map +1 -0
  212. package/packages/agent/src/api/zip-utils.js +115 -0
  213. package/packages/agent/src/auth/anthropic.d.ts +25 -0
  214. package/packages/agent/src/auth/anthropic.d.ts.map +1 -0
  215. package/packages/agent/src/auth/anthropic.js +40 -0
  216. package/packages/agent/src/auth/apply-stealth.d.ts +8 -0
  217. package/packages/agent/src/auth/apply-stealth.d.ts.map +1 -0
  218. package/packages/agent/src/auth/apply-stealth.js +35 -0
  219. package/packages/agent/src/auth/claude-code-stealth.d.ts +2 -0
  220. package/packages/agent/src/auth/claude-code-stealth.d.ts.map +1 -0
  221. package/packages/agent/src/auth/claude-code-stealth.js +104 -0
  222. package/packages/agent/src/auth/credentials.d.ts +55 -0
  223. package/packages/agent/src/auth/credentials.d.ts.map +1 -0
  224. package/packages/agent/src/auth/credentials.js +182 -0
  225. package/packages/agent/src/auth/index.d.ts +7 -0
  226. package/packages/agent/src/auth/index.d.ts.map +1 -0
  227. package/packages/agent/src/auth/index.js +3 -0
  228. package/packages/agent/src/auth/openai-codex.d.ts +27 -0
  229. package/packages/agent/src/auth/openai-codex.d.ts.map +1 -0
  230. package/packages/agent/src/auth/openai-codex.js +72 -0
  231. package/packages/agent/src/auth/types.d.ts +18 -0
  232. package/packages/agent/src/auth/types.d.ts.map +1 -0
  233. package/packages/agent/src/auth/types.js +8 -0
  234. package/packages/agent/src/awareness/registry.d.ts +27 -0
  235. package/packages/agent/src/awareness/registry.d.ts.map +1 -0
  236. package/packages/agent/src/awareness/registry.js +161 -0
  237. package/packages/agent/src/benchmark-server.d.ts +2 -0
  238. package/packages/agent/src/benchmark-server.d.ts.map +1 -0
  239. package/packages/agent/src/benchmark-server.js +773 -0
  240. package/packages/agent/src/bin.d.ts +3 -0
  241. package/packages/agent/src/bin.d.ts.map +1 -0
  242. package/packages/agent/src/bin.js +6 -0
  243. package/packages/agent/src/cli/index.d.ts +2 -0
  244. package/packages/agent/src/cli/index.d.ts.map +1 -0
  245. package/packages/agent/src/cli/index.js +40 -0
  246. package/packages/agent/src/cli/parse-duration.d.ts +5 -0
  247. package/packages/agent/src/cli/parse-duration.d.ts.map +1 -0
  248. package/packages/agent/src/cli/parse-duration.js +27 -0
  249. package/packages/agent/src/cloud/auth.d.ts +19 -0
  250. package/packages/agent/src/cloud/auth.d.ts.map +1 -0
  251. package/packages/agent/src/cloud/auth.js +107 -0
  252. package/packages/agent/src/cloud/backup.d.ts +18 -0
  253. package/packages/agent/src/cloud/backup.d.ts.map +1 -0
  254. package/packages/agent/src/cloud/backup.js +42 -0
  255. package/packages/agent/src/cloud/base-url.d.ts +3 -0
  256. package/packages/agent/src/cloud/base-url.d.ts.map +1 -0
  257. package/packages/agent/src/cloud/base-url.js +40 -0
  258. package/packages/agent/src/cloud/bridge-client.d.ts +56 -0
  259. package/packages/agent/src/cloud/bridge-client.d.ts.map +1 -0
  260. package/packages/agent/src/cloud/bridge-client.js +190 -0
  261. package/packages/agent/src/cloud/cloud-manager.d.ts +32 -0
  262. package/packages/agent/src/cloud/cloud-manager.d.ts.map +1 -0
  263. package/packages/agent/src/cloud/cloud-manager.js +119 -0
  264. package/packages/agent/src/cloud/cloud-proxy.d.ts +20 -0
  265. package/packages/agent/src/cloud/cloud-proxy.d.ts.map +1 -0
  266. package/packages/agent/src/cloud/cloud-proxy.js +34 -0
  267. package/packages/agent/src/cloud/index.d.ts +7 -0
  268. package/packages/agent/src/cloud/index.d.ts.map +1 -0
  269. package/packages/agent/src/cloud/index.js +6 -0
  270. package/packages/agent/src/cloud/reconnect.d.ts +26 -0
  271. package/packages/agent/src/cloud/reconnect.d.ts.map +1 -0
  272. package/packages/agent/src/cloud/reconnect.js +86 -0
  273. package/packages/agent/src/cloud/validate-url.d.ts +2 -0
  274. package/packages/agent/src/cloud/validate-url.d.ts.map +1 -0
  275. package/packages/agent/src/cloud/validate-url.js +162 -0
  276. package/packages/agent/src/config/character-schema.d.ts +25 -0
  277. package/packages/agent/src/config/character-schema.d.ts.map +1 -0
  278. package/packages/agent/src/config/character-schema.js +39 -0
  279. package/packages/agent/src/config/config.d.ts +6 -0
  280. package/packages/agent/src/config/config.d.ts.map +1 -0
  281. package/packages/agent/src/config/config.js +118 -0
  282. package/packages/agent/src/config/env-vars.d.ts +3 -0
  283. package/packages/agent/src/config/env-vars.d.ts.map +1 -0
  284. package/packages/agent/src/config/env-vars.js +76 -0
  285. package/packages/agent/src/config/includes.d.ts +26 -0
  286. package/packages/agent/src/config/includes.d.ts.map +1 -0
  287. package/packages/agent/src/config/includes.js +148 -0
  288. package/packages/agent/src/config/index.d.ts +16 -0
  289. package/packages/agent/src/config/index.d.ts.map +1 -0
  290. package/packages/agent/src/config/index.js +15 -0
  291. package/packages/agent/src/config/object-utils.d.ts +2 -0
  292. package/packages/agent/src/config/object-utils.d.ts.map +1 -0
  293. package/packages/agent/src/config/object-utils.js +6 -0
  294. package/packages/agent/src/config/paths.d.ts +13 -0
  295. package/packages/agent/src/config/paths.d.ts.map +1 -0
  296. package/packages/agent/src/config/paths.js +67 -0
  297. package/packages/agent/src/config/plugin-auto-enable.d.ts +16 -0
  298. package/packages/agent/src/config/plugin-auto-enable.d.ts.map +1 -0
  299. package/packages/agent/src/config/plugin-auto-enable.js +384 -0
  300. package/packages/agent/src/config/schema.d.ts +87 -0
  301. package/packages/agent/src/config/schema.d.ts.map +1 -0
  302. package/packages/agent/src/config/schema.js +928 -0
  303. package/packages/agent/src/config/telegram-custom-commands.d.ts +25 -0
  304. package/packages/agent/src/config/telegram-custom-commands.d.ts.map +1 -0
  305. package/packages/agent/src/config/telegram-custom-commands.js +71 -0
  306. package/packages/agent/src/config/types.agent-defaults.d.ts +331 -0
  307. package/packages/agent/src/config/types.agent-defaults.d.ts.map +1 -0
  308. package/packages/agent/src/config/types.agent-defaults.js +1 -0
  309. package/packages/agent/src/config/types.agents.d.ts +110 -0
  310. package/packages/agent/src/config/types.agents.d.ts.map +1 -0
  311. package/packages/agent/src/config/types.agents.js +1 -0
  312. package/packages/agent/src/config/types.d.ts +8 -0
  313. package/packages/agent/src/config/types.d.ts.map +1 -0
  314. package/packages/agent/src/config/types.eliza.d.ts +636 -0
  315. package/packages/agent/src/config/types.eliza.d.ts.map +1 -0
  316. package/packages/agent/src/config/types.eliza.js +1 -0
  317. package/packages/agent/src/config/types.gateway.d.ts +216 -0
  318. package/packages/agent/src/config/types.gateway.d.ts.map +1 -0
  319. package/packages/agent/src/config/types.gateway.js +1 -0
  320. package/packages/agent/src/config/types.hooks.d.ts +107 -0
  321. package/packages/agent/src/config/types.hooks.d.ts.map +1 -0
  322. package/packages/agent/src/config/types.hooks.js +1 -0
  323. package/packages/agent/src/config/types.js +7 -0
  324. package/packages/agent/src/config/types.messages.d.ts +176 -0
  325. package/packages/agent/src/config/types.messages.d.ts.map +1 -0
  326. package/packages/agent/src/config/types.messages.js +1 -0
  327. package/packages/agent/src/config/types.tools.d.ts +400 -0
  328. package/packages/agent/src/config/types.tools.d.ts.map +1 -0
  329. package/packages/agent/src/config/types.tools.js +1 -0
  330. package/packages/agent/src/config/zod-schema.agent-runtime.d.ts +1062 -0
  331. package/packages/agent/src/config/zod-schema.agent-runtime.d.ts.map +1 -0
  332. package/packages/agent/src/config/zod-schema.agent-runtime.js +721 -0
  333. package/packages/agent/src/config/zod-schema.core.d.ts +1021 -0
  334. package/packages/agent/src/config/zod-schema.core.d.ts.map +1 -0
  335. package/packages/agent/src/config/zod-schema.core.js +694 -0
  336. package/packages/agent/src/config/zod-schema.d.ts +4817 -0
  337. package/packages/agent/src/config/zod-schema.d.ts.map +1 -0
  338. package/packages/agent/src/config/zod-schema.hooks.d.ts +88 -0
  339. package/packages/agent/src/config/zod-schema.hooks.d.ts.map +1 -0
  340. package/packages/agent/src/config/zod-schema.hooks.js +133 -0
  341. package/packages/agent/src/config/zod-schema.js +778 -0
  342. package/packages/agent/src/config/zod-schema.providers-core.d.ts +2976 -0
  343. package/packages/agent/src/config/zod-schema.providers-core.d.ts.map +1 -0
  344. package/packages/agent/src/config/zod-schema.providers-core.js +1006 -0
  345. package/packages/agent/src/config/zod-schema.session.d.ts +183 -0
  346. package/packages/agent/src/config/zod-schema.session.d.ts.map +1 -0
  347. package/packages/agent/src/config/zod-schema.session.js +86 -0
  348. package/packages/agent/src/contracts/apps.d.ts +42 -0
  349. package/packages/agent/src/contracts/apps.d.ts.map +1 -0
  350. package/packages/agent/src/contracts/apps.js +4 -0
  351. package/packages/agent/src/contracts/awareness.d.ts +38 -0
  352. package/packages/agent/src/contracts/awareness.d.ts.map +1 -0
  353. package/packages/agent/src/contracts/awareness.js +7 -0
  354. package/packages/agent/src/contracts/config.d.ts +146 -0
  355. package/packages/agent/src/contracts/config.d.ts.map +1 -0
  356. package/packages/agent/src/contracts/config.js +4 -0
  357. package/packages/agent/src/contracts/drop.d.ts +20 -0
  358. package/packages/agent/src/contracts/drop.d.ts.map +1 -0
  359. package/packages/agent/src/contracts/drop.js +4 -0
  360. package/packages/agent/src/contracts/index.d.ts +9 -0
  361. package/packages/agent/src/contracts/index.d.ts.map +1 -0
  362. package/packages/agent/src/contracts/index.js +8 -0
  363. package/packages/agent/src/contracts/onboarding.d.ts +379 -0
  364. package/packages/agent/src/contracts/onboarding.d.ts.map +1 -0
  365. package/packages/agent/src/contracts/onboarding.js +290 -0
  366. package/packages/agent/src/contracts/permissions.d.ts +35 -0
  367. package/packages/agent/src/contracts/permissions.d.ts.map +1 -0
  368. package/packages/agent/src/contracts/permissions.js +4 -0
  369. package/packages/agent/src/contracts/verification.d.ts +9 -0
  370. package/packages/agent/src/contracts/verification.d.ts.map +1 -0
  371. package/packages/agent/src/contracts/verification.js +4 -0
  372. package/packages/agent/src/contracts/wallet.d.ts +409 -0
  373. package/packages/agent/src/contracts/wallet.d.ts.map +1 -0
  374. package/packages/agent/src/contracts/wallet.js +60 -0
  375. package/packages/agent/src/diagnostics/integration-observability.d.ts +40 -0
  376. package/packages/agent/src/diagnostics/integration-observability.d.ts.map +1 -0
  377. package/packages/agent/src/diagnostics/integration-observability.js +68 -0
  378. package/packages/agent/src/emotes/catalog.d.ts +31 -0
  379. package/packages/agent/src/emotes/catalog.d.ts.map +1 -0
  380. package/packages/agent/src/emotes/catalog.js +618 -0
  381. package/packages/agent/src/hooks/discovery.d.ts +13 -0
  382. package/packages/agent/src/hooks/discovery.d.ts.map +1 -0
  383. package/packages/agent/src/hooks/discovery.js +184 -0
  384. package/packages/agent/src/hooks/eligibility.d.ts +12 -0
  385. package/packages/agent/src/hooks/eligibility.d.ts.map +1 -0
  386. package/packages/agent/src/hooks/eligibility.js +100 -0
  387. package/packages/agent/src/hooks/index.d.ts +3 -0
  388. package/packages/agent/src/hooks/index.d.ts.map +1 -0
  389. package/packages/agent/src/hooks/index.js +2 -0
  390. package/packages/agent/src/hooks/loader.d.ts +34 -0
  391. package/packages/agent/src/hooks/loader.d.ts.map +1 -0
  392. package/packages/agent/src/hooks/loader.js +176 -0
  393. package/packages/agent/src/hooks/registry.d.ts +11 -0
  394. package/packages/agent/src/hooks/registry.d.ts.map +1 -0
  395. package/packages/agent/src/hooks/registry.js +58 -0
  396. package/packages/agent/src/hooks/types.d.ts +104 -0
  397. package/packages/agent/src/hooks/types.d.ts.map +1 -0
  398. package/packages/agent/src/hooks/types.js +8 -0
  399. package/packages/agent/src/index.d.ts +20 -0
  400. package/packages/agent/src/index.d.ts.map +1 -0
  401. package/packages/agent/src/index.js +19 -0
  402. package/packages/agent/src/onboarding-presets.d.ts +78 -0
  403. package/packages/agent/src/onboarding-presets.d.ts.map +1 -0
  404. package/packages/agent/src/onboarding-presets.js +1352 -0
  405. package/packages/agent/src/plugins/custom-rtmp/index.d.ts +12 -0
  406. package/packages/agent/src/plugins/custom-rtmp/index.d.ts.map +1 -0
  407. package/packages/agent/src/plugins/custom-rtmp/index.js +26 -0
  408. package/packages/agent/src/providers/admin-trust.d.ts +4 -0
  409. package/packages/agent/src/providers/admin-trust.d.ts.map +1 -0
  410. package/packages/agent/src/providers/admin-trust.js +53 -0
  411. package/packages/agent/src/providers/session-bridge.d.ts +24 -0
  412. package/packages/agent/src/providers/session-bridge.d.ts.map +1 -0
  413. package/packages/agent/src/providers/session-bridge.js +85 -0
  414. package/packages/agent/src/providers/session-utils.d.ts +20 -0
  415. package/packages/agent/src/providers/session-utils.d.ts.map +1 -0
  416. package/packages/agent/src/providers/session-utils.js +33 -0
  417. package/packages/agent/src/providers/simple-mode.d.ts +4 -0
  418. package/packages/agent/src/providers/simple-mode.d.ts.map +1 -0
  419. package/packages/agent/src/providers/simple-mode.js +85 -0
  420. package/packages/agent/src/providers/ui-catalog.d.ts +3 -0
  421. package/packages/agent/src/providers/ui-catalog.d.ts.map +1 -0
  422. package/packages/agent/src/providers/ui-catalog.js +123 -0
  423. package/packages/agent/src/providers/workspace-provider.d.ts +22 -0
  424. package/packages/agent/src/providers/workspace-provider.d.ts.map +1 -0
  425. package/packages/agent/src/providers/workspace-provider.js +167 -0
  426. package/packages/agent/src/providers/workspace.d.ts +54 -0
  427. package/packages/agent/src/providers/workspace.d.ts.map +1 -0
  428. package/packages/agent/src/providers/workspace.js +405 -0
  429. package/packages/agent/src/runtime/agent-event-service.d.ts +35 -0
  430. package/packages/agent/src/runtime/agent-event-service.d.ts.map +1 -0
  431. package/packages/agent/src/runtime/agent-event-service.js +16 -0
  432. package/packages/agent/src/runtime/cloud-onboarding.d.ts +55 -0
  433. package/packages/agent/src/runtime/cloud-onboarding.d.ts.map +1 -0
  434. package/packages/agent/src/runtime/cloud-onboarding.js +279 -0
  435. package/packages/agent/src/runtime/core-plugins.d.ts +14 -0
  436. package/packages/agent/src/runtime/core-plugins.d.ts.map +1 -0
  437. package/packages/agent/src/runtime/core-plugins.js +51 -0
  438. package/packages/agent/src/runtime/custom-actions.d.ts +40 -0
  439. package/packages/agent/src/runtime/custom-actions.d.ts.map +1 -0
  440. package/packages/agent/src/runtime/custom-actions.js +454 -0
  441. package/packages/agent/src/runtime/eliza-plugin.d.ts +16 -0
  442. package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -0
  443. package/packages/agent/src/runtime/eliza-plugin.js +108 -0
  444. package/packages/agent/src/runtime/eliza.d.ts +205 -0
  445. package/packages/agent/src/runtime/eliza.d.ts.map +1 -0
  446. package/packages/agent/src/runtime/eliza.js +3935 -0
  447. package/packages/agent/src/runtime/embedding-presets.d.ts +19 -0
  448. package/packages/agent/src/runtime/embedding-presets.d.ts.map +1 -0
  449. package/packages/agent/src/runtime/embedding-presets.js +53 -0
  450. package/packages/agent/src/runtime/index.d.ts +9 -0
  451. package/packages/agent/src/runtime/index.d.ts.map +1 -0
  452. package/packages/agent/src/runtime/index.js +8 -0
  453. package/packages/agent/src/runtime/onboarding-names.d.ts +11 -0
  454. package/packages/agent/src/runtime/onboarding-names.d.ts.map +1 -0
  455. package/packages/agent/src/runtime/onboarding-names.js +74 -0
  456. package/packages/agent/src/runtime/release-plugin-policy.d.ts +20 -0
  457. package/packages/agent/src/runtime/release-plugin-policy.d.ts.map +1 -0
  458. package/packages/agent/src/runtime/release-plugin-policy.js +87 -0
  459. package/packages/agent/src/runtime/restart.d.ts +45 -0
  460. package/packages/agent/src/runtime/restart.d.ts.map +1 -0
  461. package/packages/agent/src/runtime/restart.js +45 -0
  462. package/packages/agent/src/runtime/trajectory-persistence.d.ts +214 -0
  463. package/packages/agent/src/runtime/trajectory-persistence.d.ts.map +1 -0
  464. package/packages/agent/src/runtime/trajectory-persistence.js +1957 -0
  465. package/packages/agent/src/runtime/version.d.ts +2 -0
  466. package/packages/agent/src/runtime/version.d.ts.map +1 -0
  467. package/packages/agent/src/runtime/version.js +5 -0
  468. package/packages/agent/src/security/audit-log.d.ts +49 -0
  469. package/packages/agent/src/security/audit-log.d.ts.map +1 -0
  470. package/packages/agent/src/security/audit-log.js +161 -0
  471. package/packages/agent/src/security/network-policy.d.ts +6 -0
  472. package/packages/agent/src/security/network-policy.d.ts.map +1 -0
  473. package/packages/agent/src/security/network-policy.js +85 -0
  474. package/packages/agent/src/server/index.d.ts +3 -0
  475. package/packages/agent/src/server/index.d.ts.map +1 -0
  476. package/packages/agent/src/server/index.js +1 -0
  477. package/packages/agent/src/services/agent-export.d.ts +100 -0
  478. package/packages/agent/src/services/agent-export.d.ts.map +1 -0
  479. package/packages/agent/src/services/agent-export.js +729 -0
  480. package/packages/agent/src/services/app-manager.d.ts +34 -0
  481. package/packages/agent/src/services/app-manager.d.ts.map +1 -0
  482. package/packages/agent/src/services/app-manager.js +425 -0
  483. package/packages/agent/src/services/browser-capture.d.ts +39 -0
  484. package/packages/agent/src/services/browser-capture.d.ts.map +1 -0
  485. package/packages/agent/src/services/browser-capture.js +162 -0
  486. package/packages/agent/src/services/coding-agent-context.d.ts +310 -0
  487. package/packages/agent/src/services/coding-agent-context.d.ts.map +1 -0
  488. package/packages/agent/src/services/coding-agent-context.js +281 -0
  489. package/packages/agent/src/services/fallback-training-service.d.ts +78 -0
  490. package/packages/agent/src/services/fallback-training-service.d.ts.map +1 -0
  491. package/packages/agent/src/services/fallback-training-service.js +126 -0
  492. package/packages/agent/src/services/index.d.ts +18 -0
  493. package/packages/agent/src/services/index.d.ts.map +1 -0
  494. package/packages/agent/src/services/index.js +17 -0
  495. package/packages/agent/src/services/mcp-marketplace.d.ts +89 -0
  496. package/packages/agent/src/services/mcp-marketplace.d.ts.map +1 -0
  497. package/packages/agent/src/services/mcp-marketplace.js +200 -0
  498. package/packages/agent/src/services/plugin-manager-types.d.ts +139 -0
  499. package/packages/agent/src/services/plugin-manager-types.d.ts.map +1 -0
  500. package/packages/agent/src/services/plugin-manager-types.js +18 -0
  501. package/packages/agent/src/services/privy-wallets.d.ts +18 -0
  502. package/packages/agent/src/services/privy-wallets.d.ts.map +1 -0
  503. package/packages/agent/src/services/privy-wallets.js +225 -0
  504. package/packages/agent/src/services/registry-client-app-meta.d.ts +6 -0
  505. package/packages/agent/src/services/registry-client-app-meta.d.ts.map +1 -0
  506. package/packages/agent/src/services/registry-client-app-meta.js +147 -0
  507. package/packages/agent/src/services/registry-client-endpoints.d.ts +7 -0
  508. package/packages/agent/src/services/registry-client-endpoints.d.ts.map +1 -0
  509. package/packages/agent/src/services/registry-client-endpoints.js +183 -0
  510. package/packages/agent/src/services/registry-client-local.d.ts +4 -0
  511. package/packages/agent/src/services/registry-client-local.d.ts.map +1 -0
  512. package/packages/agent/src/services/registry-client-local.js +377 -0
  513. package/packages/agent/src/services/registry-client-network.d.ts +9 -0
  514. package/packages/agent/src/services/registry-client-network.d.ts.map +1 -0
  515. package/packages/agent/src/services/registry-client-network.js +109 -0
  516. package/packages/agent/src/services/registry-client-queries.d.ts +15 -0
  517. package/packages/agent/src/services/registry-client-queries.d.ts.map +1 -0
  518. package/packages/agent/src/services/registry-client-queries.js +150 -0
  519. package/packages/agent/src/services/registry-client-types.d.ts +115 -0
  520. package/packages/agent/src/services/registry-client-types.d.ts.map +1 -0
  521. package/packages/agent/src/services/registry-client-types.js +1 -0
  522. package/packages/agent/src/services/registry-client.d.ts +39 -0
  523. package/packages/agent/src/services/registry-client.d.ts.map +1 -0
  524. package/packages/agent/src/services/registry-client.js +249 -0
  525. package/packages/agent/src/services/remote-signing-service.d.ts +58 -0
  526. package/packages/agent/src/services/remote-signing-service.d.ts.map +1 -0
  527. package/packages/agent/src/services/remote-signing-service.js +185 -0
  528. package/packages/agent/src/services/sandbox-engine.d.ts +96 -0
  529. package/packages/agent/src/services/sandbox-engine.d.ts.map +1 -0
  530. package/packages/agent/src/services/sandbox-engine.js +604 -0
  531. package/packages/agent/src/services/sandbox-manager.d.ts +104 -0
  532. package/packages/agent/src/services/sandbox-manager.d.ts.map +1 -0
  533. package/packages/agent/src/services/sandbox-manager.js +353 -0
  534. package/packages/agent/src/services/self-updater.d.ts +21 -0
  535. package/packages/agent/src/services/self-updater.d.ts.map +1 -0
  536. package/packages/agent/src/services/self-updater.js +162 -0
  537. package/packages/agent/src/services/signal-pairing.d.ts +37 -0
  538. package/packages/agent/src/services/signal-pairing.d.ts.map +1 -0
  539. package/packages/agent/src/services/signal-pairing.js +124 -0
  540. package/packages/agent/src/services/signing-policy.d.ts +44 -0
  541. package/packages/agent/src/services/signing-policy.d.ts.map +1 -0
  542. package/packages/agent/src/services/signing-policy.js +165 -0
  543. package/packages/agent/src/services/skill-catalog-client.d.ts +47 -0
  544. package/packages/agent/src/services/skill-catalog-client.d.ts.map +1 -0
  545. package/packages/agent/src/services/skill-catalog-client.js +130 -0
  546. package/packages/agent/src/services/skill-marketplace.d.ts +42 -0
  547. package/packages/agent/src/services/skill-marketplace.d.ts.map +1 -0
  548. package/packages/agent/src/services/skill-marketplace.js +680 -0
  549. package/packages/agent/src/services/stream-manager.d.ts +121 -0
  550. package/packages/agent/src/services/stream-manager.d.ts.map +1 -0
  551. package/packages/agent/src/services/stream-manager.js +604 -0
  552. package/packages/agent/src/services/tts-stream-bridge.d.ts +83 -0
  553. package/packages/agent/src/services/tts-stream-bridge.d.ts.map +1 -0
  554. package/packages/agent/src/services/tts-stream-bridge.js +349 -0
  555. package/packages/agent/src/services/update-checker.d.ts +29 -0
  556. package/packages/agent/src/services/update-checker.d.ts.map +1 -0
  557. package/packages/agent/src/services/update-checker.js +134 -0
  558. package/packages/agent/src/services/version-compat.d.ts +99 -0
  559. package/packages/agent/src/services/version-compat.d.ts.map +1 -0
  560. package/packages/agent/src/services/version-compat.js +195 -0
  561. package/packages/agent/src/services/whatsapp-pairing.d.ts +41 -0
  562. package/packages/agent/src/services/whatsapp-pairing.d.ts.map +1 -0
  563. package/packages/agent/src/services/whatsapp-pairing.js +209 -0
  564. package/packages/agent/src/shared/ui-catalog-prompt.d.ts +52 -0
  565. package/packages/agent/src/shared/ui-catalog-prompt.d.ts.map +1 -0
  566. package/packages/agent/src/shared/ui-catalog-prompt.js +1028 -0
  567. package/packages/agent/src/test-support/process-helpers.d.ts +13 -0
  568. package/packages/agent/src/test-support/process-helpers.d.ts.map +1 -0
  569. package/packages/agent/src/test-support/process-helpers.js +23 -0
  570. package/packages/agent/src/test-support/route-test-helpers.d.ts +37 -0
  571. package/packages/agent/src/test-support/route-test-helpers.d.ts.map +1 -0
  572. package/packages/agent/src/test-support/route-test-helpers.js +54 -0
  573. package/packages/agent/src/test-support/test-helpers.d.ts +77 -0
  574. package/packages/agent/src/test-support/test-helpers.d.ts.map +1 -0
  575. package/packages/agent/src/test-support/test-helpers.js +210 -0
  576. package/packages/agent/src/testing/index.d.ts +4 -0
  577. package/packages/agent/src/testing/index.d.ts.map +1 -0
  578. package/packages/agent/src/testing/index.js +3 -0
  579. package/packages/agent/src/triggers/action.d.ts +3 -0
  580. package/packages/agent/src/triggers/action.d.ts.map +1 -0
  581. package/packages/agent/src/triggers/action.js +267 -0
  582. package/packages/agent/src/triggers/runtime.d.ts +24 -0
  583. package/packages/agent/src/triggers/runtime.d.ts.map +1 -0
  584. package/packages/agent/src/triggers/runtime.js +322 -0
  585. package/packages/agent/src/triggers/scheduling.d.ts +70 -0
  586. package/packages/agent/src/triggers/scheduling.d.ts.map +1 -0
  587. package/packages/agent/src/triggers/scheduling.js +355 -0
  588. package/packages/agent/src/triggers/types.d.ts +115 -0
  589. package/packages/agent/src/triggers/types.d.ts.map +1 -0
  590. package/packages/agent/src/triggers/types.js +1 -0
  591. package/packages/agent/src/utils/exec-safety.d.ts +2 -0
  592. package/packages/agent/src/utils/exec-safety.d.ts.map +1 -0
  593. package/packages/agent/src/utils/exec-safety.js +21 -0
  594. package/packages/agent/src/utils/number-parsing.d.ts +26 -0
  595. package/packages/agent/src/utils/number-parsing.d.ts.map +1 -0
  596. package/packages/agent/src/utils/number-parsing.js +52 -0
  597. package/packages/agent/src/utils/spoken-text.d.ts +2 -0
  598. package/packages/agent/src/utils/spoken-text.d.ts.map +1 -0
  599. package/packages/agent/src/utils/spoken-text.js +56 -0
  600. package/packages/agent/src/version-resolver.d.ts +3 -0
  601. package/packages/agent/src/version-resolver.d.ts.map +1 -0
  602. package/packages/agent/src/version-resolver.js +51 -0
  603. package/jest.config.js +0 -17
  604. package/src/__tests__/client-type-identification.test.ts +0 -59
  605. package/src/defaultCharacter.ts +0 -530
  606. package/src/index.ts +0 -865
  607. package/tsconfig.json +0 -16
@@ -0,0 +1,1019 @@
1
+ /**
2
+ * Database management API handlers for the Eliza Control UI.
3
+ *
4
+ * Provides endpoints for:
5
+ * - Database provider configuration (PGLite vs Postgres)
6
+ * - Connection testing for remote Postgres
7
+ * - Table browsing and introspection
8
+ * - Row-level CRUD operations
9
+ * - Raw SQL query execution
10
+ * - Database status and health
11
+ *
12
+ * All data endpoints use the active runtime's database adapter (Drizzle ORM)
13
+ * so they work identically for both PGLite and Postgres.
14
+ */
15
+ import dns from "node:dns";
16
+ import net from "node:net";
17
+ import { promisify } from "node:util";
18
+ import { logger } from "@elizaos/core";
19
+ import { loadElizaConfig, saveElizaConfig } from "../config/config";
20
+ import { isLoopbackHost, normalizeHostLike, normalizeIpForPolicy, } from "../security/network-policy";
21
+ import { readJsonBody as parseJsonBody, sendJson, sendJsonError, } from "./http-helpers";
22
+ // ---------------------------------------------------------------------------
23
+ // Helpers
24
+ // ---------------------------------------------------------------------------
25
+ async function readJsonBody(req, res) {
26
+ return parseJsonBody(req, res, {
27
+ maxBytes: 2 * 1024 * 1024,
28
+ });
29
+ }
30
+ /**
31
+ * Safely quote a SQL identifier (table or column name).
32
+ * Postgres uses double-quote escaping: embedded " becomes "".
33
+ */
34
+ function quoteIdent(name) {
35
+ return `"${name.replace(/"/g, '""')}"`;
36
+ }
37
+ /**
38
+ * Build a Postgres connection string from individual credential fields.
39
+ */
40
+ function buildConnectionString(creds) {
41
+ if (creds.connectionString)
42
+ return creds.connectionString;
43
+ const host = creds.host ?? "localhost";
44
+ const port = creds.port ?? 5432;
45
+ const user = encodeURIComponent(creds.user ?? "postgres");
46
+ const password = creds.password ? encodeURIComponent(creds.password) : "";
47
+ const database = creds.database ?? "postgres";
48
+ const auth = password ? `${user}:${password}` : user;
49
+ const sslParam = creds.ssl ? "?sslmode=require" : "";
50
+ return `postgresql://${auth}@${host}:${port}/${database}${sslParam}`;
51
+ }
52
+ /**
53
+ * Return a copy of credentials with host pinned to a validated IP address.
54
+ * For connection strings, rewrites URL hostname to avoid re-resolution later.
55
+ */
56
+ function withPinnedHost(creds, pinnedHost) {
57
+ const normalizedPinned = pinnedHost.replace(/^::ffff:/i, "");
58
+ const next = { ...creds, host: normalizedPinned };
59
+ if (next.connectionString) {
60
+ try {
61
+ const parsed = new URL(next.connectionString);
62
+ parsed.hostname = normalizedPinned;
63
+ // Preserve DNS pinning even when libpq-style query params are present.
64
+ // `host` / `hostaddr` can override URI hostname; force both to pinned IP.
65
+ parsed.searchParams.set("host", normalizedPinned);
66
+ parsed.searchParams.set("hostaddr", normalizedPinned);
67
+ next.connectionString = parsed.toString();
68
+ }
69
+ catch {
70
+ // Validation has already parsed this once, but if URL rewriting fails,
71
+ // force builder path to use the pinned host.
72
+ delete next.connectionString;
73
+ }
74
+ }
75
+ return next;
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // Host validation — prevent SSRF via database connection endpoints
79
+ // ---------------------------------------------------------------------------
80
+ const dnsLookupAll = promisify(dns.lookup);
81
+ /**
82
+ * IP ranges that are ALWAYS blocked regardless of bind address.
83
+ * Cloud metadata and "this" network are never legitimate Postgres targets.
84
+ */
85
+ const ALWAYS_BLOCKED_IP_PATTERNS = [
86
+ /^169\.254\./, // Link-local / cloud metadata (AWS, GCP, Azure)
87
+ /^0\./, // "This" network
88
+ /^fe[89ab][0-9a-f]:/i, // IPv6 link-local fe80::/10
89
+ ];
90
+ /**
91
+ * Private/internal IP ranges — blocked only when the API is bound to a
92
+ * non-loopback address (i.e. remotely reachable). When bound to 127.0.0.1
93
+ * (the default), these are allowed since local Postgres is the most common
94
+ * setup and an attacker who can reach the loopback API already has local
95
+ * network access.
96
+ */
97
+ const PRIVATE_IP_PATTERNS = [
98
+ /^127\./, // IPv4 loopback
99
+ /^10\./, // RFC 1918 Class A
100
+ /^172\.(1[6-9]|2\d|3[01])\./, // RFC 1918 Class B
101
+ /^192\.168\./, // RFC 1918 Class C
102
+ /^::1$/, // IPv6 loopback
103
+ /^f[cd][0-9a-f]{2}:/i, // IPv6 ULA (fc00::/7 includes fc00::–fdff::)
104
+ ];
105
+ /**
106
+ * Returns true when the API server is bound to a loopback-only address.
107
+ * In that case, private/internal IP ranges are allowed for DB connections
108
+ * since only local processes can reach the API.
109
+ */
110
+ function isApiLoopbackOnly() {
111
+ let bind = (process.env.ELIZA_API_BIND ?? "127.0.0.1").trim().toLowerCase();
112
+ if (!bind)
113
+ bind = "127.0.0.1";
114
+ // Accept accidental URL-shaped bind values.
115
+ if (bind.startsWith("http://") || bind.startsWith("https://")) {
116
+ try {
117
+ const parsed = new URL(bind);
118
+ bind = parsed.hostname.toLowerCase();
119
+ }
120
+ catch {
121
+ // Fall through and treat as raw host value.
122
+ }
123
+ }
124
+ // [::1]:2138 -> ::1
125
+ const bracketedIpv6 = /^\[([^\]]+)\](?::\d+)?$/.exec(bind);
126
+ if (bracketedIpv6?.[1]) {
127
+ bind = bracketedIpv6[1];
128
+ }
129
+ else {
130
+ // localhost:2138 -> localhost, 127.0.0.1:2138 -> 127.0.0.1
131
+ const singleColonHostPort = /^([^:]+):(\d+)$/.exec(bind);
132
+ if (singleColonHostPort?.[1]) {
133
+ bind = singleColonHostPort[1];
134
+ }
135
+ }
136
+ bind = bind.replace(/^\[|\]$/g, "");
137
+ // Reuse the strict loopback classifier to avoid hostname prefix bypasses
138
+ // such as "127.evil.com" that are not literal 127.0.0.0/8 IPs.
139
+ return isLoopbackHost(bind);
140
+ }
141
+ /**
142
+ * Extract all potential hosts from a Postgres connection string or credentials object.
143
+ * Includes query params like ?host= and ?hostaddr= which Postgres clients honor.
144
+ * Returns empty array if no host can be determined.
145
+ */
146
+ function extractHosts(creds) {
147
+ if (creds.connectionString) {
148
+ try {
149
+ const url = new URL(creds.connectionString);
150
+ const hosts = [];
151
+ // PostgreSQL connection strings can have ?host= param that overrides URI hostname
152
+ const hostParam = url.searchParams.get("host");
153
+ if (hostParam) {
154
+ hosts.push(...hostParam
155
+ .split(",")
156
+ .map((h) => normalizeHostLike(h))
157
+ .filter(Boolean));
158
+ }
159
+ // Also check hostaddr param
160
+ const hostAddrParam = url.searchParams.get("hostaddr");
161
+ if (hostAddrParam) {
162
+ hosts.push(...hostAddrParam
163
+ .split(",")
164
+ .map((h) => normalizeHostLike(h))
165
+ .filter(Boolean));
166
+ }
167
+ // Include URI hostname
168
+ if (url.hostname) {
169
+ hosts.push(normalizeHostLike(url.hostname));
170
+ }
171
+ return [...new Set(hosts)];
172
+ }
173
+ catch {
174
+ return []; // Unparseable — will be rejected
175
+ }
176
+ }
177
+ if (creds.host) {
178
+ const host = normalizeHostLike(creds.host);
179
+ return host ? [host] : [];
180
+ }
181
+ return [];
182
+ }
183
+ /**
184
+ * Check whether an IP address falls in a blocked range.
185
+ * When the API is remotely reachable, private ranges are also blocked.
186
+ */
187
+ function isBlockedIp(ip) {
188
+ const normalized = normalizeIpForPolicy(ip);
189
+ if (ALWAYS_BLOCKED_IP_PATTERNS.some((p) => p.test(normalized)))
190
+ return true;
191
+ if (!isApiLoopbackOnly() &&
192
+ PRIVATE_IP_PATTERNS.some((p) => p.test(normalized)))
193
+ return true;
194
+ return false;
195
+ }
196
+ /**
197
+ * Validate that all target hosts do not resolve to blocked addresses.
198
+ *
199
+ * Performs DNS resolution to catch hostnames like `metadata.google.internal`
200
+ * or `169.254.169.254.nip.io` that resolve to link-local / cloud metadata
201
+ * IPs. Also handles IPv6-mapped IPv4 addresses (e.g. `::ffff:169.254.x.y`).
202
+ *
203
+ * Returns a validation result including a pinned host IP when successful.
204
+ */
205
+ async function validateDbHost(creds, opts = {}) {
206
+ const hosts = extractHosts(creds);
207
+ if (hosts.length === 0) {
208
+ return {
209
+ error: "Could not determine target host from the provided credentials.",
210
+ pinnedHost: null,
211
+ };
212
+ }
213
+ let pinnedHost = null;
214
+ for (const host of hosts) {
215
+ const literalNormalized = normalizeIpForPolicy(host);
216
+ // First check the literal host string (catches raw IPs without DNS lookup)
217
+ if (isBlockedIp(literalNormalized)) {
218
+ return {
219
+ error: `Connection to "${host}" is blocked: link-local and metadata addresses are not allowed.`,
220
+ pinnedHost: null,
221
+ };
222
+ }
223
+ // Literal IPs are already pinned and do not require DNS.
224
+ if (net.isIP(literalNormalized)) {
225
+ if (!pinnedHost)
226
+ pinnedHost = literalNormalized;
227
+ continue;
228
+ }
229
+ // Resolve DNS and check all resulting IPs
230
+ try {
231
+ const results = await dnsLookupAll(host, { all: true });
232
+ const addresses = Array.isArray(results) ? results : [results];
233
+ for (const entry of addresses) {
234
+ const ip = typeof entry === "string"
235
+ ? entry
236
+ : entry.address;
237
+ const normalized = normalizeIpForPolicy(ip);
238
+ if (isBlockedIp(normalized)) {
239
+ return {
240
+ error: `Connection to "${host}" is blocked: it resolves to ${ip} ` +
241
+ `which is a link-local or metadata address.`,
242
+ pinnedHost: null,
243
+ };
244
+ }
245
+ if (!pinnedHost)
246
+ pinnedHost = normalized;
247
+ }
248
+ }
249
+ catch {
250
+ // For "save config" flows we allow unresolved hostnames so users can
251
+ // persist remote endpoints that are only resolvable from their runtime
252
+ // network. For "test connection" flows we keep strict DNS requirements.
253
+ if (!opts.allowUnresolvedHostnames) {
254
+ return {
255
+ error: `Connection to "${host}" failed DNS resolution during validation. ` +
256
+ "Use a resolvable hostname or a literal IP address.",
257
+ pinnedHost: null,
258
+ };
259
+ }
260
+ }
261
+ }
262
+ if (!pinnedHost) {
263
+ if (opts.allowUnresolvedHostnames) {
264
+ return { error: null, pinnedHost: null };
265
+ }
266
+ return {
267
+ error: "Could not validate any host to a concrete IP address.",
268
+ pinnedHost: null,
269
+ };
270
+ }
271
+ return { error: null, pinnedHost };
272
+ }
273
+ /** Convert a JS value to a SQL literal for use in raw queries. */
274
+ function sqlLiteral(v) {
275
+ if (v === null || v === undefined)
276
+ return "NULL";
277
+ if (typeof v === "number")
278
+ return String(v);
279
+ if (typeof v === "boolean")
280
+ return v ? "TRUE" : "FALSE";
281
+ if (typeof v === "object")
282
+ return `'${JSON.stringify(v).replace(/'/g, "''")}'::jsonb`;
283
+ return `'${String(v).replace(/'/g, "''")}'`;
284
+ }
285
+ /** Build a "col = val" SQL assignment clause. */
286
+ function sqlAssign(col, val) {
287
+ if (val === null || val === undefined)
288
+ return `${quoteIdent(col)} = NULL`;
289
+ return `${quoteIdent(col)} = ${sqlLiteral(val)}`;
290
+ }
291
+ /** Build a "col = val" or "col IS NULL" SQL WHERE predicate. */
292
+ function sqlPredicate(col, val) {
293
+ if (val === null || val === undefined)
294
+ return `${quoteIdent(col)} IS NULL`;
295
+ return `${quoteIdent(col)} = ${sqlLiteral(val)}`;
296
+ }
297
+ // Cached drizzle-orm sql helper; resolved once on first call.
298
+ let _sqlHelper = null;
299
+ async function getDrizzleSql() {
300
+ if (!_sqlHelper) {
301
+ const drizzle = await import("drizzle-orm");
302
+ _sqlHelper = drizzle.sql;
303
+ }
304
+ return _sqlHelper;
305
+ }
306
+ /** Execute raw SQL via the runtime's Drizzle adapter. */
307
+ async function executeRawSql(runtime, sqlText) {
308
+ const drizzleSql = await getDrizzleSql();
309
+ const db = runtime.adapter.db;
310
+ const rawQuery = drizzleSql?.raw(sqlText);
311
+ if (!rawQuery)
312
+ throw new Error("SQL module not available");
313
+ const result = await db.execute(rawQuery);
314
+ const rows = Array.isArray(result.rows)
315
+ ? result.rows
316
+ : result;
317
+ let columns = [];
318
+ if (result.fields && Array.isArray(result.fields)) {
319
+ columns = result.fields.map((f) => f.name);
320
+ }
321
+ else if (rows.length > 0) {
322
+ columns = Object.keys(rows[0]);
323
+ }
324
+ return { rows, columns };
325
+ }
326
+ /**
327
+ * Detect the current database provider from environment / runtime state.
328
+ */
329
+ function detectCurrentProvider() {
330
+ return process.env.POSTGRES_URL ? "postgres" : "pglite";
331
+ }
332
+ /** Verify a table name refers to a real user table. */
333
+ async function assertTableExists(runtime, tableName) {
334
+ const safe = tableName.replace(/'/g, "''");
335
+ const { rows } = await executeRawSql(runtime, `SELECT 1 FROM information_schema.tables
336
+ WHERE table_name = '${safe}'
337
+ AND table_schema NOT IN ('pg_catalog', 'information_schema')
338
+ AND table_type = 'BASE TABLE'
339
+ LIMIT 1`);
340
+ return rows.length > 0;
341
+ }
342
+ // ---------------------------------------------------------------------------
343
+ // Route handlers
344
+ // ---------------------------------------------------------------------------
345
+ /**
346
+ * GET /api/database/status
347
+ * Returns current connection status, provider, table count, version.
348
+ */
349
+ async function handleGetStatus(_req, res, runtime) {
350
+ const provider = detectCurrentProvider();
351
+ if (!runtime?.adapter) {
352
+ sendJson(res, {
353
+ provider,
354
+ connected: false,
355
+ serverVersion: null,
356
+ tableCount: 0,
357
+ pgliteDataDir: process.env.PGLITE_DATA_DIR ?? null,
358
+ postgresHost: null,
359
+ });
360
+ return;
361
+ }
362
+ const { rows } = await executeRawSql(runtime, "SELECT version()");
363
+ const serverVersion = rows.length > 0
364
+ ? String(rows[0].version ?? "")
365
+ : null;
366
+ const tableResult = await executeRawSql(runtime, `SELECT count(*) AS cnt
367
+ FROM information_schema.tables
368
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
369
+ AND table_type = 'BASE TABLE'`);
370
+ const tableCount = tableResult.rows.length > 0
371
+ ? Number(tableResult.rows[0].cnt ?? 0)
372
+ : 0;
373
+ const status = {
374
+ provider,
375
+ connected: true,
376
+ serverVersion,
377
+ tableCount,
378
+ pgliteDataDir: provider === "pglite" ? (process.env.PGLITE_DATA_DIR ?? null) : null,
379
+ postgresHost: provider === "postgres"
380
+ ? (process.env.POSTGRES_URL?.replace(/^postgresql:\/\/[^@]*@/, "").replace(/\/.*$/, "") ?? null)
381
+ : null,
382
+ };
383
+ sendJson(res, status);
384
+ }
385
+ /**
386
+ * GET /api/database/config
387
+ * Returns the persisted database configuration from eliza.json.
388
+ */
389
+ function handleGetConfig(_req, res) {
390
+ const config = loadElizaConfig();
391
+ const dbConfig = config.database ?? { provider: "pglite" };
392
+ // Mask the password in the response
393
+ const sanitized = { ...dbConfig };
394
+ if (sanitized.postgres?.password) {
395
+ sanitized.postgres = {
396
+ ...sanitized.postgres,
397
+ password: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
398
+ };
399
+ }
400
+ if (sanitized.postgres?.connectionString) {
401
+ // Mask password in connection string
402
+ sanitized.postgres = {
403
+ ...sanitized.postgres,
404
+ connectionString: sanitized.postgres.connectionString.replace(/:([^@]+)@/, ":\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022@"),
405
+ };
406
+ }
407
+ sendJson(res, {
408
+ config: sanitized,
409
+ activeProvider: detectCurrentProvider(),
410
+ needsRestart: (dbConfig.provider ?? "pglite") !== detectCurrentProvider(),
411
+ });
412
+ }
413
+ /**
414
+ * PUT /api/database/config
415
+ * Saves new database configuration. Does NOT restart the agent automatically;
416
+ * the UI prompts the user to restart.
417
+ */
418
+ async function handlePutConfig(req, res) {
419
+ const body = await readJsonBody(req, res);
420
+ if (!body)
421
+ return;
422
+ // Validate
423
+ if (body.provider &&
424
+ body.provider !== "pglite" &&
425
+ body.provider !== "postgres") {
426
+ sendJsonError(res, `Invalid provider: ${String(body.provider)}. Must be "pglite" or "postgres".`);
427
+ return;
428
+ }
429
+ // Load current config so validation can account for unchanged provider.
430
+ const config = loadElizaConfig();
431
+ const existingDb = config.database ?? {};
432
+ const effectiveProvider = body.provider ?? existingDb.provider ?? "pglite";
433
+ let validatedPostgres = null;
434
+ if (body.postgres) {
435
+ const pg = body.postgres;
436
+ if (effectiveProvider === "postgres" && !pg.connectionString && !pg.host) {
437
+ sendJsonError(res, "Postgres configuration requires either a connectionString or at least a host.");
438
+ return;
439
+ }
440
+ const validation = await validateDbHost(pg, {
441
+ allowUnresolvedHostnames: Boolean(pg.connectionString),
442
+ });
443
+ if (validation.error) {
444
+ sendJsonError(res, validation.error);
445
+ return;
446
+ }
447
+ validatedPostgres = validation.pinnedHost
448
+ ? withPinnedHost(pg, validation.pinnedHost)
449
+ : pg;
450
+ }
451
+ // Merge: keep existing postgres/pglite sub-configs unless explicitly provided
452
+ const merged = {
453
+ ...existingDb,
454
+ ...body,
455
+ };
456
+ // If switching to postgres, ensure postgres config is present
457
+ if (merged.provider === "postgres" && body.postgres) {
458
+ merged.postgres = {
459
+ ...existingDb.postgres,
460
+ ...(validatedPostgres ?? body.postgres),
461
+ };
462
+ }
463
+ // If switching to pglite, ensure pglite config is present
464
+ if (merged.provider === "pglite" && body.pglite) {
465
+ merged.pglite = { ...existingDb.pglite, ...body.pglite };
466
+ }
467
+ config.database = merged;
468
+ saveElizaConfig(config);
469
+ logger.info({ src: "database-api", provider: merged.provider }, "Database configuration saved");
470
+ sendJson(res, {
471
+ saved: true,
472
+ config: merged,
473
+ needsRestart: (merged.provider ?? "pglite") !== detectCurrentProvider(),
474
+ });
475
+ }
476
+ /**
477
+ * POST /api/database/test
478
+ * Tests a Postgres connection without persisting anything.
479
+ * Body: { connectionString?, host?, port?, user?, password?, database?, ssl? }
480
+ */
481
+ async function handleTestConnection(req, res) {
482
+ const body = await readJsonBody(req, res);
483
+ if (!body)
484
+ return;
485
+ const validation = await validateDbHost(body);
486
+ if (validation.error) {
487
+ sendJsonError(res, validation.error);
488
+ return;
489
+ }
490
+ const pinnedCreds = validation.pinnedHost
491
+ ? withPinnedHost(body, validation.pinnedHost)
492
+ : body;
493
+ const connectionString = buildConnectionString(pinnedCreds);
494
+ const start = Date.now();
495
+ // Dynamically import pg to avoid hard-coupling (it is a peer dep via plugin-sql)
496
+ let Pool;
497
+ try {
498
+ const pgModule = await import("pg");
499
+ Pool = pgModule.default?.Pool ?? pgModule.Pool;
500
+ }
501
+ catch {
502
+ sendJson(res, {
503
+ success: false,
504
+ serverVersion: null,
505
+ error: "PostgreSQL client library (pg) is not available. Ensure @elizaos/plugin-sql is installed.",
506
+ durationMs: Date.now() - start,
507
+ });
508
+ return;
509
+ }
510
+ const pool = new Pool({
511
+ connectionString,
512
+ max: 1,
513
+ connectionTimeoutMillis: 10000,
514
+ idleTimeoutMillis: 5000,
515
+ });
516
+ let client = null;
517
+ try {
518
+ client = await pool.connect();
519
+ const versionResult = await client.query("SELECT version()");
520
+ const serverVersion = String(versionResult.rows[0]?.version ?? "");
521
+ const durationMs = Date.now() - start;
522
+ sendJson(res, {
523
+ success: true,
524
+ serverVersion,
525
+ error: null,
526
+ durationMs,
527
+ });
528
+ }
529
+ catch (err) {
530
+ const durationMs = Date.now() - start;
531
+ const message = err instanceof Error ? err.message : String(err);
532
+ sendJson(res, {
533
+ success: false,
534
+ serverVersion: null,
535
+ error: message,
536
+ durationMs,
537
+ });
538
+ }
539
+ finally {
540
+ if (client)
541
+ client.release();
542
+ await pool.end();
543
+ }
544
+ }
545
+ /**
546
+ * GET /api/database/tables
547
+ * Lists all user tables with column metadata and approximate row counts.
548
+ */
549
+ async function handleGetTables(_req, res, runtime) {
550
+ // Get all user tables
551
+ const tablesResult = await executeRawSql(runtime, `SELECT
552
+ t.table_schema AS schema,
553
+ t.table_name AS name,
554
+ COALESCE(s.n_live_tup, 0) AS row_count
555
+ FROM information_schema.tables t
556
+ LEFT JOIN pg_stat_user_tables s
557
+ ON s.schemaname = t.table_schema
558
+ AND s.relname = t.table_name
559
+ WHERE t.table_schema NOT IN ('pg_catalog', 'information_schema')
560
+ AND t.table_type = 'BASE TABLE'
561
+ ORDER BY t.table_schema, t.table_name`);
562
+ // Get columns for all tables in one query
563
+ const columnsResult = await executeRawSql(runtime, `SELECT
564
+ c.table_schema AS schema,
565
+ c.table_name AS table_name,
566
+ c.column_name AS name,
567
+ c.data_type AS type,
568
+ (c.is_nullable = 'YES') AS nullable,
569
+ c.column_default AS default_value,
570
+ COALESCE(
571
+ (SELECT true
572
+ FROM information_schema.table_constraints tc
573
+ JOIN information_schema.key_column_usage kcu
574
+ ON tc.constraint_name = kcu.constraint_name
575
+ AND tc.table_schema = kcu.table_schema
576
+ WHERE tc.constraint_type = 'PRIMARY KEY'
577
+ AND tc.table_schema = c.table_schema
578
+ AND tc.table_name = c.table_name
579
+ AND kcu.column_name = c.column_name),
580
+ false
581
+ ) AS is_primary_key
582
+ FROM information_schema.columns c
583
+ WHERE c.table_schema NOT IN ('pg_catalog', 'information_schema')
584
+ ORDER BY c.table_schema, c.table_name, c.ordinal_position`);
585
+ // Group columns by table
586
+ const columnsByTable = new Map();
587
+ for (const row of columnsResult.rows) {
588
+ const key = `${String(row.schema)}.${String(row.table_name)}`;
589
+ const cols = columnsByTable.get(key) ?? [];
590
+ cols.push({
591
+ name: String(row.name),
592
+ type: String(row.type),
593
+ nullable: Boolean(row.nullable),
594
+ defaultValue: row.default_value != null ? String(row.default_value) : null,
595
+ isPrimaryKey: Boolean(row.is_primary_key),
596
+ });
597
+ columnsByTable.set(key, cols);
598
+ }
599
+ const tables = tablesResult.rows.map((row) => {
600
+ const key = `${String(row.schema)}.${String(row.name)}`;
601
+ return {
602
+ name: String(row.name),
603
+ schema: String(row.schema),
604
+ rowCount: Number(row.row_count ?? 0),
605
+ columns: columnsByTable.get(key) ?? [],
606
+ };
607
+ });
608
+ sendJson(res, { tables });
609
+ }
610
+ /**
611
+ * GET /api/database/tables/:table/rows?offset=0&limit=50&sort=col&order=asc&search=term
612
+ * Paginated row retrieval for a specific table.
613
+ */
614
+ async function handleGetRows(req, res, runtime, tableName) {
615
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
616
+ const offset = Math.max(0, Number(url.searchParams.get("offset") ?? "0"));
617
+ const limit = Math.min(500, Math.max(1, Number(url.searchParams.get("limit") ?? "50")));
618
+ const sortCol = url.searchParams.get("sort") ?? "";
619
+ const sortOrder = url.searchParams.get("order") === "desc" ? "DESC" : "ASC";
620
+ const search = url.searchParams.get("search") ?? "";
621
+ if (!(await assertTableExists(runtime, tableName))) {
622
+ sendJsonError(res, `Table "${tableName}" not found`, 404);
623
+ return;
624
+ }
625
+ // Get column names for this table (for search and sort validation)
626
+ const safeTableName = tableName.replace(/'/g, "''");
627
+ const colResult = await executeRawSql(runtime, `SELECT column_name, data_type
628
+ FROM information_schema.columns
629
+ WHERE table_name = '${safeTableName}'
630
+ AND table_schema NOT IN ('pg_catalog', 'information_schema')
631
+ ORDER BY ordinal_position`);
632
+ const columnNames = colResult.rows.map((r) => String(r.column_name));
633
+ const columnTypes = new Map(colResult.rows.map((r) => [String(r.column_name), String(r.data_type)]));
634
+ // Validate sort column
635
+ const validSort = sortCol && columnNames.includes(sortCol) ? sortCol : "";
636
+ // Build search clause: search across all text-castable columns
637
+ let whereClause = "";
638
+ if (search.trim()) {
639
+ // Escape ILIKE special characters: backslash first (since it becomes
640
+ // the escape character), then the ILIKE wildcards % and _.
641
+ const escapedSearch = search
642
+ .replace(/'/g, "''")
643
+ .replace(/\\/g, "\\\\")
644
+ .replace(/%/g, "\\%")
645
+ .replace(/_/g, "\\_");
646
+ const textColumns = columnNames.filter((col) => {
647
+ const t = columnTypes.get(col) ?? "";
648
+ return (t.includes("char") ||
649
+ t.includes("text") ||
650
+ t === "uuid" ||
651
+ t === "jsonb" ||
652
+ t === "json" ||
653
+ t === "integer" ||
654
+ t === "bigint" ||
655
+ t === "numeric" ||
656
+ t === "timestamp" ||
657
+ t.includes("timestamp"));
658
+ });
659
+ if (textColumns.length > 0) {
660
+ const conditions = textColumns.map((col) => `${quoteIdent(col)}::text ILIKE '%${escapedSearch}%' ESCAPE '\\'`);
661
+ whereClause = `WHERE (${conditions.join(" OR ")})`;
662
+ }
663
+ }
664
+ // Count total (with search filter)
665
+ const countResult = await executeRawSql(runtime, `SELECT count(*) AS total FROM ${quoteIdent(tableName)} ${whereClause}`);
666
+ const total = Number(countResult.rows[0]?.total ?? 0);
667
+ // Fetch rows
668
+ const orderClause = validSort
669
+ ? `ORDER BY ${quoteIdent(validSort)} ${sortOrder}`
670
+ : "";
671
+ const query = `SELECT * FROM ${quoteIdent(tableName)} ${whereClause} ${orderClause} LIMIT ${limit} OFFSET ${offset}`;
672
+ const result = await executeRawSql(runtime, query);
673
+ sendJson(res, {
674
+ table: tableName,
675
+ rows: result.rows,
676
+ columns: result.columns,
677
+ total,
678
+ offset,
679
+ limit,
680
+ });
681
+ }
682
+ /**
683
+ * POST /api/database/tables/:table/rows
684
+ * Insert a new row. Body: { data: Record<string, unknown> }
685
+ */
686
+ async function handleInsertRow(req, res, runtime, tableName) {
687
+ const body = await readJsonBody(req, res);
688
+ if (!body)
689
+ return;
690
+ if (!body.data ||
691
+ typeof body.data !== "object" ||
692
+ Object.keys(body.data).length === 0) {
693
+ sendJsonError(res, "Request body must include a non-empty 'data' object.");
694
+ return;
695
+ }
696
+ if (!(await assertTableExists(runtime, tableName))) {
697
+ sendJsonError(res, `Table "${tableName}" not found`, 404);
698
+ return;
699
+ }
700
+ const columns = Object.keys(body.data);
701
+ const values = Object.values(body.data);
702
+ const colList = columns.map((c) => quoteIdent(c)).join(", ");
703
+ const valList = values.map(sqlLiteral).join(", ");
704
+ const result = await executeRawSql(runtime, `INSERT INTO ${quoteIdent(tableName)} (${colList}) VALUES (${valList}) RETURNING *`);
705
+ sendJson(res, { inserted: true, row: result.rows[0] ?? null }, 201);
706
+ }
707
+ /**
708
+ * PUT /api/database/tables/:table/rows
709
+ * Update a row. Body: { where: Record<string, unknown>, data: Record<string, unknown> }
710
+ */
711
+ async function handleUpdateRow(req, res, runtime, tableName) {
712
+ const body = await readJsonBody(req, res);
713
+ if (!body)
714
+ return;
715
+ if (!body.where || Object.keys(body.where).length === 0) {
716
+ sendJsonError(res, "Request body must include a non-empty 'where' object for row identification.");
717
+ return;
718
+ }
719
+ if (!body.data || Object.keys(body.data).length === 0) {
720
+ sendJsonError(res, "Request body must include a non-empty 'data' object with fields to update.");
721
+ return;
722
+ }
723
+ const setClauses = Object.entries(body.data).map(([col, val]) => sqlAssign(col, val));
724
+ const whereClauses = Object.entries(body.where).map(([col, val]) => sqlPredicate(col, val));
725
+ const result = await executeRawSql(runtime, `UPDATE ${quoteIdent(tableName)}
726
+ SET ${setClauses.join(", ")}
727
+ WHERE ${whereClauses.join(" AND ")}
728
+ RETURNING *`);
729
+ if (result.rows.length === 0) {
730
+ sendJsonError(res, "No matching row found to update.", 404);
731
+ return;
732
+ }
733
+ sendJson(res, { updated: true, row: result.rows[0] });
734
+ }
735
+ /**
736
+ * DELETE /api/database/tables/:table/rows
737
+ * Delete a row. Body: { where: Record<string, unknown> }
738
+ */
739
+ async function handleDeleteRow(req, res, runtime, tableName) {
740
+ const body = await readJsonBody(req, res);
741
+ if (!body)
742
+ return;
743
+ if (!body.where || Object.keys(body.where).length === 0) {
744
+ sendJsonError(res, "Request body must include a non-empty 'where' object for row identification.");
745
+ return;
746
+ }
747
+ const whereClauses = Object.entries(body.where).map(([col, val]) => sqlPredicate(col, val));
748
+ const result = await executeRawSql(runtime, `DELETE FROM ${quoteIdent(tableName)}
749
+ WHERE ${whereClauses.join(" AND ")}
750
+ RETURNING *`);
751
+ if (result.rows.length === 0) {
752
+ sendJsonError(res, "No matching row found to delete.", 404);
753
+ return;
754
+ }
755
+ sendJson(res, { deleted: true, row: result.rows[0] });
756
+ }
757
+ /**
758
+ * POST /api/database/query
759
+ * Execute a raw SQL query. Body: { sql: string, readOnly?: boolean }
760
+ */
761
+ async function handleQuery(req, res, runtime) {
762
+ const body = await readJsonBody(req, res);
763
+ if (!body)
764
+ return;
765
+ if (!body.sql ||
766
+ typeof body.sql !== "string" ||
767
+ body.sql.trim().length === 0) {
768
+ sendJsonError(res, "Request body must include a non-empty 'sql' string.");
769
+ return;
770
+ }
771
+ const sqlText = body.sql.trim();
772
+ // If readOnly mode, reject mutation statements.
773
+ // Strip SQL comments, then scan for mutation keywords *anywhere* in the
774
+ // query — not just the leading keyword. This prevents bypass via CTEs
775
+ // (WITH ... AS (DELETE ...)) and other SQL constructs that nest mutations.
776
+ if (body.readOnly !== false) {
777
+ // Strip block comments (/* ... */) and line comments (-- ...).
778
+ // Use empty-string replacement (not space) to mirror how PostgreSQL
779
+ // concatenates tokens across comments — e.g. DE/* */LETE → DELETE.
780
+ // A space replacement would turn it into "DE LETE", hiding the keyword.
781
+ const stripped = sqlText
782
+ .replace(/\/\*[\s\S]*?\*\//g, "")
783
+ .replace(/--.*$/gm, "")
784
+ .trim();
785
+ // Strip string literals so that mutation keywords/functions inside quoted
786
+ // strings are ignored. Handles single-quoted ('...'), dollar-quoted
787
+ // ($$...$$), and tagged dollar-quoted ($tag$...$tag$) strings.
788
+ const noLiterals = stripped
789
+ .replace(/\$([A-Za-z0-9_]*)\$[\s\S]*?\$\1\$/g, " ")
790
+ .replace(/'(?:[^']|'')*'/g, " ");
791
+ // For keyword checks, also strip double-quoted identifiers to avoid
792
+ // matching words inside quoted table/column names.
793
+ const noStrings = noLiterals.replace(/"(?:[^"]|"")*"/g, " ");
794
+ const mutationKeywords = [
795
+ // ── DML ────────────────────────────────────────────────────────────
796
+ "INSERT",
797
+ "UPDATE",
798
+ "DELETE",
799
+ "INTO",
800
+ "COPY",
801
+ "MERGE",
802
+ // ── DDL ────────────────────────────────────────────────────────────
803
+ "DROP",
804
+ "ALTER",
805
+ "TRUNCATE",
806
+ "CREATE",
807
+ "COMMENT",
808
+ // ── Admin / privilege ──────────────────────────────────────────────
809
+ "GRANT",
810
+ "REVOKE",
811
+ "SET",
812
+ "RESET",
813
+ "LOAD",
814
+ // ── Maintenance ────────────────────────────────────────────────────
815
+ "VACUUM",
816
+ "REINDEX",
817
+ "CLUSTER",
818
+ "REFRESH",
819
+ "DISCARD",
820
+ // ── Procedural ─────────────────────────────────────────────────────
821
+ "CALL",
822
+ "DO",
823
+ // ── Async notifications (side-effects) ─────────────────────────────
824
+ "LISTEN",
825
+ "UNLISTEN",
826
+ "NOTIFY",
827
+ // ── Prepared statements (can wrap mutations) ───────────────────────
828
+ "PREPARE",
829
+ "EXECUTE",
830
+ "DEALLOCATE",
831
+ // ── Locking ────────────────────────────────────────────────────────
832
+ "LOCK",
833
+ ];
834
+ // Match mutation keywords as whole words (word boundary) anywhere in the
835
+ // query, catching them inside CTEs, subqueries, etc.
836
+ const mutationPattern = new RegExp(`\\b(${mutationKeywords.join("|")})\\b`, "i");
837
+ const match = mutationPattern.exec(noStrings);
838
+ if (match) {
839
+ sendJsonError(res, `Query rejected: "${match[1].toUpperCase()}" is a mutation keyword. Set readOnly: false to execute mutations.`);
840
+ return;
841
+ }
842
+ // PostgreSQL built-in functions that can read/write server files, mutate
843
+ // server state, or cause denial of service. These appear inside otherwise
844
+ // valid SELECT expressions, so keyword checks alone won't catch them.
845
+ //
846
+ // ── File I/O (arbitrary file read/write on the DB server) ─────────
847
+ // lo_import('/etc/passwd') — load file into large object
848
+ // lo_export(oid, '/tmp/evil') — write large object to file
849
+ // lo_unlink(oid) — delete large object
850
+ // pg_read_file('/etc/passwd') — read server file (superuser)
851
+ // pg_read_binary_file(...) — same, binary
852
+ // pg_write_file(...) — write to server files (ext. module)
853
+ // pg_stat_file(...) — stat a server file
854
+ // pg_ls_dir(...) — list server directory
855
+ //
856
+ // ── Sequence / state mutation ────────────────────────────────────
857
+ // nextval('seq'), setval('seq', n)
858
+ //
859
+ // ── Denial of service ────────────────────────────────────────────
860
+ // pg_sleep(n) — block connection for n seconds
861
+ // pg_sleep_for(interval) — same, interval version
862
+ // pg_sleep_until(timestamp) — same, deadline version
863
+ //
864
+ // ── Session / backend control ────────────────────────────────────
865
+ // pg_terminate_backend(pid) — kill another connection
866
+ // pg_cancel_backend(pid) — cancel a running query
867
+ // pg_reload_conf() — reload server configuration
868
+ // pg_rotate_logfile() — rotate the server log
869
+ // set_config(name, value, local) — SET equivalent as function
870
+ //
871
+ // ── Advisory locks (can deadlock other connections) ───────────────
872
+ // pg_advisory_lock(key) — session-level advisory lock
873
+ // pg_advisory_lock_shared(key)
874
+ // pg_try_advisory_lock(key)
875
+ const dangerousFunctions = [
876
+ // File I/O
877
+ "lo_import",
878
+ "lo_export",
879
+ "lo_unlink",
880
+ "lo_put",
881
+ "lo_from_bytea",
882
+ "pg_read_file",
883
+ "pg_read_binary_file",
884
+ "pg_write_file",
885
+ "pg_stat_file",
886
+ "pg_ls_dir",
887
+ "pg_ls_logdir",
888
+ "pg_ls_waldir",
889
+ "pg_ls_tmpdir",
890
+ "pg_ls_archive_statusdir",
891
+ // Sequence / state mutation
892
+ "nextval",
893
+ "setval",
894
+ // Denial of service
895
+ "pg_sleep",
896
+ "pg_sleep_for",
897
+ "pg_sleep_until",
898
+ // Session / backend control
899
+ "pg_terminate_backend",
900
+ "pg_cancel_backend",
901
+ "pg_reload_conf",
902
+ "pg_rotate_logfile",
903
+ "set_config",
904
+ // Advisory locks
905
+ "pg_advisory_lock",
906
+ "pg_advisory_lock_shared",
907
+ "pg_try_advisory_lock",
908
+ "pg_try_advisory_lock_shared",
909
+ "pg_advisory_xact_lock",
910
+ "pg_advisory_xact_lock_shared",
911
+ "pg_advisory_unlock",
912
+ "pg_advisory_unlock_shared",
913
+ "pg_advisory_unlock_all",
914
+ ];
915
+ const dangerousFnPattern = new RegExp(`(?:^|[^\\w$])"?(?:${dangerousFunctions.join("|")})"?\\s*\\(`, "i");
916
+ const fnMatch = dangerousFnPattern.exec(noLiterals);
917
+ if (fnMatch) {
918
+ // Extract the function name from the match for the error message.
919
+ const fnNameMatch = fnMatch[0].match(new RegExp(`(${dangerousFunctions.join("|")})`, "i"));
920
+ const fnName = fnNameMatch ? fnNameMatch[1].toUpperCase() : "UNKNOWN";
921
+ sendJsonError(res, `Query rejected: "${fnName}" is a dangerous function that can modify server state. Set readOnly: false to execute this query.`);
922
+ return;
923
+ }
924
+ // Reject multi-statement queries (naive: any semicolon not at the very end)
925
+ const trimmedForSemicolon = stripped.replace(/;\s*$/, "");
926
+ if (trimmedForSemicolon.includes(";")) {
927
+ sendJsonError(res, "Query rejected: multi-statement queries are not allowed in read-only mode.");
928
+ return;
929
+ }
930
+ }
931
+ const start = Date.now();
932
+ const result = await executeRawSql(runtime, sqlText);
933
+ const durationMs = Date.now() - start;
934
+ const queryResult = {
935
+ columns: result.columns,
936
+ rows: result.rows,
937
+ rowCount: result.rows.length,
938
+ durationMs,
939
+ };
940
+ sendJson(res, queryResult);
941
+ }
942
+ // ---------------------------------------------------------------------------
943
+ // Router
944
+ // ---------------------------------------------------------------------------
945
+ /**
946
+ * Route a database API request. Returns true if handled, false if not matched.
947
+ *
948
+ * Expected URL patterns:
949
+ * GET /api/database/status
950
+ * GET /api/database/config
951
+ * PUT /api/database/config
952
+ * POST /api/database/test
953
+ * GET /api/database/tables
954
+ * GET /api/database/tables/:table/rows
955
+ * POST /api/database/tables/:table/rows
956
+ * PUT /api/database/tables/:table/rows
957
+ * DELETE /api/database/tables/:table/rows
958
+ * POST /api/database/query
959
+ */
960
+ export async function handleDatabaseRoute(req, res, runtime, pathname) {
961
+ const method = req.method ?? "GET";
962
+ // ── GET /api/database/status ──────────────────────────────────────────
963
+ if (method === "GET" && pathname === "/api/database/status") {
964
+ await handleGetStatus(req, res, runtime);
965
+ return true;
966
+ }
967
+ // ── GET /api/database/config ──────────────────────────────────────────
968
+ if (method === "GET" && pathname === "/api/database/config") {
969
+ handleGetConfig(req, res);
970
+ return true;
971
+ }
972
+ // ── PUT /api/database/config ──────────────────────────────────────────
973
+ if (method === "PUT" && pathname === "/api/database/config") {
974
+ await handlePutConfig(req, res);
975
+ return true;
976
+ }
977
+ // ── POST /api/database/test ───────────────────────────────────────────
978
+ if (method === "POST" && pathname === "/api/database/test") {
979
+ await handleTestConnection(req, res);
980
+ return true;
981
+ }
982
+ // Routes below require a live runtime with a database adapter
983
+ if (!runtime?.adapter) {
984
+ sendJsonError(res, "Database not available. The agent may not be running or the database adapter is not initialized.", 503);
985
+ return true;
986
+ }
987
+ // ── GET /api/database/tables ──────────────────────────────────────────
988
+ if (method === "GET" && pathname === "/api/database/tables") {
989
+ await handleGetTables(req, res, runtime);
990
+ return true;
991
+ }
992
+ // ── POST /api/database/query ──────────────────────────────────────────
993
+ if (method === "POST" && pathname === "/api/database/query") {
994
+ await handleQuery(req, res, runtime);
995
+ return true;
996
+ }
997
+ // ── Table row operations: /api/database/tables/:table/rows ────────────
998
+ const rowsMatch = pathname.match(/^\/api\/database\/tables\/([^/]+)\/rows$/);
999
+ if (rowsMatch) {
1000
+ const tableNameDecoded = decodeURIComponent(rowsMatch[1]);
1001
+ if (method === "GET") {
1002
+ await handleGetRows(req, res, runtime, tableNameDecoded);
1003
+ return true;
1004
+ }
1005
+ if (method === "POST") {
1006
+ await handleInsertRow(req, res, runtime, tableNameDecoded);
1007
+ return true;
1008
+ }
1009
+ if (method === "PUT") {
1010
+ await handleUpdateRow(req, res, runtime, tableNameDecoded);
1011
+ return true;
1012
+ }
1013
+ if (method === "DELETE") {
1014
+ await handleDeleteRow(req, res, runtime, tableNameDecoded);
1015
+ return true;
1016
+ }
1017
+ }
1018
+ return false;
1019
+ }