auramaxx 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +77 -0
  3. package/apps/desktop-electron/main.js +428 -0
  4. package/bin/auramaxx.js +1063 -0
  5. package/docs/ADAPTERS.md +466 -0
  6. package/docs/AGENT_SETUP.md +159 -0
  7. package/docs/API.md +127 -0
  8. package/docs/APPS.md +199 -0
  9. package/docs/ARCHITECTURE.md +235 -0
  10. package/docs/AUTH.md +318 -0
  11. package/docs/BEST-PRACTICES.md +82 -0
  12. package/docs/CLI.md +141 -0
  13. package/docs/DESKTOP_ELECTRON.md +26 -0
  14. package/docs/DEVELOPING-APPS.md +453 -0
  15. package/docs/MCP.md +122 -0
  16. package/docs/PACKAGING_POLICY.md +19 -0
  17. package/docs/PERMISSION.md +137 -0
  18. package/docs/PROTOCOL.md +142 -0
  19. package/docs/README.md +50 -0
  20. package/docs/SKILLS.md +132 -0
  21. package/docs/TROUBLESHOOTING.md +376 -0
  22. package/docs/WORKSPACE.md +673 -0
  23. package/docs/agent-auth.md +14 -0
  24. package/docs/api/authentication.md +79 -0
  25. package/docs/api/secrets/api-keys.md +28 -0
  26. package/docs/api/secrets/credentials.md +80 -0
  27. package/docs/api/secrets/sharing.md +48 -0
  28. package/docs/api/system.md +41 -0
  29. package/docs/api/wallets/apps-strategies.md +66 -0
  30. package/docs/api/wallets/core.md +46 -0
  31. package/docs/api/wallets/data-portfolio.md +42 -0
  32. package/docs/aura-file.md +48 -0
  33. package/docs/core-concepts/FEATURES.md +114 -0
  34. package/docs/credentials.md +120 -0
  35. package/docs/external/HOW_TO_AURAMAXX/GETTING_SECRETS.md +33 -0
  36. package/docs/external/HOW_TO_AURAMAXX/README.md +45 -0
  37. package/docs/external/getting-started.md +10 -0
  38. package/docs/external/overview.md +19 -0
  39. package/docs/external/persona-paths.md +7 -0
  40. package/docs/external/share-secret.md +76 -0
  41. package/docs/external/why-aura.md +7 -0
  42. package/docs/security.md +227 -0
  43. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  44. package/docs/wallet/AI.md +508 -0
  45. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  46. package/docs/wallet/README.md +47 -0
  47. package/docs/wallet/STRATEGY.md +89 -0
  48. package/next.config.ts +28 -0
  49. package/package.json +167 -0
  50. package/postcss.config.mjs +8 -0
  51. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  52. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  53. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  54. package/prisma/migrations/20260222090000_update_admin_ttl_default/migration.sql +10 -0
  55. package/prisma/migrations/migration_lock.toml +3 -0
  56. package/prisma/schema.prisma +447 -0
  57. package/public/logo.webp +0 -0
  58. package/scripts/add-app.js +245 -0
  59. package/server/abi/SwapHelper.json +438 -0
  60. package/server/cli/approval.ts +447 -0
  61. package/server/cli/commands/actions.ts +474 -0
  62. package/server/cli/commands/api.ts +220 -0
  63. package/server/cli/commands/apikey.ts +277 -0
  64. package/server/cli/commands/app.ts +204 -0
  65. package/server/cli/commands/auth.ts +464 -0
  66. package/server/cli/commands/cron.ts +24 -0
  67. package/server/cli/commands/diary.ts +274 -0
  68. package/server/cli/commands/doctor.ts +1247 -0
  69. package/server/cli/commands/env.ts +476 -0
  70. package/server/cli/commands/experimental.ts +69 -0
  71. package/server/cli/commands/init.ts +798 -0
  72. package/server/cli/commands/lock.ts +157 -0
  73. package/server/cli/commands/mcp.ts +285 -0
  74. package/server/cli/commands/quickhack.ts +86 -0
  75. package/server/cli/commands/release-check.ts +231 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/service.ts +320 -0
  78. package/server/cli/commands/shell-hook.ts +512 -0
  79. package/server/cli/commands/skill.ts +216 -0
  80. package/server/cli/commands/start.ts +139 -0
  81. package/server/cli/commands/status.ts +59 -0
  82. package/server/cli/commands/stop.ts +36 -0
  83. package/server/cli/commands/token.ts +180 -0
  84. package/server/cli/commands/unlock.ts +50 -0
  85. package/server/cli/commands/vault.ts +1323 -0
  86. package/server/cli/commands/wallet.ts +209 -0
  87. package/server/cli/index.ts +280 -0
  88. package/server/cli/lib/approval-poll.ts +94 -0
  89. package/server/cli/lib/aura-parser.ts +64 -0
  90. package/server/cli/lib/credential-create.ts +74 -0
  91. package/server/cli/lib/credential-resolve.ts +280 -0
  92. package/server/cli/lib/dotenv-migrate.ts +116 -0
  93. package/server/cli/lib/dotenv-parser.ts +146 -0
  94. package/server/cli/lib/escalation.ts +57 -0
  95. package/server/cli/lib/http.ts +91 -0
  96. package/server/cli/lib/init-steps.ts +76 -0
  97. package/server/cli/lib/local-agent-trust.ts +45 -0
  98. package/server/cli/lib/lock-unlock-helper.ts +71 -0
  99. package/server/cli/lib/process.ts +162 -0
  100. package/server/cli/lib/prompt.ts +294 -0
  101. package/server/cli/lib/theme.ts +240 -0
  102. package/server/cli/socket.ts +579 -0
  103. package/server/cli/transport-client.ts +50 -0
  104. package/server/cron/index.ts +137 -0
  105. package/server/cron/job.ts +31 -0
  106. package/server/cron/jobs/balance-sync.ts +436 -0
  107. package/server/cron/jobs/incoming-scan.ts +506 -0
  108. package/server/cron/jobs/native-price.ts +70 -0
  109. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  110. package/server/cron/jobs/strategy-runner.ts +175 -0
  111. package/server/cron/scheduler.ts +125 -0
  112. package/server/index.ts +420 -0
  113. package/server/lib/adapters/factory.ts +119 -0
  114. package/server/lib/adapters/index.ts +19 -0
  115. package/server/lib/adapters/router.ts +297 -0
  116. package/server/lib/adapters/telegram.ts +645 -0
  117. package/server/lib/adapters/types.ts +89 -0
  118. package/server/lib/adapters/webhook.ts +95 -0
  119. package/server/lib/address.ts +49 -0
  120. package/server/lib/agent-auth/contracts.ts +1194 -0
  121. package/server/lib/agent-profiles.ts +419 -0
  122. package/server/lib/ai.ts +285 -0
  123. package/server/lib/api-registry/contracts.ts +86 -0
  124. package/server/lib/api-registry/validation.ts +172 -0
  125. package/server/lib/apikey-migration.ts +258 -0
  126. package/server/lib/app-installer.ts +505 -0
  127. package/server/lib/app-tokens.ts +247 -0
  128. package/server/lib/approval-link.ts +27 -0
  129. package/server/lib/auth.ts +314 -0
  130. package/server/lib/auto-execute.ts +160 -0
  131. package/server/lib/batch.ts +242 -0
  132. package/server/lib/cold.ts +1048 -0
  133. package/server/lib/config.ts +408 -0
  134. package/server/lib/credential-access-audit.ts +85 -0
  135. package/server/lib/credential-access-policy.ts +111 -0
  136. package/server/lib/credential-health.ts +343 -0
  137. package/server/lib/credential-import.ts +608 -0
  138. package/server/lib/credential-scope.ts +102 -0
  139. package/server/lib/credential-shares.ts +190 -0
  140. package/server/lib/credential-transport.ts +533 -0
  141. package/server/lib/credential-vault.ts +77 -0
  142. package/server/lib/credentials.ts +422 -0
  143. package/server/lib/crypto.ts +8 -0
  144. package/server/lib/db.ts +58 -0
  145. package/server/lib/defaults.ts +386 -0
  146. package/server/lib/dex/index.ts +80 -0
  147. package/server/lib/dex/relay.ts +235 -0
  148. package/server/lib/dex/types.ts +59 -0
  149. package/server/lib/dex/uniswap.ts +370 -0
  150. package/server/lib/diary.ts +34 -0
  151. package/server/lib/dont-ask-again-policy.ts +41 -0
  152. package/server/lib/e2e-agent/artifacts.ts +36 -0
  153. package/server/lib/e2e-agent/contracts.ts +112 -0
  154. package/server/lib/e2e-agent/validation.ts +135 -0
  155. package/server/lib/encrypt.ts +114 -0
  156. package/server/lib/error.ts +20 -0
  157. package/server/lib/events.ts +217 -0
  158. package/server/lib/feature-flags.ts +93 -0
  159. package/server/lib/hot.ts +357 -0
  160. package/server/lib/human-action-summary.ts +80 -0
  161. package/server/lib/key-fingerprint.ts +28 -0
  162. package/server/lib/logger.ts +340 -0
  163. package/server/lib/network.ts +137 -0
  164. package/server/lib/notifications.ts +230 -0
  165. package/server/lib/oauth2-refresh.ts +241 -0
  166. package/server/lib/oursecret.ts +71 -0
  167. package/server/lib/passkey-credential.ts +360 -0
  168. package/server/lib/passkey.ts +68 -0
  169. package/server/lib/permissions.ts +299 -0
  170. package/server/lib/pino.ts +24 -0
  171. package/server/lib/policy-preview.ts +138 -0
  172. package/server/lib/price.ts +338 -0
  173. package/server/lib/prices.ts +34 -0
  174. package/server/lib/project-scope.ts +297 -0
  175. package/server/lib/resolve-action.ts +328 -0
  176. package/server/lib/resolve.ts +36 -0
  177. package/server/lib/secret-gist-share.ts +296 -0
  178. package/server/lib/sessions.ts +634 -0
  179. package/server/lib/socket-path.ts +56 -0
  180. package/server/lib/solana/connection.ts +26 -0
  181. package/server/lib/solana/jupiter.ts +128 -0
  182. package/server/lib/solana/transfer.ts +108 -0
  183. package/server/lib/solana/wallet.ts +136 -0
  184. package/server/lib/strategy/emits.ts +21 -0
  185. package/server/lib/strategy/engine.ts +1305 -0
  186. package/server/lib/strategy/executor.ts +115 -0
  187. package/server/lib/strategy/hook-context.ts +159 -0
  188. package/server/lib/strategy/hooks.ts +990 -0
  189. package/server/lib/strategy/index.ts +28 -0
  190. package/server/lib/strategy/installer.ts +305 -0
  191. package/server/lib/strategy/loader.ts +256 -0
  192. package/server/lib/strategy/message.ts +237 -0
  193. package/server/lib/strategy/repository.ts +218 -0
  194. package/server/lib/strategy/session-logger.ts +693 -0
  195. package/server/lib/strategy/sources.ts +288 -0
  196. package/server/lib/strategy/state.ts +189 -0
  197. package/server/lib/strategy/templates.ts +403 -0
  198. package/server/lib/strategy/tick.ts +404 -0
  199. package/server/lib/strategy/types.ts +230 -0
  200. package/server/lib/swap.ts +3 -0
  201. package/server/lib/temp.ts +86 -0
  202. package/server/lib/token-metadata.ts +86 -0
  203. package/server/lib/token-safety.ts +200 -0
  204. package/server/lib/token-search.ts +444 -0
  205. package/server/lib/totp.ts +194 -0
  206. package/server/lib/transactions.ts +123 -0
  207. package/server/lib/transport.ts +84 -0
  208. package/server/lib/txhistory/decoder.ts +262 -0
  209. package/server/lib/txhistory/enricher.ts +652 -0
  210. package/server/lib/txhistory/index.ts +391 -0
  211. package/server/lib/txhistory/signatures.ts +59 -0
  212. package/server/lib/update-check.ts +35 -0
  213. package/server/lib/verified-summary.ts +414 -0
  214. package/server/lib/view-registry.ts +80 -0
  215. package/server/mcp/profile-policy.ts +30 -0
  216. package/server/mcp/server.ts +1589 -0
  217. package/server/mcp/tools.ts +276 -0
  218. package/server/middleware/auth.ts +119 -0
  219. package/server/middleware/requestLogger.ts +84 -0
  220. package/server/routes/actions.ts +539 -0
  221. package/server/routes/adapters.ts +711 -0
  222. package/server/routes/addressbook.ts +113 -0
  223. package/server/routes/ai.ts +34 -0
  224. package/server/routes/apikeys.ts +343 -0
  225. package/server/routes/apps.ts +601 -0
  226. package/server/routes/auth.ts +406 -0
  227. package/server/routes/backup.ts +404 -0
  228. package/server/routes/batch.ts +270 -0
  229. package/server/routes/bookmarks.ts +162 -0
  230. package/server/routes/credential-shares.ts +380 -0
  231. package/server/routes/credential-vaults.ts +159 -0
  232. package/server/routes/credentials.ts +1782 -0
  233. package/server/routes/dashboard.ts +97 -0
  234. package/server/routes/defaults.ts +124 -0
  235. package/server/routes/flags.ts +11 -0
  236. package/server/routes/fund.ts +225 -0
  237. package/server/routes/heartbeat.ts +375 -0
  238. package/server/routes/import.ts +364 -0
  239. package/server/routes/launch.ts +665 -0
  240. package/server/routes/lock.ts +54 -0
  241. package/server/routes/logs.ts +68 -0
  242. package/server/routes/nuke.ts +111 -0
  243. package/server/routes/passkey-credentials.ts +99 -0
  244. package/server/routes/passkey.ts +366 -0
  245. package/server/routes/portfolio.ts +217 -0
  246. package/server/routes/price.ts +63 -0
  247. package/server/routes/resolve.ts +31 -0
  248. package/server/routes/security.ts +45 -0
  249. package/server/routes/send-evm.ts +241 -0
  250. package/server/routes/send-solana.ts +281 -0
  251. package/server/routes/send.ts +178 -0
  252. package/server/routes/setup.ts +210 -0
  253. package/server/routes/strategy.ts +894 -0
  254. package/server/routes/swap-evm.ts +352 -0
  255. package/server/routes/swap-solana.ts +176 -0
  256. package/server/routes/swap.ts +356 -0
  257. package/server/routes/token.ts +247 -0
  258. package/server/routes/unlock.ts +467 -0
  259. package/server/routes/views.ts +41 -0
  260. package/server/routes/wallet-assets.ts +361 -0
  261. package/server/routes/wallet-transactions.ts +515 -0
  262. package/server/routes/wallet.ts +709 -0
  263. package/server/types.ts +146 -0
  264. package/shared/credential-field-schema.ts +248 -0
  265. package/skills/auramaxx/HEARTBEAT.md +78 -0
  266. package/skills/auramaxx/SKILL.md +745 -0
  267. package/skills/auramaxx/docs/AGENT_SETUP.md +155 -0
  268. package/skills/auramaxx/docs/API.md +127 -0
  269. package/skills/auramaxx/docs/AUTH.md +318 -0
  270. package/skills/auramaxx/docs/CLI.md +130 -0
  271. package/skills/auramaxx/docs/MCP.md +122 -0
  272. package/skills/auramaxx/docs/TROUBLESHOOTING.md +357 -0
  273. package/skills/auramaxx/docs/WORKSPACE.md +673 -0
  274. package/skills/auramaxx/docs/security.md +227 -0
  275. package/skills/task-lifecycle/SKILL.md +378 -0
  276. package/src/app/api/[...doc]/page.tsx +36 -0
  277. package/src/app/api/agent-requests/route.ts +30 -0
  278. package/src/app/api/apps/install/route.ts +132 -0
  279. package/src/app/api/apps/manifests/route.ts +16 -0
  280. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  281. package/src/app/api/docs/plain/route.ts +74 -0
  282. package/src/app/api/events/route.ts +92 -0
  283. package/src/app/api/page.tsx +290 -0
  284. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  285. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  286. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  287. package/src/app/api/workspace/[id]/route.ts +168 -0
  288. package/src/app/api/workspace/auth.ts +40 -0
  289. package/src/app/api/workspace/config/route.ts +121 -0
  290. package/src/app/api/workspace/import/route.ts +127 -0
  291. package/src/app/api/workspace/route.ts +116 -0
  292. package/src/app/app-legacy-do-not-use/page.tsx +2245 -0
  293. package/src/app/apple-icon.png +0 -0
  294. package/src/app/approve/[actionId]/page.tsx +409 -0
  295. package/src/app/docs/DocsPageContent.tsx +269 -0
  296. package/src/app/docs/[...doc]/page.tsx +41 -0
  297. package/src/app/docs/page.tsx +38 -0
  298. package/src/app/favicon.ico +0 -0
  299. package/src/app/globals.css +819 -0
  300. package/src/app/health/page.tsx +5 -0
  301. package/src/app/hello/page.tsx +102 -0
  302. package/src/app/icon.png +0 -0
  303. package/src/app/layout.tsx +39 -0
  304. package/src/app/page.tsx +1964 -0
  305. package/src/app/privacy/page.tsx +63 -0
  306. package/src/app/providers.tsx +87 -0
  307. package/src/app/share/[token]/page.tsx +295 -0
  308. package/src/app/terms/page.tsx +80 -0
  309. package/src/components/ChainSelector.tsx +44 -0
  310. package/src/components/HumanActionBar.tsx +697 -0
  311. package/src/components/NotificationDrawer.tsx +387 -0
  312. package/src/components/PasskeyEnrollmentPrompt.tsx +235 -0
  313. package/src/components/apps/AgentKeysApp.tsx +490 -0
  314. package/src/components/apps/App.tsx +153 -0
  315. package/src/components/apps/AppGrid.tsx +15 -0
  316. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  317. package/src/components/apps/DraggableApp.tsx +562 -0
  318. package/src/components/apps/IFrameApp.tsx +73 -0
  319. package/src/components/apps/LogsApp.tsx +360 -0
  320. package/src/components/apps/SendApp.tsx +394 -0
  321. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  322. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  323. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  324. package/src/components/apps/TokenApp.tsx +319 -0
  325. package/src/components/apps/TransactionsApp.tsx +438 -0
  326. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  327. package/src/components/apps/index.ts +13 -0
  328. package/src/components/design-system/Button.tsx +88 -0
  329. package/src/components/design-system/ChainIndicator.tsx +65 -0
  330. package/src/components/design-system/ChainSelector.tsx +147 -0
  331. package/src/components/design-system/ConfirmationModal.tsx +107 -0
  332. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  333. package/src/components/design-system/DownloadButton.tsx +149 -0
  334. package/src/components/design-system/Drawer.tsx +133 -0
  335. package/src/components/design-system/FilterDropdown.tsx +183 -0
  336. package/src/components/design-system/ItemPicker.tsx +157 -0
  337. package/src/components/design-system/Modal.tsx +296 -0
  338. package/src/components/design-system/Popover.tsx +142 -0
  339. package/src/components/design-system/TextInput.tsx +85 -0
  340. package/src/components/design-system/Toggle.tsx +65 -0
  341. package/src/components/design-system/TyvekCollapsibleSection.tsx +55 -0
  342. package/src/components/design-system/index.ts +14 -0
  343. package/src/components/docs/ClientSideMarkdown.tsx +51 -0
  344. package/src/components/docs/DocsSearchBar.tsx +118 -0
  345. package/src/components/docs/DocsThemeToggle.tsx +38 -0
  346. package/src/components/docs/PersistentDocGroup.tsx +91 -0
  347. package/src/components/docs/ShareUrlButton.tsx +33 -0
  348. package/src/components/docs/SidebarScrollMemory.tsx +56 -0
  349. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  350. package/src/components/icons/ChainIcons.tsx +72 -0
  351. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  352. package/src/components/layout/ContentArea.tsx +21 -0
  353. package/src/components/layout/CreateViewModal.tsx +88 -0
  354. package/src/components/layout/LeftRail.tsx +114 -0
  355. package/src/components/layout/TabBar.tsx +284 -0
  356. package/src/components/layout/WalletSidebar.tsx +1030 -0
  357. package/src/components/layout/index.ts +6 -0
  358. package/src/components/marketing/AuraMaxxSpecOverlay.tsx +653 -0
  359. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  360. package/src/components/vault/ApiKeysConsole.tsx +1272 -0
  361. package/src/components/vault/AuditConsole.tsx +600 -0
  362. package/src/components/vault/CredentialDetail.tsx +625 -0
  363. package/src/components/vault/CredentialEmpty.tsx +55 -0
  364. package/src/components/vault/CredentialField.tsx +583 -0
  365. package/src/components/vault/CredentialForm.tsx +1484 -0
  366. package/src/components/vault/CredentialList.tsx +265 -0
  367. package/src/components/vault/CredentialRow.tsx +130 -0
  368. package/src/components/vault/CredentialShareModal.tsx +273 -0
  369. package/src/components/vault/CredentialVault.tsx +1662 -0
  370. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  371. package/src/components/vault/DocsConsole.tsx +113 -0
  372. package/src/components/vault/ImportCredentialsModal.tsx +578 -0
  373. package/src/components/vault/LargeTypeModal.tsx +88 -0
  374. package/src/components/vault/PasswordGenerator.tsx +232 -0
  375. package/src/components/vault/TOTPDisplay.tsx +108 -0
  376. package/src/components/vault/TotpSetupPanel.tsx +198 -0
  377. package/src/components/vault/VaultSidebar.tsx +881 -0
  378. package/src/components/vault/credentialFormName.ts +91 -0
  379. package/src/components/vault/hooks/useVaultKeyboardShortcuts.ts +69 -0
  380. package/src/components/vault/types.ts +56 -0
  381. package/src/context/AuthContext.tsx +365 -0
  382. package/src/context/PriceContext.tsx +113 -0
  383. package/src/context/ThemeContext.tsx +164 -0
  384. package/src/context/WebSocketContext.tsx +269 -0
  385. package/src/context/WorkspaceContext.tsx +668 -0
  386. package/src/hooks/index.ts +4 -0
  387. package/src/hooks/useAgentActions.ts +552 -0
  388. package/src/hooks/useBalance.ts +103 -0
  389. package/src/hooks/useBalances.ts +129 -0
  390. package/src/hooks/useTheme.ts +156 -0
  391. package/src/instrumentation.ts +12 -0
  392. package/src/lib/api-docs.ts +154 -0
  393. package/src/lib/api.ts +474 -0
  394. package/src/lib/app-loader.ts +148 -0
  395. package/src/lib/app-registry.ts +178 -0
  396. package/src/lib/app-sdk.ts +157 -0
  397. package/src/lib/audit-console-adapter.ts +151 -0
  398. package/src/lib/auth-client.ts +75 -0
  399. package/src/lib/config.ts +74 -0
  400. package/src/lib/credential-field-schema.ts +11 -0
  401. package/src/lib/crypto.ts +112 -0
  402. package/src/lib/db.ts +21 -0
  403. package/src/lib/docs.ts +544 -0
  404. package/src/lib/events.ts +363 -0
  405. package/src/lib/pino.ts +24 -0
  406. package/src/lib/theme-handlers.ts +168 -0
  407. package/src/lib/theme.ts +351 -0
  408. package/src/lib/tokenData.ts +378 -0
  409. package/src/lib/totp-import.ts +57 -0
  410. package/src/lib/vault-crypto.ts +129 -0
  411. package/src/lib/view-registry.ts +57 -0
  412. package/src/lib/websocket-server.ts +302 -0
  413. package/src/lib/websocket-setup.ts +79 -0
  414. package/src/lib/wordlist.ts +2050 -0
  415. package/src/lib/workspace-handlers.ts +285 -0
  416. package/start.sh +170 -0
  417. package/tailwind.config.ts +99 -0
  418. package/tsconfig.json +42 -0
