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,119 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { requireWorkspaceAdmin } from '../../../auth';
|
|
4
|
+
|
|
5
|
+
const prisma = new PrismaClient();
|
|
6
|
+
|
|
7
|
+
// PATCH /api/workspace/[id]/apps/[wid] - Update app
|
|
8
|
+
export async function PATCH(
|
|
9
|
+
request: NextRequest,
|
|
10
|
+
{ params }: { params: Promise<{ id: string; wid: string }> }
|
|
11
|
+
) {
|
|
12
|
+
try {
|
|
13
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
14
|
+
if (unauthorized) return unauthorized;
|
|
15
|
+
|
|
16
|
+
const { id: workspaceId, wid: appId } = await params;
|
|
17
|
+
const body = await request.json();
|
|
18
|
+
const { x, y, width, height, zIndex, isVisible, isLocked, config } = body;
|
|
19
|
+
|
|
20
|
+
// Verify app exists and belongs to workspace
|
|
21
|
+
const existing = await prisma.workspaceApp.findUnique({
|
|
22
|
+
where: { id: appId },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!existing) {
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ success: false, error: 'App not found' },
|
|
28
|
+
{ status: 404 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (existing.workspaceId !== workspaceId) {
|
|
33
|
+
return NextResponse.json(
|
|
34
|
+
{ success: false, error: 'App does not belong to this workspace' },
|
|
35
|
+
{ status: 400 }
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const updateData: Record<string, unknown> = {};
|
|
40
|
+
if (x !== undefined) updateData.x = x;
|
|
41
|
+
if (y !== undefined) updateData.y = y;
|
|
42
|
+
if (width !== undefined) updateData.width = width;
|
|
43
|
+
if (height !== undefined) updateData.height = height;
|
|
44
|
+
if (zIndex !== undefined) updateData.zIndex = zIndex;
|
|
45
|
+
if (isVisible !== undefined) updateData.isVisible = isVisible;
|
|
46
|
+
if (isLocked !== undefined) updateData.isLocked = isLocked;
|
|
47
|
+
if (config !== undefined) updateData.config = JSON.stringify(config);
|
|
48
|
+
|
|
49
|
+
const app = await prisma.workspaceApp.update({
|
|
50
|
+
where: { id: appId },
|
|
51
|
+
data: updateData,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return NextResponse.json({
|
|
55
|
+
success: true,
|
|
56
|
+
app: {
|
|
57
|
+
id: app.id,
|
|
58
|
+
workspaceId: app.workspaceId,
|
|
59
|
+
appType: app.appType,
|
|
60
|
+
x: app.x,
|
|
61
|
+
y: app.y,
|
|
62
|
+
width: app.width,
|
|
63
|
+
height: app.height,
|
|
64
|
+
zIndex: app.zIndex,
|
|
65
|
+
isVisible: app.isVisible,
|
|
66
|
+
isLocked: app.isLocked,
|
|
67
|
+
config: app.config ? JSON.parse(app.config) : null,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('Failed to update app:', error);
|
|
72
|
+
return NextResponse.json(
|
|
73
|
+
{ success: false, error: 'Failed to update app' },
|
|
74
|
+
{ status: 500 }
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// DELETE /api/workspace/[id]/apps/[wid] - Remove app
|
|
80
|
+
export async function DELETE(
|
|
81
|
+
request: NextRequest,
|
|
82
|
+
{ params }: { params: Promise<{ id: string; wid: string }> }
|
|
83
|
+
) {
|
|
84
|
+
try {
|
|
85
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
86
|
+
if (unauthorized) return unauthorized;
|
|
87
|
+
|
|
88
|
+
const { id: workspaceId, wid: appId } = await params;
|
|
89
|
+
|
|
90
|
+
// Verify app exists and belongs to workspace
|
|
91
|
+
const existing = await prisma.workspaceApp.findUnique({
|
|
92
|
+
where: { id: appId },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (!existing) {
|
|
96
|
+
return NextResponse.json(
|
|
97
|
+
{ success: false, error: 'App not found' },
|
|
98
|
+
{ status: 404 }
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (existing.workspaceId !== workspaceId) {
|
|
103
|
+
return NextResponse.json(
|
|
104
|
+
{ success: false, error: 'App does not belong to this workspace' },
|
|
105
|
+
{ status: 400 }
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
await prisma.workspaceApp.delete({ where: { id: appId } });
|
|
110
|
+
|
|
111
|
+
return NextResponse.json({ success: true });
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('Failed to delete app:', error);
|
|
114
|
+
return NextResponse.json(
|
|
115
|
+
{ success: false, error: 'Failed to delete app' },
|
|
116
|
+
{ status: 500 }
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { requireWorkspaceAdmin } from '../../auth';
|
|
4
|
+
|
|
5
|
+
const prisma = new PrismaClient();
|
|
6
|
+
|
|
7
|
+
// POST /api/workspace/[id]/apps - Add app to workspace
|
|
8
|
+
export async function POST(
|
|
9
|
+
request: NextRequest,
|
|
10
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
11
|
+
) {
|
|
12
|
+
try {
|
|
13
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
14
|
+
if (unauthorized) return unauthorized;
|
|
15
|
+
|
|
16
|
+
const { id: workspaceId } = await params;
|
|
17
|
+
const body = await request.json();
|
|
18
|
+
const { appType, x, y, width, height, zIndex, isVisible, isLocked, config } = body;
|
|
19
|
+
|
|
20
|
+
if (!appType) {
|
|
21
|
+
return NextResponse.json(
|
|
22
|
+
{ success: false, error: 'appType is required' },
|
|
23
|
+
{ status: 400 }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Verify workspace exists
|
|
28
|
+
const workspace = await prisma.workspace.findUnique({ where: { id: workspaceId } });
|
|
29
|
+
if (!workspace) {
|
|
30
|
+
return NextResponse.json(
|
|
31
|
+
{ success: false, error: 'Workspace not found' },
|
|
32
|
+
{ status: 404 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Get max zIndex for this workspace
|
|
37
|
+
const maxZ = await prisma.workspaceApp.aggregate({
|
|
38
|
+
where: { workspaceId },
|
|
39
|
+
_max: { zIndex: true },
|
|
40
|
+
});
|
|
41
|
+
const newZIndex = zIndex ?? (maxZ._max.zIndex ?? 9) + 1;
|
|
42
|
+
|
|
43
|
+
const app = await prisma.workspaceApp.create({
|
|
44
|
+
data: {
|
|
45
|
+
workspaceId,
|
|
46
|
+
appType,
|
|
47
|
+
x: x ?? 20,
|
|
48
|
+
y: y ?? 20,
|
|
49
|
+
width: width ?? 320,
|
|
50
|
+
height: height ?? 280,
|
|
51
|
+
zIndex: newZIndex,
|
|
52
|
+
isVisible: isVisible ?? true,
|
|
53
|
+
isLocked: isLocked ?? false,
|
|
54
|
+
config: config ? JSON.stringify(config) : null,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return NextResponse.json({
|
|
59
|
+
success: true,
|
|
60
|
+
app: {
|
|
61
|
+
id: app.id,
|
|
62
|
+
workspaceId: app.workspaceId,
|
|
63
|
+
appType: app.appType,
|
|
64
|
+
x: app.x,
|
|
65
|
+
y: app.y,
|
|
66
|
+
width: app.width,
|
|
67
|
+
height: app.height,
|
|
68
|
+
zIndex: app.zIndex,
|
|
69
|
+
isVisible: app.isVisible,
|
|
70
|
+
isLocked: app.isLocked,
|
|
71
|
+
config: app.config ? JSON.parse(app.config) : null,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Failed to add app:', error);
|
|
76
|
+
return NextResponse.json(
|
|
77
|
+
{ success: false, error: 'Failed to add app' },
|
|
78
|
+
{ status: 500 }
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { requireWorkspaceAdmin } from '../../auth';
|
|
4
|
+
|
|
5
|
+
const prisma = new PrismaClient();
|
|
6
|
+
|
|
7
|
+
// GET /api/workspace/[id]/export - Export workspace as JSON
|
|
8
|
+
export async function GET(
|
|
9
|
+
request: NextRequest,
|
|
10
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
11
|
+
) {
|
|
12
|
+
try {
|
|
13
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
14
|
+
if (unauthorized) return unauthorized;
|
|
15
|
+
|
|
16
|
+
const { id } = await params;
|
|
17
|
+
|
|
18
|
+
const workspace = await prisma.workspace.findUnique({
|
|
19
|
+
where: { id },
|
|
20
|
+
include: {
|
|
21
|
+
apps: true,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!workspace) {
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ success: false, error: 'Workspace not found' },
|
|
28
|
+
{ status: 404 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const exportData = {
|
|
33
|
+
version: 1,
|
|
34
|
+
exportedAt: new Date().toISOString(),
|
|
35
|
+
workspace: {
|
|
36
|
+
name: workspace.name,
|
|
37
|
+
slug: workspace.slug,
|
|
38
|
+
icon: workspace.icon,
|
|
39
|
+
order: workspace.order,
|
|
40
|
+
isDefault: workspace.isDefault,
|
|
41
|
+
isCloseable: workspace.isCloseable,
|
|
42
|
+
},
|
|
43
|
+
apps: workspace.apps.map((w: any) => ({
|
|
44
|
+
appType: w.appType,
|
|
45
|
+
x: w.x,
|
|
46
|
+
y: w.y,
|
|
47
|
+
width: w.width,
|
|
48
|
+
height: w.height,
|
|
49
|
+
zIndex: w.zIndex,
|
|
50
|
+
isVisible: w.isVisible,
|
|
51
|
+
isLocked: w.isLocked,
|
|
52
|
+
config: w.config ? JSON.parse(w.config) : null,
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return NextResponse.json({
|
|
57
|
+
success: true,
|
|
58
|
+
data: exportData,
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Failed to export workspace:', error);
|
|
62
|
+
return NextResponse.json(
|
|
63
|
+
{ success: false, error: 'Failed to export workspace' },
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { requireWorkspaceAdmin } from '../auth';
|
|
4
|
+
|
|
5
|
+
const prisma = new PrismaClient();
|
|
6
|
+
|
|
7
|
+
// GET /api/workspace/[id] - Get workspace with apps
|
|
8
|
+
export async function GET(
|
|
9
|
+
request: NextRequest,
|
|
10
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
11
|
+
) {
|
|
12
|
+
try {
|
|
13
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
14
|
+
if (unauthorized) return unauthorized;
|
|
15
|
+
|
|
16
|
+
const { id } = await params;
|
|
17
|
+
|
|
18
|
+
const workspace = await prisma.workspace.findUnique({
|
|
19
|
+
where: { id },
|
|
20
|
+
include: {
|
|
21
|
+
apps: {
|
|
22
|
+
orderBy: { zIndex: 'asc' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!workspace) {
|
|
28
|
+
return NextResponse.json(
|
|
29
|
+
{ success: false, error: 'Workspace not found' },
|
|
30
|
+
{ status: 404 }
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return NextResponse.json({
|
|
35
|
+
success: true,
|
|
36
|
+
workspace: {
|
|
37
|
+
id: workspace.id,
|
|
38
|
+
name: workspace.name,
|
|
39
|
+
slug: workspace.slug,
|
|
40
|
+
icon: workspace.icon,
|
|
41
|
+
order: workspace.order,
|
|
42
|
+
isDefault: workspace.isDefault,
|
|
43
|
+
isCloseable: workspace.isCloseable,
|
|
44
|
+
},
|
|
45
|
+
apps: workspace.apps.map((w: any) => ({
|
|
46
|
+
id: w.id,
|
|
47
|
+
workspaceId: w.workspaceId,
|
|
48
|
+
appType: w.appType,
|
|
49
|
+
x: w.x,
|
|
50
|
+
y: w.y,
|
|
51
|
+
width: w.width,
|
|
52
|
+
height: w.height,
|
|
53
|
+
zIndex: w.zIndex,
|
|
54
|
+
isVisible: w.isVisible,
|
|
55
|
+
isLocked: w.isLocked,
|
|
56
|
+
config: w.config ? JSON.parse(w.config) : null,
|
|
57
|
+
})),
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Failed to get workspace:', error);
|
|
61
|
+
return NextResponse.json(
|
|
62
|
+
{ success: false, error: 'Failed to get workspace' },
|
|
63
|
+
{ status: 500 }
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// PATCH /api/workspace/[id] - Update workspace
|
|
69
|
+
export async function PATCH(
|
|
70
|
+
request: NextRequest,
|
|
71
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
72
|
+
) {
|
|
73
|
+
try {
|
|
74
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
75
|
+
if (unauthorized) return unauthorized;
|
|
76
|
+
|
|
77
|
+
const { id } = await params;
|
|
78
|
+
const body = await request.json();
|
|
79
|
+
const { name, icon, order, isDefault, isCloseable } = body;
|
|
80
|
+
|
|
81
|
+
// Check if workspace exists
|
|
82
|
+
const existing = await prisma.workspace.findUnique({ where: { id } });
|
|
83
|
+
if (!existing) {
|
|
84
|
+
return NextResponse.json(
|
|
85
|
+
{ success: false, error: 'Workspace not found' },
|
|
86
|
+
{ status: 404 }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// If setting as default, unset existing default
|
|
91
|
+
if (isDefault) {
|
|
92
|
+
await prisma.workspace.updateMany({
|
|
93
|
+
where: { isDefault: true, id: { not: id } },
|
|
94
|
+
data: { isDefault: false },
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const workspace = await prisma.workspace.update({
|
|
99
|
+
where: { id },
|
|
100
|
+
data: {
|
|
101
|
+
name: name ?? existing.name,
|
|
102
|
+
icon: icon ?? existing.icon,
|
|
103
|
+
order: order ?? existing.order,
|
|
104
|
+
isDefault: isDefault ?? existing.isDefault,
|
|
105
|
+
isCloseable: isCloseable ?? existing.isCloseable,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return NextResponse.json({
|
|
110
|
+
success: true,
|
|
111
|
+
workspace: {
|
|
112
|
+
id: workspace.id,
|
|
113
|
+
name: workspace.name,
|
|
114
|
+
slug: workspace.slug,
|
|
115
|
+
icon: workspace.icon,
|
|
116
|
+
order: workspace.order,
|
|
117
|
+
isDefault: workspace.isDefault,
|
|
118
|
+
isCloseable: workspace.isCloseable,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Failed to update workspace:', error);
|
|
123
|
+
return NextResponse.json(
|
|
124
|
+
{ success: false, error: 'Failed to update workspace' },
|
|
125
|
+
{ status: 500 }
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// DELETE /api/workspace/[id] - Delete workspace
|
|
131
|
+
export async function DELETE(
|
|
132
|
+
request: NextRequest,
|
|
133
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
134
|
+
) {
|
|
135
|
+
try {
|
|
136
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
137
|
+
if (unauthorized) return unauthorized;
|
|
138
|
+
|
|
139
|
+
const { id } = await params;
|
|
140
|
+
|
|
141
|
+
// Check if workspace exists and is closeable
|
|
142
|
+
const workspace = await prisma.workspace.findUnique({ where: { id } });
|
|
143
|
+
if (!workspace) {
|
|
144
|
+
return NextResponse.json(
|
|
145
|
+
{ success: false, error: 'Workspace not found' },
|
|
146
|
+
{ status: 404 }
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!workspace.isCloseable) {
|
|
151
|
+
return NextResponse.json(
|
|
152
|
+
{ success: false, error: 'Cannot delete non-closeable workspace' },
|
|
153
|
+
{ status: 400 }
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Cascade delete will remove apps
|
|
158
|
+
await prisma.workspace.delete({ where: { id } });
|
|
159
|
+
|
|
160
|
+
return NextResponse.json({ success: true });
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Failed to delete workspace:', error);
|
|
163
|
+
return NextResponse.json(
|
|
164
|
+
{ success: false, error: 'Failed to delete workspace' },
|
|
165
|
+
{ status: 500 }
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
const WALLET_API = process.env.WALLET_SERVER_URL || 'http://localhost:4242';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validate admin access with explicit token validation.
|
|
7
|
+
* This must never trust public endpoints like GET /setup.
|
|
8
|
+
*/
|
|
9
|
+
async function validateAdmin(authHeader: string | null): Promise<boolean> {
|
|
10
|
+
if (!authHeader) return false;
|
|
11
|
+
const [scheme, token] = authHeader.trim().split(/\s+/, 2);
|
|
12
|
+
if (!scheme || scheme.toLowerCase() !== 'bearer' || !token) return false;
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const resp = await fetch(`${WALLET_API}/auth/validate`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { 'Content-Type': 'application/json' },
|
|
18
|
+
body: JSON.stringify({ token }),
|
|
19
|
+
cache: 'no-store',
|
|
20
|
+
});
|
|
21
|
+
if (!resp.ok) return false;
|
|
22
|
+
const data = await resp.json() as { valid?: boolean; isAdmin?: boolean };
|
|
23
|
+
return data.valid === true && data.isAdmin === true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function requireWorkspaceAdmin(
|
|
30
|
+
request: NextRequest
|
|
31
|
+
): Promise<NextResponse | null> {
|
|
32
|
+
const authHeader = request.headers.get('authorization');
|
|
33
|
+
const isAdmin = await validateAdmin(authHeader);
|
|
34
|
+
if (isAdmin) return null;
|
|
35
|
+
|
|
36
|
+
return NextResponse.json(
|
|
37
|
+
{ success: false, error: 'Admin access required' },
|
|
38
|
+
{ status: 403 }
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { requireWorkspaceAdmin } from '../auth';
|
|
4
|
+
|
|
5
|
+
const prisma = new PrismaClient();
|
|
6
|
+
|
|
7
|
+
type ParsedChainConfig = AppConfigData & Record<string, ChainConfig>;
|
|
8
|
+
|
|
9
|
+
function parseChainConfig(raw?: string | null): ParsedChainConfig {
|
|
10
|
+
if (!raw) return {};
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(raw);
|
|
13
|
+
if (parsed && typeof parsed === 'object') {
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.warn('Invalid AppConfig.chainConfig JSON, falling back to empty overrides:', error);
|
|
18
|
+
}
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ChainConfig {
|
|
23
|
+
rpc: string;
|
|
24
|
+
chainId: number;
|
|
25
|
+
explorer: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AppConfigData {
|
|
29
|
+
chainOverrides?: Record<string, ChainConfig>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// GET /api/workspace/config - Get global app configuration
|
|
33
|
+
export async function GET(request: NextRequest) {
|
|
34
|
+
try {
|
|
35
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
36
|
+
if (unauthorized) return unauthorized;
|
|
37
|
+
|
|
38
|
+
const config = await prisma.appConfig.findUnique({
|
|
39
|
+
where: { id: 'global' },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!config) {
|
|
43
|
+
return NextResponse.json({
|
|
44
|
+
success: true,
|
|
45
|
+
config: { chainOverrides: {} },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const chainConfig = parseChainConfig(config.chainConfig);
|
|
50
|
+
|
|
51
|
+
return NextResponse.json({
|
|
52
|
+
success: true,
|
|
53
|
+
config: {
|
|
54
|
+
// Handle both old format (direct overrides) and new format (nested)
|
|
55
|
+
chainOverrides: chainConfig.chainOverrides || chainConfig,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error('Failed to get app config:', error);
|
|
60
|
+
return NextResponse.json(
|
|
61
|
+
{ success: false, error: 'Failed to get app config' },
|
|
62
|
+
{ status: 500 }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// POST /api/workspace/config - Update global app configuration
|
|
68
|
+
export async function POST(request: NextRequest) {
|
|
69
|
+
try {
|
|
70
|
+
const unauthorized = await requireWorkspaceAdmin(request);
|
|
71
|
+
if (unauthorized) return unauthorized;
|
|
72
|
+
|
|
73
|
+
const body = await request.json();
|
|
74
|
+
const { chainOverrides } = body as AppConfigData;
|
|
75
|
+
|
|
76
|
+
// Validate chain overrides if provided
|
|
77
|
+
if (chainOverrides) {
|
|
78
|
+
for (const [chain, config] of Object.entries(chainOverrides)) {
|
|
79
|
+
if (!config.rpc || typeof config.rpc !== 'string') {
|
|
80
|
+
return NextResponse.json(
|
|
81
|
+
{ success: false, error: `Invalid RPC for chain ${chain}` },
|
|
82
|
+
{ status: 400 }
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (!config.chainId || typeof config.chainId !== 'number') {
|
|
86
|
+
return NextResponse.json(
|
|
87
|
+
{ success: false, error: `Invalid chainId for chain ${chain}` },
|
|
88
|
+
{ status: 400 }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Upsert the global config
|
|
95
|
+
const updated = await prisma.appConfig.upsert({
|
|
96
|
+
where: { id: 'global' },
|
|
97
|
+
create: {
|
|
98
|
+
id: 'global',
|
|
99
|
+
chainConfig: JSON.stringify(chainOverrides || {}),
|
|
100
|
+
},
|
|
101
|
+
update: {
|
|
102
|
+
chainConfig: JSON.stringify(chainOverrides || {}),
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const parsedConfig = parseChainConfig(updated.chainConfig ?? undefined);
|
|
107
|
+
|
|
108
|
+
return NextResponse.json({
|
|
109
|
+
success: true,
|
|
110
|
+
config: {
|
|
111
|
+
chainOverrides: parsedConfig,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('Failed to update app config:', error);
|
|
116
|
+
return NextResponse.json(
|
|
117
|
+
{ success: false, error: 'Failed to update app config' },
|
|
118
|
+
{ status: 500 }
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|