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.
- package/LICENSE +26 -0
- package/README.md +77 -0
- package/apps/desktop-electron/main.js +428 -0
- package/bin/auramaxx.js +1063 -0
- package/docs/ADAPTERS.md +466 -0
- package/docs/AGENT_SETUP.md +159 -0
- package/docs/API.md +127 -0
- package/docs/APPS.md +199 -0
- package/docs/ARCHITECTURE.md +235 -0
- package/docs/AUTH.md +318 -0
- package/docs/BEST-PRACTICES.md +82 -0
- package/docs/CLI.md +141 -0
- package/docs/DESKTOP_ELECTRON.md +26 -0
- package/docs/DEVELOPING-APPS.md +453 -0
- package/docs/MCP.md +122 -0
- package/docs/PACKAGING_POLICY.md +19 -0
- package/docs/PERMISSION.md +137 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/README.md +50 -0
- package/docs/SKILLS.md +132 -0
- package/docs/TROUBLESHOOTING.md +376 -0
- package/docs/WORKSPACE.md +673 -0
- package/docs/agent-auth.md +14 -0
- package/docs/api/authentication.md +79 -0
- package/docs/api/secrets/api-keys.md +28 -0
- package/docs/api/secrets/credentials.md +80 -0
- package/docs/api/secrets/sharing.md +48 -0
- package/docs/api/system.md +41 -0
- package/docs/api/wallets/apps-strategies.md +66 -0
- package/docs/api/wallets/core.md +46 -0
- package/docs/api/wallets/data-portfolio.md +42 -0
- package/docs/aura-file.md +48 -0
- package/docs/core-concepts/FEATURES.md +114 -0
- package/docs/credentials.md +120 -0
- package/docs/external/HOW_TO_AURAMAXX/GETTING_SECRETS.md +33 -0
- package/docs/external/HOW_TO_AURAMAXX/README.md +45 -0
- package/docs/external/getting-started.md +10 -0
- package/docs/external/overview.md +19 -0
- package/docs/external/persona-paths.md +7 -0
- package/docs/external/share-secret.md +76 -0
- package/docs/external/why-aura.md +7 -0
- package/docs/security.md +227 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
- package/docs/wallet/AI.md +508 -0
- package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
- package/docs/wallet/README.md +47 -0
- package/docs/wallet/STRATEGY.md +89 -0
- package/next.config.ts +28 -0
- package/package.json +167 -0
- package/postcss.config.mjs +8 -0
- package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
- package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
- package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
- package/prisma/migrations/20260222090000_update_admin_ttl_default/migration.sql +10 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/actions.ts +474 -0
- package/server/cli/commands/api.ts +220 -0
- package/server/cli/commands/apikey.ts +277 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/auth.ts +464 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/diary.ts +274 -0
- package/server/cli/commands/doctor.ts +1247 -0
- package/server/cli/commands/env.ts +476 -0
- package/server/cli/commands/experimental.ts +69 -0
- package/server/cli/commands/init.ts +798 -0
- package/server/cli/commands/lock.ts +157 -0
- package/server/cli/commands/mcp.ts +285 -0
- package/server/cli/commands/quickhack.ts +86 -0
- package/server/cli/commands/release-check.ts +231 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/service.ts +320 -0
- package/server/cli/commands/shell-hook.ts +512 -0
- package/server/cli/commands/skill.ts +216 -0
- package/server/cli/commands/start.ts +139 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +36 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +50 -0
- package/server/cli/commands/vault.ts +1323 -0
- package/server/cli/commands/wallet.ts +209 -0
- package/server/cli/index.ts +280 -0
- package/server/cli/lib/approval-poll.ts +94 -0
- package/server/cli/lib/aura-parser.ts +64 -0
- package/server/cli/lib/credential-create.ts +74 -0
- package/server/cli/lib/credential-resolve.ts +280 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -0
- package/server/cli/lib/escalation.ts +57 -0
- package/server/cli/lib/http.ts +91 -0
- package/server/cli/lib/init-steps.ts +76 -0
- package/server/cli/lib/local-agent-trust.ts +45 -0
- package/server/cli/lib/lock-unlock-helper.ts +71 -0
- package/server/cli/lib/process.ts +162 -0
- package/server/cli/lib/prompt.ts +294 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +579 -0
- package/server/cli/transport-client.ts +50 -0
- package/server/cron/index.ts +137 -0
- package/server/cron/job.ts +31 -0
- package/server/cron/jobs/balance-sync.ts +436 -0
- package/server/cron/jobs/incoming-scan.ts +506 -0
- package/server/cron/jobs/native-price.ts +70 -0
- package/server/cron/jobs/orphan-cleanup.ts +40 -0
- package/server/cron/jobs/strategy-runner.ts +175 -0
- package/server/cron/scheduler.ts +125 -0
- package/server/index.ts +420 -0
- package/server/lib/adapters/factory.ts +119 -0
- package/server/lib/adapters/index.ts +19 -0
- package/server/lib/adapters/router.ts +297 -0
- package/server/lib/adapters/telegram.ts +645 -0
- package/server/lib/adapters/types.ts +89 -0
- package/server/lib/adapters/webhook.ts +95 -0
- package/server/lib/address.ts +49 -0
- package/server/lib/agent-auth/contracts.ts +1194 -0
- package/server/lib/agent-profiles.ts +419 -0
- package/server/lib/ai.ts +285 -0
- package/server/lib/api-registry/contracts.ts +86 -0
- package/server/lib/api-registry/validation.ts +172 -0
- package/server/lib/apikey-migration.ts +258 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/approval-link.ts +27 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/auto-execute.ts +160 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +1048 -0
- package/server/lib/config.ts +408 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +111 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +608 -0
- package/server/lib/credential-scope.ts +102 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +533 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +422 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +58 -0
- package/server/lib/defaults.ts +386 -0
- package/server/lib/dex/index.ts +80 -0
- package/server/lib/dex/relay.ts +235 -0
- package/server/lib/dex/types.ts +59 -0
- package/server/lib/dex/uniswap.ts +370 -0
- package/server/lib/diary.ts +34 -0
- package/server/lib/dont-ask-again-policy.ts +41 -0
- package/server/lib/e2e-agent/artifacts.ts +36 -0
- package/server/lib/e2e-agent/contracts.ts +112 -0
- package/server/lib/e2e-agent/validation.ts +135 -0
- package/server/lib/encrypt.ts +114 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +217 -0
- package/server/lib/feature-flags.ts +93 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/human-action-summary.ts +80 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +340 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +230 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +71 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +299 -0
- package/server/lib/pino.ts +24 -0
- package/server/lib/policy-preview.ts +138 -0
- package/server/lib/price.ts +338 -0
- package/server/lib/prices.ts +34 -0
- package/server/lib/project-scope.ts +297 -0
- package/server/lib/resolve-action.ts +328 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/secret-gist-share.ts +296 -0
- package/server/lib/sessions.ts +634 -0
- package/server/lib/socket-path.ts +56 -0
- package/server/lib/solana/connection.ts +26 -0
- package/server/lib/solana/jupiter.ts +128 -0
- package/server/lib/solana/transfer.ts +108 -0
- package/server/lib/solana/wallet.ts +136 -0
- package/server/lib/strategy/emits.ts +21 -0
- package/server/lib/strategy/engine.ts +1305 -0
- package/server/lib/strategy/executor.ts +115 -0
- package/server/lib/strategy/hook-context.ts +159 -0
- package/server/lib/strategy/hooks.ts +990 -0
- package/server/lib/strategy/index.ts +28 -0
- package/server/lib/strategy/installer.ts +305 -0
- package/server/lib/strategy/loader.ts +256 -0
- package/server/lib/strategy/message.ts +237 -0
- package/server/lib/strategy/repository.ts +218 -0
- package/server/lib/strategy/session-logger.ts +693 -0
- package/server/lib/strategy/sources.ts +288 -0
- package/server/lib/strategy/state.ts +189 -0
- package/server/lib/strategy/templates.ts +403 -0
- package/server/lib/strategy/tick.ts +404 -0
- package/server/lib/strategy/types.ts +230 -0
- package/server/lib/swap.ts +3 -0
- package/server/lib/temp.ts +86 -0
- package/server/lib/token-metadata.ts +86 -0
- package/server/lib/token-safety.ts +200 -0
- package/server/lib/token-search.ts +444 -0
- package/server/lib/totp.ts +194 -0
- package/server/lib/transactions.ts +123 -0
- package/server/lib/transport.ts +84 -0
- package/server/lib/txhistory/decoder.ts +262 -0
- package/server/lib/txhistory/enricher.ts +652 -0
- package/server/lib/txhistory/index.ts +391 -0
- package/server/lib/txhistory/signatures.ts +59 -0
- package/server/lib/update-check.ts +35 -0
- package/server/lib/verified-summary.ts +414 -0
- package/server/lib/view-registry.ts +80 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +1589 -0
- package/server/mcp/tools.ts +276 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +539 -0
- package/server/routes/adapters.ts +711 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +343 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +406 -0
- package/server/routes/backup.ts +404 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +380 -0
- package/server/routes/credential-vaults.ts +159 -0
- package/server/routes/credentials.ts +1782 -0
- package/server/routes/dashboard.ts +97 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/flags.ts +11 -0
- package/server/routes/fund.ts +225 -0
- package/server/routes/heartbeat.ts +375 -0
- package/server/routes/import.ts +364 -0
- package/server/routes/launch.ts +665 -0
- package/server/routes/lock.ts +54 -0
- package/server/routes/logs.ts +68 -0
- package/server/routes/nuke.ts +111 -0
- package/server/routes/passkey-credentials.ts +99 -0
- package/server/routes/passkey.ts +366 -0
- package/server/routes/portfolio.ts +217 -0
- package/server/routes/price.ts +63 -0
- package/server/routes/resolve.ts +31 -0
- package/server/routes/security.ts +45 -0
- package/server/routes/send-evm.ts +241 -0
- package/server/routes/send-solana.ts +281 -0
- package/server/routes/send.ts +178 -0
- package/server/routes/setup.ts +210 -0
- package/server/routes/strategy.ts +894 -0
- package/server/routes/swap-evm.ts +352 -0
- package/server/routes/swap-solana.ts +176 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +467 -0
- package/server/routes/views.ts +41 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +709 -0
- package/server/types.ts +146 -0
- package/shared/credential-field-schema.ts +248 -0
- package/skills/auramaxx/HEARTBEAT.md +78 -0
- package/skills/auramaxx/SKILL.md +745 -0
- package/skills/auramaxx/docs/AGENT_SETUP.md +155 -0
- package/skills/auramaxx/docs/API.md +127 -0
- package/skills/auramaxx/docs/AUTH.md +318 -0
- package/skills/auramaxx/docs/CLI.md +130 -0
- package/skills/auramaxx/docs/MCP.md +122 -0
- package/skills/auramaxx/docs/TROUBLESHOOTING.md +357 -0
- package/skills/auramaxx/docs/WORKSPACE.md +673 -0
- package/skills/auramaxx/docs/security.md +227 -0
- package/skills/task-lifecycle/SKILL.md +378 -0
- package/src/app/api/[...doc]/page.tsx +36 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +132 -0
- package/src/app/api/apps/manifests/route.ts +16 -0
- package/src/app/api/apps/static/[...path]/route.ts +57 -0
- package/src/app/api/docs/plain/route.ts +74 -0
- package/src/app/api/events/route.ts +92 -0
- package/src/app/api/page.tsx +290 -0
- package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
- package/src/app/api/workspace/[id]/apps/route.ts +81 -0
- package/src/app/api/workspace/[id]/export/route.ts +67 -0
- package/src/app/api/workspace/[id]/route.ts +168 -0
- package/src/app/api/workspace/auth.ts +40 -0
- package/src/app/api/workspace/config/route.ts +121 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app-legacy-do-not-use/page.tsx +2245 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/approve/[actionId]/page.tsx +409 -0
- package/src/app/docs/DocsPageContent.tsx +269 -0
- package/src/app/docs/[...doc]/page.tsx +41 -0
- package/src/app/docs/page.tsx +38 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +819 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +102 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +39 -0
- package/src/app/page.tsx +1964 -0
- package/src/app/privacy/page.tsx +63 -0
- package/src/app/providers.tsx +87 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/app/terms/page.tsx +80 -0
- package/src/components/ChainSelector.tsx +44 -0
- package/src/components/HumanActionBar.tsx +697 -0
- package/src/components/NotificationDrawer.tsx +387 -0
- package/src/components/PasskeyEnrollmentPrompt.tsx +235 -0
- package/src/components/apps/AgentKeysApp.tsx +490 -0
- package/src/components/apps/App.tsx +153 -0
- package/src/components/apps/AppGrid.tsx +15 -0
- package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
- package/src/components/apps/DraggableApp.tsx +562 -0
- package/src/components/apps/IFrameApp.tsx +73 -0
- package/src/components/apps/LogsApp.tsx +360 -0
- package/src/components/apps/SendApp.tsx +394 -0
- package/src/components/apps/SetupWizardApp.tsx +1004 -0
- package/src/components/apps/SystemDefaultsApp.tsx +845 -0
- package/src/components/apps/ThirdPartyApp.tsx +428 -0
- package/src/components/apps/TokenApp.tsx +319 -0
- package/src/components/apps/TransactionsApp.tsx +438 -0
- package/src/components/apps/WalletDetailApp.tsx +1505 -0
- package/src/components/apps/index.ts +13 -0
- package/src/components/design-system/Button.tsx +88 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +147 -0
- package/src/components/design-system/ConfirmationModal.tsx +107 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/DownloadButton.tsx +149 -0
- package/src/components/design-system/Drawer.tsx +133 -0
- package/src/components/design-system/FilterDropdown.tsx +183 -0
- package/src/components/design-system/ItemPicker.tsx +157 -0
- package/src/components/design-system/Modal.tsx +296 -0
- package/src/components/design-system/Popover.tsx +142 -0
- package/src/components/design-system/TextInput.tsx +85 -0
- package/src/components/design-system/Toggle.tsx +65 -0
- package/src/components/design-system/TyvekCollapsibleSection.tsx +55 -0
- package/src/components/design-system/index.ts +14 -0
- package/src/components/docs/ClientSideMarkdown.tsx +51 -0
- package/src/components/docs/DocsSearchBar.tsx +118 -0
- package/src/components/docs/DocsThemeToggle.tsx +38 -0
- package/src/components/docs/PersistentDocGroup.tsx +91 -0
- package/src/components/docs/ShareUrlButton.tsx +33 -0
- package/src/components/docs/SidebarScrollMemory.tsx +56 -0
- package/src/components/health/CredentialHealthDashboard.tsx +214 -0
- package/src/components/icons/ChainIcons.tsx +72 -0
- package/src/components/layout/AppStoreDrawer.tsx +369 -0
- package/src/components/layout/ContentArea.tsx +21 -0
- package/src/components/layout/CreateViewModal.tsx +88 -0
- package/src/components/layout/LeftRail.tsx +114 -0
- package/src/components/layout/TabBar.tsx +284 -0
- package/src/components/layout/WalletSidebar.tsx +1030 -0
- package/src/components/layout/index.ts +6 -0
- package/src/components/marketing/AuraMaxxSpecOverlay.tsx +653 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1272 -0
- package/src/components/vault/AuditConsole.tsx +600 -0
- package/src/components/vault/CredentialDetail.tsx +625 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +583 -0
- package/src/components/vault/CredentialForm.tsx +1484 -0
- package/src/components/vault/CredentialList.tsx +265 -0
- package/src/components/vault/CredentialRow.tsx +130 -0
- package/src/components/vault/CredentialShareModal.tsx +273 -0
- package/src/components/vault/CredentialVault.tsx +1662 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/DocsConsole.tsx +113 -0
- package/src/components/vault/ImportCredentialsModal.tsx +578 -0
- package/src/components/vault/LargeTypeModal.tsx +88 -0
- package/src/components/vault/PasswordGenerator.tsx +232 -0
- package/src/components/vault/TOTPDisplay.tsx +108 -0
- package/src/components/vault/TotpSetupPanel.tsx +198 -0
- package/src/components/vault/VaultSidebar.tsx +881 -0
- package/src/components/vault/credentialFormName.ts +91 -0
- package/src/components/vault/hooks/useVaultKeyboardShortcuts.ts +69 -0
- package/src/components/vault/types.ts +56 -0
- package/src/context/AuthContext.tsx +365 -0
- package/src/context/PriceContext.tsx +113 -0
- package/src/context/ThemeContext.tsx +164 -0
- package/src/context/WebSocketContext.tsx +269 -0
- package/src/context/WorkspaceContext.tsx +668 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useAgentActions.ts +552 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/hooks/useTheme.ts +156 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api-docs.ts +154 -0
- package/src/lib/api.ts +474 -0
- package/src/lib/app-loader.ts +148 -0
- package/src/lib/app-registry.ts +178 -0
- package/src/lib/app-sdk.ts +157 -0
- package/src/lib/audit-console-adapter.ts +151 -0
- package/src/lib/auth-client.ts +75 -0
- package/src/lib/config.ts +74 -0
- package/src/lib/credential-field-schema.ts +11 -0
- package/src/lib/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +544 -0
- package/src/lib/events.ts +363 -0
- package/src/lib/pino.ts +24 -0
- package/src/lib/theme-handlers.ts +168 -0
- package/src/lib/theme.ts +351 -0
- package/src/lib/tokenData.ts +378 -0
- package/src/lib/totp-import.ts +57 -0
- package/src/lib/vault-crypto.ts +129 -0
- package/src/lib/view-registry.ts +57 -0
- package/src/lib/websocket-server.ts +302 -0
- package/src/lib/websocket-setup.ts +79 -0
- package/src/lib/wordlist.ts +2050 -0
- package/src/lib/workspace-handlers.ts +285 -0
- package/start.sh +170 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const API_REGISTRY_ERROR_CODES = {
|
|
4
|
+
nameInvalid: 'E_NAME_INVALID',
|
|
5
|
+
egressDenied: 'E_EGRESS_DENIED',
|
|
6
|
+
signatureAlgorithmUnsupported: 'E_SIG_ALG_UNSUPPORTED',
|
|
7
|
+
permissionUnresolved: 'E_PERMISSION_UNRESOLVED',
|
|
8
|
+
keyTrustInvalid: 'E_KEY_TRUST_INVALID',
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export const API_REGISTRY_RESERVED_NAMESPACES = new Set([
|
|
12
|
+
'aura',
|
|
13
|
+
'registry',
|
|
14
|
+
'security',
|
|
15
|
+
'system',
|
|
16
|
+
'admin',
|
|
17
|
+
'root',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const API_REGISTRY_RESERVED_PACKAGE_NAMES = new Set([
|
|
21
|
+
'internal',
|
|
22
|
+
'private',
|
|
23
|
+
'null',
|
|
24
|
+
'undefined',
|
|
25
|
+
'latest',
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
export const API_REGISTRY_IDENTITY_REGEX =
|
|
29
|
+
/^@([a-z0-9][a-z0-9-]{1,38}[a-z0-9])\/([a-z0-9][a-z0-9-]{1,62}[a-z0-9])$/;
|
|
30
|
+
|
|
31
|
+
export const API_REGISTRY_ALLOWED_PERMISSIONS = [
|
|
32
|
+
'http.read',
|
|
33
|
+
'http.write',
|
|
34
|
+
'events.emit',
|
|
35
|
+
'filesystem.read:workspace',
|
|
36
|
+
'filesystem.write:workspace',
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
const scopedPermissionPattern = /^(secrets\.(read|write):[a-z0-9][a-z0-9:_-]{0,63})$/;
|
|
40
|
+
|
|
41
|
+
export const permissionSchema = z
|
|
42
|
+
.string()
|
|
43
|
+
.refine((value) => API_REGISTRY_ALLOWED_PERMISSIONS.includes(value as (typeof API_REGISTRY_ALLOWED_PERMISSIONS)[number]) || scopedPermissionPattern.test(value), {
|
|
44
|
+
message: 'Permission is outside of the MVP bounded permission catalog',
|
|
45
|
+
})
|
|
46
|
+
.refine((value) => !value.includes('*'), {
|
|
47
|
+
message: 'Wildcard permissions are not permitted in MVP',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export type KeyStatus = 'active' | 'retired' | 'compromised';
|
|
51
|
+
|
|
52
|
+
export interface PublisherKey {
|
|
53
|
+
keyId: string;
|
|
54
|
+
status: KeyStatus;
|
|
55
|
+
createdAt: string;
|
|
56
|
+
compromiseDetectedAt?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface SignatureEnvelope {
|
|
60
|
+
algorithm: string;
|
|
61
|
+
keyId: string;
|
|
62
|
+
sig: string;
|
|
63
|
+
createdAt: string;
|
|
64
|
+
payloadHash: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface LocalPolicy {
|
|
68
|
+
allow?: string[];
|
|
69
|
+
deny?: string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const API_AUDIT_EXIT_CODES = {
|
|
73
|
+
ok: 0,
|
|
74
|
+
warning: 20,
|
|
75
|
+
advisoryBlocked: 21,
|
|
76
|
+
yankedBlocked: 22,
|
|
77
|
+
integrityFailure: 23,
|
|
78
|
+
} as const;
|
|
79
|
+
|
|
80
|
+
export type AdvisorySeverity = 'low' | 'medium' | 'high' | 'critical';
|
|
81
|
+
export type AuditMode = 'ci' | 'local';
|
|
82
|
+
|
|
83
|
+
export interface AdvisoryFinding {
|
|
84
|
+
severity: AdvisorySeverity;
|
|
85
|
+
exploitKnown?: boolean;
|
|
86
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { isIPv4, isIPv6 } from 'net';
|
|
2
|
+
import {
|
|
3
|
+
AdvisoryFinding,
|
|
4
|
+
API_AUDIT_EXIT_CODES,
|
|
5
|
+
API_REGISTRY_ERROR_CODES,
|
|
6
|
+
API_REGISTRY_IDENTITY_REGEX,
|
|
7
|
+
API_REGISTRY_RESERVED_NAMESPACES,
|
|
8
|
+
API_REGISTRY_RESERVED_PACKAGE_NAMES,
|
|
9
|
+
LocalPolicy,
|
|
10
|
+
PublisherKey,
|
|
11
|
+
SignatureEnvelope,
|
|
12
|
+
permissionSchema,
|
|
13
|
+
} from './contracts';
|
|
14
|
+
|
|
15
|
+
export class ApiRegistryValidationError extends Error {
|
|
16
|
+
constructor(public readonly code: string, message: string) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'ApiRegistryValidationError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function validatePackageIdentity(identity: string): { namespace: string; name: string } {
|
|
23
|
+
const match = identity.match(API_REGISTRY_IDENTITY_REGEX);
|
|
24
|
+
if (!match) {
|
|
25
|
+
throw new ApiRegistryValidationError(
|
|
26
|
+
API_REGISTRY_ERROR_CODES.nameInvalid,
|
|
27
|
+
`Invalid package identity "${identity}". Expected @namespace/name`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const namespace = match[1];
|
|
32
|
+
const name = match[2];
|
|
33
|
+
|
|
34
|
+
if (API_REGISTRY_RESERVED_NAMESPACES.has(namespace) || API_REGISTRY_RESERVED_PACKAGE_NAMES.has(name)) {
|
|
35
|
+
throw new ApiRegistryValidationError(
|
|
36
|
+
API_REGISTRY_ERROR_CODES.nameInvalid,
|
|
37
|
+
`Package identity "${identity}" uses a reserved namespace or package name`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { namespace, name };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isFqdn(host: string): boolean {
|
|
45
|
+
// strict enough for MVP: labels with lowercase letters/digits/hyphens, at least one dot
|
|
46
|
+
if (!host.includes('.')) return false;
|
|
47
|
+
if (host.includes('*') || host.includes('/') || host.includes('?') || host.includes(':')) return false;
|
|
48
|
+
const labels = host.split('.');
|
|
49
|
+
return labels.every((label) => /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function validateAllowedHosts(allowedHosts: string[]): void {
|
|
53
|
+
for (const host of allowedHosts) {
|
|
54
|
+
if (!isFqdn(host) || isIPv4(host) || isIPv6(host)) {
|
|
55
|
+
throw new ApiRegistryValidationError(
|
|
56
|
+
API_REGISTRY_ERROR_CODES.egressDenied,
|
|
57
|
+
`Host "${host}" is invalid. allowedHosts must contain FQDN values only`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function enforceEgressPolicy(hostname: string, allowedHosts: readonly string[]): void {
|
|
64
|
+
if (!allowedHosts.includes(hostname)) {
|
|
65
|
+
throw new ApiRegistryValidationError(
|
|
66
|
+
API_REGISTRY_ERROR_CODES.egressDenied,
|
|
67
|
+
`Blocked outbound host: ${hostname}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function validateSignatureEnvelope(envelope: SignatureEnvelope): void {
|
|
73
|
+
if (envelope.algorithm !== 'ed25519') {
|
|
74
|
+
throw new ApiRegistryValidationError(
|
|
75
|
+
API_REGISTRY_ERROR_CODES.signatureAlgorithmUnsupported,
|
|
76
|
+
`Unsupported signature algorithm: ${envelope.algorithm}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!envelope.keyId || !envelope.sig || !envelope.payloadHash || !envelope.createdAt) {
|
|
81
|
+
throw new ApiRegistryValidationError(
|
|
82
|
+
API_REGISTRY_ERROR_CODES.signatureAlgorithmUnsupported,
|
|
83
|
+
'Signature envelope is missing required fields'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function resolveEffectivePermissions(
|
|
89
|
+
requiredPermissions: string[],
|
|
90
|
+
localPolicy: LocalPolicy,
|
|
91
|
+
runtimeHardDeny: Set<string>
|
|
92
|
+
): string[] {
|
|
93
|
+
for (const permission of requiredPermissions) {
|
|
94
|
+
const parsed = permissionSchema.safeParse(permission);
|
|
95
|
+
if (!parsed.success) {
|
|
96
|
+
throw new ApiRegistryValidationError(
|
|
97
|
+
API_REGISTRY_ERROR_CODES.permissionUnresolved,
|
|
98
|
+
`Required permission "${permission}" is invalid: ${parsed.error.issues.map((issue) => issue.message).join('; ')}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const deniedByRuntime = runtimeHardDeny.has(permission);
|
|
103
|
+
const deniedByPolicy = (localPolicy.deny ?? []).includes(permission);
|
|
104
|
+
const allowedByPolicy = (localPolicy.allow ?? []).includes(permission);
|
|
105
|
+
|
|
106
|
+
if (deniedByRuntime || deniedByPolicy || !allowedByPolicy) {
|
|
107
|
+
throw new ApiRegistryValidationError(
|
|
108
|
+
API_REGISTRY_ERROR_CODES.permissionUnresolved,
|
|
109
|
+
`Required permission "${permission}" could not be resolved under local/runtime policy`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return [...new Set(requiredPermissions)].sort();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function enforceHistoricalKeyTrust(key: PublisherKey, signatureCreatedAt: string): void {
|
|
118
|
+
const signatureTime = Date.parse(signatureCreatedAt);
|
|
119
|
+
const keyCreatedAt = Date.parse(key.createdAt);
|
|
120
|
+
|
|
121
|
+
if (Number.isNaN(signatureTime) || Number.isNaN(keyCreatedAt)) {
|
|
122
|
+
throw new ApiRegistryValidationError(
|
|
123
|
+
API_REGISTRY_ERROR_CODES.keyTrustInvalid,
|
|
124
|
+
'Invalid timestamp in key trust evaluation'
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (signatureTime < keyCreatedAt) {
|
|
129
|
+
throw new ApiRegistryValidationError(
|
|
130
|
+
API_REGISTRY_ERROR_CODES.keyTrustInvalid,
|
|
131
|
+
'Signature predates key creation'
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (key.status === 'compromised') {
|
|
136
|
+
const cutoff = Date.parse(key.compromiseDetectedAt ?? '');
|
|
137
|
+
if (Number.isNaN(cutoff) || signatureTime >= cutoff) {
|
|
138
|
+
throw new ApiRegistryValidationError(
|
|
139
|
+
API_REGISTRY_ERROR_CODES.keyTrustInvalid,
|
|
140
|
+
'Signature is outside historical trust window for compromised key'
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function evaluateAuditExitCode(input: {
|
|
147
|
+
mode: 'ci' | 'local';
|
|
148
|
+
yanked: boolean;
|
|
149
|
+
integrityFailure: boolean;
|
|
150
|
+
findings: AdvisoryFinding[];
|
|
151
|
+
}): number {
|
|
152
|
+
if (input.integrityFailure) return API_AUDIT_EXIT_CODES.integrityFailure;
|
|
153
|
+
if (input.yanked) return API_AUDIT_EXIT_CODES.yankedBlocked;
|
|
154
|
+
|
|
155
|
+
const hasExploitKnown = input.findings.some((finding) => Boolean(finding.exploitKnown));
|
|
156
|
+
const hasCritical = input.findings.some((finding) => finding.severity === 'critical');
|
|
157
|
+
const hasHigh = input.findings.some((finding) => finding.severity === 'high');
|
|
158
|
+
|
|
159
|
+
if (hasExploitKnown || hasCritical) {
|
|
160
|
+
return API_AUDIT_EXIT_CODES.advisoryBlocked;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (input.mode === 'ci' && hasHigh) {
|
|
164
|
+
return API_AUDIT_EXIT_CODES.advisoryBlocked;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (input.mode === 'local' && hasHigh) {
|
|
168
|
+
return API_AUDIT_EXIT_CODES.warning;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return API_AUDIT_EXIT_CODES.ok;
|
|
172
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { prisma } from './db';
|
|
2
|
+
import { createCredential, deleteCredential, getCredential, listCredentials, readCredentialSecrets, updateCredential } from './credentials';
|
|
3
|
+
import { getPrimaryVaultId, isVaultUnlocked, listVaults } from './cold';
|
|
4
|
+
import { CredentialField, CredentialFile } from '../types';
|
|
5
|
+
import { normalizeScope } from './credential-scope';
|
|
6
|
+
|
|
7
|
+
const APIKEY_TYPE = 'apikey';
|
|
8
|
+
export const APIKEY_DB_PLACEHOLDER = '__AURAMAXX_VAULT_ONLY__';
|
|
9
|
+
|
|
10
|
+
let migrationInFlight: Promise<void> | null = null;
|
|
11
|
+
let migrationSettled = false;
|
|
12
|
+
|
|
13
|
+
export interface ApiKeyCredentialRecord {
|
|
14
|
+
id: string;
|
|
15
|
+
service: string;
|
|
16
|
+
name: string;
|
|
17
|
+
keyMasked: string;
|
|
18
|
+
metadata: unknown;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getActiveVaultId(): string | null {
|
|
24
|
+
const primary = getPrimaryVaultId();
|
|
25
|
+
if (primary && isVaultUnlocked(primary)) {
|
|
26
|
+
return primary;
|
|
27
|
+
}
|
|
28
|
+
const unlocked = listVaults().find(vault => vault.isUnlocked);
|
|
29
|
+
return unlocked?.id || null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function parseMetadata(metadata: string | null): unknown {
|
|
33
|
+
if (!metadata) return null;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(metadata);
|
|
36
|
+
} catch {
|
|
37
|
+
return metadata;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function maskKey(key: string): string {
|
|
42
|
+
if (key.length <= 8) {
|
|
43
|
+
return '*'.repeat(key.length);
|
|
44
|
+
}
|
|
45
|
+
return `${key.slice(0, 4)}${'*'.repeat(key.length - 8)}${key.slice(-4)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function listApiKeyCredentialsRaw(): CredentialFile[] {
|
|
49
|
+
return listCredentials({ type: APIKEY_TYPE });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function findApiKeyCredential(service: string, name: string): CredentialFile | null {
|
|
53
|
+
const normalizedService = normalizeScope(service);
|
|
54
|
+
const normalizedName = normalizeScope(name);
|
|
55
|
+
|
|
56
|
+
for (const credential of listApiKeyCredentialsRaw()) {
|
|
57
|
+
const metaService = typeof credential.meta.service === 'string' ? normalizeScope(credential.meta.service) : '';
|
|
58
|
+
const metaName = typeof credential.meta.name === 'string' ? normalizeScope(credential.meta.name) : '';
|
|
59
|
+
if (metaService === normalizedService && metaName === normalizedName) {
|
|
60
|
+
return credential;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function findApiKeyCredentialsByService(service: string): CredentialFile[] {
|
|
68
|
+
const normalizedService = normalizeScope(service);
|
|
69
|
+
return listApiKeyCredentialsRaw().filter((credential) => {
|
|
70
|
+
const metaService = typeof credential.meta.service === 'string' ? normalizeScope(credential.meta.service) : '';
|
|
71
|
+
return metaService === normalizedService;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function toApiKeyRecord(credential: CredentialFile): ApiKeyCredentialRecord {
|
|
76
|
+
const service = typeof credential.meta.service === 'string' ? credential.meta.service : '';
|
|
77
|
+
const name = typeof credential.meta.name === 'string' ? credential.meta.name : credential.name;
|
|
78
|
+
const keyMasked = typeof credential.meta.keyMasked === 'string' ? credential.meta.keyMasked : '********';
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
id: credential.id,
|
|
82
|
+
service,
|
|
83
|
+
name,
|
|
84
|
+
keyMasked,
|
|
85
|
+
metadata: credential.meta.metadata ?? null,
|
|
86
|
+
createdAt: credential.createdAt,
|
|
87
|
+
updatedAt: credential.updatedAt,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildApiKeyMeta(service: string, name: string, key: string, metadata: unknown): Record<string, unknown> {
|
|
92
|
+
return {
|
|
93
|
+
service,
|
|
94
|
+
name,
|
|
95
|
+
tags: [normalizeScope(service)],
|
|
96
|
+
keyMasked: maskKey(key),
|
|
97
|
+
metadata: metadata ?? null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function apiKeySecretField(key: string): CredentialField[] {
|
|
102
|
+
return [{ key: 'key', value: key, type: 'secret', sensitive: true }];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isLegacyPlaintextKey(value: string): boolean {
|
|
106
|
+
return value.trim().length > 0 && value !== APIKEY_DB_PLACEHOLDER;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function migrateApiKeysFromDatabase(): Promise<{
|
|
110
|
+
migrated: number;
|
|
111
|
+
skipped: number;
|
|
112
|
+
reason?: string;
|
|
113
|
+
}> {
|
|
114
|
+
const rows = await prisma.apiKey.findMany({
|
|
115
|
+
where: { isActive: true },
|
|
116
|
+
orderBy: { createdAt: 'asc' },
|
|
117
|
+
});
|
|
118
|
+
if (rows.length === 0) {
|
|
119
|
+
return { migrated: 0, skipped: 0 };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const vaultId = getActiveVaultId();
|
|
123
|
+
if (!vaultId) {
|
|
124
|
+
return { migrated: 0, skipped: rows.length, reason: 'No unlocked vault available for credential migration' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let migrated = 0;
|
|
128
|
+
let skipped = 0;
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
if (!isLegacyPlaintextKey(row.key)) {
|
|
131
|
+
skipped++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const existing = findApiKeyCredential(row.service, row.name);
|
|
135
|
+
const meta = buildApiKeyMeta(row.service, row.name, row.key, parseMetadata(row.metadata));
|
|
136
|
+
if (existing) {
|
|
137
|
+
updateCredential(existing.id, {
|
|
138
|
+
meta,
|
|
139
|
+
sensitiveFields: apiKeySecretField(row.key),
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
createCredential(vaultId, APIKEY_TYPE, `${row.service}:${row.name}`, meta, apiKeySecretField(row.key));
|
|
143
|
+
}
|
|
144
|
+
await prisma.apiKey.update({
|
|
145
|
+
where: { id: row.id },
|
|
146
|
+
data: {
|
|
147
|
+
key: APIKEY_DB_PLACEHOLDER,
|
|
148
|
+
updatedAt: new Date(),
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
migrated++;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { migrated, skipped };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function ensureApiKeysMigrated(): Promise<void> {
|
|
158
|
+
if (migrationSettled) return;
|
|
159
|
+
if (!migrationInFlight) {
|
|
160
|
+
migrationInFlight = (async () => {
|
|
161
|
+
const result = await migrateApiKeysFromDatabase();
|
|
162
|
+
if (!result.reason) {
|
|
163
|
+
migrationSettled = true;
|
|
164
|
+
}
|
|
165
|
+
})().finally(() => {
|
|
166
|
+
migrationInFlight = null;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await migrationInFlight;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function listApiKeyCredentials(): ApiKeyCredentialRecord[] {
|
|
173
|
+
return listApiKeyCredentialsRaw().map(toApiKeyRecord);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function upsertApiKeyCredential(
|
|
177
|
+
service: string,
|
|
178
|
+
name: string,
|
|
179
|
+
key: string,
|
|
180
|
+
metadata: unknown,
|
|
181
|
+
): ApiKeyCredentialRecord {
|
|
182
|
+
const vaultId = getActiveVaultId();
|
|
183
|
+
if (!vaultId) {
|
|
184
|
+
throw new Error('No unlocked vault available for API key credential storage');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const existing = findApiKeyCredential(service, name);
|
|
188
|
+
const nextMeta = buildApiKeyMeta(service, name, key, metadata);
|
|
189
|
+
|
|
190
|
+
const credential = existing
|
|
191
|
+
? updateCredential(existing.id, {
|
|
192
|
+
meta: nextMeta,
|
|
193
|
+
sensitiveFields: apiKeySecretField(key),
|
|
194
|
+
})
|
|
195
|
+
: createCredential(
|
|
196
|
+
vaultId,
|
|
197
|
+
APIKEY_TYPE,
|
|
198
|
+
`${service}:${name}`,
|
|
199
|
+
nextMeta,
|
|
200
|
+
apiKeySecretField(key),
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return toApiKeyRecord(credential);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function deleteApiKeyCredentialById(id: string): ApiKeyCredentialRecord | null {
|
|
207
|
+
const credential = getCredential(id);
|
|
208
|
+
if (!credential || credential.type !== APIKEY_TYPE) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const record = toApiKeyRecord(credential);
|
|
212
|
+
deleteCredential(id);
|
|
213
|
+
return record;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function deleteApiKeyCredentialByServiceName(service: string, name: string): ApiKeyCredentialRecord | null {
|
|
217
|
+
const credential = findApiKeyCredential(service, name);
|
|
218
|
+
if (!credential) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const record = toApiKeyRecord(credential);
|
|
222
|
+
deleteCredential(credential.id);
|
|
223
|
+
return record;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function readApiKeyValueByServiceName(service: string, name: string): string | null {
|
|
227
|
+
const credential = findApiKeyCredential(service, name);
|
|
228
|
+
if (!credential) return null;
|
|
229
|
+
try {
|
|
230
|
+
const fields = readCredentialSecrets(credential.id);
|
|
231
|
+
const keyField = fields.find(field => normalizeScope(field.key) === 'key');
|
|
232
|
+
return keyField?.value || null;
|
|
233
|
+
} catch {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function readApiKeyValueByService(service: string): string | null {
|
|
239
|
+
const credentials = findApiKeyCredentialsByService(service);
|
|
240
|
+
if (credentials.length === 0) return null;
|
|
241
|
+
|
|
242
|
+
const preferred = credentials.find((credential) => {
|
|
243
|
+
const metaName = typeof credential.meta.name === 'string' ? normalizeScope(credential.meta.name) : '';
|
|
244
|
+
return metaName === 'default';
|
|
245
|
+
}) || credentials[0];
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const fields = readCredentialSecrets(preferred.id);
|
|
249
|
+
const keyField = fields.find(field => normalizeScope(field.key) === 'key');
|
|
250
|
+
return keyField?.value || null;
|
|
251
|
+
} catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function hasActiveApiKeyCredential(service: string): boolean {
|
|
257
|
+
return findApiKeyCredentialsByService(service).length > 0;
|
|
258
|
+
}
|