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,634 @@
1
+ import { AgentTokenPayload, TokenSession, LimitValue, SpentValue } from '../types';
2
+ import { prisma } from './db';
3
+ import { events } from './events';
4
+ import { getFundLimit } from './auth';
5
+
6
+ /**
7
+ * WALLET TOKEN SECURITY MODEL
8
+ * ===========================
9
+ *
10
+ * IN MEMORY (security-critical, resets on restart):
11
+ * - SIGNING_KEY: Random key for HMAC signing tokens
12
+ * - sessions Map: Active token sessions with spending tracking
13
+ * - revokedTokens Set: Tokens revoked this session
14
+ *
15
+ * IN DATABASE (for UI/logs only, NOT used for auth):
16
+ * - AgentToken table: Metadata for display (hash, agentId, limit, etc.)
17
+ * - Synced on create/spend/revoke but DB is just a mirror
18
+ *
19
+ * On server restart:
20
+ * - New SIGNING_KEY generated → ALL old tokens become invalid
21
+ * - Old DB records show as "inactive" (not in memory = can't sign)
22
+ * - This is a SECURITY FEATURE: restart = re-approve
23
+ *
24
+ * Token validation flow:
25
+ * 1. Agent sends token in Authorization header
26
+ * 2. Server verifies HMAC signature with in-memory SIGNING_KEY
27
+ * 3. If valid, checks spending limit in memory sessions Map
28
+ * 4. DB is NEVER consulted for auth decisions
29
+ */
30
+
31
+ // Limit types for per-permission tracking
32
+ export type LimitType = 'fund' | 'send' | 'swap';
33
+
34
+ /**
35
+ * Resolve a limit value, handling both plain numbers and address-keyed Records.
36
+ * - Plain number: return as-is (backward compat, single-currency)
37
+ * - Record<string, number>: look up by currency address
38
+ * - If currency is provided but limit is a plain number, return the number (backward compat)
39
+ */
40
+ export function resolveLimit(
41
+ limitValue: LimitValue | undefined,
42
+ currency?: string
43
+ ): number | undefined {
44
+ if (limitValue === undefined) return undefined;
45
+ if (typeof limitValue === 'number') return limitValue;
46
+ // Record<string, number> — look up by currency
47
+ if (currency && limitValue[currency] !== undefined) {
48
+ return limitValue[currency];
49
+ }
50
+ // No matching currency in record = unlimited for that currency
51
+ return undefined;
52
+ }
53
+
54
+ /**
55
+ * Get spent amount from a SpentValue, handling both plain numbers and address-keyed Records.
56
+ */
57
+ function resolveSpent(spentValue: SpentValue | undefined, currency?: string): number {
58
+ if (spentValue === undefined) return 0;
59
+ if (typeof spentValue === 'number') return spentValue;
60
+ if (currency) return spentValue[currency] || 0;
61
+ // No currency specified on a Record — return aggregate spend for display
62
+ return Object.values(spentValue).reduce((total, value) => total + value, 0);
63
+ }
64
+
65
+ /**
66
+ * Record spent amount into a SpentValue, handling both plain numbers and address-keyed Records.
67
+ * Mutates the session's spentByType in place.
68
+ */
69
+ function addToSpent(
70
+ session: TokenSession,
71
+ limitType: LimitType,
72
+ amount: number,
73
+ currency?: string
74
+ ): number {
75
+ if (!session.spentByType) {
76
+ session.spentByType = { fund: 0, send: 0, swap: 0 };
77
+ }
78
+ const current = session.spentByType[limitType];
79
+
80
+ if (currency && current !== undefined && typeof current === 'object') {
81
+ // Already a Record, add to the currency key
82
+ current[currency] = (current[currency] || 0) + amount;
83
+ return current[currency];
84
+ } else if (currency && (current === undefined || typeof current === 'number')) {
85
+ // Need to upgrade to Record if we have a currency
86
+ // But for backward compat, if no currency was previously tracked, just use the number
87
+ // Only upgrade if the limit is also a Record
88
+ const limitValue = session.token.limits?.[limitType];
89
+ if (typeof limitValue === 'object') {
90
+ // Upgrade to Record
91
+ const record: Record<string, number> = {};
92
+ record[currency] = (typeof current === 'number' ? 0 : 0) + amount;
93
+ session.spentByType[limitType] = record;
94
+ return record[currency];
95
+ }
96
+ // Limit is a plain number, keep spent as plain number
97
+ const newSpent = (typeof current === 'number' ? current : 0) + amount;
98
+ session.spentByType[limitType] = newSpent;
99
+ return newSpent;
100
+ } else {
101
+ // No currency, plain number
102
+ const newSpent = (typeof current === 'number' ? current : 0) + amount;
103
+ session.spentByType[limitType] = newSpent;
104
+ return newSpent;
105
+ }
106
+ }
107
+
108
+ // In-memory session tracking - resets on server restart
109
+ const sessions = new Map<string, TokenSession>();
110
+
111
+ // Revoked token hashes (in memory)
112
+ const revokedTokens = new Set<string>();
113
+
114
+ /**
115
+ * Register a new token in memory AND database
116
+ * Called when human approves agent access
117
+ */
118
+ export async function registerToken(
119
+ tokenHash: string,
120
+ token: AgentTokenPayload
121
+ ): Promise<void> {
122
+ // Store in memory (authoritative for auth)
123
+ sessions.set(tokenHash, {
124
+ token,
125
+ spent: 0,
126
+ spentByType: { fund: 0, send: 0, swap: 0 },
127
+ credentialReads: 0,
128
+ tokenIssuedAt: token.iat,
129
+ });
130
+
131
+ // Get fund limit for DB storage (backward compatibility)
132
+ const fundLimit = getFundLimit(token);
133
+
134
+ // Store in DB (for UI/logs only)
135
+ try {
136
+ await prisma.agentToken.upsert({
137
+ where: { tokenHash },
138
+ create: {
139
+ tokenHash,
140
+ agentId: token.agentId,
141
+ limit: fundLimit,
142
+ spent: 0,
143
+ permissions: JSON.stringify(token.permissions),
144
+ expiresAt: new Date(token.exp),
145
+ },
146
+ update: {
147
+ agentId: token.agentId,
148
+ limit: fundLimit,
149
+ spent: 0,
150
+ permissions: JSON.stringify(token.permissions),
151
+ expiresAt: new Date(token.exp),
152
+ isRevoked: false,
153
+ revokedAt: null,
154
+ },
155
+ });
156
+ } catch (err) {
157
+ console.error('Failed to store token in DB (non-critical):', err);
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Initialize or get a session for a token
163
+ */
164
+ export function getSession(tokenHash: string, token: AgentTokenPayload): TokenSession {
165
+ let session = sessions.get(tokenHash);
166
+ if (!session) {
167
+ session = { token, spent: 0, spentByType: { fund: 0, send: 0, swap: 0 }, credentialReads: 0, tokenIssuedAt: token.iat };
168
+ sessions.set(tokenHash, session);
169
+ }
170
+ // Ensure spentByType exists (for backward compatibility with existing sessions)
171
+ if (!session.spentByType) {
172
+ session.spentByType = { fund: 0, send: 0, swap: 0 };
173
+ }
174
+ return session;
175
+ }
176
+
177
+ /**
178
+ * Check if token exists in memory (is valid for current server session)
179
+ */
180
+ export function isActiveInMemory(tokenHash: string): boolean {
181
+ return sessions.has(tokenHash);
182
+ }
183
+
184
+ /**
185
+ * Record spending against a token's limit (legacy - uses fund limit)
186
+ */
187
+ export async function recordSpend(tokenHash: string, amount: number): Promise<void> {
188
+ return recordSpendByType(tokenHash, 'fund', amount);
189
+ }
190
+
191
+ /**
192
+ * Record spending against a specific limit type.
193
+ * @param currency - Optional currency address for address-keyed limits (e.g., native token address)
194
+ */
195
+ export async function recordSpendByType(
196
+ tokenHash: string,
197
+ limitType: LimitType,
198
+ amount: number,
199
+ currency?: string
200
+ ): Promise<void> {
201
+ const session = sessions.get(tokenHash);
202
+ if (session) {
203
+ // Update the specific limit type (handles both plain number and Record)
204
+ addToSpent(session, limitType, amount, currency);
205
+
206
+ // Also update legacy spent field for fund
207
+ if (limitType === 'fund') {
208
+ session.spent += amount;
209
+ }
210
+
211
+ emitSpentEvent(tokenHash, session, limitType, amount, currency);
212
+
213
+ // NOTE: All limit tracking is memory-only, consistent with the security model.
214
+ // On restart, SIGNING_KEY regenerates → all tokens invalid → agents re-approve with fresh limits.
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Check if a spend would exceed the token's limit (legacy - uses fund limit)
220
+ */
221
+ export function checkLimit(tokenHash: string, token: AgentTokenPayload, amount: number): boolean {
222
+ return checkLimitByType(tokenHash, token, 'fund', amount);
223
+ }
224
+
225
+ /**
226
+ * Resolve the effective limit for a given type, handling fund fallback for send.
227
+ */
228
+ function getEffectiveLimit(token: AgentTokenPayload, limitType: LimitType, currency?: string): number | undefined {
229
+ if (limitType === 'fund') {
230
+ const rawLimit = token.limits?.fund;
231
+ return rawLimit !== undefined ? resolveLimit(rawLimit, currency) : getFundLimit(token);
232
+ }
233
+ const rawLimit = token.limits?.[limitType];
234
+ let limit = resolveLimit(rawLimit, currency);
235
+ // Send defaults to fund limit if not explicitly set and fund limit exists
236
+ if (limit === undefined && limitType === 'send') {
237
+ const fundRaw = token.limits?.fund;
238
+ const fundLimit = fundRaw !== undefined ? resolveLimit(fundRaw, currency) : getFundLimit(token);
239
+ if (fundLimit !== undefined && fundLimit > 0) limit = fundLimit;
240
+ }
241
+ return limit;
242
+ }
243
+
244
+ /**
245
+ * Check if a spend would exceed a specific limit type
246
+ * Returns true if within limit, false if would exceed
247
+ * If no limit is set for that type, returns true (unlimited)
248
+ * @param currency - Optional currency address for address-keyed limits
249
+ */
250
+ export function checkLimitByType(
251
+ tokenHash: string,
252
+ token: AgentTokenPayload,
253
+ limitType: LimitType,
254
+ amount: number,
255
+ currency?: string
256
+ ): boolean {
257
+ const session = getSession(tokenHash, token);
258
+ const limit = getEffectiveLimit(token, limitType, currency);
259
+
260
+ // No limit set = unlimited
261
+ if (limit === undefined) {
262
+ return true;
263
+ }
264
+
265
+ // Check against spent
266
+ const spent = resolveSpent(session.spentByType?.[limitType], currency);
267
+ return spent + amount <= limit;
268
+ }
269
+
270
+ /**
271
+ * Atomically check limit AND reserve the amount in one synchronous call.
272
+ * Prevents TOCTOU race: two concurrent requests can't both pass the check
273
+ * because the deduction happens immediately (Node is single-threaded for sync code).
274
+ *
275
+ * Returns { ok: true } if reserved, or { ok: false, remaining } if limit exceeded.
276
+ * On tx failure, call releaseSpend() to roll back the reservation.
277
+ */
278
+ export function reserveSpend(
279
+ tokenHash: string,
280
+ token: AgentTokenPayload,
281
+ limitType: LimitType,
282
+ amount: number,
283
+ currency?: string
284
+ ): { ok: true } | { ok: false; remaining: number } {
285
+ const session = getSession(tokenHash, token);
286
+ const limit = getEffectiveLimit(token, limitType, currency);
287
+
288
+ // No limit set = unlimited, reserve (record) immediately
289
+ if (limit === undefined) {
290
+ addToSpent(session, limitType, amount, currency);
291
+ if (limitType === 'fund') session.spent += amount;
292
+ emitSpentEvent(tokenHash, session, limitType, amount, currency);
293
+ return { ok: true };
294
+ }
295
+
296
+ // Check against spent
297
+ const spent = resolveSpent(session.spentByType?.[limitType], currency);
298
+ if (spent + amount > limit) {
299
+ const remaining = Math.max(0, limit - spent);
300
+ return { ok: false, remaining };
301
+ }
302
+
303
+ // Reserve: deduct immediately
304
+ addToSpent(session, limitType, amount, currency);
305
+ if (limitType === 'fund') session.spent += amount;
306
+ emitSpentEvent(tokenHash, session, limitType, amount, currency);
307
+ return { ok: true };
308
+ }
309
+
310
+ /**
311
+ * Roll back a previously reserved spend (e.g., when a transaction fails).
312
+ */
313
+ export function releaseSpend(
314
+ tokenHash: string,
315
+ limitType: LimitType,
316
+ amount: number,
317
+ currency?: string
318
+ ): void {
319
+ const session = sessions.get(tokenHash);
320
+ if (!session) return;
321
+ addToSpent(session, limitType, -amount, currency);
322
+ if (limitType === 'fund') session.spent = Math.max(0, session.spent - amount);
323
+ }
324
+
325
+ /**
326
+ * Emit WebSocket tokenSpent event (shared by reserveSpend and recordSpendByType).
327
+ */
328
+ function emitSpentEvent(
329
+ tokenHash: string,
330
+ session: TokenSession,
331
+ limitType: LimitType,
332
+ amount: number,
333
+ currency?: string
334
+ ): void {
335
+ const limitValue = session.token.limits?.[limitType] ?? (limitType === 'fund' ? getFundLimit(session.token) : undefined);
336
+ const limit = resolveLimit(
337
+ typeof limitValue === 'number' || typeof limitValue === 'object' ? limitValue : undefined,
338
+ currency
339
+ );
340
+ const newSpent = resolveSpent(session.spentByType?.[limitType], currency);
341
+ const remaining = limit !== undefined ? Math.max(0, limit - newSpent) : undefined;
342
+ events.tokenSpent({ tokenHash, amount, newSpent, remaining: remaining ?? 0, limitType });
343
+ }
344
+
345
+ /**
346
+ * Get remaining allowance for a token (legacy - uses fund limit)
347
+ */
348
+ export function getRemaining(tokenHash: string, token: AgentTokenPayload): number {
349
+ return getRemainingByType(tokenHash, token, 'fund');
350
+ }
351
+
352
+ /**
353
+ * Get remaining allowance for a specific limit type
354
+ * Returns Infinity if no limit is set
355
+ * @param currency - Optional currency address for address-keyed limits
356
+ */
357
+ export function getRemainingByType(
358
+ tokenHash: string,
359
+ token: AgentTokenPayload,
360
+ limitType: LimitType,
361
+ currency?: string
362
+ ): number {
363
+ const session = getSession(tokenHash, token);
364
+ const limit = getEffectiveLimit(token, limitType, currency);
365
+
366
+ // No limit set = unlimited
367
+ if (limit === undefined) {
368
+ return Infinity;
369
+ }
370
+
371
+ const spent = resolveSpent(session.spentByType?.[limitType], currency);
372
+ return Math.max(0, limit - spent);
373
+ }
374
+
375
+ /**
376
+ * Get session info for a token
377
+ */
378
+ export function getSessionInfo(tokenHash: string): TokenSession | null {
379
+ return sessions.get(tokenHash) || null;
380
+ }
381
+
382
+ /** Budget summary for hook AI context */
383
+ export interface SessionBudget {
384
+ limits: Record<string, number>;
385
+ spent: Record<string, number>;
386
+ remaining: Record<string, number>;
387
+ }
388
+
389
+ /**
390
+ * Get a simplified budget summary for a token session.
391
+ * Only includes limit types that have actual limits set.
392
+ * Missing keys = unlimited for that permission type.
393
+ */
394
+ export function getSessionBudget(tokenHash: string): SessionBudget {
395
+ const session = sessions.get(tokenHash);
396
+ if (!session) return { limits: {}, spent: {}, remaining: {} };
397
+
398
+ const budget: SessionBudget = { limits: {}, spent: {}, remaining: {} };
399
+
400
+ for (const type of ['fund', 'send', 'swap'] as const) {
401
+ let limit: number | undefined;
402
+ if (type === 'fund') {
403
+ limit = session.token.limits?.fund !== undefined
404
+ ? resolveLimit(session.token.limits.fund)
405
+ : (getFundLimit(session.token) || undefined);
406
+ } else {
407
+ limit = session.token.limits?.[type] !== undefined
408
+ ? resolveLimit(session.token.limits[type])
409
+ : undefined;
410
+ }
411
+
412
+ if (limit !== undefined && limit > 0) {
413
+ const spent = resolveSpent(session.spentByType?.[type]);
414
+ budget.limits[type] = limit;
415
+ budget.spent[type] = spent;
416
+ budget.remaining[type] = Math.max(0, limit - spent);
417
+ }
418
+ }
419
+
420
+ return budget;
421
+ }
422
+
423
+ // ─── Credential Access Tracking ─────────────────────────────────────
424
+
425
+ /**
426
+ * Check if a token is allowed to read credentials.
427
+ * Enforces TTL (from iat) and maxReads limits.
428
+ */
429
+ export function checkCredentialAccess(
430
+ tokenHash: string,
431
+ token: AgentTokenPayload
432
+ ): { ok: true } | { ok: false; reason: string } {
433
+ const session = getSession(tokenHash, token);
434
+ const access = token.credentialAccess;
435
+
436
+ // Check TTL from iat
437
+ if (access?.ttl !== undefined && session.tokenIssuedAt) {
438
+ const elapsed = (Date.now() - session.tokenIssuedAt) / 1000;
439
+ if (elapsed > access.ttl) {
440
+ return { ok: false, reason: 'Credential access TTL expired' };
441
+ }
442
+ }
443
+
444
+ // Check maxReads
445
+ if (access?.maxReads !== undefined) {
446
+ const reads = session.credentialReads ?? 0;
447
+ if (reads >= access.maxReads) {
448
+ return { ok: false, reason: 'Credential read limit reached' };
449
+ }
450
+ }
451
+
452
+ return { ok: true };
453
+ }
454
+
455
+ /**
456
+ * Record a successful credential read against the session.
457
+ */
458
+ export function recordCredentialRead(tokenHash: string): void {
459
+ const session = sessions.get(tokenHash);
460
+ if (session) {
461
+ session.credentialReads = (session.credentialReads ?? 0) + 1;
462
+ }
463
+ }
464
+
465
+ /**
466
+ * Clear all sessions (for testing)
467
+ */
468
+ export function clearSessions(): void {
469
+ sessions.clear();
470
+ revokedTokens.clear();
471
+ }
472
+
473
+ /**
474
+ * Revoke a token by its hash
475
+ */
476
+ export async function revokeToken(tokenHash: string): Promise<boolean> {
477
+ const existed = sessions.has(tokenHash);
478
+
479
+ // Revoke in memory
480
+ revokedTokens.add(tokenHash);
481
+ sessions.delete(tokenHash);
482
+
483
+ // Emit WebSocket event if token existed
484
+ if (existed) {
485
+ events.tokenRevoked({ tokenHash });
486
+ }
487
+
488
+ // Sync to DB (P2025 = record not found — silently ignore during cleanup)
489
+ try {
490
+ await prisma.agentToken.update({
491
+ where: { tokenHash },
492
+ data: {
493
+ isRevoked: true,
494
+ revokedAt: new Date(),
495
+ },
496
+ });
497
+ } catch (err: unknown) {
498
+ const prismaError = err as { code?: string };
499
+ if (prismaError.code !== 'P2025') {
500
+ console.error('Failed to sync revoke to DB:', err);
501
+ }
502
+ }
503
+
504
+ return existed;
505
+ }
506
+
507
+ /**
508
+ * Revoke all active token sessions.
509
+ * Used by global lock flows to force full re-authentication.
510
+ */
511
+ export async function revokeAllTokens(): Promise<number> {
512
+ const activeTokenHashes = Array.from(sessions.keys());
513
+ await Promise.all(activeTokenHashes.map((tokenHash) => revokeToken(tokenHash)));
514
+ return activeTokenHashes.length;
515
+ }
516
+
517
+ /**
518
+ * Check if a token is revoked
519
+ */
520
+ export function isRevoked(tokenHash: string): boolean {
521
+ return revokedTokens.has(tokenHash);
522
+ }
523
+
524
+ /**
525
+ * List all tokens from DB, marking which are active in memory
526
+ * Active = exists in memory with valid signing key
527
+ * Inactive = in DB but not in memory (server restarted, expired, revoked)
528
+ */
529
+ export async function listTokensFromDb(): Promise<Array<{
530
+ tokenHash: string;
531
+ agentId: string;
532
+ createdAt: number;
533
+ limit: number;
534
+ spent: number;
535
+ remaining: number;
536
+ permissions: string[];
537
+ expiresAt: number;
538
+ isExpired: boolean;
539
+ isRevoked: boolean;
540
+ isActive: boolean; // true = valid in memory, false = DB record only
541
+ limits?: { fund?: number; send?: number; swap?: number };
542
+ spentByType?: { fund?: number; send?: number; swap?: number };
543
+ }>> {
544
+ const now = Date.now();
545
+
546
+ try {
547
+ const dbTokens = await prisma.agentToken.findMany({
548
+ orderBy: { createdAt: 'desc' },
549
+ });
550
+
551
+ return dbTokens.map(t => {
552
+ const isExpired = t.expiresAt.getTime() < now;
553
+ const isActiveInMem = sessions.has(t.tokenHash) && !revokedTokens.has(t.tokenHash);
554
+ const memSession = sessions.get(t.tokenHash);
555
+ const fundSpent = memSession ? resolveSpent(memSession.spentByType?.fund) : undefined;
556
+
557
+ // Use memory values if active, otherwise DB values
558
+ const spent = memSession && fundSpent !== undefined ? fundSpent : t.spent;
559
+ const limit = memSession ? getFundLimit(memSession.token) : t.limit;
560
+
561
+ return {
562
+ tokenHash: t.tokenHash,
563
+ agentId: t.agentId,
564
+ createdAt: t.createdAt.getTime(),
565
+ limit,
566
+ spent,
567
+ remaining: Math.max(0, limit - spent),
568
+ permissions: JSON.parse(t.permissions),
569
+ expiresAt: t.expiresAt.getTime(),
570
+ isExpired,
571
+ isRevoked: t.isRevoked || revokedTokens.has(t.tokenHash),
572
+ isActive: isActiveInMem && !isExpired,
573
+ limits: memSession?.token.limits,
574
+ spentByType: memSession?.spentByType,
575
+ };
576
+ });
577
+ } catch (err) {
578
+ console.error('Failed to list tokens from DB:', err);
579
+ return [];
580
+ }
581
+ }
582
+
583
+ /**
584
+ * List only in-memory sessions (legacy function for compatibility)
585
+ */
586
+ export function listSessions(): Array<{
587
+ tokenHash: string;
588
+ agentId: string;
589
+ limit: number;
590
+ spent: number;
591
+ remaining: number;
592
+ permissions: string[];
593
+ expiresAt: number;
594
+ isExpired: boolean;
595
+ isRevoked: boolean;
596
+ limits?: { fund?: number; send?: number; swap?: number };
597
+ spentByType?: { fund?: number; send?: number; swap?: number };
598
+ }> {
599
+ const now = Date.now();
600
+ const result: Array<{
601
+ tokenHash: string;
602
+ agentId: string;
603
+ limit: number;
604
+ spent: number;
605
+ remaining: number;
606
+ permissions: string[];
607
+ expiresAt: number;
608
+ isExpired: boolean;
609
+ isRevoked: boolean;
610
+ limits?: { fund?: number; send?: number; swap?: number };
611
+ spentByType?: { fund?: number; send?: number; swap?: number };
612
+ }> = [];
613
+
614
+ sessions.forEach((session, tokenHash) => {
615
+ const isExpired = session.token.exp < now;
616
+ const fundLimit = getFundLimit(session.token);
617
+ const fundSpent = resolveSpent(session.spentByType?.fund);
618
+ result.push({
619
+ tokenHash,
620
+ agentId: session.token.agentId,
621
+ limit: fundLimit,
622
+ spent: fundSpent,
623
+ remaining: Math.max(0, fundLimit - fundSpent),
624
+ permissions: session.token.permissions,
625
+ expiresAt: session.token.exp,
626
+ isExpired,
627
+ isRevoked: revokedTokens.has(tokenHash),
628
+ limits: session.token.limits,
629
+ spentByType: session.spentByType,
630
+ });
631
+ });
632
+
633
+ return result;
634
+ }
@@ -0,0 +1,56 @@
1
+ const DEFAULT_SOCKET_PORT = '4242';
2
+
3
+ function parsePort(raw?: string): string | undefined {
4
+ if (!raw) return undefined;
5
+ const trimmed = raw.trim();
6
+ if (!trimmed) return undefined;
7
+ if (/^\d+$/.test(trimmed)) return trimmed;
8
+ try {
9
+ const url = new URL(trimmed);
10
+ if (url.port) return url.port;
11
+ if (url.protocol === 'https:') return '443';
12
+ if (url.protocol === 'http:') return '80';
13
+ } catch {
14
+ // Ignore parse errors and use legacy path fallback.
15
+ }
16
+ return undefined;
17
+ }
18
+
19
+ function resolveUid(uid?: number | string): number | string {
20
+ if (uid !== undefined && uid !== null) return uid;
21
+ return process.getuid?.() ?? 'unknown';
22
+ }
23
+
24
+ export function resolveAuraSocketPath(options: {
25
+ uid?: number | string;
26
+ serverUrl?: string;
27
+ serverPort?: string | number;
28
+ } = {}): string {
29
+ const explicit = process.env.AURA_SOCKET_PATH;
30
+ if (explicit && explicit.trim()) return explicit.trim();
31
+
32
+ const uid = resolveUid(options.uid);
33
+ const port =
34
+ parsePort(options.serverPort !== undefined ? String(options.serverPort) : undefined) ||
35
+ parsePort(options.serverUrl) ||
36
+ parsePort(process.env.WALLET_SERVER_PORT) ||
37
+ parsePort(process.env.WALLET_SERVER_URL);
38
+
39
+ if (port && port !== DEFAULT_SOCKET_PORT) {
40
+ return `/tmp/aura-cli-${uid}-${port}.sock`;
41
+ }
42
+
43
+ return `/tmp/aura-cli-${uid}.sock`;
44
+ }
45
+
46
+ export function resolveAuraSocketCandidates(options: {
47
+ uid?: number | string;
48
+ serverUrl?: string;
49
+ serverPort?: string | number;
50
+ } = {}): string[] {
51
+ const primary = resolveAuraSocketPath(options);
52
+ const uid = resolveUid(options.uid);
53
+ const legacy = `/tmp/aura-cli-${uid}.sock`;
54
+ if (primary === legacy) return [legacy];
55
+ return [primary, legacy];
56
+ }
@@ -0,0 +1,26 @@
1
+ import { Connection } from '@solana/web3.js';
2
+ import { getRpcUrl } from '../config';
3
+
4
+ // Cached connections by chain
5
+ const connections = new Map<string, Connection>();
6
+
7
+ /**
8
+ * Get a Solana Connection for the given chain.
9
+ * Caches connection instances (same pattern as EVM providers).
10
+ */
11
+ export async function getSolanaConnection(chain: string = 'solana'): Promise<Connection> {
12
+ const cached = connections.get(chain);
13
+ if (cached) return cached;
14
+
15
+ const rpcUrl = await getRpcUrl(chain);
16
+ const connection = new Connection(rpcUrl, 'confirmed');
17
+ connections.set(chain, connection);
18
+ return connection;
19
+ }
20
+
21
+ /**
22
+ * Clear cached connections (for testing).
23
+ */
24
+ export function clearSolanaConnections(): void {
25
+ connections.clear();
26
+ }