auramaxx 1.0.0-alpha.4

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 (363) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +112 -0
  3. package/bin/aurawallet.js +121 -0
  4. package/docs/ADAPTERS.md +467 -0
  5. package/docs/API.md +2679 -0
  6. package/docs/APPS.md +198 -0
  7. package/docs/ARCHITECTURE.md +350 -0
  8. package/docs/AUTH.md +698 -0
  9. package/docs/BEST-PRACTICES.md +121 -0
  10. package/docs/CLI.md +61 -0
  11. package/docs/DEVELOPING-APPS.md +452 -0
  12. package/docs/EXTENSION.md +97 -0
  13. package/docs/JOBS.md +33 -0
  14. package/docs/MCP.md +76 -0
  15. package/docs/PROTOCOL.md +142 -0
  16. package/docs/SETUP.md +219 -0
  17. package/docs/WORKSPACE.md +672 -0
  18. package/docs/agent-auth.md +63 -0
  19. package/docs/aura-file.md +48 -0
  20. package/docs/credentials.md +53 -0
  21. package/docs/external/getting-started.md +65 -0
  22. package/docs/external/overview.md +45 -0
  23. package/docs/external/use-cases.md +48 -0
  24. package/docs/external/why-aura.md +35 -0
  25. package/docs/jobs/connect-agent.md +77 -0
  26. package/docs/jobs/migrate-from-dotenv.md +79 -0
  27. package/docs/jobs/recover-from-lockout.md +72 -0
  28. package/docs/jobs/secure-ci.md +63 -0
  29. package/docs/oauth2.md +42 -0
  30. package/docs/passkeys.md +60 -0
  31. package/docs/security.md +540 -0
  32. package/docs/specs/aura-open-protocol.md +61 -0
  33. package/docs/specs/aura-provider-plugin.md +24 -0
  34. package/docs/specs/aura-registry-model.md +31 -0
  35. package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
  36. package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
  37. package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
  38. package/docs/specs/fixtures/valid-basic.aura +4 -0
  39. package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
  40. package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
  41. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  42. package/docs/totp.md +40 -0
  43. package/docs/wallet/AI.md +508 -0
  44. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  45. package/docs/wallet/README.md +47 -0
  46. package/docs/wallet/STRATEGY.md +89 -0
  47. package/next.config.ts +21 -0
  48. package/package.json +151 -0
  49. package/postcss.config.mjs +8 -0
  50. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  51. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  52. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  53. package/prisma/migrations/migration_lock.toml +3 -0
  54. package/prisma/schema.prisma +447 -0
  55. package/public/logo-chevron.svg +31 -0
  56. package/public/logo-concentric.svg +31 -0
  57. package/public/logo-crosshatch.svg +39 -0
  58. package/public/logo-dashed.svg +39 -0
  59. package/public/logo-horizontal.svg +31 -0
  60. package/public/logo-m56.svg +64 -0
  61. package/public/logo.webp +0 -0
  62. package/scripts/add-app.js +245 -0
  63. package/scripts/init.sh +57 -0
  64. package/scripts/migrate-apikeys-to-credentials.ts +35 -0
  65. package/scripts/sandbox-agent-flow.sh +235 -0
  66. package/scripts/sandbox.sh +175 -0
  67. package/scripts/validate-job-docs.mjs +125 -0
  68. package/server/abi/SwapHelper.json +438 -0
  69. package/server/cli/approval.ts +447 -0
  70. package/server/cli/commands/app.ts +204 -0
  71. package/server/cli/commands/cron.ts +24 -0
  72. package/server/cli/commands/doctor.ts +1007 -0
  73. package/server/cli/commands/env.ts +456 -0
  74. package/server/cli/commands/init.ts +752 -0
  75. package/server/cli/commands/mcp.ts +125 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/shell-hook.ts +468 -0
  78. package/server/cli/commands/start.ts +62 -0
  79. package/server/cli/commands/status.ts +59 -0
  80. package/server/cli/commands/stop.ts +14 -0
  81. package/server/cli/commands/token.ts +180 -0
  82. package/server/cli/commands/unlock.ts +49 -0
  83. package/server/cli/commands/vault.ts +417 -0
  84. package/server/cli/index.ts +328 -0
  85. package/server/cli/lib/aura-parser.ts +64 -0
  86. package/server/cli/lib/credential-create.ts +74 -0
  87. package/server/cli/lib/credential-resolve.ts +254 -0
  88. package/server/cli/lib/dotenv-migrate.ts +116 -0
  89. package/server/cli/lib/dotenv-parser.ts +146 -0
  90. package/server/cli/lib/http.ts +91 -0
  91. package/server/cli/lib/init-steps.ts +76 -0
  92. package/server/cli/lib/local-agent-trust.ts +45 -0
  93. package/server/cli/lib/process.ts +136 -0
  94. package/server/cli/lib/prompt.ts +85 -0
  95. package/server/cli/lib/theme.ts +240 -0
  96. package/server/cli/socket.ts +570 -0
  97. package/server/cli/transport-client.ts +50 -0
  98. package/server/cron/index.ts +137 -0
  99. package/server/cron/job.ts +31 -0
  100. package/server/cron/jobs/balance-sync.ts +436 -0
  101. package/server/cron/jobs/incoming-scan.ts +506 -0
  102. package/server/cron/jobs/native-price.ts +70 -0
  103. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  104. package/server/cron/jobs/strategy-runner.ts +175 -0
  105. package/server/cron/scheduler.ts +125 -0
  106. package/server/index.ts +406 -0
  107. package/server/lib/adapters/factory.ts +110 -0
  108. package/server/lib/adapters/index.ts +19 -0
  109. package/server/lib/adapters/router.ts +297 -0
  110. package/server/lib/adapters/telegram.ts +645 -0
  111. package/server/lib/adapters/types.ts +89 -0
  112. package/server/lib/adapters/webhook.ts +95 -0
  113. package/server/lib/address.ts +49 -0
  114. package/server/lib/agent-auth/contracts.ts +1194 -0
  115. package/server/lib/agent-profiles.ts +328 -0
  116. package/server/lib/ai.ts +285 -0
  117. package/server/lib/api-registry/contracts.ts +86 -0
  118. package/server/lib/api-registry/validation.ts +172 -0
  119. package/server/lib/apikey-migration.ts +189 -0
  120. package/server/lib/app-installer.ts +505 -0
  121. package/server/lib/app-tokens.ts +247 -0
  122. package/server/lib/auth.ts +314 -0
  123. package/server/lib/batch.ts +242 -0
  124. package/server/lib/cold.ts +874 -0
  125. package/server/lib/config.ts +381 -0
  126. package/server/lib/credential-access-audit.ts +85 -0
  127. package/server/lib/credential-access-policy.ts +110 -0
  128. package/server/lib/credential-health.ts +343 -0
  129. package/server/lib/credential-import.ts +487 -0
  130. package/server/lib/credential-scope.ts +87 -0
  131. package/server/lib/credential-shares.ts +190 -0
  132. package/server/lib/credential-transport.ts +342 -0
  133. package/server/lib/credential-vault.ts +77 -0
  134. package/server/lib/credentials.ts +333 -0
  135. package/server/lib/crypto.ts +8 -0
  136. package/server/lib/db.ts +15 -0
  137. package/server/lib/defaults.ts +366 -0
  138. package/server/lib/dex/index.ts +80 -0
  139. package/server/lib/dex/relay.ts +235 -0
  140. package/server/lib/dex/types.ts +59 -0
  141. package/server/lib/dex/uniswap.ts +370 -0
  142. package/server/lib/e2e-agent/artifacts.ts +36 -0
  143. package/server/lib/e2e-agent/contracts.ts +112 -0
  144. package/server/lib/e2e-agent/validation.ts +135 -0
  145. package/server/lib/encrypt.ts +128 -0
  146. package/server/lib/error.ts +20 -0
  147. package/server/lib/events.ts +205 -0
  148. package/server/lib/hot.ts +357 -0
  149. package/server/lib/key-fingerprint.ts +28 -0
  150. package/server/lib/logger.ts +331 -0
  151. package/server/lib/network.ts +137 -0
  152. package/server/lib/notifications.ts +219 -0
  153. package/server/lib/oauth2-refresh.ts +241 -0
  154. package/server/lib/oursecret.ts +54 -0
  155. package/server/lib/passkey-credential.ts +360 -0
  156. package/server/lib/passkey.ts +68 -0
  157. package/server/lib/permissions.ts +248 -0
  158. package/server/lib/pino.ts +24 -0
  159. package/server/lib/policy-preview.ts +138 -0
  160. package/server/lib/price.ts +338 -0
  161. package/server/lib/prices.ts +34 -0
  162. package/server/lib/project-scope.ts +239 -0
  163. package/server/lib/resolve-action.ts +427 -0
  164. package/server/lib/resolve.ts +36 -0
  165. package/server/lib/sessions.ts +632 -0
  166. package/server/lib/solana/connection.ts +26 -0
  167. package/server/lib/solana/jupiter.ts +128 -0
  168. package/server/lib/solana/transfer.ts +108 -0
  169. package/server/lib/solana/wallet.ts +136 -0
  170. package/server/lib/strategy/emits.ts +21 -0
  171. package/server/lib/strategy/engine.ts +1305 -0
  172. package/server/lib/strategy/executor.ts +115 -0
  173. package/server/lib/strategy/hook-context.ts +158 -0
  174. package/server/lib/strategy/hooks.ts +990 -0
  175. package/server/lib/strategy/index.ts +28 -0
  176. package/server/lib/strategy/installer.ts +305 -0
  177. package/server/lib/strategy/loader.ts +256 -0
  178. package/server/lib/strategy/message.ts +235 -0
  179. package/server/lib/strategy/repository.ts +218 -0
  180. package/server/lib/strategy/session-logger.ts +693 -0
  181. package/server/lib/strategy/sources.ts +288 -0
  182. package/server/lib/strategy/state.ts +189 -0
  183. package/server/lib/strategy/templates.ts +403 -0
  184. package/server/lib/strategy/tick.ts +404 -0
  185. package/server/lib/strategy/types.ts +230 -0
  186. package/server/lib/swap.ts +3 -0
  187. package/server/lib/temp.ts +86 -0
  188. package/server/lib/token-metadata.ts +86 -0
  189. package/server/lib/token-safety.ts +200 -0
  190. package/server/lib/token-search.ts +444 -0
  191. package/server/lib/totp.ts +194 -0
  192. package/server/lib/transactions.ts +123 -0
  193. package/server/lib/transport.ts +75 -0
  194. package/server/lib/txhistory/decoder.ts +262 -0
  195. package/server/lib/txhistory/enricher.ts +652 -0
  196. package/server/lib/txhistory/index.ts +391 -0
  197. package/server/lib/txhistory/signatures.ts +59 -0
  198. package/server/lib/verified-summary.ts +421 -0
  199. package/server/mcp/profile-policy.ts +30 -0
  200. package/server/mcp/server.ts +619 -0
  201. package/server/mcp/tools.ts +523 -0
  202. package/server/middleware/auth.ts +119 -0
  203. package/server/middleware/requestLogger.ts +84 -0
  204. package/server/routes/actions.ts +459 -0
  205. package/server/routes/adapters.ts +703 -0
  206. package/server/routes/addressbook.ts +113 -0
  207. package/server/routes/ai.ts +34 -0
  208. package/server/routes/apikeys.ts +295 -0
  209. package/server/routes/apps.ts +601 -0
  210. package/server/routes/auth.ts +457 -0
  211. package/server/routes/backup.ts +340 -0
  212. package/server/routes/batch.ts +270 -0
  213. package/server/routes/bookmarks.ts +162 -0
  214. package/server/routes/credential-shares.ts +198 -0
  215. package/server/routes/credential-vaults.ts +154 -0
  216. package/server/routes/credentials.ts +1290 -0
  217. package/server/routes/dashboard.ts +71 -0
  218. package/server/routes/defaults.ts +124 -0
  219. package/server/routes/fund.ts +229 -0
  220. package/server/routes/import.ts +352 -0
  221. package/server/routes/launch.ts +665 -0
  222. package/server/routes/lock.ts +54 -0
  223. package/server/routes/logs.ts +68 -0
  224. package/server/routes/nuke.ts +111 -0
  225. package/server/routes/passkey-credentials.ts +99 -0
  226. package/server/routes/passkey.ts +346 -0
  227. package/server/routes/portfolio.ts +217 -0
  228. package/server/routes/price.ts +63 -0
  229. package/server/routes/resolve.ts +31 -0
  230. package/server/routes/security.ts +45 -0
  231. package/server/routes/send-evm.ts +241 -0
  232. package/server/routes/send-solana.ts +281 -0
  233. package/server/routes/send.ts +178 -0
  234. package/server/routes/setup.ts +210 -0
  235. package/server/routes/strategy.ts +894 -0
  236. package/server/routes/swap-evm.ts +353 -0
  237. package/server/routes/swap-solana.ts +177 -0
  238. package/server/routes/swap.ts +356 -0
  239. package/server/routes/token.ts +247 -0
  240. package/server/routes/unlock.ts +403 -0
  241. package/server/routes/wallet-assets.ts +361 -0
  242. package/server/routes/wallet-transactions.ts +515 -0
  243. package/server/routes/wallet.ts +710 -0
  244. package/server/types.ts +146 -0
  245. package/skills/aurawallet/SKILL.md +739 -0
  246. package/skills/aurawallet-setup/SKILL.md +74 -0
  247. package/skills/security-review/SKILL.md +148 -0
  248. package/src/app/api/agent-requests/route.ts +30 -0
  249. package/src/app/api/apps/install/route.ts +126 -0
  250. package/src/app/api/apps/manifests/route.ts +16 -0
  251. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  252. package/src/app/api/events/route.ts +92 -0
  253. package/src/app/api/page.tsx +212 -0
  254. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  255. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  256. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  257. package/src/app/api/workspace/[id]/route.ts +168 -0
  258. package/src/app/api/workspace/auth.ts +34 -0
  259. package/src/app/api/workspace/config/route.ts +106 -0
  260. package/src/app/api/workspace/import/route.ts +127 -0
  261. package/src/app/api/workspace/route.ts +116 -0
  262. package/src/app/app/page.tsx +2122 -0
  263. package/src/app/apple-icon.png +0 -0
  264. package/src/app/docs/page.tsx +178 -0
  265. package/src/app/favicon.ico +0 -0
  266. package/src/app/globals.css +572 -0
  267. package/src/app/health/page.tsx +5 -0
  268. package/src/app/hello/page.tsx +15 -0
  269. package/src/app/icon.png +0 -0
  270. package/src/app/layout.tsx +34 -0
  271. package/src/app/page.tsx +986 -0
  272. package/src/app/providers.tsx +90 -0
  273. package/src/app/share/[token]/page.tsx +295 -0
  274. package/src/components/ChainSelector.tsx +144 -0
  275. package/src/components/HumanActionBar.tsx +695 -0
  276. package/src/components/NotificationDrawer.tsx +129 -0
  277. package/src/components/apps/AgentKeysApp.tsx +490 -0
  278. package/src/components/apps/App.tsx +153 -0
  279. package/src/components/apps/AppGrid.tsx +15 -0
  280. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  281. package/src/components/apps/DraggableApp.tsx +562 -0
  282. package/src/components/apps/IFrameApp.tsx +73 -0
  283. package/src/components/apps/LogsApp.tsx +360 -0
  284. package/src/components/apps/SendApp.tsx +394 -0
  285. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  286. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  287. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  288. package/src/components/apps/TokenApp.tsx +319 -0
  289. package/src/components/apps/TransactionsApp.tsx +438 -0
  290. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  291. package/src/components/apps/index.ts +13 -0
  292. package/src/components/design-system/Button.tsx +53 -0
  293. package/src/components/design-system/ChainIndicator.tsx +65 -0
  294. package/src/components/design-system/ChainSelector.tsx +137 -0
  295. package/src/components/design-system/ConfirmationModal.tsx +106 -0
  296. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  297. package/src/components/design-system/Drawer.tsx +123 -0
  298. package/src/components/design-system/FilterDropdown.tsx +72 -0
  299. package/src/components/design-system/Modal.tsx +206 -0
  300. package/src/components/design-system/Popover.tsx +142 -0
  301. package/src/components/design-system/TextInput.tsx +85 -0
  302. package/src/components/design-system/Toggle.tsx +58 -0
  303. package/src/components/design-system/index.ts +11 -0
  304. package/src/components/docs/DocsThemeToggle.tsx +49 -0
  305. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  306. package/src/components/icons/ChainIcons.tsx +72 -0
  307. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  308. package/src/components/layout/ContentArea.tsx +21 -0
  309. package/src/components/layout/TabBar.tsx +278 -0
  310. package/src/components/layout/WalletSidebar.tsx +1033 -0
  311. package/src/components/layout/index.ts +4 -0
  312. package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
  313. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  314. package/src/components/vault/ApiKeysConsole.tsx +1080 -0
  315. package/src/components/vault/AuditConsole.tsx +584 -0
  316. package/src/components/vault/CredentialDetail.tsx +455 -0
  317. package/src/components/vault/CredentialEmpty.tsx +55 -0
  318. package/src/components/vault/CredentialField.tsx +361 -0
  319. package/src/components/vault/CredentialForm.tsx +1212 -0
  320. package/src/components/vault/CredentialList.tsx +165 -0
  321. package/src/components/vault/CredentialRow.tsx +97 -0
  322. package/src/components/vault/CredentialShareModal.tsx +178 -0
  323. package/src/components/vault/CredentialVault.tsx +754 -0
  324. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  325. package/src/components/vault/ImportCredentialsModal.tsx +515 -0
  326. package/src/components/vault/LargeTypeModal.tsx +64 -0
  327. package/src/components/vault/PasswordGenerator.tsx +224 -0
  328. package/src/components/vault/TOTPDisplay.tsx +123 -0
  329. package/src/components/vault/VaultSidebar.tsx +413 -0
  330. package/src/components/vault/types.ts +54 -0
  331. package/src/context/AuthContext.tsx +337 -0
  332. package/src/context/PriceContext.tsx +113 -0
  333. package/src/context/ThemeContext.tsx +164 -0
  334. package/src/context/WebSocketContext.tsx +269 -0
  335. package/src/context/WorkspaceContext.tsx +668 -0
  336. package/src/hooks/index.ts +3 -0
  337. package/src/hooks/useAgentActions.ts +368 -0
  338. package/src/hooks/useBalance.ts +103 -0
  339. package/src/hooks/useBalances.ts +129 -0
  340. package/src/instrumentation.ts +12 -0
  341. package/src/lib/api.ts +449 -0
  342. package/src/lib/app-loader.ts +148 -0
  343. package/src/lib/app-registry.ts +178 -0
  344. package/src/lib/app-sdk.ts +157 -0
  345. package/src/lib/audit-console-adapter.ts +151 -0
  346. package/src/lib/auth-client.ts +75 -0
  347. package/src/lib/config.ts +74 -0
  348. package/src/lib/crypto.ts +112 -0
  349. package/src/lib/db.ts +21 -0
  350. package/src/lib/docs.ts +390 -0
  351. package/src/lib/events.ts +361 -0
  352. package/src/lib/pino.ts +24 -0
  353. package/src/lib/theme-handlers.ts +168 -0
  354. package/src/lib/theme.ts +351 -0
  355. package/src/lib/tokenData.ts +378 -0
  356. package/src/lib/vault-crypto.ts +129 -0
  357. package/src/lib/websocket-server.ts +302 -0
  358. package/src/lib/websocket-setup.ts +79 -0
  359. package/src/lib/wordlist.ts +2050 -0
  360. package/src/lib/workspace-handlers.ts +285 -0
  361. package/start.sh +80 -0
  362. package/tailwind.config.ts +99 -0
  363. package/tsconfig.json +42 -0
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Credential CRUD — Encrypted Credential File Management
3
+ * =======================================================
4
+ *
5
+ * Create, read, update, delete credential files in ~/.aurawallet/credentials/.
6
+ * Sensitive fields are encrypted with the vault's derived credential key.
7
+ * Non-sensitive metadata is stored as plaintext for search/filtering.
8
+ */
9
+
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { randomBytes } from 'crypto';
13
+ import { DATA_PATHS } from './config';
14
+ import { getCredentialVaultKey } from './credential-vault';
15
+ import { encryptWithSeed, decryptWithSeed } from './encrypt';
16
+ import { CredentialType, CredentialField, CredentialFile, EncryptedData } from '../types';
17
+
18
+ export type CredentialLocation = 'active' | 'archive' | 'recently_deleted';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // ID generation
22
+ // ---------------------------------------------------------------------------
23
+
24
+ function generateCredentialId(): string {
25
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
26
+ const bytes = randomBytes(8);
27
+ let id = 'cred-';
28
+ for (let i = 0; i < 8; i++) {
29
+ id += chars[bytes[i] % chars.length];
30
+ }
31
+ return id;
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // File helpers
36
+ // ---------------------------------------------------------------------------
37
+
38
+ function getCredentialsDir(location: CredentialLocation): string {
39
+ if (location === 'archive') return DATA_PATHS.credentialsArchive;
40
+ if (location === 'recently_deleted') return DATA_PATHS.credentialsRecentlyDeleted;
41
+ return DATA_PATHS.credentials;
42
+ }
43
+
44
+ function getCredentialPath(id: string, location: CredentialLocation = 'active'): string {
45
+ return path.join(getCredentialsDir(location), `${id}.json`);
46
+ }
47
+
48
+ function readCredentialFile(id: string, location: CredentialLocation = 'active'): CredentialFile | null {
49
+ const filePath = getCredentialPath(id, location);
50
+ if (!fs.existsSync(filePath)) return null;
51
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
52
+ }
53
+
54
+ function writeCredentialFile(cred: CredentialFile, location: CredentialLocation = 'active'): void {
55
+ const dir = getCredentialsDir(location);
56
+ if (!fs.existsSync(dir)) {
57
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
58
+ }
59
+ fs.writeFileSync(getCredentialPath(cred.id, location), JSON.stringify(cred, null, 2));
60
+ }
61
+
62
+ function moveCredentialFile(
63
+ id: string,
64
+ from: CredentialLocation,
65
+ to: CredentialLocation,
66
+ ): CredentialFile | null {
67
+ const sourcePath = getCredentialPath(id, from);
68
+ if (!fs.existsSync(sourcePath)) return null;
69
+
70
+ const destinationPath = getCredentialPath(id, to);
71
+ const destinationDir = getCredentialsDir(to);
72
+ if (!fs.existsSync(destinationDir)) {
73
+ fs.mkdirSync(destinationDir, { recursive: true, mode: 0o700 });
74
+ }
75
+
76
+ fs.renameSync(sourcePath, destinationPath);
77
+ return readCredentialFile(id, to);
78
+ }
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // CRUD operations
82
+ // ---------------------------------------------------------------------------
83
+
84
+ /**
85
+ * Create a new credential.
86
+ * Encrypts sensitive fields with the vault's derived credential key.
87
+ */
88
+ export function createCredential(
89
+ vaultId: string,
90
+ type: CredentialType,
91
+ name: string,
92
+ meta: Record<string, unknown>,
93
+ sensitiveFields: CredentialField[]
94
+ ): CredentialFile {
95
+ const vaultKey = getCredentialVaultKey(vaultId);
96
+ if (!vaultKey) {
97
+ throw new Error(`Credential vault for ${vaultId} is locked`);
98
+ }
99
+
100
+ const id = generateCredentialId();
101
+ const now = new Date().toISOString();
102
+
103
+ const encrypted = encryptWithSeed(JSON.stringify(sensitiveFields), vaultKey);
104
+
105
+ const cred: CredentialFile = {
106
+ id,
107
+ vaultId,
108
+ type,
109
+ name,
110
+ meta,
111
+ encrypted,
112
+ createdAt: now,
113
+ updatedAt: now,
114
+ };
115
+
116
+ writeCredentialFile(cred);
117
+ return cred;
118
+ }
119
+
120
+ /**
121
+ * Get credential metadata (no decryption).
122
+ */
123
+ export function getCredential(id: string, location: CredentialLocation = 'active'): CredentialFile | null {
124
+ return readCredentialFile(id, location);
125
+ }
126
+
127
+ export function findCredentialLocation(id: string): CredentialLocation | null {
128
+ if (readCredentialFile(id, 'active')) return 'active';
129
+ if (readCredentialFile(id, 'archive')) return 'archive';
130
+ if (readCredentialFile(id, 'recently_deleted')) return 'recently_deleted';
131
+ return null;
132
+ }
133
+
134
+ /**
135
+ * Decrypt and return the sensitive fields of a credential.
136
+ */
137
+ export function readCredentialSecrets(id: string, location: CredentialLocation = 'active'): CredentialField[] {
138
+ const cred = readCredentialFile(id, location);
139
+ if (!cred) {
140
+ throw new Error(`Credential not found: ${id}`);
141
+ }
142
+
143
+ const vaultKey = getCredentialVaultKey(cred.vaultId);
144
+ if (!vaultKey) {
145
+ throw new Error(`Credential vault for ${cred.vaultId} is locked`);
146
+ }
147
+
148
+ const decrypted = decryptWithSeed(cred.encrypted, vaultKey);
149
+ return JSON.parse(decrypted) as CredentialField[];
150
+ }
151
+
152
+ /**
153
+ * Update a credential's metadata and/or sensitive fields.
154
+ */
155
+ export function updateCredential(
156
+ id: string,
157
+ updates: {
158
+ name?: string;
159
+ meta?: Record<string, unknown>;
160
+ sensitiveFields?: CredentialField[];
161
+ }
162
+ ): CredentialFile {
163
+ const cred = readCredentialFile(id, 'active');
164
+ if (!cred) {
165
+ throw new Error(`Credential not found: ${id}`);
166
+ }
167
+
168
+ if (updates.name !== undefined) {
169
+ cred.name = updates.name;
170
+ }
171
+
172
+ if (updates.meta !== undefined) {
173
+ cred.meta = updates.meta;
174
+ }
175
+
176
+ if (updates.sensitiveFields !== undefined) {
177
+ const vaultKey = getCredentialVaultKey(cred.vaultId);
178
+ if (!vaultKey) {
179
+ throw new Error(`Credential vault for ${cred.vaultId} is locked`);
180
+ }
181
+ cred.encrypted = encryptWithSeed(JSON.stringify(updates.sensitiveFields), vaultKey);
182
+ }
183
+
184
+ cred.updatedAt = new Date().toISOString();
185
+ writeCredentialFile(cred, 'active');
186
+ return cred;
187
+ }
188
+
189
+ /**
190
+ * Permanently delete a credential file in the given location.
191
+ */
192
+ export function deleteCredential(id: string, location: CredentialLocation = 'active'): boolean {
193
+ const filePath = getCredentialPath(id, location);
194
+ if (!fs.existsSync(filePath)) return false;
195
+ fs.unlinkSync(filePath);
196
+ return true;
197
+ }
198
+
199
+ export function archiveCredential(id: string): CredentialFile | null {
200
+ const moved = moveCredentialFile(id, 'active', 'archive');
201
+ if (!moved) return null;
202
+
203
+ const now = new Date().toISOString();
204
+ moved.archivedAt = now;
205
+ delete moved.deletedAt;
206
+ moved.updatedAt = now;
207
+ writeCredentialFile(moved, 'archive');
208
+ return moved;
209
+ }
210
+
211
+ export function deleteArchivedCredential(id: string): CredentialFile | null {
212
+ const moved = moveCredentialFile(id, 'archive', 'recently_deleted');
213
+ if (!moved) return null;
214
+
215
+ const now = new Date().toISOString();
216
+ moved.archivedAt = moved.archivedAt || now;
217
+ moved.deletedAt = now;
218
+ moved.updatedAt = now;
219
+ writeCredentialFile(moved, 'recently_deleted');
220
+ return moved;
221
+ }
222
+
223
+ export function restoreArchivedCredential(id: string): CredentialFile | null {
224
+ const moved = moveCredentialFile(id, 'archive', 'active');
225
+ if (!moved) return null;
226
+
227
+ delete moved.archivedAt;
228
+ delete moved.deletedAt;
229
+ moved.updatedAt = new Date().toISOString();
230
+ writeCredentialFile(moved, 'active');
231
+ return moved;
232
+ }
233
+
234
+ export function restoreDeletedCredential(id: string): CredentialFile | null {
235
+ const moved = moveCredentialFile(id, 'recently_deleted', 'archive');
236
+ if (!moved) return null;
237
+
238
+ moved.archivedAt = moved.archivedAt || new Date().toISOString();
239
+ delete moved.deletedAt;
240
+ moved.updatedAt = new Date().toISOString();
241
+ writeCredentialFile(moved, 'archive');
242
+ return moved;
243
+ }
244
+
245
+ export function purgeDeletedCredentials(retentionDays = 30): {
246
+ scanned: number;
247
+ purged: number;
248
+ errors: Array<{ id: string; error: string }>;
249
+ } {
250
+ const dir = getCredentialsDir('recently_deleted');
251
+ if (!fs.existsSync(dir)) {
252
+ return { scanned: 0, purged: 0, errors: [] };
253
+ }
254
+
255
+ const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
256
+ const files = fs.readdirSync(dir).filter(file => file.startsWith('cred-') && file.endsWith('.json'));
257
+ const errors: Array<{ id: string; error: string }> = [];
258
+ let purged = 0;
259
+
260
+ for (const file of files) {
261
+ const id = file.replace(/\.json$/, '');
262
+ try {
263
+ const cred = readCredentialFile(id, 'recently_deleted');
264
+ if (!cred) continue;
265
+
266
+ const deletedAt = cred.deletedAt || cred.updatedAt || cred.createdAt;
267
+ const deletedMs = Date.parse(deletedAt);
268
+ if (Number.isNaN(deletedMs)) continue;
269
+
270
+ if (deletedMs <= cutoffMs) {
271
+ deleteCredential(id, 'recently_deleted');
272
+ purged += 1;
273
+ }
274
+ } catch (error) {
275
+ errors.push({
276
+ id,
277
+ error: error instanceof Error ? error.message : 'Unknown error',
278
+ });
279
+ }
280
+ }
281
+
282
+ return {
283
+ scanned: files.length,
284
+ purged,
285
+ errors,
286
+ };
287
+ }
288
+
289
+ /**
290
+ * List credentials with optional filters.
291
+ * Returns metadata only (no decryption).
292
+ */
293
+ export function listCredentials(filters?: {
294
+ vaultId?: string;
295
+ type?: CredentialType;
296
+ tag?: string;
297
+ query?: string;
298
+ }, location: CredentialLocation = 'active'): CredentialFile[] {
299
+ const dir = getCredentialsDir(location);
300
+ if (!fs.existsSync(dir)) return [];
301
+
302
+ const files = fs.readdirSync(dir);
303
+ const results: CredentialFile[] = [];
304
+
305
+ for (const file of files) {
306
+ if (!file.startsWith('cred-') || !file.endsWith('.json')) continue;
307
+
308
+ try {
309
+ const raw = fs.readFileSync(path.join(dir, file), 'utf-8');
310
+ const cred: CredentialFile = JSON.parse(raw);
311
+
312
+ // Apply filters
313
+ if (filters?.vaultId && cred.vaultId !== filters.vaultId) continue;
314
+ if (filters?.type && cred.type !== filters.type) continue;
315
+ if (filters?.tag) {
316
+ const tags = (cred.meta.tags as string[] | undefined) || [];
317
+ if (!tags.some(t => t.toLowerCase() === filters.tag!.toLowerCase())) continue;
318
+ }
319
+ if (filters?.query) {
320
+ const q = filters.query.toLowerCase();
321
+ if (!cred.name.toLowerCase().includes(q) && !cred.id.toLowerCase().includes(q)) continue;
322
+ }
323
+
324
+ results.push(cred);
325
+ } catch {
326
+ // skip corrupt files
327
+ }
328
+ }
329
+
330
+ // Sort by updatedAt descending
331
+ results.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
332
+ return results;
333
+ }
@@ -0,0 +1,8 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ /**
4
+ * Hash a secret for storage (we only store the hash, never the secret)
5
+ */
6
+ export function hashSecret(secret: string): string {
7
+ return createHash('sha256').update(secret).digest('hex');
8
+ }
@@ -0,0 +1,15 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ import { getDbUrl } from './config';
3
+
4
+ // Resolve DATABASE_URL to ~/.aurawallet/aurawallet.db (unless tests override)
5
+ process.env.DATABASE_URL = getDbUrl();
6
+
7
+ const globalForPrisma = globalThis as unknown as {
8
+ prisma: PrismaClient | undefined;
9
+ };
10
+
11
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient();
12
+
13
+ if (process.env.NODE_ENV !== 'production') {
14
+ globalForPrisma.prisma = prisma;
15
+ }