auramaxx 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +112 -0
- package/bin/aurawallet.js +121 -0
- package/docs/ADAPTERS.md +467 -0
- package/docs/API.md +2679 -0
- package/docs/APPS.md +198 -0
- package/docs/ARCHITECTURE.md +350 -0
- package/docs/AUTH.md +698 -0
- package/docs/BEST-PRACTICES.md +121 -0
- package/docs/CLI.md +61 -0
- package/docs/DEVELOPING-APPS.md +452 -0
- package/docs/EXTENSION.md +97 -0
- package/docs/JOBS.md +33 -0
- package/docs/MCP.md +76 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/SETUP.md +219 -0
- package/docs/WORKSPACE.md +672 -0
- package/docs/agent-auth.md +63 -0
- package/docs/aura-file.md +48 -0
- package/docs/credentials.md +53 -0
- package/docs/external/getting-started.md +65 -0
- package/docs/external/overview.md +45 -0
- package/docs/external/use-cases.md +48 -0
- package/docs/external/why-aura.md +35 -0
- package/docs/jobs/connect-agent.md +77 -0
- package/docs/jobs/migrate-from-dotenv.md +79 -0
- package/docs/jobs/recover-from-lockout.md +72 -0
- package/docs/jobs/secure-ci.md +63 -0
- package/docs/oauth2.md +42 -0
- package/docs/passkeys.md +60 -0
- package/docs/security.md +540 -0
- package/docs/specs/aura-open-protocol.md +61 -0
- package/docs/specs/aura-provider-plugin.md +24 -0
- package/docs/specs/aura-registry-model.md +31 -0
- package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
- package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
- package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
- package/docs/specs/fixtures/valid-basic.aura +4 -0
- package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
- package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
- package/docs/totp.md +40 -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 +21 -0
- package/package.json +151 -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/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo-chevron.svg +31 -0
- package/public/logo-concentric.svg +31 -0
- package/public/logo-crosshatch.svg +39 -0
- package/public/logo-dashed.svg +39 -0
- package/public/logo-horizontal.svg +31 -0
- package/public/logo-m56.svg +64 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/scripts/init.sh +57 -0
- package/scripts/migrate-apikeys-to-credentials.ts +35 -0
- package/scripts/sandbox-agent-flow.sh +235 -0
- package/scripts/sandbox.sh +175 -0
- package/scripts/validate-job-docs.mjs +125 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/doctor.ts +1007 -0
- package/server/cli/commands/env.ts +456 -0
- package/server/cli/commands/init.ts +752 -0
- package/server/cli/commands/mcp.ts +125 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/shell-hook.ts +468 -0
- package/server/cli/commands/start.ts +62 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +14 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +49 -0
- package/server/cli/commands/vault.ts +417 -0
- package/server/cli/index.ts +328 -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 +254 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -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/process.ts +136 -0
- package/server/cli/lib/prompt.ts +85 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +570 -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 +406 -0
- package/server/lib/adapters/factory.ts +110 -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 +328 -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 +189 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +874 -0
- package/server/lib/config.ts +381 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +110 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +487 -0
- package/server/lib/credential-scope.ts +87 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +342 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +333 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +15 -0
- package/server/lib/defaults.ts +366 -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/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 +128 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +205 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +331 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +219 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +54 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +248 -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 +239 -0
- package/server/lib/resolve-action.ts +427 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/sessions.ts +632 -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 +158 -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 +235 -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 +75 -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/verified-summary.ts +421 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +619 -0
- package/server/mcp/tools.ts +523 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +459 -0
- package/server/routes/adapters.ts +703 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +295 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +457 -0
- package/server/routes/backup.ts +340 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +198 -0
- package/server/routes/credential-vaults.ts +154 -0
- package/server/routes/credentials.ts +1290 -0
- package/server/routes/dashboard.ts +71 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/fund.ts +229 -0
- package/server/routes/import.ts +352 -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 +346 -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 +353 -0
- package/server/routes/swap-solana.ts +177 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +403 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +710 -0
- package/server/types.ts +146 -0
- package/skills/aurawallet/SKILL.md +739 -0
- package/skills/aurawallet-setup/SKILL.md +74 -0
- package/skills/security-review/SKILL.md +148 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +126 -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/events/route.ts +92 -0
- package/src/app/api/page.tsx +212 -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 +34 -0
- package/src/app/api/workspace/config/route.ts +106 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app/page.tsx +2122 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/docs/page.tsx +178 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +572 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +15 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +34 -0
- package/src/app/page.tsx +986 -0
- package/src/app/providers.tsx +90 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/components/ChainSelector.tsx +144 -0
- package/src/components/HumanActionBar.tsx +695 -0
- package/src/components/NotificationDrawer.tsx +129 -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 +53 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +137 -0
- package/src/components/design-system/ConfirmationModal.tsx +106 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/Drawer.tsx +123 -0
- package/src/components/design-system/FilterDropdown.tsx +72 -0
- package/src/components/design-system/Modal.tsx +206 -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 +58 -0
- package/src/components/design-system/index.ts +11 -0
- package/src/components/docs/DocsThemeToggle.tsx +49 -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/TabBar.tsx +278 -0
- package/src/components/layout/WalletSidebar.tsx +1033 -0
- package/src/components/layout/index.ts +4 -0
- package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1080 -0
- package/src/components/vault/AuditConsole.tsx +584 -0
- package/src/components/vault/CredentialDetail.tsx +455 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +361 -0
- package/src/components/vault/CredentialForm.tsx +1212 -0
- package/src/components/vault/CredentialList.tsx +165 -0
- package/src/components/vault/CredentialRow.tsx +97 -0
- package/src/components/vault/CredentialShareModal.tsx +178 -0
- package/src/components/vault/CredentialVault.tsx +754 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/ImportCredentialsModal.tsx +515 -0
- package/src/components/vault/LargeTypeModal.tsx +64 -0
- package/src/components/vault/PasswordGenerator.tsx +224 -0
- package/src/components/vault/TOTPDisplay.tsx +123 -0
- package/src/components/vault/VaultSidebar.tsx +413 -0
- package/src/components/vault/types.ts +54 -0
- package/src/context/AuthContext.tsx +337 -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 +3 -0
- package/src/hooks/useAgentActions.ts +368 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api.ts +449 -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/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +390 -0
- package/src/lib/events.ts +361 -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/vault-crypto.ts +129 -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 +80 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Best Practices
|
|
2
|
+
|
|
3
|
+
Guidance for humans, agents, and developers working with AuraWallet.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## For Humans
|
|
8
|
+
|
|
9
|
+
### Password Management
|
|
10
|
+
|
|
11
|
+
- Use a strong, unique password for each vault (min 8 characters, passphrase recommended)
|
|
12
|
+
- Never store your vault password digitally — treat it like a seed phrase
|
|
13
|
+
- If you forget your password, the seed phrase is your only recovery path
|
|
14
|
+
|
|
15
|
+
### Spending Limit Strategy
|
|
16
|
+
|
|
17
|
+
- Start with low limits (`fund: 0.1`) and increase as you build trust with an agent's behavior
|
|
18
|
+
- Set per-type limits: `fund` controls cold wallet exposure, `send` and `swap` control hot wallet activity
|
|
19
|
+
- Review token spending in the dashboard regularly — spending resets on server restart
|
|
20
|
+
|
|
21
|
+
### Multi-Vault Usage
|
|
22
|
+
|
|
23
|
+
- Use separate vaults for separate purposes (e.g., trading vault, savings vault)
|
|
24
|
+
- Each vault has its own password — unlocking one does not unlock others
|
|
25
|
+
- Hot wallets are bound to their vault and cannot be moved between vaults
|
|
26
|
+
|
|
27
|
+
### Backup Schedule
|
|
28
|
+
|
|
29
|
+
- Back up your seed phrase on paper immediately after vault creation
|
|
30
|
+
- Store it offline in a secure location (safe, safety deposit box)
|
|
31
|
+
- Never photograph, screenshot, or digitally copy your seed phrase
|
|
32
|
+
- Test your backup by verifying the cold wallet address matches
|
|
33
|
+
|
|
34
|
+
### Token Hygiene
|
|
35
|
+
|
|
36
|
+
- Revoke tokens you're no longer using — don't leave stale tokens active
|
|
37
|
+
- Each agent should have its own token with its own limits
|
|
38
|
+
- Review active tokens periodically in the dashboard
|
|
39
|
+
- Server restart invalidates all tokens — this is intentional security, not a bug
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## For Agents
|
|
44
|
+
|
|
45
|
+
### Permission Scoping
|
|
46
|
+
|
|
47
|
+
- Request the minimum permissions needed for your task
|
|
48
|
+
- Use `trade:all` for trading operations instead of listing individual permissions
|
|
49
|
+
- `trade:all` does NOT include `apikey:set` or `adapter:manage` — request those explicitly if needed for onboarding
|
|
50
|
+
- Never request `admin:*` unless you genuinely need full access
|
|
51
|
+
|
|
52
|
+
### Token Lifecycle
|
|
53
|
+
|
|
54
|
+
- Tokens live only in server memory — expect them to vanish on restart
|
|
55
|
+
- Always implement re-authentication logic: catch 401 → re-request via `POST /auth`
|
|
56
|
+
- Don't persist tokens to disk — request fresh ones each session
|
|
57
|
+
- The token from `GET /auth/:id?secret=...` can only be read once — save it immediately
|
|
58
|
+
|
|
59
|
+
### Error Handling Patterns
|
|
60
|
+
|
|
61
|
+
| Error | Pattern |
|
|
62
|
+
|-------|---------|
|
|
63
|
+
| 401 `Invalid or expired token` | Re-request token via `POST /auth`, wait for human approval |
|
|
64
|
+
| 401 `Cold wallet must be unlocked` | Tell human to unlock at dashboard or `http://localhost:4242/unlock` |
|
|
65
|
+
| 403 `Insufficient permissions` | Use `request_human_action` for one-time approval, or `POST /auth/request-permissions` for permanent upgrade |
|
|
66
|
+
| 403 `Amount exceeds spending limit` | Use `request_human_action` with the specific amount needed |
|
|
67
|
+
| Connection refused | Server not running — tell human to run `npx aurawallet start` |
|
|
68
|
+
|
|
69
|
+
### Spending Budget Management
|
|
70
|
+
|
|
71
|
+
- Track your remaining budget by remembering cumulative spend per type
|
|
72
|
+
- When approaching a limit, use `request_human_action` to request approval for the specific operation
|
|
73
|
+
- Budget resets on server restart (new token required anyway)
|
|
74
|
+
- For ongoing operations, request higher initial limits rather than repeatedly escalating
|
|
75
|
+
|
|
76
|
+
### Multi-Step Operations
|
|
77
|
+
|
|
78
|
+
- Check `GET /setup` before starting any workflow — know what's configured
|
|
79
|
+
- For operations that require multiple endpoints (e.g., create wallet → fund → swap), verify each step succeeded before proceeding
|
|
80
|
+
- If a multi-step operation fails partway through, report what completed and what didn't — don't silently retry
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## For Developers
|
|
85
|
+
|
|
86
|
+
### Route Auth Patterns
|
|
87
|
+
|
|
88
|
+
Every route follows one of these patterns:
|
|
89
|
+
|
|
90
|
+
| Pattern | Example | How |
|
|
91
|
+
|---------|---------|-----|
|
|
92
|
+
| Public | `GET /health` | No auth check |
|
|
93
|
+
| Any valid token | `GET /wallets` | `requireAuth` middleware |
|
|
94
|
+
| Specific permission | `POST /swap` | `requireAuth` + `requirePermission('swap')` |
|
|
95
|
+
| Admin only | `POST /nuke` | `requireAuth` + `requirePermission('admin:*')` |
|
|
96
|
+
| Wallet access | `POST /send` | Auth + permission + `tokenCanAccessWallet()` |
|
|
97
|
+
|
|
98
|
+
### Adding New Permissions Checklist
|
|
99
|
+
|
|
100
|
+
1. Add the permission string to the relevant route in `server/routes/`
|
|
101
|
+
2. Add the permission to the reference table in `docs/AUTH.md`
|
|
102
|
+
3. If it belongs in a compound permission (`trade:all`, `wallet:write`), update the expansion in `server/lib/auth.ts`
|
|
103
|
+
4. Add the route → permission mapping to the Route → Permission table in `docs/AUTH.md`
|
|
104
|
+
5. Update `docs/security.md` if the permission affects the security model
|
|
105
|
+
|
|
106
|
+
### Security Checklist
|
|
107
|
+
|
|
108
|
+
- [ ] Auth decisions use memory only (SIGNING_KEY, sessions Map) — never the database
|
|
109
|
+
- [ ] Wallet ownership checked via `tokenCanAccessWallet()` before any wallet operation
|
|
110
|
+
- [ ] Spending limits checked and updated atomically in the sessions Map
|
|
111
|
+
- [ ] Cold wallet operations require the vault to be unlocked (mnemonic in memory)
|
|
112
|
+
- [ ] New endpoints have appropriate rate limiting tier
|
|
113
|
+
- [ ] Input validation on all user-supplied data (amounts, addresses, strings)
|
|
114
|
+
- [ ] No secrets logged or returned in error messages
|
|
115
|
+
|
|
116
|
+
### Testing Patterns
|
|
117
|
+
|
|
118
|
+
- Auth tests should verify both positive (has permission) and negative (lacks permission) cases
|
|
119
|
+
- Spending limit tests should verify enforcement, accumulation, and the boundary case (exact limit)
|
|
120
|
+
- Wallet ownership tests should verify both tokenHash-based and walletAccess-based access
|
|
121
|
+
- Server restart tests should verify all tokens are invalidated and sessions cleared
|
package/docs/CLI.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CLI (`aura` / `aurawallet`)
|
|
2
|
+
|
|
3
|
+
Binary aliases:
|
|
4
|
+
|
|
5
|
+
- `npx aurawallet ...`
|
|
6
|
+
- `npx aura ...` (same binary)
|
|
7
|
+
|
|
8
|
+
## Core commands
|
|
9
|
+
|
|
10
|
+
- `init` — first-time setup
|
|
11
|
+
- `start` / `stop` / `status` / `unlock`
|
|
12
|
+
- `restore` — backup restore
|
|
13
|
+
- `mcp` — run MCP server
|
|
14
|
+
- `vault` — credential retrieval
|
|
15
|
+
- `env` — `.aura`-based env loading
|
|
16
|
+
- `shell-hook` — auto-load env on `cd`
|
|
17
|
+
|
|
18
|
+
## `vault` examples
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx aurawallet vault list
|
|
22
|
+
npx aurawallet vault get openai-prod --field api_key
|
|
23
|
+
npx aurawallet vault get github-admin --totp
|
|
24
|
+
npx aurawallet vault get stripe --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Auth behavior:
|
|
28
|
+
|
|
29
|
+
- default: Unix socket bootstrap (`/tmp/aura-cli-{uid}.sock`)
|
|
30
|
+
- headless/CI: set `AURA_TOKEN`
|
|
31
|
+
|
|
32
|
+
## `env` examples
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx aurawallet env init --from .env
|
|
36
|
+
npx aurawallet env check
|
|
37
|
+
npx aurawallet env list
|
|
38
|
+
npx aurawallet env -- npm run dev
|
|
39
|
+
npx aurawallet env inject
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## `shell-hook`
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx aurawallet shell-hook install
|
|
46
|
+
cd my-project
|
|
47
|
+
npx aurawallet shell-hook allow
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Requires whitelist (`shell-allowed.json`)
|
|
51
|
+
- Caches resolved vars with encrypted-at-rest cache blobs
|
|
52
|
+
|
|
53
|
+
## `restore`
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx aurawallet restore --list
|
|
57
|
+
npx aurawallet restore --latest
|
|
58
|
+
npx aurawallet restore --dry-run --latest
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Restores DB + credential files, then runs Prisma migrations.
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# Developing Apps
|
|
2
|
+
|
|
3
|
+
Detailed reference for building AuraWallet UI apps — manifest format, SDK API, theming, security, and storage.
|
|
4
|
+
|
|
5
|
+
For a high-level overview and installation guide, see [APPS.md](./APPS.md). For building strategy apps (tick-based and message-based), see [DEVELOPING-STRATEGIES.md](./wallet/DEVELOPING-STRATEGIES.md). For AI engine internals, see [AI.md](./wallet/AI.md).
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [File Structure](#file-structure)
|
|
10
|
+
2. [App SDK API (window.AuraApp)](#app-sdk-api-windowauraapp)
|
|
11
|
+
3. [Theming](#theming)
|
|
12
|
+
4. [Manifest Reference](#manifest-reference)
|
|
13
|
+
5. [Security Model](#security-model)
|
|
14
|
+
6. [Storage API (REST)](#storage-api-rest)
|
|
15
|
+
7. [Example: Annotated Kanban App](#example-annotated-kanban-app)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## File Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
apps/
|
|
23
|
+
my-app/
|
|
24
|
+
app.md # Manifest (YAML frontmatter + description)
|
|
25
|
+
index.html # UI entry point (HTML + inline JS/CSS)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- `app.md` is required. The engine discovers apps by scanning `apps/*/app.md`.
|
|
29
|
+
- `index.html` is optional. Apps without it show a default placeholder on the dashboard. Strategy-only (headless) apps commonly omit it.
|
|
30
|
+
- The folder name becomes the app `id`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## App SDK API (`window.AuraApp`)
|
|
35
|
+
|
|
36
|
+
The SDK is automatically injected into every installed app iframe. It is available as `window.AuraApp` (or just `AuraApp`). Storage methods and `fetch()` use direct HTTP calls with an injected Bearer token; `send()` uses direct HTTP; `on()` uses postMessage to communicate with the host.
|
|
37
|
+
|
|
38
|
+
### `AuraApp.storage.get(key)`
|
|
39
|
+
|
|
40
|
+
Read a value from persistent storage.
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
var data = await AuraApp.storage.get('myKey');
|
|
44
|
+
// data is the parsed JSON value, or null if not found
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **Parameters:** `key` (string) -- the storage key
|
|
48
|
+
- **Returns:** `Promise<any>` -- the stored value, or `null` if the key does not exist
|
|
49
|
+
|
|
50
|
+
### `AuraApp.storage.set(key, value)`
|
|
51
|
+
|
|
52
|
+
Write a value to persistent storage. Values are JSON-serialized.
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
await AuraApp.storage.set('myKey', { count: 42, items: ['a', 'b'] });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- **Parameters:** `key` (string), `value` (any JSON-serializable value)
|
|
59
|
+
- **Returns:** `Promise<any>` -- the stored value on success
|
|
60
|
+
- **Behavior:** Upserts -- creates the key if it does not exist, updates if it does
|
|
61
|
+
|
|
62
|
+
### `AuraApp.storage.delete(key)`
|
|
63
|
+
|
|
64
|
+
Delete a key from persistent storage.
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
var ok = await AuraApp.storage.delete('myKey');
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- **Parameters:** `key` (string)
|
|
71
|
+
- **Returns:** `Promise<boolean>` -- `true` on success
|
|
72
|
+
- **Error:** Rejects if the key does not exist
|
|
73
|
+
|
|
74
|
+
### `AuraApp.send(message)`
|
|
75
|
+
|
|
76
|
+
Send a natural language message to the app's AI and receive a reply.
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
var reply = await AuraApp.send('Check the ETH balance on my hot wallet');
|
|
80
|
+
console.log(reply); // "Your hot wallet has 2.5 ETH"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- **Parameters:** `message` (string) -- natural language instruction
|
|
84
|
+
- **Returns:** `Promise<string | null>` -- the AI's text reply, or `null` if no reply was generated
|
|
85
|
+
- **Rate limit:** 10 messages per 60 seconds per app
|
|
86
|
+
- **Requires:** App must have a `hooks.message` field in its manifest
|
|
87
|
+
|
|
88
|
+
### `AuraApp.fetch(url, options)`
|
|
89
|
+
|
|
90
|
+
Fetch an external URL via the server-side proxy. Apps run in sandboxed `blob:` iframes with an opaque origin, so direct `fetch()` calls to external APIs will fail with CORS errors. This method proxies the request through the wallet server.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Simple GET
|
|
94
|
+
var data = await AuraApp.fetch('https://api.example.com/prices');
|
|
95
|
+
|
|
96
|
+
// POST with headers
|
|
97
|
+
var result = await AuraApp.fetch('https://api.example.com/submit', {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { 'Content-Type': 'application/json' },
|
|
100
|
+
body: JSON.stringify({ token: '0xABC' })
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- **Parameters:**
|
|
105
|
+
- `url` (string) -- the external URL to fetch (must be HTTP or HTTPS)
|
|
106
|
+
- `options` (object, optional): `method`, `headers`, `body`
|
|
107
|
+
- **Returns:** `Promise<any>` -- parsed JSON or text string
|
|
108
|
+
- **Rate limit:** 60 requests per 60 seconds per app
|
|
109
|
+
- **Restrictions:** Only HTTP/HTTPS; private IPs blocked (SSRF prevention); 10s timeout
|
|
110
|
+
|
|
111
|
+
### `AuraApp.action(params)`
|
|
112
|
+
|
|
113
|
+
Request human approval for a privileged operation. Creates a pending action request. On approval, a temporary scoped token is created and the action auto-executes.
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
var result = await AuraApp.action({
|
|
117
|
+
summary: 'Buy $DOGE2 for 0.005 ETH',
|
|
118
|
+
permissions: ['swap'],
|
|
119
|
+
limits: { swap: 0.005 },
|
|
120
|
+
walletAccess: ['0x...'],
|
|
121
|
+
ttl: 60
|
|
122
|
+
});
|
|
123
|
+
// result = { success: true, requestId: '...', secret: '...' }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- **Parameters:** `params` (object): `summary` (string, required), `permissions` (string[], required), `limits` (object), `walletAccess` (string[]), `ttl` (number)
|
|
127
|
+
- **Returns:** `Promise<{ success, requestId, secret }>`
|
|
128
|
+
- **Requires:** `action:create` permission in the manifest
|
|
129
|
+
|
|
130
|
+
**Event sequence on approval:** `action:resolved` → `action:executed` → `agent:message`
|
|
131
|
+
|
|
132
|
+
### `AuraApp.on(channel, callback)`
|
|
133
|
+
|
|
134
|
+
Subscribe to a real-time event channel. Events are forwarded from the WebSocket to your iframe via postMessage.
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
var unsub = AuraApp.on('tx:created', function(data) {
|
|
138
|
+
console.log('New transaction:', data);
|
|
139
|
+
});
|
|
140
|
+
unsub(); // unsubscribe
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- **Parameters:** `channel` (string), `callback` (function)
|
|
144
|
+
- **Returns:** unsubscribe function
|
|
145
|
+
|
|
146
|
+
#### Common Event Channels
|
|
147
|
+
|
|
148
|
+
| Channel | Data | Description |
|
|
149
|
+
|---------|------|-------------|
|
|
150
|
+
| `tx:created` | `{walletAddress, id, type, txHash, amount}` | New transaction |
|
|
151
|
+
| `asset:changed` | `{walletAddress, tokenAddress, symbol}` | Asset added/removed |
|
|
152
|
+
| `wallet:created` | `{address, tier, chain}` | New wallet created |
|
|
153
|
+
| `strategy:tick` | `{strategyId, intents, duration, state}` | Strategy tick completed |
|
|
154
|
+
| `strategy:error` | `{strategyId, error, phase}` | Strategy error |
|
|
155
|
+
| `action:executed` | `{requestId, approved, status, result}` | Action auto-executed (app-scoped) |
|
|
156
|
+
| `agent:message` | `{message}` | AI follow-up after action (app-scoped) |
|
|
157
|
+
|
|
158
|
+
Strategy hooks can emit custom app-scoped events via the `emit` field in hook responses:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{ "emit": { "channel": "price-update", "data": { "price": 42 } } }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Theming
|
|
167
|
+
|
|
168
|
+
The host injects CSS variables from the current theme into every app iframe. Use these to match the dashboard in both light and dark modes.
|
|
169
|
+
|
|
170
|
+
### CSS Variables
|
|
171
|
+
|
|
172
|
+
| Variable | Purpose | Fallback |
|
|
173
|
+
|----------|---------|----------|
|
|
174
|
+
| `--color-background` | Page background | `#fafafa` |
|
|
175
|
+
| `--color-background-alt` | Alternate background | `#f4f4f5` |
|
|
176
|
+
| `--color-surface` | App/card background | `#ffffff` |
|
|
177
|
+
| `--color-surface-alt` | Alternate surface | `#f9fafb` |
|
|
178
|
+
| `--color-text` | Primary text | `#0a0a0a` |
|
|
179
|
+
| `--color-text-muted` | Secondary text | `#6b7280` |
|
|
180
|
+
| `--color-text-faint` | Tertiary text | `#9ca3af` |
|
|
181
|
+
| `--color-border` | Standard borders | `#d4d4d8` |
|
|
182
|
+
| `--color-border-muted` | Subtle borders | `#e4e4e7` |
|
|
183
|
+
| `--color-border-focus` | Focused borders | `#0a0a0a` |
|
|
184
|
+
| `--color-accent` | Accent/highlight | `#ccff00` |
|
|
185
|
+
| `--color-info` | Info accent | `#0047ff` |
|
|
186
|
+
| `--color-success` | Success state | `#22c55e` |
|
|
187
|
+
| `--color-warning` | Warning state | `#ff4d00` |
|
|
188
|
+
|
|
189
|
+
Always provide fallback values:
|
|
190
|
+
|
|
191
|
+
```css
|
|
192
|
+
body {
|
|
193
|
+
background: var(--color-surface, #fff);
|
|
194
|
+
color: var(--color-text, #0a0a0a);
|
|
195
|
+
font-family: ui-monospace, monospace;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Injected Base Styles
|
|
200
|
+
|
|
201
|
+
The host injects a base reset into every app:
|
|
202
|
+
|
|
203
|
+
```css
|
|
204
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
205
|
+
body {
|
|
206
|
+
font-family: ui-monospace, monospace;
|
|
207
|
+
overflow: auto;
|
|
208
|
+
background: var(--color-surface, #fff);
|
|
209
|
+
color: var(--color-text, #0a0a0a);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Your app's own `<style>` blocks are applied after this reset.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Manifest Reference
|
|
218
|
+
|
|
219
|
+
The manifest is a Markdown file with YAML frontmatter. The body text after `---` is the description shown in the App Store.
|
|
220
|
+
|
|
221
|
+
```markdown
|
|
222
|
+
---
|
|
223
|
+
name: My App
|
|
224
|
+
icon: Zap
|
|
225
|
+
# ...fields...
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
Description shown in the App Store listing.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### All Fields
|
|
232
|
+
|
|
233
|
+
| Field | Type | Required | Default | Description |
|
|
234
|
+
|-------|------|:---:|---------|-------------|
|
|
235
|
+
| `name` | string | yes | folder name | Display name |
|
|
236
|
+
| `icon` | string | no | `Box` | [Lucide](https://lucide.dev) icon name |
|
|
237
|
+
| `category` | string | no | `general` | App Store category filter |
|
|
238
|
+
| `size` | string | no | `1x1` | Default grid size `WxH` (1=320x280, 2=640x560, 3=960x840) |
|
|
239
|
+
| `permissions` | string[] | no | `[]` | Wallet permissions the app needs |
|
|
240
|
+
| `data` | string[] | no | `[]` | Real-time WebSocket channels to subscribe to (informational) |
|
|
241
|
+
|
|
242
|
+
### Permissions
|
|
243
|
+
|
|
244
|
+
Declare the permissions your app needs. Apps with permissions or limits require human approval before the engine creates auth tokens for them. Zero-permission apps skip approval.
|
|
245
|
+
|
|
246
|
+
Valid permission strings (see [AUTH.md](./AUTH.md) for full details):
|
|
247
|
+
|
|
248
|
+
| Permission | Description |
|
|
249
|
+
|------------|-------------|
|
|
250
|
+
| `wallet:list` | List/view wallets and balances |
|
|
251
|
+
| `wallet:create:hot` | Create hot wallets |
|
|
252
|
+
| `wallet:create:temp` | Create temp wallets |
|
|
253
|
+
| `wallet:rename` | Rename wallets |
|
|
254
|
+
| `wallet:export` | Export private keys |
|
|
255
|
+
| `send:hot` | Send from hot wallets |
|
|
256
|
+
| `send:temp` | Send from temp wallets |
|
|
257
|
+
| `swap` | Execute token swaps |
|
|
258
|
+
| `fund` | Transfer cold to hot |
|
|
259
|
+
| `launch` | Launch tokens via Doppler |
|
|
260
|
+
| `action:create` | Create human action requests |
|
|
261
|
+
| `apikey:get` | Read API keys |
|
|
262
|
+
| `apikey:set` | Manage API keys |
|
|
263
|
+
| `strategy:read` | View strategies |
|
|
264
|
+
| `strategy:manage` | Enable/disable strategies |
|
|
265
|
+
| `trade:all` | Compound: all trading + apikey:get |
|
|
266
|
+
| `wallet:write` | Compound: all wallet write ops |
|
|
267
|
+
|
|
268
|
+
### Extending Your App with Strategy Fields
|
|
269
|
+
|
|
270
|
+
Any app can become AI-powered by adding strategy fields to its `app.md` manifest. A strategy is just an app that activates the AI engine — there is no separate directory or manifest format.
|
|
271
|
+
|
|
272
|
+
The strategy-specific fields are:
|
|
273
|
+
|
|
274
|
+
| Field | Purpose |
|
|
275
|
+
|-------|---------|
|
|
276
|
+
| `ticker` | Schedule tick interval (`sniper`, `active`, `standard`, `slow`, `maintenance`) |
|
|
277
|
+
| `jobs` | Multi-interval scheduling (alternative to `ticker`) |
|
|
278
|
+
| `hooks` | Natural-language AI instructions (`tick`, `message`, `init`, `execute`, `result`, `shutdown`) |
|
|
279
|
+
| `sources` | External data endpoints fetched each tick |
|
|
280
|
+
| `keys` | API key declarations |
|
|
281
|
+
| `config` | Strategy configuration passed to hooks |
|
|
282
|
+
| `limits` | Spending caps (`fund`, `send`) |
|
|
283
|
+
| `allowedHosts` | Hostnames allowed for external fetches |
|
|
284
|
+
|
|
285
|
+
Adding any of these fields turns your app into a strategy. The base fields (`name`, `icon`, `category`, `size`, `permissions`, `data`) remain the same.
|
|
286
|
+
|
|
287
|
+
See [DEVELOPING-STRATEGIES.md](./wallet/DEVELOPING-STRATEGIES.md) for the full reference on these fields, hook lifecycle, sources, intents, and examples.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Security Model
|
|
292
|
+
|
|
293
|
+
Installed apps run in a strict sandbox with isolation guarantees.
|
|
294
|
+
|
|
295
|
+
### Sandbox Restrictions
|
|
296
|
+
|
|
297
|
+
The iframe is created with `sandbox="allow-scripts"` **without** `allow-same-origin`:
|
|
298
|
+
|
|
299
|
+
| Capability | Allowed? | Reason |
|
|
300
|
+
|-----------|----------|--------|
|
|
301
|
+
| JavaScript execution | Yes | `allow-scripts` is set |
|
|
302
|
+
| Access parent DOM | No | No `allow-same-origin` |
|
|
303
|
+
| Read/write cookies | No | Opaque origin |
|
|
304
|
+
| Use localStorage/sessionStorage | No | Opaque origin |
|
|
305
|
+
| Submit forms | No | No `allow-forms` |
|
|
306
|
+
| Open popups | No | No `allow-popups` |
|
|
307
|
+
| Navigate top frame | No | No `allow-top-navigation` |
|
|
308
|
+
|
|
309
|
+
Apps are loaded via blob URLs (opaque origin `null`). Each app runs in complete isolation from the parent page and other apps.
|
|
310
|
+
|
|
311
|
+
### Communication Model
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
App iframe --fetch()--------> Express :4242/apps/<id>/storage/* (Bearer token)
|
|
315
|
+
App iframe --fetch()--------> Express :4242/apps/<id>/message (Bearer token)
|
|
316
|
+
App iframe --fetch()--------> Express :4242/apps/<id>/fetch (Bearer token, proxied)
|
|
317
|
+
App iframe --postMessage--> Host (subscriptions via on())
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
The Bearer token is injected as `window.__AURA_TOKEN__` before the SDK loads. Tokens are scoped per-app and carry only `app:storage` permission by default.
|
|
321
|
+
|
|
322
|
+
### What Apps Cannot Do
|
|
323
|
+
|
|
324
|
+
- Access the parent page's DOM, JavaScript scope, or React state
|
|
325
|
+
- Read admin tokens or wallet credentials (apps get scoped tokens)
|
|
326
|
+
- Access other apps' storage (tokens scoped by app ID)
|
|
327
|
+
- Load external scripts (`<script src="...">` tags are stripped)
|
|
328
|
+
- Fetch private/internal IPs (SSRF prevention)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Storage API (REST)
|
|
333
|
+
|
|
334
|
+
The SDK wraps these endpoints, but they can also be called directly with a Bearer token.
|
|
335
|
+
|
|
336
|
+
### Endpoints (Express :4242)
|
|
337
|
+
|
|
338
|
+
| Endpoint | Method | Permission | Description |
|
|
339
|
+
|----------|--------|------------|-------------|
|
|
340
|
+
| `/apps/:appId/storage` | GET | `app:storage` | List all keys and values |
|
|
341
|
+
| `/apps/:appId/storage/:key` | GET | `app:storage` | Read a single value |
|
|
342
|
+
| `/apps/:appId/storage/:key` | PUT | `app:storage` | Write a value (upsert) |
|
|
343
|
+
| `/apps/:appId/storage/:key` | DELETE | `app:storage` | Delete a key |
|
|
344
|
+
| `/apps/:appId/apikey/:keyName` | GET | `app:accesskey` | Read an API key |
|
|
345
|
+
| `/apps/:appId/approve` | POST | `strategy:manage` | Approve app permissions |
|
|
346
|
+
| `/apps/:appId/approve` | DELETE | `strategy:manage` | Revoke app approval |
|
|
347
|
+
| `/apps/:appId/token` | GET | admin | Get app's Bearer token |
|
|
348
|
+
|
|
349
|
+
Storage is scoped by `appId`. A token with `app:storage` can only access storage matching its own `agentId`. Use `app:storage:all` for cross-app access.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Example: Annotated Kanban App
|
|
354
|
+
|
|
355
|
+
A complete UI app (`apps/example-kanban/`) demonstrating storage, theming, and vanilla JS patterns.
|
|
356
|
+
|
|
357
|
+
### Manifest (`app.md`)
|
|
358
|
+
|
|
359
|
+
```markdown
|
|
360
|
+
---
|
|
361
|
+
name: Kanban Board
|
|
362
|
+
icon: LayoutGrid
|
|
363
|
+
category: productivity
|
|
364
|
+
size: 2x2
|
|
365
|
+
permissions:
|
|
366
|
+
data:
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
A simple kanban board for tracking tasks. Demonstrates app storage
|
|
370
|
+
persistence -- your cards survive page reloads.
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Entry Point (`index.html`)
|
|
374
|
+
|
|
375
|
+
```html
|
|
376
|
+
<!DOCTYPE html>
|
|
377
|
+
<html>
|
|
378
|
+
<head>
|
|
379
|
+
<style>
|
|
380
|
+
body {
|
|
381
|
+
font-family: ui-monospace, monospace;
|
|
382
|
+
background: var(--color-surface, #fff);
|
|
383
|
+
color: var(--color-text, #0a0a0a);
|
|
384
|
+
padding: 8px;
|
|
385
|
+
font-size: 10px;
|
|
386
|
+
}
|
|
387
|
+
.column {
|
|
388
|
+
border: 1px solid var(--color-border, #d4d4d8);
|
|
389
|
+
background: var(--color-background-alt, #f4f4f5);
|
|
390
|
+
}
|
|
391
|
+
.card {
|
|
392
|
+
background: var(--color-surface, #fff);
|
|
393
|
+
border: 1px solid var(--color-border, #d4d4d8);
|
|
394
|
+
}
|
|
395
|
+
.card:hover {
|
|
396
|
+
border-color: var(--color-border-focus, #0a0a0a);
|
|
397
|
+
}
|
|
398
|
+
</style>
|
|
399
|
+
</head>
|
|
400
|
+
<body>
|
|
401
|
+
<div class="header">
|
|
402
|
+
<span class="title">Kanban</span>
|
|
403
|
+
<button class="add-btn" onclick="showAddForm()">+ ADD</button>
|
|
404
|
+
</div>
|
|
405
|
+
<div class="columns" id="columns"></div>
|
|
406
|
+
|
|
407
|
+
<script>
|
|
408
|
+
var app = window.AuraApp;
|
|
409
|
+
var state = { cards: [] };
|
|
410
|
+
|
|
411
|
+
function save() {
|
|
412
|
+
if (app && app.storage) {
|
|
413
|
+
app.storage.set('kanban', state).catch(function() {});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function init() {
|
|
418
|
+
if (app && app.storage) {
|
|
419
|
+
app.storage.get('kanban').then(function(data) {
|
|
420
|
+
if (data && data.cards) { state = data; }
|
|
421
|
+
render();
|
|
422
|
+
}).catch(function() { render(); });
|
|
423
|
+
} else {
|
|
424
|
+
render();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function escapeHtml(str) {
|
|
429
|
+
var div = document.createElement('div');
|
|
430
|
+
div.textContent = str;
|
|
431
|
+
return div.innerHTML;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function render() {
|
|
435
|
+
// Build columns, cards, drag-and-drop handlers
|
|
436
|
+
// Each state change calls save() then render()
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
init();
|
|
440
|
+
</script>
|
|
441
|
+
</body>
|
|
442
|
+
</html>
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Key Patterns
|
|
446
|
+
|
|
447
|
+
1. **Theme integration** -- All colors use `var(--color-*)` with fallbacks
|
|
448
|
+
2. **Storage persistence** -- `storage.get()` on init, `storage.set()` on every change
|
|
449
|
+
3. **Graceful degradation** -- Works even if `AuraApp` is not available
|
|
450
|
+
4. **XSS prevention** -- User input escaped via `textContent`/`innerHTML`
|
|
451
|
+
5. **Vanilla JS only** -- No build step, no external dependencies
|
|
452
|
+
6. **Inline everything** -- All CSS and JS in a single file (external `<script src>` tags are stripped)
|