@@ -0,0 +1,340 @@
1
+ /**
2
+ * Event logger helper for consistent event emission across Express routes
3
+ * Convenience wrapper around events.custom() for structured logging
4
+ */
5
+
6
+ import { events } from './events';
7
+
8
+ export type EventCategory = 'auth' | 'wallet' | 'transaction' | 'token' | 'request' | 'system' | 'agent';
9
+
10
+ export interface LogParams {
11
+ category: EventCategory;
12
+ action: string;
13
+ description: string;
14
+ agentId?: string;
15
+ walletAddress?: string;
16
+ txHash?: string;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+
20
+ /**
21
+ * Log an event with structured data
22
+ * Emits to WebSocket and stores in database
23
+ */
24
+ export function logEvent(params: LogParams): void {
25
+ const eventType = `${params.category}:${params.action}`;
26
+ events.custom(eventType, {
27
+ description: params.description,
28
+ agentId: params.agentId,
29
+ walletAddress: params.walletAddress,
30
+ txHash: params.txHash,
31
+ timestamp: Date.now(),
32
+ ...params.metadata,
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Convenience methods for common events
38
+ */
39
+ export const logger = {
40
+ // ── Auth Events ──────────────────────────────────────────────
41
+
42
+ /** Wallet unlocked event */
43
+ unlocked: (address: string) =>
44
+ logEvent({
45
+ category: 'auth',
46
+ action: 'unlocked',
47
+ description: `Wallet unlocked: ${address.slice(0, 10)}...`,
48
+ walletAddress: address,
49
+ }),
50
+
51
+ /** Wallet locked event */
52
+ locked: () =>
53
+ logEvent({
54
+ category: 'auth',
55
+ action: 'locked',
56
+ description: 'Wallet locked',
57
+ }),
58
+
59
+ /** Auth failure (invalid/expired/revoked token, missing header) */
60
+ authFailed: (reason: string, path: string, metadata?: Record<string, unknown>) =>
61
+ logEvent({
62
+ category: 'auth',
63
+ action: 'auth_failed',
64
+ description: `Auth failed: ${reason}`,
65
+ metadata: { path, reason, ...metadata },
66
+ }),
67
+
68
+ /** Permission denied */
69
+ permissionDenied: (permission: string, agentId: string, path: string) =>
70
+ logEvent({
71
+ category: 'auth',
72
+ action: 'permission_denied',
73
+ description: `Permission denied: ${permission}`,
74
+ agentId,
75
+ metadata: { permission, path },
76
+ }),
77
+
78
+ /** Token validated successfully */
79
+ tokenValidated: (agentId: string, tokenHash: string) =>
80
+ logEvent({
81
+ category: 'auth',
82
+ action: 'token_validated',
83
+ description: `Token validated for ${agentId}`,
84
+ agentId,
85
+ metadata: { tokenHash },
86
+ }),
87
+
88
+ // ── Token Events ─────────────────────────────────────────────
89
+
90
+ /** Agent token created */
91
+ tokenCreated: (agentId: string, tokenHash: string, limit: number, permissions: string[]) =>
92
+ logEvent({
93
+ category: 'token',
94
+ action: 'created',
95
+ description: `Token created for ${agentId} (limit: ${limit} ETH)`,
96
+ agentId,
97
+ metadata: { tokenHash, limit, permissions },
98
+ }),
99
+
100
+ /** Agent token revoked */
101
+ tokenRevoked: (tokenHash: string, revokedBy?: string) =>
102
+ logEvent({
103
+ category: 'token',
104
+ action: 'revoked',
105
+ description: `Token revoked: ${tokenHash.slice(0, 12)}...`,
106
+ metadata: { tokenHash, revokedBy },
107
+ }),
108
+
109
+ /** Spending limit exceeded */
110
+ limitExceeded: (agentId: string, limitType: string, requested: number, remaining: number) =>
111
+ logEvent({
112
+ category: 'token',
113
+ action: 'limit_exceeded',
114
+ description: `${limitType} limit exceeded: requested ${requested}, remaining ${remaining}`,
115
+ agentId,
116
+ metadata: { limitType, requested, remaining },
117
+ }),
118
+
119
+ // ── Wallet Events ────────────────────────────────────────────
120
+
121
+ /** Cold wallet setup event */
122
+ setup: (address: string) =>
123
+ logEvent({
124
+ category: 'wallet',
125
+ action: 'setup',
126
+ description: `Cold wallet created: ${address.slice(0, 10)}...`,
127
+ walletAddress: address,
128
+ }),
129
+
130
+ /** Hot/temp wallet created event */
131
+ walletCreated: (address: string, tier: string, agentId?: string) =>
132
+ logEvent({
133
+ category: 'wallet',
134
+ action: 'created',
135
+ description: `${tier} wallet created`,
136
+ walletAddress: address,
137
+ agentId,
138
+ metadata: { tier },
139
+ }),
140
+
141
+ /** Wallet renamed/updated */
142
+ walletRenamed: (address: string, agentId?: string) =>
143
+ logEvent({
144
+ category: 'wallet',
145
+ action: 'renamed',
146
+ description: `Wallet updated: ${address.slice(0, 10)}...`,
147
+ walletAddress: address,
148
+ agentId,
149
+ }),
150
+
151
+ /** Wallet private key exported */
152
+ walletExported: (address: string, agentId?: string) =>
153
+ logEvent({
154
+ category: 'wallet',
155
+ action: 'exported',
156
+ description: `Private key exported: ${address.slice(0, 10)}...`,
157
+ walletAddress: address,
158
+ agentId,
159
+ }),
160
+
161
+ /** Seed phrase exported */
162
+ seedExported: (vaultId?: string) =>
163
+ logEvent({
164
+ category: 'wallet',
165
+ action: 'seed_exported',
166
+ description: `Seed phrase exported${vaultId ? ` (vault: ${vaultId})` : ''}`,
167
+ metadata: { vaultId },
168
+ }),
169
+
170
+ // ── Transaction Events ───────────────────────────────────────
171
+
172
+ /** ETH send event */
173
+ send: (from: string, to: string, amount: string, txHash: string, agentId?: string) =>
174
+ logEvent({
175
+ category: 'transaction',
176
+ action: 'send',
177
+ description: `Sent ${amount} ETH`,
178
+ walletAddress: from,
179
+ txHash,
180
+ agentId,
181
+ metadata: { to, amount },
182
+ }),
183
+
184
+ /** Cold to hot fund transfer event */
185
+ fund: (to: string, amount: string, txHash: string, agentId?: string) =>
186
+ logEvent({
187
+ category: 'transaction',
188
+ action: 'fund',
189
+ description: `Funded ${amount} ETH`,
190
+ walletAddress: to,
191
+ txHash,
192
+ agentId,
193
+ metadata: { amount },
194
+ }),
195
+
196
+ /** Token swap event */
197
+ swap: (wallet: string, fromToken: string, toToken: string, amount: string, txHash: string, agentId?: string) =>
198
+ logEvent({
199
+ category: 'transaction',
200
+ action: 'swap',
201
+ description: `Swapped ${amount} ${fromToken} to ${toToken}`,
202
+ walletAddress: wallet,
203
+ txHash,
204
+ agentId,
205
+ metadata: { fromToken, toToken, amount },
206
+ }),
207
+
208
+ // ── Agent Events ─────────────────────────────────────────────
209
+
210
+ /** Agent requested access */
211
+ agentRequested: (agentId: string, requestId: string, limit: number) =>
212
+ logEvent({
213
+ category: 'agent',
214
+ action: 'access_requested',
215
+ description: `${agentId} requested access (limit: ${limit} ETH)`,
216
+ agentId,
217
+ metadata: { requestId, limit },
218
+ }),
219
+
220
+ /** Agent polled for token */
221
+ agentPolled: (requestId: string) =>
222
+ logEvent({
223
+ category: 'agent',
224
+ action: 'polled',
225
+ description: `Token poll for request ${requestId}`,
226
+ metadata: { requestId },
227
+ }),
228
+
229
+ /** Permission update requested */
230
+ permissionRequested: (agentId: string, requestId: string, permissions: string[]) =>
231
+ logEvent({
232
+ category: 'agent',
233
+ action: 'permission_requested',
234
+ description: `${agentId} requested permission update`,
235
+ agentId,
236
+ metadata: { requestId, permissions },
237
+ }),
238
+
239
+ /** Action created by agent */
240
+ actionCreated: (agentId: string, requestId: string, type: string, summary: string) =>
241
+ logEvent({
242
+ category: 'agent',
243
+ action: 'action_created',
244
+ description: `${agentId} created ${type}: ${summary}`,
245
+ agentId,
246
+ metadata: { requestId, type, summary },
247
+ }),
248
+
249
+ /** Action resolved (approved/rejected) */
250
+ actionResolved: (requestId: string, type: string, approved: boolean, resolvedBy: string) =>
251
+ logEvent({
252
+ category: 'agent',
253
+ action: 'action_resolved',
254
+ description: `${type} ${approved ? 'approved' : 'rejected'} by ${resolvedBy}`,
255
+ metadata: { requestId, type, approved, resolvedBy },
256
+ }),
257
+
258
+ // ── System Events ────────────────────────────────────────────
259
+
260
+ /** System nuke (full reset) */
261
+ nuke: () =>
262
+ logEvent({
263
+ category: 'system',
264
+ action: 'nuke',
265
+ description: 'System nuke: all data wiped',
266
+ }),
267
+
268
+ /** Database backup */
269
+ backup: (filename: string) =>
270
+ logEvent({
271
+ category: 'system',
272
+ action: 'backup',
273
+ description: `Database backup created: ${filename}`,
274
+ metadata: { filename },
275
+ }),
276
+
277
+ /** API key created */
278
+ apiKeyCreated: (service: string, name: string) =>
279
+ logEvent({
280
+ category: 'system',
281
+ action: 'apikey_created',
282
+ description: `API key created: ${service}/${name}`,
283
+ metadata: { service, name },
284
+ }),
285
+
286
+ /** API key deleted */
287
+ apiKeyDeleted: (service: string, name: string) =>
288
+ logEvent({
289
+ category: 'system',
290
+ action: 'apikey_deleted',
291
+ description: `API key deleted: ${service}/${name}`,
292
+ metadata: { service, name },
293
+ }),
294
+
295
+ /** All API keys revoked */
296
+ apiKeysRevokedAll: (revokedCount: number) =>
297
+ logEvent({
298
+ category: 'system',
299
+ action: 'apikey_revoked_all',
300
+ description: `All API keys revoked (${revokedCount})`,
301
+ metadata: { revokedCount },
302
+ }),
303
+
304
+ /** Strategy toggled */
305
+ strategyToggled: (strategyId: string, enabled: boolean) =>
306
+ logEvent({
307
+ category: 'system',
308
+ action: 'strategy_toggled',
309
+ description: `Strategy ${strategyId} ${enabled ? 'enabled' : 'disabled'}`,
310
+ metadata: { strategyId, enabled },
311
+ }),
312
+
313
+ /** Adapter configuration changed */
314
+ adapterChanged: (action: string, type: string) =>
315
+ logEvent({
316
+ category: 'system',
317
+ action: 'adapter_changed',
318
+ description: `Adapter ${type}: ${action}`,
319
+ metadata: { action, type },
320
+ }),
321
+
322
+ /** App operation */
323
+ appOperation: (operation: string, appId: string, agentId?: string) =>
324
+ logEvent({
325
+ category: 'system',
326
+ action: 'app_operation',
327
+ description: `App ${operation}: ${appId}`,
328
+ agentId,
329
+ metadata: { operation, appId },
330
+ }),
331
+
332
+ /** Server error */
333
+ error: (message: string, path?: string, metadata?: Record<string, unknown>) =>
334
+ logEvent({
335
+ category: 'system',
336
+ action: 'error',
337
+ description: `Error: ${message}`,
338
+ metadata: { path, ...metadata },
339
+ }),
340
+ };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Network / SSRF Utilities
3
+ * ========================
4
+ * Shared utilities for validating external URLs and preventing SSRF attacks.
5
+ * Used by the strategy executor, source fetcher, app fetch proxy,
6
+ * webhook adapter, and app installer.
7
+ */
8
+
9
+ import { isIPv4, isIPv6 } from 'net';
10
+ import dns from 'dns';
11
+ import { getErrorMessage } from './error';
12
+
13
+ /**
14
+ * Check whether a resolved IP address is in a private/reserved range.
15
+ * Handles both IPv4 and IPv6 (including IPv4-mapped IPv6 addresses).
16
+ */
17
+ export function isPrivateIp(ip: string): boolean {
18
+ if (isIPv4(ip)) {
19
+ const parts = ip.split('.').map(Number);
20
+ const [a, b] = parts;
21
+ if (a === 127) return true; // 127.0.0.0/8 loopback
22
+ if (a === 10) return true; // 10.0.0.0/8 private
23
+ if (a === 172 && b >= 16 && b <= 31) return true; // 172.16.0.0/12 private
24
+ if (a === 192 && b === 168) return true; // 192.168.0.0/16 private
25
+ if (a === 169 && b === 254) return true; // 169.254.0.0/16 link-local
26
+ if (a === 0) return true; // 0.0.0.0/8
27
+ return false;
28
+ }
29
+
30
+ if (isIPv6(ip)) {
31
+ const normalized = ip.toLowerCase();
32
+
33
+ // Loopback
34
+ if (normalized === '::1') return true;
35
+
36
+ // IPv4-mapped IPv6 — ::ffff:a.b.c.d
37
+ if (normalized.startsWith('::ffff:')) {
38
+ const embedded = normalized.slice(7);
39
+ if (isIPv4(embedded)) return isPrivateIp(embedded);
40
+ }
41
+
42
+ // Link-local fe80::/10 — first 10 bits = 1111 1110 10
43
+ // Covers fe80:: through febf::
44
+ const firstSegment = normalized.split(':')[0];
45
+ if (firstSegment.length >= 3) {
46
+ const prefix = firstSegment.slice(0, 3);
47
+ if (prefix === 'fe8' || prefix === 'fe9' || prefix === 'fea' || prefix === 'feb') return true;
48
+ }
49
+
50
+ // Unique local fc00::/7 — first 7 bits = 1111 110
51
+ // Covers fc00:: through fdff::
52
+ if (normalized.startsWith('fc') || normalized.startsWith('fd')) return true;
53
+
54
+ return false;
55
+ }
56
+
57
+ // Unknown format — treat as suspicious
58
+ return false;
59
+ }
60
+
61
+ /**
62
+ * Resolve a hostname via DNS and verify the resolved IP is not private.
63
+ * Throws if the hostname resolves to a private/reserved IP.
64
+ */
65
+ export async function resolveAndValidateHost(hostname: string): Promise<void> {
66
+ // If the hostname is already a raw IP, check directly
67
+ if (isIPv4(hostname) || isIPv6(hostname)) {
68
+ if (isPrivateIp(hostname)) {
69
+ throw new Error(`Address "${hostname}" is a private/reserved IP`);
70
+ }
71
+ return;
72
+ }
73
+
74
+ let address: string;
75
+ try {
76
+ const result = await dns.promises.lookup(hostname);
77
+ address = result.address;
78
+ } catch (err) {
79
+ const msg = getErrorMessage(err);
80
+ throw new Error(`DNS lookup failed for "${hostname}": ${msg}`);
81
+ }
82
+
83
+ if (isPrivateIp(address)) {
84
+ throw new Error(`Host "${hostname}" resolves to private IP ${address}`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Full validation pipeline for an external URL:
90
+ * 1. Parse the URL
91
+ * 2. Verify protocol is http: or https:
92
+ * 3. If allowedHosts is provided, verify hostname is in the list
93
+ * 4. DNS-resolve and verify the IP is not private
94
+ */
95
+ // Reserved test TLDs (RFC 2606) — skip DNS resolution in test environments
96
+ const TEST_TLDS = ['.example.com', '.example.org', '.example.net', '.test', '.localhost'];
97
+
98
+ export async function validateExternalUrl(
99
+ url: string,
100
+ allowedHosts?: string[],
101
+ ): Promise<void> {
102
+ let parsed: URL;
103
+ try {
104
+ parsed = new URL(url);
105
+ } catch {
106
+ throw new Error(`Invalid URL: ${url}`);
107
+ }
108
+
109
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
110
+ throw new Error(`Protocol "${parsed.protocol}" is not allowed. Only http: and https: are permitted`);
111
+ }
112
+
113
+ if (allowedHosts && allowedHosts.length > 0) {
114
+ if (!allowedHosts.includes(parsed.hostname)) {
115
+ throw new Error(`Host "${parsed.hostname}" is not in the allowed hosts list`);
116
+ }
117
+ }
118
+
119
+ // Skip DNS resolution for RFC 2606 reserved test domains in test environments
120
+ if (process.env.NODE_ENV === 'test' && TEST_TLDS.some(tld => parsed.hostname.endsWith(tld))) {
121
+ return;
122
+ }
123
+
124
+ await resolveAndValidateHost(parsed.hostname);
125
+ }
126
+
127
+ /**
128
+ * Sanitize a path segment (e.g., strategyId, appId) to prevent
129
+ * path traversal when interpolated into REST API URLs.
130
+ * Throws if the segment contains forbidden characters.
131
+ */
132
+ export function sanitizePathSegment(segment: string): string {
133
+ if (segment.includes('/') || segment.includes('..') || segment.includes('\\')) {
134
+ throw new Error(`Invalid path segment: "${segment}" contains forbidden characters`);
135
+ }
136
+ return segment;
137
+ }
@@ -0,0 +1,230 @@
1
+ import { prisma } from './db';
2
+ import { loadConfig } from './config';
3
+
4
+ interface NotificationAction {
5
+ id: string;
6
+ label: string;
7
+ type: 'primary' | 'secondary' | 'danger' | 'link';
8
+ action: 'api' | 'navigate' | 'dismiss';
9
+ endpoint?: string;
10
+ method?: string;
11
+ body?: Record<string, unknown>;
12
+ href?: string;
13
+ external?: boolean;
14
+ }
15
+
16
+ interface CreateNotificationParams {
17
+ type: 'pending_approval' | 'info' | 'warning' | 'success' | 'error' | 'system';
18
+ category?: 'transaction' | 'security' | 'token' | 'wallet' | 'general';
19
+ title: string;
20
+ message: string;
21
+ actions?: NotificationAction[];
22
+ metadata?: Record<string, unknown>;
23
+ humanActionId?: string;
24
+ expiresAt?: Date;
25
+ source?: 'system' | 'agent' | 'user';
26
+ agentId?: string;
27
+ }
28
+
29
+ export async function createNotification(params: CreateNotificationParams) {
30
+ return prisma.notification.create({
31
+ data: {
32
+ type: params.type,
33
+ category: params.category,
34
+ title: params.title,
35
+ message: params.message,
36
+ actions: params.actions ? JSON.stringify(params.actions) : null,
37
+ metadata: params.metadata ? JSON.stringify(params.metadata) : null,
38
+ humanActionId: params.humanActionId,
39
+ expiresAt: params.expiresAt,
40
+ source: params.source || 'system',
41
+ agentId: params.agentId,
42
+ },
43
+ });
44
+ }
45
+
46
+ export async function createHumanActionNotification(request: {
47
+ id: string;
48
+ type: string;
49
+ fromTier: string;
50
+ toAddress: string | null;
51
+ amount: string | null;
52
+ chain: string;
53
+ metadata?: string | null;
54
+ }) {
55
+ const config = loadConfig();
56
+ const explorer = config.chains[request.chain]?.explorer || 'https://basescan.org';
57
+
58
+ const typeLabels: Record<string, string> = {
59
+ fund: 'Fund Request',
60
+ send: 'Send Request',
61
+ agent_access: 'Agent Access Request',
62
+ auth: 'Agent Auth Request',
63
+ action: 'Action Request',
64
+ notify: 'Token Alert',
65
+ };
66
+
67
+ const title = typeLabels[request.type] || 'Pending Request';
68
+ const shortAddr = request.toAddress
69
+ ? `${request.toAddress.slice(0, 6)}...${request.toAddress.slice(-4)}`
70
+ : 'Unknown';
71
+
72
+ let message: string;
73
+ if (request.type === 'agent_access' || request.type === 'auth') {
74
+ // Parse metadata to get agent info
75
+ let agentId = 'Unknown Agent';
76
+ let limit = 0;
77
+ let requestedLimitExplicit = false;
78
+ let summary = '';
79
+ if (request.metadata) {
80
+ try {
81
+ const meta = JSON.parse(request.metadata);
82
+ agentId = meta.agentId || agentId;
83
+ if (typeof meta.limit === 'number') limit = meta.limit;
84
+ if (typeof meta?.limits?.fund === 'number') limit = meta.limits.fund;
85
+ requestedLimitExplicit = meta.requestedLimitExplicit === true;
86
+ if (typeof meta.summary === 'string') summary = meta.summary;
87
+ } catch {
88
+ // ignore
89
+ }
90
+ }
91
+ if (summary) {
92
+ message = summary;
93
+ } else if (requestedLimitExplicit) {
94
+ message = `${agentId} requesting ${limit} ETH access`;
95
+ } else {
96
+ message = `${agentId} requesting access`;
97
+ }
98
+ } else if (request.type === 'action') {
99
+ let summary = 'Action pending';
100
+ let callerAgentId = 'app';
101
+ if (request.metadata) {
102
+ try {
103
+ const meta = JSON.parse(request.metadata);
104
+ const vs = meta.verifiedSummary;
105
+ summary = vs?.oneLiner || meta.summary || summary;
106
+ callerAgentId = meta.agentId || callerAgentId;
107
+ } catch {}
108
+ }
109
+ message = `${callerAgentId}: ${summary}`;
110
+ } else if (request.amount) {
111
+ message = `${request.amount} ETH to ${shortAddr}`;
112
+ } else {
113
+ message = `Request to ${shortAddr}`;
114
+ }
115
+
116
+ const actions: NotificationAction[] = [
117
+ {
118
+ id: 'approve',
119
+ label: 'APPROVE',
120
+ type: 'primary',
121
+ action: 'api',
122
+ endpoint: `/actions/${request.id}/resolve`,
123
+ method: 'POST',
124
+ body: { approved: true },
125
+ },
126
+ {
127
+ id: 'reject',
128
+ label: 'REJECT',
129
+ type: 'danger',
130
+ action: 'api',
131
+ endpoint: `/actions/${request.id}/resolve`,
132
+ method: 'POST',
133
+ body: { approved: false },
134
+ },
135
+ ];
136
+
137
+ const metadata: Record<string, unknown> = {
138
+ requestType: request.type,
139
+ fromTier: request.fromTier,
140
+ toAddress: request.toAddress,
141
+ amount: request.amount,
142
+ chain: request.chain,
143
+ explorer,
144
+ };
145
+
146
+ if (request.metadata) {
147
+ try {
148
+ const parsed = JSON.parse(request.metadata);
149
+ Object.assign(metadata, parsed);
150
+ } catch {
151
+ // ignore parse errors
152
+ }
153
+ }
154
+
155
+ return createNotification({
156
+ type: 'pending_approval',
157
+ category: 'transaction',
158
+ title,
159
+ message,
160
+ actions,
161
+ metadata,
162
+ humanActionId: request.id,
163
+ source: 'system',
164
+ });
165
+ }
166
+
167
+ export async function resolveNotificationForRequest(
168
+ requestId: string,
169
+ resolution: 'approved' | 'rejected',
170
+ resultData?: { txHash?: string; explorer?: string }
171
+ ) {
172
+ // Find and dismiss the pending notification
173
+ const notification = await prisma.notification.findFirst({
174
+ where: { humanActionId: requestId },
175
+ });
176
+
177
+ if (notification) {
178
+ await prisma.notification.update({
179
+ where: { id: notification.id },
180
+ data: { dismissed: true, read: true },
181
+ });
182
+ }
183
+
184
+ // Create a success/info notification about the resolution
185
+ if (resolution === 'approved' && resultData?.txHash) {
186
+ const actions: NotificationAction[] = [];
187
+ if (resultData.explorer) {
188
+ actions.push({
189
+ id: 'view_tx',
190
+ label: 'VIEW TX',
191
+ type: 'link',
192
+ action: 'navigate',
193
+ href: `${resultData.explorer}/tx/${resultData.txHash}`,
194
+ external: true,
195
+ });
196
+ }
197
+ actions.push({
198
+ id: 'dismiss',
199
+ label: 'DISMISS',
200
+ type: 'secondary',
201
+ action: 'dismiss',
202
+ });
203
+
204
+ await createNotification({
205
+ type: 'success',
206
+ category: 'transaction',
207
+ title: 'Transaction Approved',
208
+ message: `TX: ${resultData.txHash.slice(0, 10)}...${resultData.txHash.slice(-6)}`,
209
+ actions,
210
+ metadata: { txHash: resultData.txHash, explorer: resultData.explorer },
211
+ source: 'system',
212
+ });
213
+ } else if (resolution === 'rejected') {
214
+ await createNotification({
215
+ type: 'info',
216
+ category: 'transaction',
217
+ title: 'Request Rejected',
218
+ message: 'The pending request was rejected.',
219
+ actions: [
220
+ {
221
+ id: 'dismiss',
222
+ label: 'DISMISS',
223
+ type: 'secondary',
224
+ action: 'dismiss',
225
+ },
226
+ ],
227
+ source: 'system',
228
+ });
229
+ }
230
+ }