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,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch execution engine — pure logic, no Express dependency.
|
|
3
|
+
*
|
|
4
|
+
* Validates batch requests, builds execution waves via topological sort,
|
|
5
|
+
* and resolves template references between sub-request responses.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface BatchSubRequest {
|
|
9
|
+
id: string;
|
|
10
|
+
method: string;
|
|
11
|
+
path: string;
|
|
12
|
+
body?: Record<string, unknown>;
|
|
13
|
+
dependsOn?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BatchResponse {
|
|
17
|
+
status: number;
|
|
18
|
+
body: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const VALID_METHODS = new Set(['GET', 'POST', 'PUT', 'DELETE']);
|
|
22
|
+
const MAX_REQUESTS = 20;
|
|
23
|
+
|
|
24
|
+
// ── Validation ──
|
|
25
|
+
|
|
26
|
+
export interface ValidationSuccess {
|
|
27
|
+
valid: true;
|
|
28
|
+
waves: string[][];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ValidationFailure {
|
|
32
|
+
valid: false;
|
|
33
|
+
error: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ValidationResult = ValidationSuccess | ValidationFailure;
|
|
37
|
+
|
|
38
|
+
export function validateBatchRequest(requests: unknown): ValidationResult {
|
|
39
|
+
if (!Array.isArray(requests)) {
|
|
40
|
+
return { valid: false, error: 'requests must be an array' };
|
|
41
|
+
}
|
|
42
|
+
if (requests.length === 0) {
|
|
43
|
+
return { valid: false, error: 'requests array must not be empty' };
|
|
44
|
+
}
|
|
45
|
+
if (requests.length > MAX_REQUESTS) {
|
|
46
|
+
return { valid: false, error: `requests array exceeds maximum of ${MAX_REQUESTS} items` };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ids = new Set<string>();
|
|
50
|
+
for (const req of requests) {
|
|
51
|
+
if (!req || typeof req !== 'object') {
|
|
52
|
+
return { valid: false, error: 'Each request must be an object' };
|
|
53
|
+
}
|
|
54
|
+
const r = req as Record<string, unknown>;
|
|
55
|
+
|
|
56
|
+
if (typeof r.id !== 'string' || !r.id.trim()) {
|
|
57
|
+
return { valid: false, error: 'Each request must have a non-empty string id' };
|
|
58
|
+
}
|
|
59
|
+
if (ids.has(r.id)) {
|
|
60
|
+
return { valid: false, error: `Duplicate request id: ${r.id}` };
|
|
61
|
+
}
|
|
62
|
+
ids.add(r.id);
|
|
63
|
+
|
|
64
|
+
if (typeof r.method !== 'string' || !VALID_METHODS.has(r.method.toUpperCase())) {
|
|
65
|
+
return { valid: false, error: `Invalid method "${r.method}" for request "${r.id}". Must be GET, POST, PUT, or DELETE` };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof r.path !== 'string' || !r.path.startsWith('/')) {
|
|
69
|
+
return { valid: false, error: `Invalid path for request "${r.id}". Path must start with /` };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (r.dependsOn !== undefined) {
|
|
73
|
+
if (typeof r.dependsOn !== 'string') {
|
|
74
|
+
return { valid: false, error: `dependsOn must be a string for request "${r.id}"` };
|
|
75
|
+
}
|
|
76
|
+
if (r.dependsOn === r.id) {
|
|
77
|
+
return { valid: false, error: `Request "${r.id}" cannot depend on itself` };
|
|
78
|
+
}
|
|
79
|
+
if (!ids.has(r.dependsOn)) {
|
|
80
|
+
// Check if the target exists anywhere in the array (not just seen so far)
|
|
81
|
+
const exists = requests.some((other: any) => other?.id === r.dependsOn);
|
|
82
|
+
if (!exists) {
|
|
83
|
+
return { valid: false, error: `Request "${r.id}" depends on unknown request "${r.dependsOn}"` };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Cycle detection via Kahn's algorithm
|
|
90
|
+
const typed = requests as BatchSubRequest[];
|
|
91
|
+
const cycleCheck = detectCycles(typed);
|
|
92
|
+
if (cycleCheck) {
|
|
93
|
+
return { valid: false, error: cycleCheck };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const waves = buildWaves(typed);
|
|
97
|
+
return { valid: true, waves };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ── Cycle Detection (Kahn's Algorithm) ──
|
|
101
|
+
|
|
102
|
+
function detectCycles(requests: BatchSubRequest[]): string | null {
|
|
103
|
+
const inDegree = new Map<string, number>();
|
|
104
|
+
const dependents = new Map<string, string[]>(); // dep -> [ids that depend on it]
|
|
105
|
+
|
|
106
|
+
for (const req of requests) {
|
|
107
|
+
inDegree.set(req.id, 0);
|
|
108
|
+
dependents.set(req.id, []);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const req of requests) {
|
|
112
|
+
if (req.dependsOn) {
|
|
113
|
+
inDegree.set(req.id, (inDegree.get(req.id) || 0) + 1);
|
|
114
|
+
dependents.get(req.dependsOn)!.push(req.id);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const queue: string[] = [];
|
|
119
|
+
for (const [id, degree] of inDegree) {
|
|
120
|
+
if (degree === 0) queue.push(id);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let processed = 0;
|
|
124
|
+
while (queue.length > 0) {
|
|
125
|
+
const id = queue.shift()!;
|
|
126
|
+
processed++;
|
|
127
|
+
for (const dep of dependents.get(id) || []) {
|
|
128
|
+
const newDegree = (inDegree.get(dep) || 1) - 1;
|
|
129
|
+
inDegree.set(dep, newDegree);
|
|
130
|
+
if (newDegree === 0) queue.push(dep);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (processed < requests.length) {
|
|
135
|
+
return 'Circular dependency detected in requests';
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── Wave Building (Topological Sort) ──
|
|
141
|
+
|
|
142
|
+
export function buildWaves(requests: BatchSubRequest[]): string[][] {
|
|
143
|
+
// Map each request to its wave number
|
|
144
|
+
const waveMap = new Map<string, number>();
|
|
145
|
+
const requestMap = new Map<string, BatchSubRequest>();
|
|
146
|
+
|
|
147
|
+
for (const req of requests) {
|
|
148
|
+
requestMap.set(req.id, req);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Compute wave for each request
|
|
152
|
+
function getWave(id: string): number {
|
|
153
|
+
if (waveMap.has(id)) return waveMap.get(id)!;
|
|
154
|
+
|
|
155
|
+
const req = requestMap.get(id)!;
|
|
156
|
+
if (!req.dependsOn) {
|
|
157
|
+
waveMap.set(id, 0);
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const depWave = getWave(req.dependsOn);
|
|
162
|
+
const wave = depWave + 1;
|
|
163
|
+
waveMap.set(id, wave);
|
|
164
|
+
return wave;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const req of requests) {
|
|
168
|
+
getWave(req.id);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Group by wave
|
|
172
|
+
const waves: Map<number, string[]> = new Map();
|
|
173
|
+
for (const req of requests) {
|
|
174
|
+
const w = waveMap.get(req.id)!;
|
|
175
|
+
if (!waves.has(w)) waves.set(w, []);
|
|
176
|
+
waves.get(w)!.push(req.id);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Sort wave numbers and return arrays
|
|
180
|
+
const sortedKeys = [...waves.keys()].sort((a, b) => a - b);
|
|
181
|
+
return sortedKeys.map(k => waves.get(k)!);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ── Template Resolution ──
|
|
185
|
+
|
|
186
|
+
export function resolveTemplates(str: string, responses: Map<string, BatchResponse>): string {
|
|
187
|
+
return str.replace(/\$\{([^}]+)\}/g, (_match, expr: string) => {
|
|
188
|
+
const segments = expr.split('.');
|
|
189
|
+
const requestId = segments[0];
|
|
190
|
+
const pathSegments = segments.slice(1);
|
|
191
|
+
|
|
192
|
+
const response = responses.get(requestId);
|
|
193
|
+
if (!response) {
|
|
194
|
+
throw new Error(`Template reference "${expr}": request "${requestId}" not found in responses`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let current: unknown = response.body;
|
|
198
|
+
for (const segment of pathSegments) {
|
|
199
|
+
if (current === null || current === undefined) {
|
|
200
|
+
throw new Error(`Template reference "${expr}": cannot access "${segment}" on null/undefined`);
|
|
201
|
+
}
|
|
202
|
+
if (typeof current === 'object') {
|
|
203
|
+
// Try numeric index for arrays
|
|
204
|
+
if (Array.isArray(current)) {
|
|
205
|
+
const idx = parseInt(segment, 10);
|
|
206
|
+
if (Number.isNaN(idx)) {
|
|
207
|
+
throw new Error(`Template reference "${expr}": "${segment}" is not a valid array index`);
|
|
208
|
+
}
|
|
209
|
+
current = current[idx];
|
|
210
|
+
} else {
|
|
211
|
+
current = (current as Record<string, unknown>)[segment];
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
throw new Error(`Template reference "${expr}": cannot access "${segment}" on ${typeof current}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (current === undefined) {
|
|
219
|
+
throw new Error(`Template reference "${expr}": path not found in response`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Convert to string for interpolation
|
|
223
|
+
if (current === null) return 'null';
|
|
224
|
+
if (typeof current === 'object') return JSON.stringify(current);
|
|
225
|
+
return String(current);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function resolveBodyTemplates(body: unknown, responses: Map<string, BatchResponse>): unknown {
|
|
230
|
+
if (body === null || body === undefined) return body;
|
|
231
|
+
if (typeof body === 'string') return resolveTemplates(body, responses);
|
|
232
|
+
if (Array.isArray(body)) return body.map(item => resolveBodyTemplates(item, responses));
|
|
233
|
+
if (typeof body === 'object') {
|
|
234
|
+
const result: Record<string, unknown> = {};
|
|
235
|
+
for (const [key, value] of Object.entries(body as Record<string, unknown>)) {
|
|
236
|
+
result[key] = resolveBodyTemplates(value, responses);
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
// Numbers, booleans, etc. pass through unchanged
|
|
241
|
+
return body;
|
|
242
|
+
}
|