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,625 @@
1
+ 'use client';
2
+
3
+ import React, { useState, useEffect, useCallback } from 'react';
4
+ import { Button, ConfirmationModal } from '@/components/design-system';
5
+ import { api, Api } from '@/lib/api';
6
+ import { CREDENTIAL_FIELD_KEYS, NOTE_CONTENT_KEY } from '@/lib/credential-field-schema';
7
+ import { CredentialField } from './CredentialField';
8
+ import { TOTPDisplay } from './TOTPDisplay';
9
+ import { LargeTypeModal } from './LargeTypeModal';
10
+ import { CredentialShareModal } from './CredentialShareModal';
11
+ import { CredentialWalletWidget } from './CredentialWalletWidget';
12
+ import type { CredentialMeta, CredentialLifecycleFilter, WalletLinkMetaV1 } from './types';
13
+
14
+ interface CredentialDetailProps {
15
+ credential: CredentialMeta;
16
+ vaultName: string;
17
+ lifecycle: CredentialLifecycleFilter;
18
+ onEdit: () => void;
19
+ onDelete: () => void;
20
+ onRestore: () => void;
21
+ onDuplicate?: () => void;
22
+ }
23
+
24
+ function formatDate(iso: string): string {
25
+ const d = new Date(iso);
26
+ return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
27
+ }
28
+
29
+ export const CredentialDetail: React.FC<CredentialDetailProps> = ({
30
+ credential,
31
+ vaultName,
32
+ lifecycle,
33
+ onEdit,
34
+ onDelete,
35
+ onRestore,
36
+ onDuplicate,
37
+ }) => {
38
+ const [largeTypeValue, setLargeTypeValue] = useState<string | null>(null);
39
+ const [deleteOpen, setDeleteOpen] = useState(false);
40
+ const [shareOpen, setShareOpen] = useState(false);
41
+ const [reauthMessage, setReauthMessage] = useState<string | null>(null);
42
+ const [reauthLoading, setReauthLoading] = useState(false);
43
+ const [reauthUrl, setReauthUrl] = useState<string | null>(null);
44
+ const [reauthState, setReauthState] = useState<string | null>(null);
45
+ const [reauthCode, setReauthCode] = useState('');
46
+
47
+ const handleShowLargeType = (value: string) => {
48
+ setLargeTypeValue(value);
49
+ };
50
+
51
+ useEffect(() => {
52
+ setReauthMessage(null);
53
+ setReauthLoading(false);
54
+ setReauthUrl(null);
55
+ setReauthState(null);
56
+ setReauthCode('');
57
+ }, [credential.id]);
58
+
59
+ const handleReauthStart = useCallback(async () => {
60
+ setReauthLoading(true);
61
+ setReauthMessage(null);
62
+ try {
63
+ const res = await api.post<{
64
+ success: boolean;
65
+ message?: string;
66
+ authorization_url?: string;
67
+ state?: string;
68
+ }>(Api.Wallet, `/credentials/${credential.id}/reauth`);
69
+ setReauthUrl(res.authorization_url || null);
70
+ setReauthState(res.state || null);
71
+ setReauthMessage(res.message || 'Authorization URL generated. Complete provider consent, then paste code.');
72
+ } catch (err) {
73
+ setReauthMessage(err instanceof Error ? err.message : 'Failed to start re-auth');
74
+ } finally {
75
+ setReauthLoading(false);
76
+ }
77
+ }, [credential.id]);
78
+
79
+ const handleReauthComplete = useCallback(async () => {
80
+ if (!reauthCode.trim() || !reauthState) {
81
+ setReauthMessage('Enter authorization code after consent to complete re-auth.');
82
+ return;
83
+ }
84
+ setReauthLoading(true);
85
+ try {
86
+ const res = await api.post<{ success: boolean; message?: string }>(Api.Wallet, `/credentials/${credential.id}/reauth`, {
87
+ code: reauthCode.trim(),
88
+ state: reauthState,
89
+ });
90
+ setReauthMessage(res.message || 'Re-auth complete. Refresh credential details.');
91
+ setReauthCode('');
92
+ } catch (err) {
93
+ setReauthMessage(err instanceof Error ? err.message : 'Failed to complete re-auth');
94
+ } finally {
95
+ setReauthLoading(false);
96
+ }
97
+ }, [credential.id, reauthCode, reauthState]);
98
+
99
+ const typeLabelMap: Record<string, string> = {
100
+ login: 'Login',
101
+ card: 'Card',
102
+ note: 'Note',
103
+ plain_note: 'Plain Note',
104
+ hot_wallet: 'Hot Wallet',
105
+ apikey: 'API Key',
106
+ custom: 'Key / Value',
107
+ oauth2: 'OAuth2',
108
+ ssh: 'SSH Key',
109
+ gpg: 'GPG Key',
110
+ };
111
+ const typeLabel = typeLabelMap[credential.type] || credential.type.charAt(0).toUpperCase() + credential.type.slice(1);
112
+ // If sensitive_field_keys is present, use it to conditionally render optional fields like notes.
113
+ // If absent (old credentials), default to empty — hides optional fields rather than showing broken ones.
114
+ const sensitiveKeys: string[] = (credential.meta.sensitive_field_keys as string[] | undefined) ?? [];
115
+ const walletLink = (credential.meta.walletLink as WalletLinkMetaV1 | undefined);
116
+ const isActiveLifecycle = lifecycle === 'active';
117
+
118
+ const deleteButtonLabel = isActiveLifecycle
119
+ ? 'ARCHIVE'
120
+ : lifecycle === 'archive'
121
+ ? 'DELETE'
122
+ : 'PURGE';
123
+ const deleteConfirmLabel = lifecycle === 'recently_deleted' ? 'PURGE' : 'CONFIRM';
124
+ const deleteModalTitle = isActiveLifecycle
125
+ ? 'Archive Credential'
126
+ : lifecycle === 'archive'
127
+ ? 'Delete Credential'
128
+ : 'Purge Credential';
129
+ const deleteModalVariant = lifecycle === 'recently_deleted' ? 'danger' as const : 'warning' as const;
130
+ const deleteMessage = isActiveLifecycle
131
+ ? 'This credential will be moved to Archive.'
132
+ : lifecycle === 'archive'
133
+ ? 'This credential will be moved to Recently Deleted.'
134
+ : 'This credential will be permanently deleted now.';
135
+ const restoreLabel = lifecycle === 'archive' ? 'RESTORE' : 'RESTORE TO ARCHIVE';
136
+ const sensitiveFieldBehavior = {
137
+ sensitiveClickBehavior: 'copy' as const,
138
+ };
139
+
140
+ return (
141
+ <div className="p-6 flex flex-col relative">
142
+ {/* Vertical classification label */}
143
+ <div className="absolute top-6 -left-1 text-vertical label-specimen-sm text-[var(--color-text-faint,#9ca3af)] select-none opacity-40 hidden lg:block">
144
+ CLASSIFIED
145
+ </div>
146
+
147
+ {/* Header */}
148
+ <div className="mb-6">
149
+ <h2 className="font-mono font-bold text-lg text-[var(--color-text,#0a0a0a)]">
150
+ {credential.name}
151
+ </h2>
152
+ <div className="flex items-center gap-2 mt-1">
153
+ <span className="shard-start inline-block bg-[var(--color-text,#0a0a0a)] text-[var(--color-surface,#ffffff)] font-mono text-[8px] font-bold uppercase tracking-widest px-2 py-0.5">
154
+ {typeLabel}
155
+ </span>
156
+ <span className="font-mono text-[9px] uppercase tracking-widest text-[var(--color-text-muted,#6b7280)]">
157
+ {vaultName}
158
+ </span>
159
+ </div>
160
+ </div>
161
+
162
+ {/* Fields */}
163
+ <div className="flex-1 space-y-0.5">
164
+ {credential.type === 'login' && (
165
+ <>
166
+ <CredentialField
167
+ label="URL"
168
+ value={credential.meta.url}
169
+ credentialId={credential.id}
170
+ fieldKey={CREDENTIAL_FIELD_KEYS.login.url}
171
+ isSensitive={false}
172
+ onShowLargeType={handleShowLargeType}
173
+ />
174
+ <CredentialField
175
+ label="Username"
176
+ value={credential.meta.username}
177
+ credentialId={credential.id}
178
+ fieldKey={CREDENTIAL_FIELD_KEYS.login.username}
179
+ isSensitive={false}
180
+ onShowLargeType={handleShowLargeType}
181
+ />
182
+ <CredentialField
183
+ label="Password"
184
+ credentialId={credential.id}
185
+ fieldKey={CREDENTIAL_FIELD_KEYS.login.password}
186
+ isSensitive={true}
187
+ onShowLargeType={handleShowLargeType}
188
+ {...sensitiveFieldBehavior}
189
+ />
190
+ {isActiveLifecycle && <TOTPDisplay credentialId={credential.id} />}
191
+ {(sensitiveKeys.includes(CREDENTIAL_FIELD_KEYS.login.notes)) && (
192
+ <CredentialField
193
+ label="Notes"
194
+ credentialId={credential.id}
195
+ fieldKey={CREDENTIAL_FIELD_KEYS.login.notes}
196
+ isSensitive={true}
197
+ onShowLargeType={handleShowLargeType}
198
+ {...sensitiveFieldBehavior}
199
+ />
200
+ )}
201
+ </>
202
+ )}
203
+
204
+ {credential.type === 'card' && (
205
+ <>
206
+ <CredentialField
207
+ label="Cardholder"
208
+ value={credential.meta.cardholder}
209
+ credentialId={credential.id}
210
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.cardholder}
211
+ isSensitive={false}
212
+ onShowLargeType={handleShowLargeType}
213
+ />
214
+ <CredentialField
215
+ label="Brand"
216
+ value={credential.meta.brand}
217
+ credentialId={credential.id}
218
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.brand}
219
+ isSensitive={false}
220
+ onShowLargeType={handleShowLargeType}
221
+ />
222
+ {credential.meta.last4 && (
223
+ <CredentialField
224
+ label="Card"
225
+ value={`•••• ${credential.meta.last4}`}
226
+ credentialId={credential.id}
227
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.last4}
228
+ isSensitive={false}
229
+ onShowLargeType={handleShowLargeType}
230
+ />
231
+ )}
232
+ <CredentialField
233
+ label="Number"
234
+ credentialId={credential.id}
235
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.number}
236
+ isSensitive={true}
237
+ onShowLargeType={handleShowLargeType}
238
+ {...sensitiveFieldBehavior}
239
+ />
240
+ <CredentialField
241
+ label="Expiry"
242
+ credentialId={credential.id}
243
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.expiry}
244
+ isSensitive={true}
245
+ onShowLargeType={handleShowLargeType}
246
+ {...sensitiveFieldBehavior}
247
+ />
248
+ <CredentialField
249
+ label="CVV"
250
+ credentialId={credential.id}
251
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.cvv}
252
+ isSensitive={true}
253
+ onShowLargeType={handleShowLargeType}
254
+ {...sensitiveFieldBehavior}
255
+ />
256
+ <CredentialField
257
+ label="Billing ZIP"
258
+ value={credential.meta.billing_zip as string | undefined}
259
+ credentialId={credential.id}
260
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.billingZip}
261
+ isSensitive={false}
262
+ onShowLargeType={handleShowLargeType}
263
+ />
264
+ {(sensitiveKeys.includes(CREDENTIAL_FIELD_KEYS.card.notes)) && (
265
+ <CredentialField
266
+ label="Notes"
267
+ credentialId={credential.id}
268
+ fieldKey={CREDENTIAL_FIELD_KEYS.card.notes}
269
+ isSensitive={true}
270
+ onShowLargeType={handleShowLargeType}
271
+ {...sensitiveFieldBehavior}
272
+ />
273
+ )}
274
+ </>
275
+ )}
276
+
277
+ {credential.type === 'note' && (
278
+ <CredentialField
279
+ label="Content"
280
+ credentialId={credential.id}
281
+ fieldKey={NOTE_CONTENT_KEY}
282
+ isSensitive={true}
283
+ onShowLargeType={handleShowLargeType}
284
+ sensitiveInteractionMode="markdown-hover-copy"
285
+ disableLargeType
286
+ />
287
+ )}
288
+
289
+ {credential.type === 'plain_note' && (
290
+ <CredentialField
291
+ label="Content"
292
+ value={(credential.meta[NOTE_CONTENT_KEY] as string | undefined) || (credential.meta.value as string | undefined)}
293
+ credentialId={credential.id}
294
+ fieldKey={NOTE_CONTENT_KEY}
295
+ isSensitive={false}
296
+ onShowLargeType={handleShowLargeType}
297
+ renderMarkdown
298
+ disableLargeType
299
+ />
300
+ )}
301
+
302
+ {credential.type === 'apikey' && (
303
+ <>
304
+ <CredentialField
305
+ label="Key"
306
+ value={credential.meta.key as string | undefined}
307
+ credentialId={credential.id}
308
+ fieldKey={CREDENTIAL_FIELD_KEYS.apikey.key}
309
+ isSensitive={false}
310
+ onShowLargeType={handleShowLargeType}
311
+ />
312
+ <CredentialField
313
+ label="Value"
314
+ credentialId={credential.id}
315
+ fieldKey={CREDENTIAL_FIELD_KEYS.apikey.value}
316
+ isSensitive={true}
317
+ onShowLargeType={handleShowLargeType}
318
+ sensitiveClickBehavior="copy"
319
+ />
320
+ </>
321
+ )}
322
+
323
+ {credential.type === 'hot_wallet' && (
324
+ <>
325
+ <CredentialField
326
+ label="Address"
327
+ value={(credential.meta.address as string | undefined) || walletLink?.walletAddress}
328
+ credentialId={credential.id}
329
+ fieldKey={CREDENTIAL_FIELD_KEYS.hot_wallet.address}
330
+ isSensitive={false}
331
+ onShowLargeType={handleShowLargeType}
332
+ />
333
+ <CredentialField
334
+ label="Chain"
335
+ value={(credential.meta.chain as string | undefined) || walletLink?.chain}
336
+ credentialId={credential.id}
337
+ fieldKey={CREDENTIAL_FIELD_KEYS.hot_wallet.chain}
338
+ isSensitive={false}
339
+ onShowLargeType={handleShowLargeType}
340
+ />
341
+ <CredentialField
342
+ label="Private Key"
343
+ credentialId={credential.id}
344
+ fieldKey={CREDENTIAL_FIELD_KEYS.hot_wallet.privateKey}
345
+ isSensitive={true}
346
+ onShowLargeType={handleShowLargeType}
347
+ {...sensitiveFieldBehavior}
348
+ />
349
+ </>
350
+ )}
351
+
352
+
353
+ {credential.type === 'custom' && (
354
+ <>
355
+ <CredentialField
356
+ label="Key"
357
+ value={(credential.meta.primaryKey as string | undefined) || 'value'}
358
+ credentialId={credential.id}
359
+ fieldKey="primaryKey"
360
+ isSensitive={false}
361
+ onShowLargeType={handleShowLargeType}
362
+ />
363
+ <CredentialField
364
+ label="Value"
365
+ credentialId={credential.id}
366
+ fieldKey={(credential.meta.primaryKey as string | undefined) || CREDENTIAL_FIELD_KEYS.custom.value}
367
+ isSensitive={true}
368
+ onShowLargeType={handleShowLargeType}
369
+ {...sensitiveFieldBehavior}
370
+ />
371
+ </>
372
+ )}
373
+
374
+ {credential.type === 'ssh' && (
375
+ <>
376
+ <CredentialField label="Fingerprint" value={credential.meta.fingerprint as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.fingerprint} isSensitive={false} onShowLargeType={handleShowLargeType} />
377
+ <CredentialField label="Key Type" value={credential.meta.key_type as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.keyType} isSensitive={false} onShowLargeType={handleShowLargeType} />
378
+ <CredentialField label="Hosts" value={Array.isArray(credential.meta.hosts) ? (credential.meta.hosts as string[]).join(', ') : undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.hosts} isSensitive={false} onShowLargeType={handleShowLargeType} />
379
+ <CredentialField label="Public Key" value={credential.meta.public_key as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.publicKey} isSensitive={false} onShowLargeType={handleShowLargeType} />
380
+ <CredentialField label="Private Key" credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.privateKey} isSensitive={true} onShowLargeType={handleShowLargeType} {...sensitiveFieldBehavior} />
381
+ <CredentialField label="Passphrase" credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.ssh.passphrase} isSensitive={true} onShowLargeType={handleShowLargeType} {...sensitiveFieldBehavior} />
382
+ </>
383
+ )}
384
+
385
+ {credential.type === 'gpg' && (
386
+ <>
387
+ <CredentialField label="Fingerprint" value={credential.meta.fingerprint as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.fingerprint} isSensitive={false} onShowLargeType={handleShowLargeType} />
388
+ <CredentialField label="Key ID" value={credential.meta.key_id as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.keyId} isSensitive={false} onShowLargeType={handleShowLargeType} />
389
+ <CredentialField label="UID Email" value={credential.meta.uid_email as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.uidEmail} isSensitive={false} onShowLargeType={handleShowLargeType} />
390
+ <CredentialField label="Expires At" value={credential.meta.expires_at as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.expiresAt} isSensitive={false} onShowLargeType={handleShowLargeType} />
391
+ <CredentialField label="Public Key" value={credential.meta.public_key as string | undefined} credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.publicKey} isSensitive={false} onShowLargeType={handleShowLargeType} />
392
+ <CredentialField label="Private Key" credentialId={credential.id} fieldKey={CREDENTIAL_FIELD_KEYS.gpg.privateKey} isSensitive={true} onShowLargeType={handleShowLargeType} {...sensitiveFieldBehavior} />
393
+ </>
394
+ )}
395
+ {credential.type === 'oauth2' && (
396
+ <>
397
+ <CredentialField
398
+ label="Token Endpoint"
399
+ value={credential.meta.token_endpoint as string | undefined}
400
+ credentialId={credential.id}
401
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.tokenEndpoint}
402
+ isSensitive={false}
403
+ onShowLargeType={handleShowLargeType}
404
+ />
405
+ <CredentialField
406
+ label="Scopes"
407
+ value={credential.meta.scopes as string | undefined}
408
+ credentialId={credential.id}
409
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.scopes}
410
+ isSensitive={false}
411
+ onShowLargeType={handleShowLargeType}
412
+ />
413
+ <CredentialField
414
+ label="Auth Method"
415
+ value={credential.meta.auth_method as string | undefined}
416
+ credentialId={credential.id}
417
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.authMethod}
418
+ isSensitive={false}
419
+ onShowLargeType={handleShowLargeType}
420
+ />
421
+ {(credential.meta.needs_reauth || reauthUrl) && (
422
+ <div className="px-2 py-2 my-1 border border-[var(--color-danger,#ef4444)]/30 bg-[var(--color-danger,#ef4444)]/10 text-[var(--color-danger,#ef4444)] font-mono text-[10px]">
423
+ ⚠️ Re-authentication required
424
+ {!!credential.meta.reauth_reason && (
425
+ <span className="block text-[9px] text-[var(--color-danger,#ef4444)]/70 mt-0.5">
426
+ {String(credential.meta.reauth_reason as string)}
427
+ </span>
428
+ )}
429
+ <button
430
+ className="mt-1 px-2 py-0.5 bg-[var(--color-danger,#ef4444)]/20 hover:bg-[var(--color-danger,#ef4444)]/30 text-[var(--color-danger,#ef4444)] text-[9px] font-bold uppercase tracking-wider disabled:opacity-50"
431
+ onClick={handleReauthStart}
432
+ disabled={reauthLoading}
433
+ >
434
+ {reauthLoading ? 'Loading…' : 'Start Re-auth'}
435
+ </button>
436
+ {reauthUrl && (
437
+ <a
438
+ href={reauthUrl}
439
+ target="_blank"
440
+ rel="noopener noreferrer"
441
+ className="mt-1 ml-2 inline-block px-2 py-0.5 bg-[var(--color-danger,#ef4444)]/20 hover:bg-[var(--color-danger,#ef4444)]/30 text-[var(--color-danger,#ef4444)] text-[9px] font-bold uppercase tracking-wider"
442
+ >
443
+ Open Consent
444
+ </a>
445
+ )}
446
+ {reauthState && (
447
+ <div className="mt-2 flex items-center gap-2">
448
+ <input
449
+ value={reauthCode}
450
+ onChange={(e) => setReauthCode(e.target.value)}
451
+ placeholder="Paste authorization code"
452
+ className="flex-1 px-2 py-1 border border-[var(--color-danger,#ef4444)]/30 bg-transparent text-[9px]"
453
+ />
454
+ <button
455
+ className="px-2 py-1 bg-[var(--color-danger,#ef4444)]/20 hover:bg-[var(--color-danger,#ef4444)]/30 text-[var(--color-danger,#ef4444)] text-[9px] font-bold uppercase tracking-wider disabled:opacity-50"
456
+ onClick={handleReauthComplete}
457
+ disabled={reauthLoading || !reauthCode.trim()}
458
+ >
459
+ Complete Re-auth
460
+ </button>
461
+ </div>
462
+ )}
463
+ {reauthMessage && (
464
+ <div className="mt-1 text-[9px] text-[var(--color-danger,#ef4444)]/90 break-words">
465
+ {reauthMessage}
466
+ </div>
467
+ )}
468
+ </div>
469
+ )}
470
+ {credential.meta.last_refreshed && (
471
+ <div className="px-1 py-1">
472
+ <span className="font-mono text-[9px] font-bold uppercase tracking-widest text-[var(--color-text-muted,#6b7280)]">
473
+ Last Refreshed:{' '}
474
+ </span>
475
+ <span className="font-mono text-[10px] text-[var(--color-text-muted,#6b7280)]">
476
+ {new Date(String(credential.meta.last_refreshed)).toLocaleString()}
477
+ </span>
478
+ </div>
479
+ )}
480
+ {(() => {
481
+ const expiresAt = credential.meta.expires_at as number | null | undefined;
482
+ const now = Math.floor(Date.now() / 1000);
483
+ const isExpired = !expiresAt || now >= expiresAt;
484
+ const expiryLabel = !expiresAt
485
+ ? 'No token yet'
486
+ : isExpired
487
+ ? 'Expired — will auto-refresh on next read'
488
+ : `Valid for ${Math.floor((expiresAt - now) / 60)}m`;
489
+ return (
490
+ <div className="px-1 py-2">
491
+ <span className="font-mono text-[9px] font-bold uppercase tracking-widest text-[var(--color-text-muted,#6b7280)]">
492
+ Token Status:{' '}
493
+ </span>
494
+ <span
495
+ className="font-mono text-[10px] font-bold"
496
+ style={{ color: isExpired ? 'var(--color-danger,#ef4444)' : 'var(--color-success,#00c853)' }}
497
+ >
498
+ {expiryLabel}
499
+ </span>
500
+ </div>
501
+ );
502
+ })()}
503
+ <CredentialField
504
+ label="Access Token"
505
+ credentialId={credential.id}
506
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.accessToken}
507
+ isSensitive={true}
508
+ onShowLargeType={handleShowLargeType}
509
+ {...sensitiveFieldBehavior}
510
+ />
511
+ <CredentialField
512
+ label="Refresh Token"
513
+ credentialId={credential.id}
514
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.refreshToken}
515
+ isSensitive={true}
516
+ onShowLargeType={handleShowLargeType}
517
+ {...sensitiveFieldBehavior}
518
+ />
519
+ <CredentialField
520
+ label="Client ID"
521
+ credentialId={credential.id}
522
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.clientId}
523
+ isSensitive={true}
524
+ onShowLargeType={handleShowLargeType}
525
+ {...sensitiveFieldBehavior}
526
+ />
527
+ <CredentialField
528
+ label="Client Secret"
529
+ credentialId={credential.id}
530
+ fieldKey={CREDENTIAL_FIELD_KEYS.oauth2.clientSecret}
531
+ isSensitive={true}
532
+ onShowLargeType={handleShowLargeType}
533
+ {...sensitiveFieldBehavior}
534
+ />
535
+ </>
536
+ )}
537
+ </div>
538
+
539
+ {walletLink && <CredentialWalletWidget walletLink={walletLink} />}
540
+
541
+ {/* Tags */}
542
+ {credential.meta.tags && credential.meta.tags.length > 0 && (
543
+ <div className="mt-4 flex flex-wrap gap-1.5">
544
+ {credential.meta.tags.map((tag) => (
545
+ <span
546
+ key={tag}
547
+ className="inline-block font-mono text-[9px] px-2 py-0.5 bg-[var(--color-accent,#ccff00)]/10 text-[var(--color-text-muted,#6b7280)]"
548
+ >
549
+ {tag}
550
+ </span>
551
+ ))}
552
+ </div>
553
+ )}
554
+
555
+ {/* Metadata footer */}
556
+ <div className="mt-4 pt-3 border-t border-[var(--color-border,#d4d4d8)]">
557
+ <div className="font-mono text-[8px] text-[var(--color-text-faint,#9ca3af)] space-y-0.5">
558
+ <div>Created {formatDate(credential.createdAt)}</div>
559
+ <div>Updated {formatDate(credential.updatedAt)}</div>
560
+ {credential.archivedAt && <div>Archived {formatDate(credential.archivedAt)}</div>}
561
+ {credential.deletedAt && <div>Deleted {formatDate(credential.deletedAt)}</div>}
562
+ <div>Vault: {vaultName}</div>
563
+ </div>
564
+ </div>
565
+
566
+ {/* Actions bar */}
567
+ <div className="mt-4 flex gap-2">
568
+ {isActiveLifecycle && (
569
+ <Button variant="secondary" size="sm" onClick={() => setShareOpen(true)}>
570
+ SHARE
571
+ </Button>
572
+ )}
573
+ {isActiveLifecycle && (
574
+ <Button variant="secondary" size="sm" onClick={onEdit}>
575
+ EDIT
576
+ </Button>
577
+ )}
578
+ {isActiveLifecycle && onDuplicate && (
579
+ <Button variant="secondary" size="sm" onClick={onDuplicate}>
580
+ DUPLICATE
581
+ </Button>
582
+ )}
583
+ {!isActiveLifecycle && (
584
+ <Button variant="secondary" size="sm" onClick={onRestore}>
585
+ {restoreLabel}
586
+ </Button>
587
+ )}
588
+ <Button
589
+ variant="danger"
590
+ size="sm"
591
+ onClick={() => setDeleteOpen(true)}
592
+ >
593
+ {deleteButtonLabel}
594
+ </Button>
595
+ </div>
596
+
597
+ <ConfirmationModal
598
+ isOpen={deleteOpen}
599
+ onClose={() => setDeleteOpen(false)}
600
+ onConfirm={() => {
601
+ setDeleteOpen(false);
602
+ onDelete();
603
+ }}
604
+ title={deleteModalTitle}
605
+ message={deleteMessage}
606
+ confirmText={deleteConfirmLabel}
607
+ variant={deleteModalVariant}
608
+ />
609
+
610
+ {/* Large type modal */}
611
+ <LargeTypeModal
612
+ isOpen={largeTypeValue != null}
613
+ onClose={() => setLargeTypeValue(null)}
614
+ value={largeTypeValue ?? ''}
615
+ />
616
+
617
+ <CredentialShareModal
618
+ isOpen={shareOpen}
619
+ onClose={() => setShareOpen(false)}
620
+ credentialId={credential.id}
621
+ credentialName={credential.name}
622
+ />
623
+ </div>
624
+ );
625
+ };
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { ShieldCheck, Plus } from 'lucide-react';
5
+ import { Button } from '@/components/design-system';
6
+
7
+ interface CredentialEmptyProps {
8
+ variant: 'no-selection' | 'empty-vault' | 'empty-lifecycle';
9
+ onAdd?: () => void;
10
+ }
11
+
12
+ export const CredentialEmpty: React.FC<CredentialEmptyProps> = ({ variant, onAdd }) => {
13
+ if (variant === 'no-selection') {
14
+ return (
15
+ <div className="flex-1 flex items-center justify-center h-full">
16
+ <div className="text-center">
17
+ <ShieldCheck size={32} className="mx-auto mb-3 text-[var(--color-text-faint,#9ca3af)]" />
18
+ <div className="font-mono text-[11px] tracking-widest uppercase text-[var(--color-text-muted,#6b7280)]">
19
+ Select a credential from the list
20
+ </div>
21
+ </div>
22
+ </div>
23
+ );
24
+ }
25
+
26
+ if (variant === 'empty-lifecycle') {
27
+ return (
28
+ <div className="flex-1 flex items-center justify-center h-full">
29
+ <div className="text-center">
30
+ <ShieldCheck size={32} className="mx-auto mb-3 text-[var(--color-text-faint,#9ca3af)]" />
31
+ <div className="font-mono text-[11px] tracking-widest uppercase text-[var(--color-text-muted,#6b7280)] mb-1">
32
+ No credentials in this section
33
+ </div>
34
+ </div>
35
+ </div>
36
+ );
37
+ }
38
+
39
+ return (
40
+ <div className="flex-1 flex items-center justify-center h-full">
41
+ <div className="text-center">
42
+ <ShieldCheck size={32} className="mx-auto mb-3 text-[var(--color-text-faint,#9ca3af)]" />
43
+ <div className="font-mono text-[11px] tracking-widest uppercase text-[var(--color-text-muted,#6b7280)] mb-1">
44
+ Your vault is empty
45
+ </div>
46
+ <div className="font-mono text-[9px] text-[var(--color-text-faint,#9ca3af)] mb-4">
47
+ Create your first credential
48
+ </div>
49
+ <Button size="sm" onClick={onAdd} icon={<Plus size={10} />}>
50
+ ADD
51
+ </Button>
52
+ </div>
53
+ </div>
54
+ );
55
+ };