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,132 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { installApp, removeApp } from '../../../../../server/lib/app-installer';
|
|
3
|
+
|
|
4
|
+
const WALLET_API = process.env.WALLET_SERVER_URL || 'http://localhost:4242';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validate admin access with explicit token validation.
|
|
8
|
+
* This must never trust public endpoints like GET /setup.
|
|
9
|
+
*/
|
|
10
|
+
async function validateAdmin(authHeader: string | null): Promise<boolean> {
|
|
11
|
+
if (!authHeader) return false;
|
|
12
|
+
const [scheme, token] = authHeader.trim().split(/\s+/, 2);
|
|
13
|
+
if (!scheme || scheme.toLowerCase() !== 'bearer' || !token) return false;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const resp = await fetch(`${WALLET_API}/auth/validate`, {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: { 'Content-Type': 'application/json' },
|
|
19
|
+
body: JSON.stringify({ token }),
|
|
20
|
+
cache: 'no-store',
|
|
21
|
+
});
|
|
22
|
+
if (!resp.ok) return false;
|
|
23
|
+
const data = await resp.json() as { valid?: boolean; isAdmin?: boolean };
|
|
24
|
+
return data.valid === true && data.isAdmin === true;
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* POST /api/apps/install — Install a app from a source
|
|
32
|
+
* Body: { source: string, name?: string, force?: boolean }
|
|
33
|
+
*/
|
|
34
|
+
export async function POST(req: NextRequest) {
|
|
35
|
+
const authHeader = req.headers.get('authorization');
|
|
36
|
+
const isAdmin = await validateAdmin(authHeader);
|
|
37
|
+
if (!isAdmin) {
|
|
38
|
+
return NextResponse.json(
|
|
39
|
+
{ success: false, error: 'Admin access required' },
|
|
40
|
+
{ status: 403 },
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const body = await req.json();
|
|
46
|
+
const { source, name, force } = body;
|
|
47
|
+
|
|
48
|
+
if (!source || typeof source !== 'string') {
|
|
49
|
+
return NextResponse.json(
|
|
50
|
+
{ success: false, error: 'source is required' },
|
|
51
|
+
{ status: 400 },
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = installApp(source, { name, force });
|
|
56
|
+
|
|
57
|
+
// Hot-reload: create token for the new app without restart
|
|
58
|
+
try {
|
|
59
|
+
await fetch(`${WALLET_API}/apps/${result.id}/reload`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: authHeader!,
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
} catch {
|
|
67
|
+
// Non-critical — app will get a token on next server restart
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return NextResponse.json({
|
|
71
|
+
success: true,
|
|
72
|
+
app: {
|
|
73
|
+
id: result.id,
|
|
74
|
+
name: result.name,
|
|
75
|
+
source: result.source,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
} catch (err) {
|
|
79
|
+
const message = err instanceof Error ? err.message : 'Install failed';
|
|
80
|
+
return NextResponse.json(
|
|
81
|
+
{ success: false, error: message },
|
|
82
|
+
{ status: 400 },
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* DELETE /api/apps/install — Remove an installed app
|
|
89
|
+
* Body: { appId: string }
|
|
90
|
+
*/
|
|
91
|
+
export async function DELETE(req: NextRequest) {
|
|
92
|
+
const authHeader = req.headers.get('authorization');
|
|
93
|
+
const isAdmin = await validateAdmin(authHeader);
|
|
94
|
+
if (!isAdmin) {
|
|
95
|
+
return NextResponse.json(
|
|
96
|
+
{ success: false, error: 'Admin access required' },
|
|
97
|
+
{ status: 403 },
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const body = await req.json();
|
|
103
|
+
const { appId } = body;
|
|
104
|
+
|
|
105
|
+
if (!appId || typeof appId !== 'string') {
|
|
106
|
+
return NextResponse.json(
|
|
107
|
+
{ success: false, error: 'appId is required' },
|
|
108
|
+
{ status: 400 },
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Revoke the app's token via Express (separate process, holds token in memory)
|
|
113
|
+
try {
|
|
114
|
+
await fetch(`${WALLET_API}/apps/${appId}/approve`, {
|
|
115
|
+
method: 'DELETE',
|
|
116
|
+
headers: { Authorization: authHeader! },
|
|
117
|
+
});
|
|
118
|
+
} catch {
|
|
119
|
+
// Non-critical if Express is down — token expires in 24h max
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
removeApp(appId);
|
|
123
|
+
|
|
124
|
+
return NextResponse.json({ success: true, appId, removed: true });
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const message = err instanceof Error ? err.message : 'Remove failed';
|
|
127
|
+
return NextResponse.json(
|
|
128
|
+
{ success: false, error: message },
|
|
129
|
+
{ status: 400 },
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { loadAppManifests } from '@/lib/app-loader';
|
|
3
|
+
|
|
4
|
+
// GET /api/apps/manifests - Return all loaded app manifests
|
|
5
|
+
export async function GET() {
|
|
6
|
+
try {
|
|
7
|
+
const manifests = loadAppManifests();
|
|
8
|
+
return NextResponse.json({ success: true, manifests });
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error('Failed to load app manifests:', error);
|
|
11
|
+
return NextResponse.json(
|
|
12
|
+
{ success: false, error: 'Failed to load app manifests' },
|
|
13
|
+
{ status: 500 }
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
const MIME_TYPES: Record<string, string> = {
|
|
6
|
+
'.html': 'text/html',
|
|
7
|
+
'.css': 'text/css',
|
|
8
|
+
'.js': 'application/javascript',
|
|
9
|
+
'.json': 'application/json',
|
|
10
|
+
'.png': 'image/png',
|
|
11
|
+
'.jpg': 'image/jpeg',
|
|
12
|
+
'.svg': 'image/svg+xml',
|
|
13
|
+
'.gif': 'image/gif',
|
|
14
|
+
'.ico': 'image/x-icon',
|
|
15
|
+
'.woff': 'font/woff',
|
|
16
|
+
'.woff2': 'font/woff2',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// GET /api/apps/static/[...path] - Serve static files from apps/ directory
|
|
20
|
+
export async function GET(
|
|
21
|
+
_request: NextRequest,
|
|
22
|
+
{ params }: { params: Promise<{ path: string[] }> }
|
|
23
|
+
) {
|
|
24
|
+
try {
|
|
25
|
+
const { path: segments } = await params;
|
|
26
|
+
const relativePath = segments.join('/');
|
|
27
|
+
|
|
28
|
+
// Security: prevent path traversal
|
|
29
|
+
if (relativePath.includes('..') || relativePath.includes('\0')) {
|
|
30
|
+
return NextResponse.json({ error: 'Invalid path' }, { status: 400 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const appsDir = path.join(process.cwd(), 'apps');
|
|
34
|
+
const filePath = path.join(appsDir, relativePath);
|
|
35
|
+
|
|
36
|
+
// Ensure resolved path is within apps/
|
|
37
|
+
const resolved = path.resolve(filePath);
|
|
38
|
+
if (!resolved.startsWith(path.resolve(appsDir))) {
|
|
39
|
+
return NextResponse.json({ error: 'Invalid path' }, { status: 400 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
43
|
+
return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
47
|
+
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
48
|
+
const content = fs.readFileSync(filePath);
|
|
49
|
+
|
|
50
|
+
return new NextResponse(content, {
|
|
51
|
+
headers: { 'Content-Type': contentType },
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Failed to serve app static file:', error);
|
|
55
|
+
return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import {
|
|
3
|
+
README_DOC_FILENAME,
|
|
4
|
+
listDocFiles,
|
|
5
|
+
normalizeRequestedDocFilename,
|
|
6
|
+
readDocFile,
|
|
7
|
+
renderMarkdown,
|
|
8
|
+
} from '@/lib/docs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* GET /api/docs/plain?file=<filename>&q=<query>
|
|
12
|
+
* Returns docs list plus rendered markdown for selected file.
|
|
13
|
+
*/
|
|
14
|
+
export async function GET(request: NextRequest) {
|
|
15
|
+
try {
|
|
16
|
+
const { searchParams } = new URL(request.url);
|
|
17
|
+
const requestedFile = searchParams.get('file') || README_DOC_FILENAME;
|
|
18
|
+
const normalizedRequested = normalizeRequestedDocFilename(requestedFile);
|
|
19
|
+
const rawQuery = searchParams.get('q') || '';
|
|
20
|
+
const normalizedQuery = rawQuery.trim().toLowerCase();
|
|
21
|
+
const isDevMode = process.env.NODE_ENV !== 'production';
|
|
22
|
+
|
|
23
|
+
// Embedded vault docs only expose internal docs in dev mode.
|
|
24
|
+
const allDocs = (await listDocFiles()).filter((doc) => isDevMode || !doc.filename.startsWith('internal/'));
|
|
25
|
+
const contentByFile = new Map<string, string>();
|
|
26
|
+
const docs = normalizedQuery
|
|
27
|
+
? (await Promise.all(allDocs.map(async (doc) => {
|
|
28
|
+
const content = await readDocFile(doc.filename);
|
|
29
|
+
contentByFile.set(doc.filename, content);
|
|
30
|
+
const haystack = `${doc.filename}\n${doc.title}\n${doc.summary}\n${content}`.toLowerCase();
|
|
31
|
+
return haystack.includes(normalizedQuery) ? doc : null;
|
|
32
|
+
}))).filter((doc): doc is NonNullable<typeof doc> => doc !== null)
|
|
33
|
+
: allDocs;
|
|
34
|
+
|
|
35
|
+
if (docs.length === 0) {
|
|
36
|
+
const markdownHtml = normalizedQuery
|
|
37
|
+
? renderMarkdown(`No docs match \`${rawQuery.trim()}\`.`)
|
|
38
|
+
: renderMarkdown('No docs found.');
|
|
39
|
+
return NextResponse.json({
|
|
40
|
+
success: true,
|
|
41
|
+
docs: [],
|
|
42
|
+
selectedFile: '',
|
|
43
|
+
content: '',
|
|
44
|
+
markdownHtml,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const available = new Set(docs.map((doc) => doc.filename));
|
|
49
|
+
const fallback = available.has(README_DOC_FILENAME)
|
|
50
|
+
? README_DOC_FILENAME
|
|
51
|
+
: docs[0]?.filename || README_DOC_FILENAME;
|
|
52
|
+
const selectedFile = available.has(normalizedRequested) ? normalizedRequested : fallback;
|
|
53
|
+
const content = contentByFile.get(selectedFile) ?? await readDocFile(selectedFile);
|
|
54
|
+
const markdownHtml = renderMarkdown(content, { currentDocFilename: selectedFile });
|
|
55
|
+
|
|
56
|
+
return NextResponse.json({
|
|
57
|
+
success: true,
|
|
58
|
+
docs: docs.map((doc) => ({
|
|
59
|
+
filename: doc.filename,
|
|
60
|
+
title: doc.title,
|
|
61
|
+
summary: doc.summary,
|
|
62
|
+
})),
|
|
63
|
+
selectedFile,
|
|
64
|
+
content,
|
|
65
|
+
markdownHtml,
|
|
66
|
+
});
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error('[DocsPlain] Failed to load docs:', error);
|
|
69
|
+
return NextResponse.json(
|
|
70
|
+
{ success: false, error: 'Failed to load docs content' },
|
|
71
|
+
{ status: 500 },
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { broadcast } from '@/lib/websocket-server';
|
|
3
|
+
import { prisma } from '@/lib/db';
|
|
4
|
+
import type { WalletEvent } from '@/lib/events';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GET /api/events
|
|
8
|
+
* Query events from database with optional filtering
|
|
9
|
+
* No authentication required
|
|
10
|
+
*/
|
|
11
|
+
export async function GET(request: NextRequest) {
|
|
12
|
+
try {
|
|
13
|
+
const { searchParams } = new URL(request.url);
|
|
14
|
+
const type = searchParams.get('type');
|
|
15
|
+
const category = searchParams.get('category');
|
|
16
|
+
const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 250);
|
|
17
|
+
const offset = parseInt(searchParams.get('offset') || '0');
|
|
18
|
+
|
|
19
|
+
// Build where clause
|
|
20
|
+
const where: Record<string, unknown> = {};
|
|
21
|
+
if (type) {
|
|
22
|
+
where.type = type;
|
|
23
|
+
} else if (category) {
|
|
24
|
+
where.type = { startsWith: `${category}:` };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Query events
|
|
28
|
+
const [events, total] = await Promise.all([
|
|
29
|
+
prisma.event.findMany({
|
|
30
|
+
where,
|
|
31
|
+
orderBy: { timestamp: 'desc' },
|
|
32
|
+
take: limit,
|
|
33
|
+
skip: offset,
|
|
34
|
+
}),
|
|
35
|
+
prisma.event.count({ where }),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
return NextResponse.json({
|
|
39
|
+
success: true,
|
|
40
|
+
events: events.map((e: any) => ({
|
|
41
|
+
...e,
|
|
42
|
+
data: typeof e.data === 'string' ? JSON.parse(e.data) : e.data,
|
|
43
|
+
})),
|
|
44
|
+
pagination: {
|
|
45
|
+
total,
|
|
46
|
+
limit,
|
|
47
|
+
offset,
|
|
48
|
+
hasMore: offset + events.length < total,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('[Events] Error fetching events:', error);
|
|
53
|
+
return NextResponse.json(
|
|
54
|
+
{ success: false, error: 'Failed to fetch events' },
|
|
55
|
+
{ status: 500 }
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* POST /api/events
|
|
62
|
+
* Webhook endpoint to receive events from Express server
|
|
63
|
+
* and broadcast them to WebSocket clients
|
|
64
|
+
*/
|
|
65
|
+
export async function POST(request: NextRequest) {
|
|
66
|
+
try {
|
|
67
|
+
const event: WalletEvent = await request.json();
|
|
68
|
+
|
|
69
|
+
// Validate event structure
|
|
70
|
+
if (!event.type || !event.timestamp || !event.data) {
|
|
71
|
+
return NextResponse.json(
|
|
72
|
+
{ error: 'Invalid event structure' },
|
|
73
|
+
{ status: 400 }
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Broadcast to all connected WebSocket clients
|
|
78
|
+
broadcast(event);
|
|
79
|
+
|
|
80
|
+
return NextResponse.json({
|
|
81
|
+
success: true,
|
|
82
|
+
type: event.type,
|
|
83
|
+
clientsNotified: true,
|
|
84
|
+
});
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('[Events] Error processing webhook:', error);
|
|
87
|
+
return NextResponse.json(
|
|
88
|
+
{ error: 'Failed to process event' },
|
|
89
|
+
{ status: 500 }
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
import { redirect } from 'next/navigation';
|
|
3
|
+
import { headers } from 'next/headers';
|
|
4
|
+
import DocsSearchBar from '@/components/docs/DocsSearchBar';
|
|
5
|
+
import PersistentDocGroup from '@/components/docs/PersistentDocGroup';
|
|
6
|
+
import DocsThemeToggle from '@/components/docs/DocsThemeToggle';
|
|
7
|
+
import ShareUrlButton from '@/components/docs/ShareUrlButton';
|
|
8
|
+
import ClientSideMarkdown from '@/components/docs/ClientSideMarkdown';
|
|
9
|
+
import SidebarScrollMemory from '@/components/docs/SidebarScrollMemory';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
API_ENTRY_DOC,
|
|
13
|
+
getApiDocHref,
|
|
14
|
+
listApiDocFiles,
|
|
15
|
+
listApiDocGroups,
|
|
16
|
+
normalizeApiDocFilename,
|
|
17
|
+
readApiDocFile,
|
|
18
|
+
} from '@/lib/api-docs';
|
|
19
|
+
import { renderMarkdown } from '@/lib/docs';
|
|
20
|
+
|
|
21
|
+
interface ApiReferencePageProps {
|
|
22
|
+
searchParams?: Promise<{
|
|
23
|
+
doc?: string | string[];
|
|
24
|
+
query?: string | string[];
|
|
25
|
+
q?: string | string[];
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const resolveParam = (value?: string | string[]) => {
|
|
30
|
+
if (!value) return '';
|
|
31
|
+
return Array.isArray(value) ? value[0] : value;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const resolveSearchQuery = (value?: string | string[]) => {
|
|
35
|
+
const resolved = resolveParam(value);
|
|
36
|
+
return resolved ? resolved.trim() : '';
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const docMatchesSearch = (
|
|
40
|
+
doc: { filename: string; title: string; summary: string },
|
|
41
|
+
normalizedQuery: string,
|
|
42
|
+
) => {
|
|
43
|
+
if (!normalizedQuery) return true;
|
|
44
|
+
const haystack = `${doc.filename} ${doc.title} ${doc.summary}`.toLowerCase();
|
|
45
|
+
return haystack.includes(normalizedQuery);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getApiHref = (filename: string, searchQuery: string) => {
|
|
49
|
+
const base = getApiDocHref(filename);
|
|
50
|
+
const normalizedQuery = searchQuery.trim();
|
|
51
|
+
if (!normalizedQuery) return base;
|
|
52
|
+
const params = new URLSearchParams({ query: normalizedQuery });
|
|
53
|
+
return `${base}?${params.toString()}`;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getDocNavLabel = (filename: string, title: string) => {
|
|
57
|
+
if (filename === API_ENTRY_DOC) return title;
|
|
58
|
+
const base = filename.split('/').pop() ?? filename;
|
|
59
|
+
if (base.toLowerCase() === 'readme.md') {
|
|
60
|
+
const parent = filename.split('/').slice(-2, -1)[0];
|
|
61
|
+
return parent ? `${parent}` : 'README';
|
|
62
|
+
}
|
|
63
|
+
return base.replace(/\.md$/i, '');
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const getGroupStorageKey = (label: string) =>
|
|
67
|
+
`api:sidebar:${label.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`;
|
|
68
|
+
|
|
69
|
+
const shouldHideHomeLink = async () => {
|
|
70
|
+
const requestHeaders = await headers();
|
|
71
|
+
const host = requestHeaders.get('x-forwarded-host') ?? requestHeaders.get('host') ?? '';
|
|
72
|
+
const firstHost = host.split(',')[0]?.trim() ?? '';
|
|
73
|
+
const hostname = firstHost.split(':')[0].toLowerCase();
|
|
74
|
+
return hostname === 'auramaxx.sh';
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export async function ApiReferencePageContent({ selectedFilename, searchQuery = '' }: { selectedFilename?: string | null; searchQuery?: string }) {
|
|
78
|
+
const hideHomeLink = await shouldHideHomeLink();
|
|
79
|
+
const selectedRequested = normalizeApiDocFilename(selectedFilename);
|
|
80
|
+
|
|
81
|
+
const allDocs = await listApiDocFiles();
|
|
82
|
+
const groups = await listApiDocGroups();
|
|
83
|
+
const selectedDoc = allDocs.find((doc) => doc.filename === selectedRequested)
|
|
84
|
+
?? allDocs.find((doc) => doc.filename === API_ENTRY_DOC)
|
|
85
|
+
?? allDocs[0];
|
|
86
|
+
|
|
87
|
+
const normalizedSearch = searchQuery.trim().toLowerCase();
|
|
88
|
+
const filteredGroups = normalizedSearch
|
|
89
|
+
? groups
|
|
90
|
+
.map((group) => ({
|
|
91
|
+
...group,
|
|
92
|
+
docs: group.docs.filter((doc) => docMatchesSearch(doc, normalizedSearch)),
|
|
93
|
+
}))
|
|
94
|
+
.filter((group) => group.docs.length > 0)
|
|
95
|
+
: groups;
|
|
96
|
+
|
|
97
|
+
const visibleDocCount = filteredGroups.reduce((count, group) => count + group.docs.length, 0);
|
|
98
|
+
const autoOpenSections = normalizedSearch.length > 0;
|
|
99
|
+
const shareUrl = `https://auramaxx.sh${getApiHref(selectedDoc?.filename ?? API_ENTRY_DOC, searchQuery)}`;
|
|
100
|
+
const rawContent = selectedDoc ? await readApiDocFile(selectedDoc.filename) : '# No API docs found';
|
|
101
|
+
const html = renderMarkdown(rawContent);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="min-h-screen bg-[var(--color-background,#f4f4f5)] relative p-4 py-8">
|
|
105
|
+
{/* Background matching Sterile Field */}
|
|
106
|
+
<div className="fixed inset-0 pointer-events-none z-0 overflow-hidden">
|
|
107
|
+
{/* Sterile Grid */}
|
|
108
|
+
<div className="absolute inset-0 bg-grid-adaptive bg-[size:4rem_4rem] opacity-30" />
|
|
109
|
+
|
|
110
|
+
{/* Tyvek Texture Overlay */}
|
|
111
|
+
<div className="absolute inset-0 tyvek-texture opacity-40 mix-blend-multiply" />
|
|
112
|
+
|
|
113
|
+
{/* Giant Background Typography */}
|
|
114
|
+
<div className="absolute top-[5%] left-[5%] opacity-5 select-none">
|
|
115
|
+
<h1 className="text-[15vw] font-bold leading-none text-[var(--color-text,#0a0a0a)] font-mono tracking-tighter">
|
|
116
|
+
AURA
|
|
117
|
+
</h1>
|
|
118
|
+
</div>
|
|
119
|
+
<div className="absolute bottom-[5%] right-[5%] opacity-5 select-none">
|
|
120
|
+
<h1 className="text-[15vw] font-bold leading-none text-[var(--color-text,#0a0a0a)] font-mono tracking-tighter text-right">
|
|
121
|
+
MAXXING
|
|
122
|
+
</h1>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* Lab Markings - Corner Finder Patterns */}
|
|
126
|
+
<div className="absolute top-10 left-10 w-32 h-32 border-l-4 border-t-4 border-[var(--color-text,#0a0a0a)] opacity-10">
|
|
127
|
+
<div className="absolute top-2 left-2 w-4 h-4 bg-[var(--color-text,#0a0a0a)]" />
|
|
128
|
+
</div>
|
|
129
|
+
<div className="absolute bottom-10 right-10 w-32 h-32 border-r-4 border-b-4 border-[var(--color-text,#0a0a0a)] opacity-10 flex items-end justify-end">
|
|
130
|
+
<div className="absolute bottom-2 right-2 w-4 h-4 bg-[var(--color-text,#0a0a0a)]" />
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
{/* Logo header */}
|
|
135
|
+
<Link
|
|
136
|
+
href="/"
|
|
137
|
+
className="fixed top-4 left-4 sm:top-6 sm:left-6 z-30 flex items-center gap-2 sm:gap-3 hover:opacity-80 transition-opacity"
|
|
138
|
+
>
|
|
139
|
+
<div className="w-8 h-8 sm:w-10 sm:h-10">
|
|
140
|
+
<img src="/logo.webp" alt="AuraMaxx" className="w-full h-full object-contain" />
|
|
141
|
+
</div>
|
|
142
|
+
<div className="hidden sm:block font-black text-xl tracking-tighter text-[var(--color-text,#0a0a0a)]">AURAMAXX</div>
|
|
143
|
+
</Link>
|
|
144
|
+
|
|
145
|
+
{/* Nav */}
|
|
146
|
+
<div className="fixed top-5 right-4 sm:top-7 sm:right-6 z-30 flex items-center gap-2 sm:gap-3 font-mono text-[9px] sm:text-[10px] tracking-widest">
|
|
147
|
+
<Link href="/docs" className="text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors">DOCS</Link>
|
|
148
|
+
{!hideHomeLink && (
|
|
149
|
+
<Link href="/" className="text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors">HOME</Link>
|
|
150
|
+
)}
|
|
151
|
+
<a href="https://github.com/Aura-Industry/auramaxx" target="_blank" rel="noopener noreferrer" className="text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors">GITHUB</a>
|
|
152
|
+
<a href="https://x.com/npxauramaxx" target="_blank" rel="noopener noreferrer" className="text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors">X</a>
|
|
153
|
+
<a href="https://x.com/hi_im_nico" target="_blank" rel="noopener noreferrer" className="text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors">HELP</a>
|
|
154
|
+
<DocsThemeToggle />
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div className="relative z-[5] max-w-[1400px] mx-auto pt-16">
|
|
158
|
+
<div className="grid gap-4 md:grid-cols-[240px_minmax(0,1fr)]">
|
|
159
|
+
{/* Sidebar (sticky) */}
|
|
160
|
+
<aside className="font-mono">
|
|
161
|
+
<div id="api-sidebar-scroll-container" className="md:sticky md:top-20 md:max-h-[calc(100vh-6rem)] md:overflow-y-auto">
|
|
162
|
+
<SidebarScrollMemory containerId="api-sidebar-scroll-container" storageKey="api:sidebar:scroll" />
|
|
163
|
+
<details open className="group sidebar-always-open bg-[var(--color-surface,#f4f4f2)] border border-[var(--color-border,#d4d4d8)] shadow-lg overflow-hidden font-mono">
|
|
164
|
+
<summary className="px-4 py-3 border-b border-[var(--color-border,#d4d4d8)] bg-[var(--color-surface-alt,#fafafa)] flex items-center justify-between cursor-pointer md:cursor-default list-none [&::-webkit-details-marker]:hidden">
|
|
165
|
+
<Link href="/api" className="font-sans font-bold text-sm text-[var(--color-text,#0a0a0a)] uppercase tracking-tight hover:opacity-70 transition-opacity">API Index</Link>
|
|
166
|
+
<span className="flex items-center gap-2">
|
|
167
|
+
<span className="text-[9px] text-[var(--color-text-faint,#9ca3af)] font-bold">QTY: {visibleDocCount.toString().padStart(3, '0')}</span>
|
|
168
|
+
<svg className="w-3 h-3 text-[var(--color-text-muted,#6b7280)] transition-transform group-open:rotate-180 md:hidden" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M6 9l6 6 6-6" /></svg>
|
|
169
|
+
</span>
|
|
170
|
+
</summary>
|
|
171
|
+
<div className="p-3 space-y-4">
|
|
172
|
+
{filteredGroups.map((group) => (
|
|
173
|
+
group.collapsible ? (
|
|
174
|
+
<PersistentDocGroup
|
|
175
|
+
key={group.label}
|
|
176
|
+
storageKey={getGroupStorageKey(group.label)}
|
|
177
|
+
label={group.label}
|
|
178
|
+
forceOpen={autoOpenSections}
|
|
179
|
+
>
|
|
180
|
+
{group.docs.map((doc) => {
|
|
181
|
+
const isActive = selectedDoc?.filename === doc.filename;
|
|
182
|
+
return (
|
|
183
|
+
<Link
|
|
184
|
+
key={doc.filename}
|
|
185
|
+
href={getApiHref(doc.filename, searchQuery)}
|
|
186
|
+
className={`block px-3 py-1.5 text-[11px] uppercase transition-colors border ${
|
|
187
|
+
isActive
|
|
188
|
+
? 'border-[var(--color-border,#d4d4d8)] bg-[var(--color-text,#0a0a0a)] text-[var(--color-surface,#ffffff)]'
|
|
189
|
+
: 'border-transparent hover:border-[var(--color-border-muted,#e5e5e5)] hover:bg-[var(--color-surface-alt,#fafafa)] text-[var(--color-text-muted,#6b7280)]'
|
|
190
|
+
}`}
|
|
191
|
+
>
|
|
192
|
+
{getDocNavLabel(doc.filename, doc.title)}
|
|
193
|
+
</Link>
|
|
194
|
+
);
|
|
195
|
+
})}
|
|
196
|
+
</PersistentDocGroup>
|
|
197
|
+
) : (
|
|
198
|
+
<div key={group.label}>
|
|
199
|
+
<div className="text-[8px] text-[var(--color-text-faint,#9ca3af)] tracking-widest mb-1 px-1 uppercase">{group.label}</div>
|
|
200
|
+
<div className="space-y-0.5">
|
|
201
|
+
{group.docs.map((doc) => {
|
|
202
|
+
const isActive = selectedDoc?.filename === doc.filename;
|
|
203
|
+
return (
|
|
204
|
+
<Link
|
|
205
|
+
key={doc.filename}
|
|
206
|
+
href={getApiHref(doc.filename, searchQuery)}
|
|
207
|
+
className={`block px-3 py-1.5 text-[11px] uppercase transition-colors border ${
|
|
208
|
+
isActive
|
|
209
|
+
? 'border-[var(--color-border,#d4d4d8)] bg-[var(--color-text,#0a0a0a)] text-[var(--color-surface,#ffffff)]'
|
|
210
|
+
: 'border-transparent hover:border-[var(--color-border-muted,#e5e5e5)] hover:bg-[var(--color-surface-alt,#fafafa)] text-[var(--color-text-muted,#6b7280)]'
|
|
211
|
+
}`}
|
|
212
|
+
>
|
|
213
|
+
{getDocNavLabel(doc.filename, doc.title)}
|
|
214
|
+
</Link>
|
|
215
|
+
);
|
|
216
|
+
})}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
)
|
|
220
|
+
))}
|
|
221
|
+
|
|
222
|
+
{filteredGroups.length === 0 && (
|
|
223
|
+
<div className="px-1 py-2 text-[9px] text-[var(--color-text-muted,#6b7280)]">
|
|
224
|
+
No API docs found for "{searchQuery}".
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
{/* Barcode + Stripe */}
|
|
230
|
+
<div className="flex items-center gap-3 px-4 py-2 border-t border-[var(--color-border,#d4d4d8)]">
|
|
231
|
+
<div className="h-4 flex-1 bg-[repeating-linear-gradient(90deg,var(--color-text,#000),var(--color-text,#000)_1px,transparent_1px,transparent_3px)] opacity-30" />
|
|
232
|
+
</div>
|
|
233
|
+
<div className="h-2 w-full" style={{
|
|
234
|
+
backgroundImage: 'repeating-linear-gradient(45deg, var(--color-text, #000), var(--color-text, #000) 5px, transparent 5px, transparent 10px)',
|
|
235
|
+
opacity: 0.1,
|
|
236
|
+
}} />
|
|
237
|
+
</details>
|
|
238
|
+
</div>
|
|
239
|
+
</aside>
|
|
240
|
+
|
|
241
|
+
{/* Content */}
|
|
242
|
+
<div className="bg-[var(--color-surface,#f4f4f2)] border border-[var(--color-border,#d4d4d8)] shadow-lg overflow-hidden font-mono">
|
|
243
|
+
<div className="px-4 py-3 border-b border-[var(--color-border,#d4d4d8)] bg-[var(--color-surface-alt,#fafafa)] flex items-center justify-between">
|
|
244
|
+
<span className="font-sans font-bold text-sm text-[var(--color-text,#0a0a0a)] uppercase tracking-tight">
|
|
245
|
+
{selectedDoc?.title ?? 'API Reference'}
|
|
246
|
+
</span>
|
|
247
|
+
<div className="flex items-center gap-2">
|
|
248
|
+
<span className="text-[9px] text-[var(--color-text-muted,#6b7280)]">{selectedDoc?.filename ?? API_ENTRY_DOC}</span>
|
|
249
|
+
<ShareUrlButton url={shareUrl} />
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<ClientSideMarkdown className="p-5 prose-mono" html={html} />
|
|
254
|
+
|
|
255
|
+
{/* Footer */}
|
|
256
|
+
<div className="px-4 py-2 border-t border-[var(--color-border,#d4d4d8)] bg-[var(--color-surface-alt,#fafafa)]">
|
|
257
|
+
<div className="text-[8px] text-[var(--color-text-faint,#9ca3af)] uppercase tracking-wider mb-1">DOCUMENT REFERENCE</div>
|
|
258
|
+
<div className="text-[9px] text-[var(--color-text,#0a0a0a)] font-bold">{selectedDoc?.filename ?? API_ENTRY_DOC}</div>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
{/* Barcode + Stripe */}
|
|
262
|
+
<div className="flex items-center gap-3 px-4 py-2 border-t border-[var(--color-border,#d4d4d8)]">
|
|
263
|
+
<div className="h-4 flex-1 bg-[repeating-linear-gradient(90deg,var(--color-text,#000),var(--color-text,#000)_1px,transparent_1px,transparent_3px)] opacity-30" />
|
|
264
|
+
<span className="text-[8px] text-[var(--color-text-faint,#9ca3af)] tracking-wider">AURAMAXX</span>
|
|
265
|
+
</div>
|
|
266
|
+
<div className="h-2 w-full" style={{
|
|
267
|
+
backgroundImage: 'repeating-linear-gradient(45deg, var(--color-text, #000), var(--color-text, #000) 5px, transparent 5px, transparent 10px)',
|
|
268
|
+
opacity: 0.1,
|
|
269
|
+
}} />
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<DocsSearchBar initialQuery={searchQuery} />
|
|
275
|
+
</div>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export default async function ApiReferencePage({ searchParams }: ApiReferencePageProps) {
|
|
280
|
+
const resolvedSearchParams = searchParams ? await searchParams : undefined;
|
|
281
|
+
const queryDocParam = resolveParam(resolvedSearchParams?.doc);
|
|
282
|
+
const selectedRequested = normalizeApiDocFilename(queryDocParam);
|
|
283
|
+
const searchQuery = resolveSearchQuery(resolvedSearchParams?.query) || resolveSearchQuery(resolvedSearchParams?.q);
|
|
284
|
+
|
|
285
|
+
if (queryDocParam) {
|
|
286
|
+
redirect(getApiHref(selectedRequested, searchQuery));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return <ApiReferencePageContent selectedFilename={selectedRequested} searchQuery={searchQuery} />;
|
|
290
|
+
}
|