@agent-native/dispatch 0.6.1 → 0.8.0
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/README.md +38 -1
- package/dist/actions/apply-dream-proposal.d.ts +3 -0
- package/dist/actions/apply-dream-proposal.d.ts.map +1 -0
- package/dist/actions/apply-dream-proposal.js +11 -0
- package/dist/actions/apply-dream-proposal.js.map +1 -0
- package/dist/actions/create-dream-report.d.ts +3 -0
- package/dist/actions/create-dream-report.d.ts.map +1 -0
- package/dist/actions/create-dream-report.js +67 -0
- package/dist/actions/create-dream-report.js.map +1 -0
- package/dist/actions/create-pylon-ticket.d.ts +3 -0
- package/dist/actions/create-pylon-ticket.d.ts.map +1 -0
- package/dist/actions/create-pylon-ticket.js +94 -0
- package/dist/actions/create-pylon-ticket.js.map +1 -0
- package/dist/actions/create-vault-grant.js +1 -1
- package/dist/actions/create-vault-grant.js.map +1 -1
- package/dist/actions/create-vault-secret.d.ts.map +1 -1
- package/dist/actions/create-vault-secret.js +4 -3
- package/dist/actions/create-vault-secret.js.map +1 -1
- package/dist/actions/create-workspace-resource.js +3 -3
- package/dist/actions/create-workspace-resource.js.map +1 -1
- package/dist/actions/delete-workspace-resource.js +1 -1
- package/dist/actions/delete-workspace-resource.js.map +1 -1
- package/dist/actions/ensure-dream-job.d.ts +3 -0
- package/dist/actions/ensure-dream-job.d.ts.map +1 -0
- package/dist/actions/ensure-dream-job.js +73 -0
- package/dist/actions/ensure-dream-job.js.map +1 -0
- package/dist/actions/get-dream-settings.d.ts +3 -0
- package/dist/actions/get-dream-settings.d.ts.map +1 -0
- package/dist/actions/get-dream-settings.js +11 -0
- package/dist/actions/get-dream-settings.js.map +1 -0
- package/dist/actions/get-dream.d.ts +3 -0
- package/dist/actions/get-dream.d.ts.map +1 -0
- package/dist/actions/get-dream.js +13 -0
- package/dist/actions/get-dream.js.map +1 -0
- package/dist/actions/get-vault-access-settings.d.ts +3 -0
- package/dist/actions/get-vault-access-settings.d.ts.map +1 -0
- package/dist/actions/get-vault-access-settings.js +10 -0
- package/dist/actions/get-vault-access-settings.js.map +1 -0
- package/dist/actions/get-workspace-resource-effective-context.d.ts +3 -0
- package/dist/actions/get-workspace-resource-effective-context.d.ts.map +1 -0
- package/dist/actions/get-workspace-resource-effective-context.js +27 -0
- package/dist/actions/get-workspace-resource-effective-context.js.map +1 -0
- package/dist/actions/grant-vault-secrets-to-app.js +1 -1
- package/dist/actions/grant-vault-secrets-to-app.js.map +1 -1
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +38 -4
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-dream-candidates.d.ts +3 -0
- package/dist/actions/list-dream-candidates.d.ts.map +1 -0
- package/dist/actions/list-dream-candidates.js +68 -0
- package/dist/actions/list-dream-candidates.js.map +1 -0
- package/dist/actions/list-dreams.d.ts +3 -0
- package/dist/actions/list-dreams.d.ts.map +1 -0
- package/dist/actions/list-dreams.js +17 -0
- package/dist/actions/list-dreams.js.map +1 -0
- package/dist/actions/list-integrations-catalog.js +1 -1
- package/dist/actions/list-integrations-catalog.js.map +1 -1
- package/dist/actions/list-vault-grants.js +1 -1
- package/dist/actions/list-vault-grants.js.map +1 -1
- package/dist/actions/list-workspace-apps.d.ts.map +1 -1
- package/dist/actions/list-workspace-apps.js +5 -1
- package/dist/actions/list-workspace-apps.js.map +1 -1
- package/dist/actions/list-workspace-resources-for-app.d.ts +3 -0
- package/dist/actions/list-workspace-resources-for-app.d.ts.map +1 -0
- package/dist/actions/list-workspace-resources-for-app.js +12 -0
- package/dist/actions/list-workspace-resources-for-app.js.map +1 -0
- package/dist/actions/list-workspace-resources.js +1 -1
- package/dist/actions/list-workspace-resources.js.map +1 -1
- package/dist/actions/navigate.d.ts +1 -0
- package/dist/actions/navigate.d.ts.map +1 -1
- package/dist/actions/navigate.js +2 -1
- package/dist/actions/navigate.js.map +1 -1
- package/dist/actions/preview-dream-proposal.d.ts +3 -0
- package/dist/actions/preview-dream-proposal.d.ts.map +1 -0
- package/dist/actions/preview-dream-proposal.js +13 -0
- package/dist/actions/preview-dream-proposal.js.map +1 -0
- package/dist/actions/preview-workspace-resource-change.d.ts +3 -0
- package/dist/actions/preview-workspace-resource-change.d.ts.map +1 -0
- package/dist/actions/preview-workspace-resource-change.js +24 -0
- package/dist/actions/preview-workspace-resource-change.js.map +1 -0
- package/dist/actions/reject-dream-proposal.d.ts +3 -0
- package/dist/actions/reject-dream-proposal.d.ts.map +1 -0
- package/dist/actions/reject-dream-proposal.js +12 -0
- package/dist/actions/reject-dream-proposal.js.map +1 -0
- package/dist/actions/restore-starter-workspace-resources.d.ts +3 -0
- package/dist/actions/restore-starter-workspace-resources.d.ts.map +1 -0
- package/dist/actions/restore-starter-workspace-resources.js +14 -0
- package/dist/actions/restore-starter-workspace-resources.js.map +1 -0
- package/dist/actions/send-code-agent-remote-command.d.ts +3 -0
- package/dist/actions/send-code-agent-remote-command.d.ts.map +1 -0
- package/dist/actions/send-code-agent-remote-command.js +53 -0
- package/dist/actions/send-code-agent-remote-command.js.map +1 -0
- package/dist/actions/set-dream-settings.d.ts +3 -0
- package/dist/actions/set-dream-settings.d.ts.map +1 -0
- package/dist/actions/set-dream-settings.js +41 -0
- package/dist/actions/set-dream-settings.js.map +1 -0
- package/dist/actions/set-vault-access-settings.d.ts +3 -0
- package/dist/actions/set-vault-access-settings.d.ts.map +1 -0
- package/dist/actions/set-vault-access-settings.js +13 -0
- package/dist/actions/set-vault-access-settings.js.map +1 -0
- package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +6 -0
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/actions/sync-vault-to-app.js +1 -1
- package/dist/actions/sync-vault-to-app.js.map +1 -1
- package/dist/actions/update-workspace-app-metadata.d.ts +3 -0
- package/dist/actions/update-workspace-app-metadata.d.ts.map +1 -0
- package/dist/actions/update-workspace-app-metadata.js +30 -0
- package/dist/actions/update-workspace-app-metadata.js.map +1 -0
- package/dist/actions/update-workspace-resource.js +1 -1
- package/dist/actions/update-workspace-resource.js.map +1 -1
- package/dist/actions/view-screen.d.ts.map +1 -1
- package/dist/actions/view-screen.js +77 -4
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/app-keys-popover.js +16 -5
- package/dist/components/app-keys-popover.js.map +1 -1
- package/dist/components/approval-value-block.d.ts +7 -0
- package/dist/components/approval-value-block.d.ts.map +1 -0
- package/dist/components/approval-value-block.js +22 -0
- package/dist/components/approval-value-block.js.map +1 -0
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +41 -16
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-shell.d.ts +4 -4
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +6 -6
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +18 -4
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +2 -2
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/components/ui/chart.d.ts +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +63 -3
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-resource-effective-stack.d.ts +11 -0
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -0
- package/dist/components/workspace-resource-effective-stack.js +59 -0
- package/dist/components/workspace-resource-effective-stack.js.map +1 -0
- package/dist/components/workspace-resource-impact-preview.d.ts +9 -0
- package/dist/components/workspace-resource-impact-preview.d.ts.map +1 -0
- package/dist/components/workspace-resource-impact-preview.js +39 -0
- package/dist/components/workspace-resource-impact-preview.js.map +1 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +59 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.d.ts +714 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +44 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +3 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +35 -8
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/catch-all-target.d.ts +2 -0
- package/dist/lib/catch-all-target.d.ts.map +1 -0
- package/dist/lib/catch-all-target.js +95 -0
- package/dist/lib/catch-all-target.js.map +1 -0
- package/dist/lib/utils.d.ts +2 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +5 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +9 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/pages/$appId.d.ts +2 -2
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +17 -8
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/approval.d.ts.map +1 -1
- package/dist/routes/pages/approval.js +4 -1
- package/dist/routes/pages/approval.js.map +1 -1
- package/dist/routes/pages/approvals.js +1 -1
- package/dist/routes/pages/approvals.js.map +1 -1
- package/dist/routes/pages/dream-settings.d.ts +34 -0
- package/dist/routes/pages/dream-settings.d.ts.map +1 -0
- package/dist/routes/pages/dream-settings.js +68 -0
- package/dist/routes/pages/dream-settings.js.map +1 -0
- package/dist/routes/pages/dreams.d.ts +5 -0
- package/dist/routes/pages/dreams.d.ts.map +1 -0
- package/dist/routes/pages/dreams.js +435 -0
- package/dist/routes/pages/dreams.js.map +1 -0
- package/dist/routes/pages/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +20 -15
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/new-app.js +1 -1
- package/dist/routes/pages/new-app.js.map +1 -1
- package/dist/routes/pages/overview.d.ts.map +1 -1
- package/dist/routes/pages/overview.js +5 -1
- package/dist/routes/pages/overview.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +23 -5
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +187 -35
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts +13 -0
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +298 -11
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/dispatch-integrations.d.ts +1 -1
- package/dist/server/lib/dispatch-integrations.d.ts.map +1 -1
- package/dist/server/lib/dispatch-integrations.js +9 -4
- package/dist/server/lib/dispatch-integrations.js.map +1 -1
- package/dist/server/lib/dispatch-remote-commands.d.ts +83 -0
- package/dist/server/lib/dispatch-remote-commands.d.ts.map +1 -0
- package/dist/server/lib/dispatch-remote-commands.js +256 -0
- package/dist/server/lib/dispatch-remote-commands.js.map +1 -0
- package/dist/server/lib/dispatch-store.d.ts +26 -0
- package/dist/server/lib/dispatch-store.d.ts.map +1 -1
- package/dist/server/lib/dispatch-store.js +17 -1
- package/dist/server/lib/dispatch-store.js.map +1 -1
- package/dist/server/lib/dreams-store.d.ts +398 -0
- package/dist/server/lib/dreams-store.d.ts.map +1 -0
- package/dist/server/lib/dreams-store.js +2330 -0
- package/dist/server/lib/dreams-store.js.map +1 -0
- package/dist/server/lib/env-config.d.ts.map +1 -1
- package/dist/server/lib/env-config.js +5 -0
- package/dist/server/lib/env-config.js.map +1 -1
- package/dist/server/lib/onboarding-steps.d.ts +12 -0
- package/dist/server/lib/onboarding-steps.d.ts.map +1 -0
- package/dist/server/lib/onboarding-steps.js +47 -0
- package/dist/server/lib/onboarding-steps.js.map +1 -0
- package/dist/server/lib/thread-debug-store.d.ts +2 -2
- package/dist/server/lib/vault-store.d.ts +55 -0
- package/dist/server/lib/vault-store.d.ts.map +1 -1
- package/dist/server/lib/vault-store.js +210 -41
- package/dist/server/lib/vault-store.js.map +1 -1
- package/dist/server/lib/workspace-resources-store.d.ts +181 -17
- package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
- package/dist/server/lib/workspace-resources-store.js +737 -108
- package/dist/server/lib/workspace-resources-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.d.ts.map +1 -1
- package/dist/server/plugins/agent-chat.js +2 -1
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/core-routes.d.ts.map +1 -1
- package/dist/server/plugins/core-routes.js +4 -0
- package/dist/server/plugins/core-routes.js.map +1 -1
- package/dist/server/plugins/integrations.js +2 -2
- package/dist/server/plugins/integrations.js.map +1 -1
- package/package.json +15 -11
- package/src/actions/apply-dream-proposal.ts +12 -0
- package/src/actions/create-dream-report.ts +76 -0
- package/src/actions/create-pylon-ticket.ts +109 -0
- package/src/actions/create-vault-grant.ts +1 -1
- package/src/actions/create-vault-secret.ts +4 -3
- package/src/actions/create-workspace-resource.ts +3 -3
- package/src/actions/delete-workspace-resource.ts +1 -1
- package/src/actions/ensure-dream-job.ts +76 -0
- package/src/actions/get-dream-settings.ts +12 -0
- package/src/actions/get-dream.ts +14 -0
- package/src/actions/get-vault-access-settings.ts +11 -0
- package/src/actions/get-workspace-resource-effective-context.ts +34 -0
- package/src/actions/grant-vault-secrets-to-app.ts +1 -1
- package/src/actions/index.spec.ts +26 -0
- package/src/actions/index.ts +39 -4
- package/src/actions/list-dream-candidates.ts +77 -0
- package/src/actions/list-dreams.ts +17 -0
- package/src/actions/list-integrations-catalog.ts +1 -1
- package/src/actions/list-vault-grants.ts +1 -1
- package/src/actions/list-workspace-apps.ts +5 -1
- package/src/actions/list-workspace-resources-for-app.ts +13 -0
- package/src/actions/list-workspace-resources.ts +1 -1
- package/src/actions/navigate.ts +2 -1
- package/src/actions/preview-dream-proposal.ts +14 -0
- package/src/actions/preview-workspace-resource-change.ts +25 -0
- package/src/actions/reject-dream-proposal.ts +12 -0
- package/src/actions/restore-starter-workspace-resources.ts +17 -0
- package/src/actions/send-code-agent-remote-command.ts +59 -0
- package/src/actions/set-dream-settings.spec.ts +81 -0
- package/src/actions/set-dream-settings.ts +44 -0
- package/src/actions/set-vault-access-settings.ts +16 -0
- package/src/actions/start-workspace-app-creation.ts +8 -0
- package/src/actions/sync-vault-to-app.ts +1 -1
- package/src/actions/update-workspace-app-metadata.ts +32 -0
- package/src/actions/update-workspace-resource.ts +1 -1
- package/src/actions/view-screen.ts +94 -3
- package/src/components/app-keys-popover.tsx +23 -7
- package/src/components/approval-value-block.spec.tsx +59 -0
- package/src/components/approval-value-block.tsx +33 -0
- package/src/components/create-app-popover.tsx +50 -16
- package/src/components/dispatch-shell.tsx +16 -15
- package/src/components/layout/Layout.tsx +19 -5
- package/src/components/messaging-setup-panel.tsx +54 -39
- package/src/components/workspace-app-card.tsx +268 -1
- package/src/components/workspace-resource-effective-stack.spec.tsx +125 -0
- package/src/components/workspace-resource-effective-stack.tsx +141 -0
- package/src/components/workspace-resource-impact-preview.spec.tsx +147 -0
- package/src/components/workspace-resource-impact-preview.tsx +116 -0
- package/src/db/migrations.ts +59 -0
- package/src/db/schema.ts +46 -2
- package/src/hooks/use-navigation-state.ts +34 -9
- package/src/lib/catch-all-target.spec.ts +218 -0
- package/src/lib/catch-all-target.ts +99 -0
- package/src/lib/utils.ts +6 -1
- package/src/lib/workspace-apps.ts +9 -0
- package/src/routes/index.ts +1 -0
- package/src/routes/pages/$appId.tsx +21 -8
- package/src/routes/pages/approval.tsx +14 -1
- package/src/routes/pages/approvals.tsx +1 -1
- package/src/routes/pages/dream-settings.spec.ts +130 -0
- package/src/routes/pages/dream-settings.ts +103 -0
- package/src/routes/pages/dreams.tsx +1828 -0
- package/src/routes/pages/integrations.tsx +57 -18
- package/src/routes/pages/new-app.tsx +1 -1
- package/src/routes/pages/overview.tsx +11 -3
- package/src/routes/pages/vault.tsx +76 -9
- package/src/routes/pages/workspace.tsx +577 -97
- package/src/server/lib/app-creation-store.spec.ts +61 -2
- package/src/server/lib/app-creation-store.ts +389 -13
- package/src/server/lib/dispatch-integrations.ts +10 -3
- package/src/server/lib/dispatch-remote-commands.spec.ts +167 -0
- package/src/server/lib/dispatch-remote-commands.ts +375 -0
- package/src/server/lib/dispatch-store.ts +37 -1
- package/src/server/lib/dreams-store.spec.ts +1492 -0
- package/src/server/lib/dreams-store.ts +3168 -0
- package/src/server/lib/env-config.ts +5 -0
- package/src/server/lib/onboarding-steps.ts +49 -0
- package/src/server/lib/vault-store.spec.ts +69 -0
- package/src/server/lib/vault-store.ts +266 -49
- package/src/server/lib/workspace-resource-approval-lifecycle.spec.ts +236 -0
- package/src/server/lib/workspace-resources-store.spec.ts +1106 -0
- package/src/server/lib/workspace-resources-store.ts +1001 -134
- package/src/server/plugins/agent-chat.ts +2 -1
- package/src/server/plugins/core-routes.ts +5 -0
- package/src/server/plugins/integrations.ts +2 -2
- package/dist/actions/sync-workspace-resources-to-all.d.ts +0 -3
- package/dist/actions/sync-workspace-resources-to-all.d.ts.map +0 -1
- package/dist/actions/sync-workspace-resources-to-all.js +0 -9
- package/dist/actions/sync-workspace-resources-to-all.js.map +0 -1
- package/dist/actions/sync-workspace-resources-to-app.d.ts +0 -3
- package/dist/actions/sync-workspace-resources-to-app.d.ts.map +0 -1
- package/dist/actions/sync-workspace-resources-to-app.js +0 -11
- package/dist/actions/sync-workspace-resources-to-app.js.map +0 -1
- package/src/actions/sync-workspace-resources-to-all.ts +0 -10
- package/src/actions/sync-workspace-resources-to-app.ts +0 -12
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch-specific onboarding steps.
|
|
3
|
+
*
|
|
4
|
+
* Slack/Telegram/etc. are auto-registered at order 60 by the framework when
|
|
5
|
+
* their env keys are declared `required: true` in `env-config.ts`. Without
|
|
6
|
+
* any earlier dispatch-specific step, a brand-new workspace lands on
|
|
7
|
+
* "Connect Slack" as the first visible to-do — which is intimidating before
|
|
8
|
+
* the user has even created a real app. This step nudges them at adding
|
|
9
|
+
* their first workspace app first.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { registerOnboardingStep } from "@agent-native/core/onboarding";
|
|
13
|
+
import { listWorkspaceApps } from "./app-creation-store.js";
|
|
14
|
+
|
|
15
|
+
let registered = false;
|
|
16
|
+
|
|
17
|
+
export function registerDispatchOnboardingSteps(): void {
|
|
18
|
+
if (registered) return;
|
|
19
|
+
registered = true;
|
|
20
|
+
|
|
21
|
+
registerOnboardingStep({
|
|
22
|
+
id: "dispatch:create-first-app",
|
|
23
|
+
title: "Create your first app",
|
|
24
|
+
description:
|
|
25
|
+
"Add a workspace app like Mail, Calendar, or Slides — or describe a custom app from the Apps page.",
|
|
26
|
+
order: 5,
|
|
27
|
+
required: false,
|
|
28
|
+
methods: [
|
|
29
|
+
{
|
|
30
|
+
id: "open-apps",
|
|
31
|
+
kind: "link",
|
|
32
|
+
primary: true,
|
|
33
|
+
label: "Browse apps",
|
|
34
|
+
payload: { url: "/dispatch/apps", external: false },
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
isComplete: async () => {
|
|
38
|
+
try {
|
|
39
|
+
const apps = await listWorkspaceApps({
|
|
40
|
+
includeAgentCards: false,
|
|
41
|
+
includeArchived: true,
|
|
42
|
+
});
|
|
43
|
+
return apps.some((app) => !app.isDispatch);
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
const mocks = vi.hoisted(() => ({
|
|
4
|
+
writeAppSecret: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
vi.mock("@agent-native/core/secrets", () => ({
|
|
8
|
+
writeAppSecret: mocks.writeAppSecret,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
credentialStoreScopeForVaultCtx,
|
|
13
|
+
syncSecretsToCredentialStore,
|
|
14
|
+
} from "./vault-store.js";
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.clearAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("credentialStoreScopeForVaultCtx", () => {
|
|
21
|
+
it("uses org scope when vault sync runs inside an org", () => {
|
|
22
|
+
expect(
|
|
23
|
+
credentialStoreScopeForVaultCtx({
|
|
24
|
+
ownerEmail: "admin@example.test",
|
|
25
|
+
orgId: "org_123",
|
|
26
|
+
}),
|
|
27
|
+
).toEqual({ scope: "org", scopeId: "org_123" });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("uses workspace solo scope when no org is active", () => {
|
|
31
|
+
expect(
|
|
32
|
+
credentialStoreScopeForVaultCtx({
|
|
33
|
+
ownerEmail: "owner@example.test",
|
|
34
|
+
orgId: null,
|
|
35
|
+
}),
|
|
36
|
+
).toEqual({
|
|
37
|
+
scope: "workspace",
|
|
38
|
+
scopeId: "solo:owner@example.test",
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("syncSecretsToCredentialStore", () => {
|
|
44
|
+
it("writes vault secrets into app_secrets without returning values", async () => {
|
|
45
|
+
const result = await syncSecretsToCredentialStore(
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
name: "OpenAI API Key",
|
|
49
|
+
credentialKey: "OPENAI_API_KEY",
|
|
50
|
+
value: "sk-test-key",
|
|
51
|
+
} as any,
|
|
52
|
+
],
|
|
53
|
+
{ ownerEmail: "admin@example.test", orgId: "org_123" },
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(mocks.writeAppSecret).toHaveBeenCalledWith({
|
|
57
|
+
key: "OPENAI_API_KEY",
|
|
58
|
+
value: "sk-test-key",
|
|
59
|
+
scope: "org",
|
|
60
|
+
scopeId: "org_123",
|
|
61
|
+
description: "Synced from Dispatch vault: OpenAI API Key",
|
|
62
|
+
});
|
|
63
|
+
expect(result).toEqual({
|
|
64
|
+
scope: "org",
|
|
65
|
+
scopeId: "org_123",
|
|
66
|
+
keys: ["OPENAI_API_KEY"],
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { and, desc, eq, isNull, or } from "drizzle-orm";
|
|
3
3
|
import { discoverAgents } from "@agent-native/core/server/agent-discovery";
|
|
4
|
+
import { writeAppSecret, type SecretScope } from "@agent-native/core/secrets";
|
|
5
|
+
import {
|
|
6
|
+
getOrgSetting,
|
|
7
|
+
getUserSetting,
|
|
8
|
+
putOrgSetting,
|
|
9
|
+
putUserSetting,
|
|
10
|
+
} from "@agent-native/core/settings";
|
|
4
11
|
import { getDb, schema } from "../../db/index.js";
|
|
5
12
|
import {
|
|
6
13
|
currentOwnerEmail,
|
|
@@ -8,6 +15,16 @@ import {
|
|
|
8
15
|
recordAudit,
|
|
9
16
|
} from "./dispatch-store.js";
|
|
10
17
|
|
|
18
|
+
const VAULT_ACCESS_SETTINGS_KEY = "dispatch-vault-access-settings";
|
|
19
|
+
|
|
20
|
+
export type VaultAccessMode = "all-apps" | "manual";
|
|
21
|
+
|
|
22
|
+
export interface VaultAccessSettings {
|
|
23
|
+
mode: VaultAccessMode;
|
|
24
|
+
scope: "org" | "user";
|
|
25
|
+
scopeId: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
/**
|
|
12
29
|
* Caller-supplied access context for vault operations.
|
|
13
30
|
*
|
|
@@ -40,10 +57,10 @@ function ctxScope<T extends { ownerEmail: any; orgId: any }>(
|
|
|
40
57
|
table: T,
|
|
41
58
|
ctx: VaultCtx,
|
|
42
59
|
) {
|
|
43
|
-
|
|
44
|
-
eq(table.ownerEmail, ctx.ownerEmail),
|
|
45
|
-
|
|
46
|
-
);
|
|
60
|
+
if (!ctx.orgId) {
|
|
61
|
+
return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));
|
|
62
|
+
}
|
|
63
|
+
return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
/** Build a ctx that scopes to a specific row's owner/org (used when a
|
|
@@ -68,12 +85,57 @@ function safeJson(value: unknown) {
|
|
|
68
85
|
return JSON.stringify(value ?? null);
|
|
69
86
|
}
|
|
70
87
|
|
|
71
|
-
function
|
|
88
|
+
function scopedFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {
|
|
89
|
+
return ctxScope(table, requireVaultCtx());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function normalizeCredentialKey(value: string) {
|
|
93
|
+
return value.trim();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function vaultAccessScope() {
|
|
72
97
|
const orgId = currentOrgId();
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
if (orgId) return { scope: "org" as const, scopeId: orgId };
|
|
99
|
+
return { scope: "user" as const, scopeId: currentOwnerEmail() };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseVaultAccessMode(value: unknown): VaultAccessMode {
|
|
103
|
+
return value === "manual" ? "manual" : "all-apps";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function getVaultAccessSettings(): Promise<VaultAccessSettings> {
|
|
107
|
+
const scope = vaultAccessScope();
|
|
108
|
+
const raw =
|
|
109
|
+
scope.scope === "org"
|
|
110
|
+
? await getOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY)
|
|
111
|
+
: await getUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY);
|
|
112
|
+
return {
|
|
113
|
+
...scope,
|
|
114
|
+
mode: parseVaultAccessMode(raw?.mode),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function setVaultAccessSettings(input: {
|
|
119
|
+
mode: VaultAccessMode;
|
|
120
|
+
}): Promise<VaultAccessSettings> {
|
|
121
|
+
const scope = vaultAccessScope();
|
|
122
|
+
const next = { mode: parseVaultAccessMode(input.mode) };
|
|
123
|
+
if (scope.scope === "org") {
|
|
124
|
+
await putOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
|
|
125
|
+
} else {
|
|
126
|
+
await putUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
|
|
127
|
+
}
|
|
128
|
+
await recordAudit({
|
|
129
|
+
action: "vault.access-settings.updated",
|
|
130
|
+
targetType: "vault-settings",
|
|
131
|
+
targetId: VAULT_ACCESS_SETTINGS_KEY,
|
|
132
|
+
summary:
|
|
133
|
+
next.mode === "all-apps"
|
|
134
|
+
? "Set vault access to all workspace apps"
|
|
135
|
+
: "Set vault access to manual per-app grants",
|
|
136
|
+
metadata: next,
|
|
137
|
+
});
|
|
138
|
+
return getVaultAccessSettings();
|
|
77
139
|
}
|
|
78
140
|
|
|
79
141
|
// ─── Vault Audit ──────────────────────────────────────────────────
|
|
@@ -106,7 +168,7 @@ export async function listVaultAudit(limit = 50) {
|
|
|
106
168
|
return db
|
|
107
169
|
.select()
|
|
108
170
|
.from(schema.vaultAuditLog)
|
|
109
|
-
.where(
|
|
171
|
+
.where(scopedFilter(schema.vaultAuditLog))
|
|
110
172
|
.orderBy(desc(schema.vaultAuditLog.createdAt))
|
|
111
173
|
.limit(limit);
|
|
112
174
|
}
|
|
@@ -118,7 +180,7 @@ export async function listSecrets() {
|
|
|
118
180
|
return db
|
|
119
181
|
.select()
|
|
120
182
|
.from(schema.vaultSecrets)
|
|
121
|
-
.where(
|
|
183
|
+
.where(scopedFilter(schema.vaultSecrets))
|
|
122
184
|
.orderBy(desc(schema.vaultSecrets.updatedAt));
|
|
123
185
|
}
|
|
124
186
|
|
|
@@ -149,6 +211,55 @@ export async function createSecret(
|
|
|
149
211
|
) {
|
|
150
212
|
const db = getDb();
|
|
151
213
|
const timestamp = now();
|
|
214
|
+
const credentialKey = normalizeCredentialKey(input.credentialKey);
|
|
215
|
+
if (!credentialKey) throw new Error("Credential key is required");
|
|
216
|
+
const existing = await db
|
|
217
|
+
.select()
|
|
218
|
+
.from(schema.vaultSecrets)
|
|
219
|
+
.where(
|
|
220
|
+
and(
|
|
221
|
+
eq(schema.vaultSecrets.credentialKey, credentialKey),
|
|
222
|
+
ctxScope(schema.vaultSecrets, ctx),
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
.orderBy(desc(schema.vaultSecrets.updatedAt))
|
|
226
|
+
.limit(1);
|
|
227
|
+
|
|
228
|
+
if (existing[0]) {
|
|
229
|
+
await db
|
|
230
|
+
.update(schema.vaultSecrets)
|
|
231
|
+
.set({
|
|
232
|
+
name: input.name,
|
|
233
|
+
credentialKey,
|
|
234
|
+
value: input.value,
|
|
235
|
+
provider: input.provider || null,
|
|
236
|
+
description: input.description || null,
|
|
237
|
+
updatedAt: timestamp,
|
|
238
|
+
})
|
|
239
|
+
.where(
|
|
240
|
+
and(
|
|
241
|
+
eq(schema.vaultSecrets.id, existing[0].id),
|
|
242
|
+
ctxScope(schema.vaultSecrets, ctx),
|
|
243
|
+
),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
await recordVaultAudit({
|
|
247
|
+
action: "secret.updated",
|
|
248
|
+
secretId: existing[0].id,
|
|
249
|
+
summary: `Updated secret "${input.name}" (${credentialKey})`,
|
|
250
|
+
metadata: { credentialKey, provider: input.provider },
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
await recordAudit({
|
|
254
|
+
action: "vault.secret.updated",
|
|
255
|
+
targetType: "vault-secret",
|
|
256
|
+
targetId: existing[0].id,
|
|
257
|
+
summary: `Updated vault secret "${input.name}" (${credentialKey})`,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
return getSecret(existing[0].id, ctx);
|
|
261
|
+
}
|
|
262
|
+
|
|
152
263
|
const secretId = id();
|
|
153
264
|
const actor = ctx.ownerEmail;
|
|
154
265
|
|
|
@@ -157,7 +268,7 @@ export async function createSecret(
|
|
|
157
268
|
ownerEmail: actor,
|
|
158
269
|
orgId: ctx.orgId,
|
|
159
270
|
name: input.name,
|
|
160
|
-
credentialKey
|
|
271
|
+
credentialKey,
|
|
161
272
|
value: input.value,
|
|
162
273
|
provider: input.provider || null,
|
|
163
274
|
description: input.description || null,
|
|
@@ -169,15 +280,15 @@ export async function createSecret(
|
|
|
169
280
|
await recordVaultAudit({
|
|
170
281
|
action: "secret.created",
|
|
171
282
|
secretId,
|
|
172
|
-
summary: `Created secret "${input.name}" (${
|
|
173
|
-
metadata: { credentialKey
|
|
283
|
+
summary: `Created secret "${input.name}" (${credentialKey})`,
|
|
284
|
+
metadata: { credentialKey, provider: input.provider },
|
|
174
285
|
});
|
|
175
286
|
|
|
176
287
|
await recordAudit({
|
|
177
288
|
action: "vault.secret.created",
|
|
178
289
|
targetType: "vault-secret",
|
|
179
290
|
targetId: secretId,
|
|
180
|
-
summary: `Created vault secret "${input.name}" (${
|
|
291
|
+
summary: `Created vault secret "${input.name}" (${credentialKey})`,
|
|
181
292
|
});
|
|
182
293
|
|
|
183
294
|
return getSecret(secretId, ctx);
|
|
@@ -259,7 +370,7 @@ export async function listGrants(filter?: {
|
|
|
259
370
|
appId?: string;
|
|
260
371
|
}) {
|
|
261
372
|
const db = getDb();
|
|
262
|
-
const conditions = [
|
|
373
|
+
const conditions = [scopedFilter(schema.vaultGrants)];
|
|
263
374
|
if (filter?.secretId) {
|
|
264
375
|
conditions.push(eq(schema.vaultGrants.secretId, filter.secretId) as any);
|
|
265
376
|
}
|
|
@@ -340,7 +451,16 @@ export async function grantSecretsToApp(
|
|
|
340
451
|
appId: string,
|
|
341
452
|
ctx: VaultCtx = requireVaultCtx(),
|
|
342
453
|
) {
|
|
454
|
+
const access = await getVaultAccessSettings();
|
|
343
455
|
const uniqueSecretIds = Array.from(new Set(secretIds));
|
|
456
|
+
if (access.mode === "all-apps") {
|
|
457
|
+
return {
|
|
458
|
+
appId,
|
|
459
|
+
accessMode: access.mode,
|
|
460
|
+
created: [],
|
|
461
|
+
skipped: uniqueSecretIds,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
344
464
|
const existingActive = (await listGrants({ appId })).filter(
|
|
345
465
|
(grant) => grant.status === "active",
|
|
346
466
|
);
|
|
@@ -362,7 +482,7 @@ export async function grantSecretsToApp(
|
|
|
362
482
|
}
|
|
363
483
|
}
|
|
364
484
|
|
|
365
|
-
return { appId, created, skipped };
|
|
485
|
+
return { appId, accessMode: access.mode, created, skipped };
|
|
366
486
|
}
|
|
367
487
|
|
|
368
488
|
export async function revokeGrant(
|
|
@@ -403,6 +523,40 @@ export async function revokeGrant(
|
|
|
403
523
|
return getGrant(grantId, ctx);
|
|
404
524
|
}
|
|
405
525
|
|
|
526
|
+
// ─── Shared Credential Store Sync ─────────────────────────────────
|
|
527
|
+
|
|
528
|
+
type VaultSecretRow = typeof schema.vaultSecrets.$inferSelect;
|
|
529
|
+
|
|
530
|
+
export function credentialStoreScopeForVaultCtx(ctx: VaultCtx): {
|
|
531
|
+
scope: Extract<SecretScope, "org" | "workspace">;
|
|
532
|
+
scopeId: string;
|
|
533
|
+
} {
|
|
534
|
+
if (ctx.orgId) return { scope: "org", scopeId: ctx.orgId };
|
|
535
|
+
return { scope: "workspace", scopeId: `solo:${ctx.ownerEmail}` };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export async function syncSecretsToCredentialStore(
|
|
539
|
+
secrets: VaultSecretRow[],
|
|
540
|
+
ctx: VaultCtx,
|
|
541
|
+
) {
|
|
542
|
+
const target = credentialStoreScopeForVaultCtx(ctx);
|
|
543
|
+
const syncedKeys: string[] = [];
|
|
544
|
+
|
|
545
|
+
for (const secret of secrets) {
|
|
546
|
+
if (!secret.credentialKey || !secret.value) continue;
|
|
547
|
+
await writeAppSecret({
|
|
548
|
+
key: secret.credentialKey,
|
|
549
|
+
value: secret.value,
|
|
550
|
+
scope: target.scope,
|
|
551
|
+
scopeId: target.scopeId,
|
|
552
|
+
description: `Synced from Dispatch vault: ${secret.name}`,
|
|
553
|
+
});
|
|
554
|
+
syncedKeys.push(secret.credentialKey);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return { ...target, keys: syncedKeys };
|
|
558
|
+
}
|
|
559
|
+
|
|
406
560
|
// ─── Sync ──────────────────────────────────────────────────────
|
|
407
561
|
|
|
408
562
|
export async function syncGrantsToApp(
|
|
@@ -410,46 +564,78 @@ export async function syncGrantsToApp(
|
|
|
410
564
|
ctx: VaultCtx = requireVaultCtx(),
|
|
411
565
|
) {
|
|
412
566
|
const db = getDb();
|
|
567
|
+
const access = await getVaultAccessSettings();
|
|
413
568
|
const agents = await discoverAgents("dispatch");
|
|
414
569
|
const agent = agents.find((a) => a.id === appId);
|
|
415
570
|
if (!agent) throw new Error(`App "${appId}" not found in agent registry`);
|
|
416
571
|
|
|
417
|
-
const
|
|
418
|
-
const activeGrants =
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
572
|
+
const secretsToSync: VaultSecretRow[] = [];
|
|
573
|
+
const activeGrants =
|
|
574
|
+
access.mode === "manual"
|
|
575
|
+
? (await listGrants({ appId })).filter((g) => g.status === "active")
|
|
576
|
+
: [];
|
|
422
577
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
578
|
+
if (access.mode === "all-apps") {
|
|
579
|
+
const secrets = await listSecrets();
|
|
580
|
+
for (const secret of secrets) {
|
|
581
|
+
secretsToSync.push(secret);
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
for (const grant of activeGrants) {
|
|
585
|
+
const secret = await getSecret(grant.secretId, ctx);
|
|
586
|
+
if (secret) {
|
|
587
|
+
secretsToSync.push(secret);
|
|
588
|
+
}
|
|
429
589
|
}
|
|
430
590
|
}
|
|
431
591
|
|
|
432
|
-
if (
|
|
433
|
-
return { appId, synced: 0, keys: [] };
|
|
592
|
+
if (secretsToSync.length === 0) {
|
|
593
|
+
return { appId, accessMode: access.mode, synced: 0, keys: [] };
|
|
434
594
|
}
|
|
435
595
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
596
|
+
const credentialStoreSync = await syncSecretsToCredentialStore(
|
|
597
|
+
secretsToSync,
|
|
598
|
+
ctx,
|
|
599
|
+
);
|
|
600
|
+
const vars = secretsToSync.map((secret) => ({
|
|
601
|
+
key: secret.credentialKey,
|
|
602
|
+
value: secret.value,
|
|
603
|
+
}));
|
|
604
|
+
let envVarSync:
|
|
605
|
+
| { status: "synced"; keys: string[] }
|
|
606
|
+
| { status: "skipped"; reason: string }
|
|
607
|
+
| { status: "failed"; reason: string };
|
|
608
|
+
|
|
609
|
+
// Best-effort push to the app's env-vars endpoint for local/dev apps that
|
|
610
|
+
// still read process.env directly. Production/shared-DB apps intentionally
|
|
611
|
+
// reject env writes; the encrypted app_secrets sync above is the canonical
|
|
612
|
+
// path for request-scoped credentials.
|
|
613
|
+
try {
|
|
614
|
+
const res = await fetch(`${agent.url}/_agent-native/env-vars`, {
|
|
615
|
+
method: "POST",
|
|
616
|
+
headers: { "Content-Type": "application/json" },
|
|
617
|
+
body: JSON.stringify({ vars }),
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
if (res.ok) {
|
|
621
|
+
const result = await res.json();
|
|
622
|
+
envVarSync = { status: "synced", keys: result.saved || [] };
|
|
623
|
+
} else {
|
|
624
|
+
const err = await res.text().catch(() => "Unknown error");
|
|
625
|
+
envVarSync = { status: "skipped", reason: err };
|
|
626
|
+
}
|
|
627
|
+
} catch (err) {
|
|
628
|
+
envVarSync = {
|
|
629
|
+
status: "failed",
|
|
630
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
631
|
+
};
|
|
446
632
|
}
|
|
447
633
|
|
|
448
|
-
const
|
|
449
|
-
const syncedKeys: string[] = result.saved || [];
|
|
634
|
+
const syncedKeys = credentialStoreSync.keys;
|
|
450
635
|
const timestamp = now();
|
|
451
636
|
|
|
452
|
-
// Update syncedAt on grants that were successfully pushed
|
|
637
|
+
// Update syncedAt on grants that were successfully pushed to the shared
|
|
638
|
+
// credential store. All-apps mode has no explicit grant rows to update.
|
|
453
639
|
for (const grant of activeGrants) {
|
|
454
640
|
const secret = await getSecret(grant.secretId, ctx);
|
|
455
641
|
if (secret && syncedKeys.includes(secret.credentialKey)) {
|
|
@@ -464,17 +650,36 @@ export async function syncGrantsToApp(
|
|
|
464
650
|
action: "secret.synced",
|
|
465
651
|
appId,
|
|
466
652
|
summary: `Synced ${syncedKeys.length} secret(s) to ${appId}: ${syncedKeys.join(", ")}`,
|
|
467
|
-
metadata: {
|
|
653
|
+
metadata: {
|
|
654
|
+
syncedKeys,
|
|
655
|
+
accessMode: access.mode,
|
|
656
|
+
credentialStore: {
|
|
657
|
+
scope: credentialStoreSync.scope,
|
|
658
|
+
scopeId: credentialStoreSync.scopeId,
|
|
659
|
+
},
|
|
660
|
+
envVars: envVarSync,
|
|
661
|
+
},
|
|
468
662
|
});
|
|
469
663
|
|
|
470
|
-
return {
|
|
664
|
+
return {
|
|
665
|
+
appId,
|
|
666
|
+
accessMode: access.mode,
|
|
667
|
+
synced: syncedKeys.length,
|
|
668
|
+
keys: syncedKeys,
|
|
669
|
+
credentialStore: {
|
|
670
|
+
scope: credentialStoreSync.scope,
|
|
671
|
+
scopeId: credentialStoreSync.scopeId,
|
|
672
|
+
synced: credentialStoreSync.keys.length,
|
|
673
|
+
},
|
|
674
|
+
envVars: envVarSync,
|
|
675
|
+
};
|
|
471
676
|
}
|
|
472
677
|
|
|
473
678
|
// ─── Requests ──────────────────────────────────────────────────────
|
|
474
679
|
|
|
475
680
|
export async function listRequests(filter?: { status?: string }) {
|
|
476
681
|
const db = getDb();
|
|
477
|
-
const conditions = [
|
|
682
|
+
const conditions = [scopedFilter(schema.vaultRequests)];
|
|
478
683
|
if (filter?.status) {
|
|
479
684
|
conditions.push(eq(schema.vaultRequests.status, filter.status) as any);
|
|
480
685
|
}
|
|
@@ -671,10 +876,12 @@ export interface AppIntegrations {
|
|
|
671
876
|
url: string;
|
|
672
877
|
color: string;
|
|
673
878
|
integrations: IntegrationEntry[];
|
|
879
|
+
vaultAccessMode: VaultAccessMode;
|
|
674
880
|
reachable: boolean;
|
|
675
881
|
}
|
|
676
882
|
|
|
677
883
|
export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
884
|
+
const access = await getVaultAccessSettings();
|
|
678
885
|
const agents = await discoverAgents("dispatch");
|
|
679
886
|
const grants = await listGrants();
|
|
680
887
|
const secrets = await listSecrets();
|
|
@@ -695,6 +902,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
|
695
902
|
url: agent.url,
|
|
696
903
|
color: agent.color,
|
|
697
904
|
integrations: [],
|
|
905
|
+
vaultAccessMode: access.mode,
|
|
698
906
|
reachable: false,
|
|
699
907
|
});
|
|
700
908
|
continue;
|
|
@@ -720,7 +928,9 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
|
720
928
|
required: env.required,
|
|
721
929
|
configured: env.configured,
|
|
722
930
|
vaultGranted:
|
|
723
|
-
!!matchingSecret &&
|
|
931
|
+
!!matchingSecret &&
|
|
932
|
+
(access.mode === "all-apps" ||
|
|
933
|
+
grantedSecretIds.has(matchingSecret.id)),
|
|
724
934
|
vaultSecretId: matchingSecret?.id,
|
|
725
935
|
};
|
|
726
936
|
});
|
|
@@ -731,6 +941,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
|
731
941
|
url: agent.url,
|
|
732
942
|
color: agent.color,
|
|
733
943
|
integrations,
|
|
944
|
+
vaultAccessMode: access.mode,
|
|
734
945
|
reachable: true,
|
|
735
946
|
});
|
|
736
947
|
} catch {
|
|
@@ -740,6 +951,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
|
740
951
|
url: agent.url,
|
|
741
952
|
color: agent.color,
|
|
742
953
|
integrations: [],
|
|
954
|
+
vaultAccessMode: access.mode,
|
|
743
955
|
reachable: false,
|
|
744
956
|
});
|
|
745
957
|
}
|
|
@@ -751,15 +963,20 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
|
|
|
751
963
|
// ─── Vault Overview (for dashboard) ──────────────────────────────
|
|
752
964
|
|
|
753
965
|
export async function listVaultOverview() {
|
|
754
|
-
const [secrets, grants, requests] = await Promise.all([
|
|
966
|
+
const [secrets, grants, requests, access] = await Promise.all([
|
|
755
967
|
listSecrets(),
|
|
756
968
|
listGrants(),
|
|
757
969
|
listRequests(),
|
|
970
|
+
getVaultAccessSettings(),
|
|
758
971
|
]);
|
|
972
|
+
const manualGrantCount = grants.filter((g) => g.status === "active").length;
|
|
759
973
|
|
|
760
974
|
return {
|
|
975
|
+
accessMode: access.mode,
|
|
761
976
|
secretCount: secrets.length,
|
|
762
|
-
activeGrantCount:
|
|
977
|
+
activeGrantCount:
|
|
978
|
+
access.mode === "all-apps" ? secrets.length : manualGrantCount,
|
|
979
|
+
manualGrantCount,
|
|
763
980
|
pendingRequestCount: requests.filter((r) => r.status === "pending").length,
|
|
764
981
|
};
|
|
765
982
|
}
|