@agent-native/dispatch 0.24.6 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/actions/connect-external-agent.d.ts +18 -0
- package/dist/actions/connect-external-agent.d.ts.map +1 -0
- package/dist/actions/connect-external-agent.js +68 -0
- package/dist/actions/connect-external-agent.js.map +1 -0
- package/dist/actions/create-workspace-resource.d.ts +14 -14
- package/dist/actions/create-workspace-resource.js +9 -2
- package/dist/actions/create-workspace-resource.js.map +1 -1
- package/dist/actions/create_workspace_app_embed_session.d.ts +13 -0
- package/dist/actions/create_workspace_app_embed_session.d.ts.map +1 -0
- package/dist/actions/create_workspace_app_embed_session.js +30 -0
- package/dist/actions/create_workspace_app_embed_session.js.map +1 -0
- package/dist/actions/import-agent-pack.d.ts +96 -0
- package/dist/actions/import-agent-pack.d.ts.map +1 -0
- package/dist/actions/import-agent-pack.js +116 -0
- package/dist/actions/import-agent-pack.js.map +1 -0
- package/dist/actions/import-agent.d.ts +60 -0
- package/dist/actions/import-agent.d.ts.map +1 -0
- package/dist/actions/import-agent.js +82 -0
- package/dist/actions/import-agent.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +10 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-agent-pack.d.ts +36 -0
- package/dist/actions/list-agent-pack.d.ts.map +1 -0
- package/dist/actions/list-agent-pack.js +32 -0
- package/dist/actions/list-agent-pack.js.map +1 -0
- package/dist/actions/list-workspace-resource-options.d.ts +1 -1
- package/dist/actions/list-workspace-resource-options.js +8 -1
- package/dist/actions/list-workspace-resource-options.js.map +1 -1
- package/dist/actions/list-workspace-resources.d.ts +1 -1
- package/dist/actions/list-workspace-resources.js +8 -1
- package/dist/actions/list-workspace-resources.js.map +1 -1
- package/dist/actions/navigate.js +1 -1
- package/dist/actions/navigate.js.map +1 -1
- package/dist/actions/provider-api-register.d.ts +10 -10
- package/dist/actions/update-workspace-resource.d.ts +13 -13
- package/dist/actions/view-screen.js +18 -1
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +1 -8
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +33 -106
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/simple-agents-panel.d.ts +9 -0
- package/dist/components/simple-agents-panel.d.ts.map +1 -0
- package/dist/components/simple-agents-panel.js +405 -0
- package/dist/components/simple-agents-panel.js.map +1 -0
- package/dist/components/workspace-app-host.d.ts +29 -0
- package/dist/components/workspace-app-host.d.ts.map +1 -0
- package/dist/components/workspace-app-host.js +145 -0
- package/dist/components/workspace-app-host.js.map +1 -0
- package/dist/db/migrations.d.ts +2 -4
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +25 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.js +1 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +1 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +10 -0
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/agent-pack.d.ts +31 -0
- package/dist/lib/agent-pack.d.ts.map +1 -0
- package/dist/lib/agent-pack.js +149 -0
- package/dist/lib/agent-pack.js.map +1 -0
- package/dist/lib/simple-agent-profile.d.ts +36 -0
- package/dist/lib/simple-agent-profile.d.ts.map +1 -0
- package/dist/lib/simple-agent-profile.js +183 -0
- package/dist/lib/simple-agent-profile.js.map +1 -0
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +11 -1
- package/dist/routes/pages/agents.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +4 -95
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +62 -10
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/server/lib/agent-pack-store.d.ts +24 -0
- package/dist/server/lib/agent-pack-store.d.ts.map +1 -0
- package/dist/server/lib/agent-pack-store.js +22 -0
- package/dist/server/lib/agent-pack-store.js.map +1 -0
- package/dist/server/lib/dispatch-store.d.ts.map +1 -1
- package/dist/server/lib/dispatch-store.js +4 -0
- package/dist/server/lib/dispatch-store.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts +11 -0
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +155 -9
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/dist/server/lib/workspace-resources-store.d.ts +15 -1
- package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
- package/dist/server/lib/workspace-resources-store.js +11 -2
- package/dist/server/lib/workspace-resources-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.js +13 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/shared/feature-flags.d.ts +7 -0
- package/dist/shared/feature-flags.d.ts.map +1 -0
- package/dist/shared/feature-flags.js +12 -0
- package/dist/shared/feature-flags.js.map +1 -0
- package/dist/shared/workspace-sso.d.ts +36 -0
- package/dist/shared/workspace-sso.d.ts.map +1 -0
- package/dist/shared/workspace-sso.js +99 -0
- package/dist/shared/workspace-sso.js.map +1 -0
- package/package.json +5 -3
- package/src/actions/connect-external-agent.ts +92 -0
- package/src/actions/create-workspace-resource.ts +9 -2
- package/src/actions/create_workspace_app_embed_session.ts +32 -0
- package/src/actions/import-agent-pack.ts +146 -0
- package/src/actions/import-agent.ts +102 -0
- package/src/actions/index.spec.ts +13 -0
- package/src/actions/index.ts +10 -0
- package/src/actions/list-agent-pack.ts +43 -0
- package/src/actions/list-workspace-resource-options.ts +8 -1
- package/src/actions/list-workspace-resources.ts +8 -1
- package/src/actions/navigate.ts +1 -1
- package/src/actions/view-screen.spec.ts +29 -1
- package/src/actions/view-screen.ts +19 -1
- package/src/components/app-icon.spec.tsx +10 -0
- package/src/components/index.ts +1 -0
- package/src/components/layout/Layout.spec.tsx +2 -0
- package/src/components/layout/Layout.tsx +59 -171
- package/src/components/simple-agents-panel.spec.tsx +73 -0
- package/src/components/simple-agents-panel.tsx +1226 -0
- package/src/components/workspace-app-host.spec.tsx +204 -0
- package/src/components/workspace-app-host.tsx +359 -0
- package/src/db/migrations.spec.ts +5 -1
- package/src/db/migrations.ts +28 -1
- package/src/db/schema.ts +1 -1
- package/src/hooks/use-navigation-state.spec.ts +25 -0
- package/src/hooks/use-navigation-state.ts +11 -0
- package/src/lib/agent-pack.spec.ts +47 -0
- package/src/lib/agent-pack.ts +226 -0
- package/src/lib/simple-agent-profile.spec.ts +77 -0
- package/src/lib/simple-agent-profile.ts +247 -0
- package/src/routes/index.spec.ts +1 -0
- package/src/routes/pages/agents.tsx +21 -1
- package/src/routes/pages/apps.$appId.tsx +3 -240
- package/src/routes/pages/chat.spec.tsx +62 -0
- package/src/routes/pages/chat.tsx +117 -9
- package/src/server/lib/agent-pack-store.ts +35 -0
- package/src/server/lib/dispatch-store.ts +8 -0
- package/src/server/lib/mcp-gateway.spec.ts +141 -0
- package/src/server/lib/mcp-gateway.ts +227 -15
- package/src/server/lib/workspace-resources-store.ts +9 -2
- package/src/server/plugins/agent-chat.ts +13 -0
- package/src/shared/feature-flags.ts +13 -0
- package/src/shared/workspace-sso.ts +118 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-store.js","sourceRoot":"","sources":["../../../src/server/lib/dispatch-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nimport { and, desc, eq, isNull, or, sql } from \"@agent-native/core/db/schema\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"@agent-native/core/server\";\nimport { getOrgSetting, putOrgSetting } from \"@agent-native/core/settings\";\n\nimport { getDb, schema } from \"../../db/index.js\";\n\nexport const SHARED_DISPATCH_OWNER = \"dispatch@shared\";\nconst APPROVAL_POLICY_KEY = \"dispatch-approval-policy\";\nconst APPROVAL_APPLY_LEASE_MS = 5 * 60 * 1000;\n\n// ─── /link rate limiting ──────────────────────────────────────────────────\n//\n// Failed `/link <token>` attempts are rate-limited per `(platform, externalUserId)`\n// to deter token brute-force after the H5 entropy bump. The window /\n// threshold are tuned so legitimate retries (typo, expired token) don't\n// trip the limit, while a scripted attacker burns out their per-account\n// budget quickly.\n//\n// State is process-local: works for the single-node dispatch deployment\n// we ship today. TODO: move to a SQL-backed counter table when dispatch\n// is sharded across multiple regions / processes — otherwise an\n// attacker can scale around the limit by hammering more than one node.\nconst LINK_FAIL_WINDOW_MS = 5 * 60 * 1000;\nconst LINK_FAIL_BLOCK_MS = 30 * 60 * 1000;\nconst LINK_FAIL_THRESHOLD = 5;\n\ninterface LinkFailureState {\n failures: number[]; // unix-ms timestamps of recent failures within the window\n blockedUntil: number; // unix-ms; 0 if not currently blocked\n}\n\nconst _linkFailureMap = new Map<string, LinkFailureState>();\n\nfunction linkFailureKey(\n platform: string,\n externalUserId: string | null | undefined,\n): string {\n return `${platform}::${externalUserId ?? \"\"}`;\n}\n\nfunction getLinkFailureState(key: string): LinkFailureState {\n let state = _linkFailureMap.get(key);\n if (!state) {\n state = { failures: [], blockedUntil: 0 };\n _linkFailureMap.set(key, state);\n }\n return state;\n}\n\nfunction isLinkAttemptBlocked(\n platform: string,\n externalUserId: string | null | undefined,\n): { blocked: true; retryAfterMs: number } | { blocked: false } {\n if (!externalUserId) return { blocked: false };\n const key = linkFailureKey(platform, externalUserId);\n const state = _linkFailureMap.get(key);\n if (!state) return { blocked: false };\n const nowMs = Date.now();\n if (state.blockedUntil > nowMs) {\n return { blocked: true, retryAfterMs: state.blockedUntil - nowMs };\n }\n return { blocked: false };\n}\n\nfunction recordLinkFailure(\n platform: string,\n externalUserId: string | null | undefined,\n): void {\n if (!externalUserId) return;\n const key = linkFailureKey(platform, externalUserId);\n const state = getLinkFailureState(key);\n const nowMs = Date.now();\n // Drop expired failure timestamps before counting.\n state.failures = state.failures.filter(\n (ts) => nowMs - ts < LINK_FAIL_WINDOW_MS,\n );\n state.failures.push(nowMs);\n if (state.failures.length >= LINK_FAIL_THRESHOLD) {\n state.blockedUntil = nowMs + LINK_FAIL_BLOCK_MS;\n state.failures = [];\n }\n}\n\nfunction clearLinkFailures(\n platform: string,\n externalUserId: string | null | undefined,\n): void {\n if (!externalUserId) return;\n _linkFailureMap.delete(linkFailureKey(platform, externalUserId));\n}\n\n/**\n * 429-style error returned when /link attempts are rate-limited. The\n * adapter layer can branch on `code === \"LINK_RATE_LIMITED\"` to send a\n * platform-appropriate message back to the user.\n */\nexport class LinkRateLimitError extends Error {\n readonly code = \"LINK_RATE_LIMITED\";\n constructor(public readonly retryAfterMs: number) {\n super(\n `Too many failed link attempts. Try again in ${Math.ceil(retryAfterMs / 60_000)} minute(s).`,\n );\n }\n}\n\nexport interface DispatchApprovalPolicy {\n enabled: boolean;\n approverEmails: string[];\n}\n\nexport interface DispatchDestinationInput {\n id?: string;\n name: string;\n platform: string;\n destination: string;\n threadRef?: string | null;\n notes?: string | null;\n}\n\ntype DispatchApprovalRequest =\n typeof schema.dispatchApprovalRequests.$inferSelect;\n\nexport function currentOwnerEmail(): string {\n const email = getRequestUserEmail();\n if (!email) throw new Error(\"no authenticated user\");\n return email;\n}\n\nexport function currentOrgId(): string | null {\n return getRequestOrgId() || null;\n}\n\n/**\n * Caller-supplied access context for dispatch operations that work by\n * id (destinations, etc.). Looking up a row by id alone is unsafe —\n * UUIDs are not authorization. A row matches the ctx if either the\n * caller owns it or it lives in the caller's active org.\n */\nexport interface DispatchCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\nexport function requireDispatchCtx(): DispatchCtx {\n return { ownerEmail: currentOwnerEmail(), orgId: currentOrgId() };\n}\n\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: DispatchCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction safeJson(value: unknown) {\n return JSON.stringify(value ?? null);\n}\n\nexport async function getApprovalPolicy(): Promise<DispatchApprovalPolicy> {\n const orgId = currentOrgId();\n if (!orgId) return { enabled: false, approverEmails: [] };\n const raw = await getOrgSetting(orgId, APPROVAL_POLICY_KEY);\n return {\n enabled: raw?.enabled === true,\n approverEmails: Array.isArray(raw?.approverEmails)\n ? raw.approverEmails.filter(\n (value): value is string => typeof value === \"string\",\n )\n : [],\n };\n}\n\nasync function applyApprovalPolicy(\n input: DispatchApprovalPolicy,\n actor = currentOwnerEmail(),\n orgId = currentOrgId(),\n) {\n if (!orgId) {\n throw new Error(\n \"Dispatch approval settings require an active organization\",\n );\n }\n await putOrgSetting(orgId, APPROVAL_POLICY_KEY, {\n enabled: input.enabled,\n approverEmails: input.approverEmails,\n });\n await recordAudit({\n action: \"settings.updated\",\n targetType: \"dispatch-settings\",\n targetId: APPROVAL_POLICY_KEY,\n summary: input.enabled\n ? \"Enabled approval flow for durable dispatch changes\"\n : \"Disabled approval flow for durable dispatch changes\",\n metadata: input,\n actor,\n });\n return {\n enabled: input.enabled,\n approverEmails: input.approverEmails,\n };\n}\n\nexport async function setApprovalPolicy(input: DispatchApprovalPolicy) {\n const current = await getApprovalPolicy();\n if (!current.enabled) {\n return applyApprovalPolicy(input);\n }\n return createApprovalRequest({\n changeType: \"approval-policy.update\",\n targetType: \"dispatch-settings\",\n targetId: APPROVAL_POLICY_KEY,\n summary: input.enabled\n ? \"Update dispatch approval policy\"\n : \"Disable dispatch approval policy\",\n payload: input,\n beforeValue: current,\n afterValue: input,\n });\n}\n\nexport async function recordAudit(input: {\n action: string;\n targetType: string;\n targetId?: string | null;\n summary: string;\n metadata?: unknown;\n actor?: string;\n ownerEmail?: string;\n orgId?: string | null;\n}) {\n const db = getDb();\n const timestamp = now();\n await db.insert(schema.dispatchAuditEvents).values({\n id: id(),\n ownerEmail: input.ownerEmail || currentOwnerEmail(),\n orgId: input.orgId !== undefined ? input.orgId : currentOrgId(),\n actor: input.actor || currentOwnerEmail(),\n action: input.action,\n targetType: input.targetType,\n targetId: input.targetId || null,\n summary: input.summary,\n metadata: input.metadata ? safeJson(input.metadata) : null,\n createdAt: timestamp,\n });\n}\n\nexport async function listAuditEvents(limit = 50) {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchAuditEvents)\n .where(\n and(\n eq(schema.dispatchAuditEvents.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchAuditEvents.orgId, orgId)\n : isNull(schema.dispatchAuditEvents.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchAuditEvents.createdAt))\n .limit(limit);\n}\n\nexport async function listDestinations() {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchDestinations.orgId, orgId)\n : isNull(schema.dispatchDestinations.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchDestinations.updatedAt));\n}\n\nexport async function getDestinationById(\n destinationId: string,\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nasync function applyDestinationUpsert(\n input: DispatchDestinationInput,\n actor = currentOwnerEmail(),\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const timestamp = now();\n const destinationId = input.id || id();\n const existing = input.id ? await getDestinationById(input.id, ctx) : null;\n\n if (existing) {\n await db\n .update(schema.dispatchDestinations)\n .set({\n name: input.name,\n platform: input.platform,\n destination: input.destination,\n threadRef: input.threadRef || null,\n notes: input.notes || null,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n );\n } else {\n await db.insert(schema.dispatchDestinations).values({\n id: destinationId,\n ownerEmail: ctx.ownerEmail,\n orgId: ctx.orgId,\n name: input.name,\n platform: input.platform,\n destination: input.destination,\n threadRef: input.threadRef || null,\n notes: input.notes || null,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n }\n\n await recordAudit({\n actor,\n action: existing ? \"destination.updated\" : \"destination.created\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `${existing ? \"Updated\" : \"Created\"} ${input.platform} destination ${input.name}`,\n metadata: input,\n });\n\n return getDestinationById(destinationId, ctx);\n}\n\nasync function applyDestinationDelete(\n destinationId: string,\n actor = currentOwnerEmail(),\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const existing = await getDestinationById(destinationId, ctx);\n if (!existing) {\n throw new Error(\"Destination not found\");\n }\n await db\n .delete(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n );\n await recordAudit({\n actor,\n action: \"destination.deleted\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `Deleted ${existing.platform} destination ${existing.name}`,\n metadata: existing,\n });\n return existing;\n}\n\nasync function notifyApprovers(requestId: string, summary: string) {\n const policy = await getApprovalPolicy();\n const apiKey = process.env.SENDGRID_API_KEY;\n const from = process.env.SENDGRID_FROM_EMAIL;\n const appUrl = process.env.APP_URL;\n if (!apiKey || !from || !appUrl || policy.approverEmails.length === 0) return;\n\n await fetch(\"https://api.sendgrid.com/v3/mail/send\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n personalizations: [\n {\n to: policy.approverEmails.map((email) => ({ email })),\n subject: \"Dispatch approval requested\",\n },\n ],\n from: { email: from },\n content: [\n {\n type: \"text/plain\",\n value: `${summary}\\n\\nReview it here: ${appUrl}/approvals`,\n },\n ],\n custom_args: { requestId },\n }),\n }).catch(() => {});\n}\n\nexport async function createApprovalRequest(input: {\n changeType: string;\n targetType: string;\n targetId?: string | null;\n summary: string;\n payload: unknown;\n beforeValue?: unknown;\n afterValue?: unknown;\n}) {\n const db = getDb();\n const timestamp = now();\n const requestId = id();\n await db.insert(schema.dispatchApprovalRequests).values({\n id: requestId,\n ownerEmail: currentOwnerEmail(),\n orgId: currentOrgId(),\n changeType: input.changeType,\n targetType: input.targetType,\n targetId: input.targetId || null,\n status: \"pending\",\n summary: input.summary,\n payload: safeJson(input.payload),\n beforeValue:\n input.beforeValue === undefined ? null : safeJson(input.beforeValue),\n afterValue:\n input.afterValue === undefined ? null : safeJson(input.afterValue),\n requestedBy: currentOwnerEmail(),\n reviewedBy: null,\n reviewedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n await recordAudit({\n action: \"approval.requested\",\n targetType: input.targetType,\n targetId: input.targetId || requestId,\n summary: input.summary,\n metadata: input,\n });\n await notifyApprovers(requestId, input.summary);\n return getApprovalRequest(requestId);\n}\n\nexport async function upsertDestination(input: DispatchDestinationInput) {\n const policy = await getApprovalPolicy();\n if (policy.enabled) {\n const existing = input.id ? await getDestinationById(input.id) : null;\n return createApprovalRequest({\n changeType: \"destination.upsert\",\n targetType: \"destination\",\n targetId: input.id || null,\n summary: `${existing ? \"Update\" : \"Create\"} ${input.platform} destination ${input.name}`,\n payload: input,\n beforeValue: existing,\n afterValue: input,\n });\n }\n return applyDestinationUpsert(input);\n}\n\nexport async function deleteDestination(destinationId: string) {\n const policy = await getApprovalPolicy();\n const existing = await getDestinationById(destinationId);\n if (!existing) {\n throw new Error(\"Destination not found\");\n }\n if (policy.enabled) {\n return createApprovalRequest({\n changeType: \"destination.delete\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `Delete ${existing.platform} destination ${existing.name}`,\n payload: { id: destinationId },\n beforeValue: existing,\n afterValue: null,\n });\n }\n return applyDestinationDelete(destinationId);\n}\n\nexport async function listApprovalRequests() {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchApprovalRequests)\n .where(\n and(\n eq(schema.dispatchApprovalRequests.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchApprovalRequests.orgId, orgId)\n : isNull(schema.dispatchApprovalRequests.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchApprovalRequests.updatedAt));\n}\n\nasync function getApprovalRequest(\n requestId: string,\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.dispatchApprovalRequests)\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nasync function applyApprovedRequest(request: DispatchApprovalRequest) {\n const payload = JSON.parse(request.payload);\n const requestCtx = {\n ownerEmail: request.ownerEmail,\n orgId: request.orgId,\n };\n if (request.changeType === \"destination.upsert\") {\n return applyDestinationUpsert(\n payload,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"destination.delete\") {\n return applyDestinationDelete(\n payload.id,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"approval-policy.update\") {\n return applyApprovalPolicy(\n payload,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx.orgId,\n );\n }\n if (request.changeType === \"dream-proposal.apply\") {\n const { applyApprovedDreamProposal } = await import(\"./dreams-store.js\");\n return applyApprovedDreamProposal(\n payload.proposalId,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.create\") {\n const { applyWorkspaceResourceCreate } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceCreate(\n payload.input,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.update\") {\n const { applyWorkspaceResourceUpdate } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceUpdate(\n payload.id,\n payload.input,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.delete\") {\n const { applyWorkspaceResourceDelete } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceDelete(\n payload.id,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n throw new Error(`Unsupported approval request type: ${request.changeType}`);\n}\n\nexport async function approveRequest(requestId: string) {\n const db = getDb();\n const ctx = requireDispatchCtx();\n const request = await getApprovalRequest(requestId, ctx);\n if (!request) throw new Error(\"Approval request not found\");\n\n const timestamp = now();\n const staleApplyingBefore = timestamp - APPROVAL_APPLY_LEASE_MS;\n // Fence the transition on the current status so a concurrent approve can't\n // both win. A crashed worker can leave its lease in \"applying\", so reclaim\n // only a lease that has been idle for the full lease interval.\n const claimed = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"applying\",\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n or(\n eq(schema.dispatchApprovalRequests.status, \"pending\"),\n and(\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n sql`${schema.dispatchApprovalRequests.updatedAt} < ${staleApplyingBefore}`,\n ),\n ),\n ),\n )\n .returning();\n\n if (claimed.length === 0) {\n const current = (await getApprovalRequest(requestId, ctx)) ?? request;\n if (current.status === \"applying\") {\n throw new Error(\"Approval is already being applied\");\n }\n return current;\n }\n\n const applying = claimed[0];\n try {\n await applyApprovedRequest(applying);\n } catch (error) {\n // Applying a request can have succeeded partially before throwing. Do not\n // return it to pending: that would allow an immediate retry to duplicate a\n // non-idempotent effect. Keep the lease until it becomes stale, which\n // serializes any recovery attempt behind the same fencing rule.\n await db\n .update(schema.dispatchApprovalRequests)\n .set({ updatedAt: now() })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n ),\n );\n throw error;\n }\n const [updated] = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"approved\",\n reviewedBy: currentOwnerEmail(),\n reviewedAt: timestamp,\n updatedAt: now(),\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n ),\n )\n .returning();\n if (!updated) throw new Error(\"Approval request disappeared\");\n await recordAudit({\n action: \"approval.approved\",\n targetType: updated.targetType,\n targetId: requestId,\n summary: `Approved ${updated.summary}`,\n metadata: updated,\n });\n return updated;\n}\n\nexport async function rejectRequest(requestId: string, reason?: string | null) {\n const db = getDb();\n const ctx = requireDispatchCtx();\n const request = await getApprovalRequest(requestId, ctx);\n if (!request) throw new Error(\"Approval request not found\");\n\n const timestamp = now();\n const claimed = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"rejected\",\n reviewedBy: currentOwnerEmail(),\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"pending\"),\n ),\n )\n .returning();\n\n if (claimed.length === 0) {\n return (await getApprovalRequest(requestId, ctx)) ?? request;\n }\n\n const updated = claimed[0];\n await recordAudit({\n action: \"approval.rejected\",\n targetType: updated.targetType,\n targetId: requestId,\n summary: `Rejected ${updated.summary}`,\n metadata: { request: updated, reason: reason || null },\n });\n return updated;\n}\n\nexport async function createLinkToken(platform: string) {\n const db = getDb();\n const timestamp = now();\n // 16 bytes = 128 bits of entropy. Previous size was 4 bytes (32 bits,\n // ~4.29 billion keyspace) which is brute-forceable in well under an\n // hour given a 7-day expiry and no rate limiting on /link attempts.\n // Old 8-hex-char tokens minted before this change continue to verify\n // until they expire; we don't migrate retroactively. See\n // /tmp/security-audit/07-webhooks.md (H5).\n const token = crypto.randomBytes(16).toString(\"hex\");\n const recordId = id();\n const owner = currentOwnerEmail();\n await db.insert(schema.dispatchLinkTokens).values({\n id: recordId,\n token,\n ownerEmail: owner,\n orgId: currentOrgId(),\n platform,\n createdBy: owner,\n expiresAt: timestamp + 7 * 24 * 60 * 60 * 1000,\n claimedAt: null,\n claimedByExternalUserId: null,\n claimedByExternalUserName: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n await recordAudit({\n action: \"identity.link-token-created\",\n targetType: \"link-token\",\n targetId: recordId,\n summary: `Created ${platform} link token for ${owner}`,\n metadata: { token, platform },\n });\n return {\n token,\n command: `/link ${token}`,\n platform,\n expiresAt: timestamp + 7 * 24 * 60 * 60 * 1000,\n };\n}\n\nexport async function listIdentityState() {\n const db = getDb();\n const owner = currentOwnerEmail();\n const orgId = currentOrgId();\n const filters = and(\n eq(schema.dispatchIdentityLinks.ownerEmail, owner),\n orgId\n ? eq(schema.dispatchIdentityLinks.orgId, orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n );\n const tokenFilters = and(\n eq(schema.dispatchLinkTokens.ownerEmail, owner),\n orgId\n ? eq(schema.dispatchLinkTokens.orgId, orgId)\n : isNull(schema.dispatchLinkTokens.orgId),\n );\n const [links, tokens] = await Promise.all([\n db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(filters)\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt)),\n db\n .select()\n .from(schema.dispatchLinkTokens)\n .where(tokenFilters)\n .orderBy(desc(schema.dispatchLinkTokens.updatedAt)),\n ]);\n return { links, tokens };\n}\n\nexport async function resolveLinkedOwner(\n platform: string,\n externalUserId?: string | null,\n options: {\n orgId?: string | null;\n allowAnyOrgFallback?: boolean;\n } = {},\n) {\n if (!externalUserId) return null;\n const db = getDb();\n const orgId = options.orgId !== undefined ? options.orgId : currentOrgId();\n const rows = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, platform),\n eq(schema.dispatchIdentityLinks.externalUserId, externalUserId),\n orgId\n ? eq(schema.dispatchIdentityLinks.orgId, orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt))\n .limit(1);\n if (rows[0]?.ownerEmail) return rows[0].ownerEmail;\n\n if (!options.allowAnyOrgFallback || orgId) return null;\n\n // Webhook processors run outside a normal request/org context. A linked\n // Slack/Telegram identity may still be scoped to an org, so fall back to any\n // org only when every matching link resolves to the same owner.\n const fallbackRows = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, platform),\n eq(schema.dispatchIdentityLinks.externalUserId, externalUserId),\n ),\n )\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt))\n .limit(25);\n const owners = new Set(fallbackRows.map((row) => row.ownerEmail));\n return owners.size === 1 ? fallbackRows[0]?.ownerEmail || null : null;\n}\n\nexport async function consumeLinkToken(input: {\n platform: string;\n token: string;\n externalUserId?: string | null;\n externalUserName?: string | null;\n}) {\n if (!input.externalUserId) {\n throw new Error(\"Linking requires a platform user id\");\n }\n\n // Rate-limit failed attempts per (platform, externalUserId). Once\n // tripped, all further attempts are short-circuited until the block\n // window passes — including the lookup, so an attacker can't probe\n // for valid tokens during the block.\n const blockState = isLinkAttemptBlocked(input.platform, input.externalUserId);\n if (blockState.blocked) {\n throw new LinkRateLimitError(blockState.retryAfterMs);\n }\n\n const db = getDb();\n const tokenRows = await db\n .select()\n .from(schema.dispatchLinkTokens)\n .where(\n and(\n eq(schema.dispatchLinkTokens.platform, input.platform),\n eq(schema.dispatchLinkTokens.token, input.token),\n ),\n )\n .orderBy(desc(schema.dispatchLinkTokens.createdAt))\n .limit(2);\n if (tokenRows.length > 1) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token is ambiguous. Create a fresh token and retry.\");\n }\n const tokenRow = tokenRows[0];\n if (!tokenRow) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token not found\");\n }\n if (tokenRow.claimedAt) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token has already been claimed\");\n }\n if (tokenRow.expiresAt < now()) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token has expired\");\n }\n\n const timestamp = now();\n const [existing] = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, input.platform),\n eq(schema.dispatchIdentityLinks.externalUserId, input.externalUserId),\n tokenRow.orgId\n ? eq(schema.dispatchIdentityLinks.orgId, tokenRow.orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n ),\n )\n .limit(1);\n\n if (existing) {\n await db\n .update(schema.dispatchIdentityLinks)\n .set({\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n externalUserName: input.externalUserName || null,\n linkedBy: tokenRow.createdBy,\n updatedAt: timestamp,\n })\n .where(eq(schema.dispatchIdentityLinks.id, existing.id));\n } else {\n await db.insert(schema.dispatchIdentityLinks).values({\n id: id(),\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n platform: input.platform,\n externalUserId: input.externalUserId,\n externalUserName: input.externalUserName || null,\n linkedBy: tokenRow.createdBy,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n }\n\n await db\n .update(schema.dispatchLinkTokens)\n .set({\n claimedAt: timestamp,\n claimedByExternalUserId: input.externalUserId,\n claimedByExternalUserName: input.externalUserName || null,\n updatedAt: timestamp,\n })\n .where(eq(schema.dispatchLinkTokens.id, tokenRow.id));\n\n // Successful claim — reset the rate-limit budget so subsequent\n // links from this external user start fresh.\n clearLinkFailures(input.platform, input.externalUserId);\n\n await recordAudit({\n actor: tokenRow.createdBy,\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n action: \"identity.linked\",\n targetType: \"identity-link\",\n targetId: input.externalUserId,\n summary: `Linked ${input.platform} user ${input.externalUserName || input.externalUserId}`,\n metadata: input,\n });\n\n return tokenRow.ownerEmail;\n}\n\nexport async function listOverview() {\n const [destinations, approvals, identities, audit, settings] =\n await Promise.all([\n listDestinations(),\n listApprovalRequests(),\n listIdentityState(),\n listAuditEvents(12),\n getApprovalPolicy(),\n ]);\n\n return {\n counts: {\n destinations: destinations.length,\n pendingApprovals: approvals.filter((item) => item.status === \"pending\")\n .length,\n linkedIdentities: identities.links.length,\n activeTokens: identities.tokens.filter(\n (item) => !item.claimedAt && item.expiresAt > now(),\n ).length,\n },\n recentDestinations: destinations.slice(0, 5),\n recentApprovals: approvals.slice(0, 5),\n recentAudit: audit.slice(0, 8),\n settings,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dispatch-store.js","sourceRoot":"","sources":["../../../src/server/lib/dispatch-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nimport { and, desc, eq, isNull, or, sql } from \"@agent-native/core/db/schema\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"@agent-native/core/server\";\nimport { getOrgSetting, putOrgSetting } from \"@agent-native/core/settings\";\n\nimport { getDb, schema } from \"../../db/index.js\";\n\nexport const SHARED_DISPATCH_OWNER = \"dispatch@shared\";\nconst APPROVAL_POLICY_KEY = \"dispatch-approval-policy\";\nconst APPROVAL_APPLY_LEASE_MS = 5 * 60 * 1000;\n\n// ─── /link rate limiting ──────────────────────────────────────────────────\n//\n// Failed `/link <token>` attempts are rate-limited per `(platform, externalUserId)`\n// to deter token brute-force after the H5 entropy bump. The window /\n// threshold are tuned so legitimate retries (typo, expired token) don't\n// trip the limit, while a scripted attacker burns out their per-account\n// budget quickly.\n//\n// State is process-local: works for the single-node dispatch deployment\n// we ship today. TODO: move to a SQL-backed counter table when dispatch\n// is sharded across multiple regions / processes — otherwise an\n// attacker can scale around the limit by hammering more than one node.\nconst LINK_FAIL_WINDOW_MS = 5 * 60 * 1000;\nconst LINK_FAIL_BLOCK_MS = 30 * 60 * 1000;\nconst LINK_FAIL_THRESHOLD = 5;\n\ninterface LinkFailureState {\n failures: number[]; // unix-ms timestamps of recent failures within the window\n blockedUntil: number; // unix-ms; 0 if not currently blocked\n}\n\nconst _linkFailureMap = new Map<string, LinkFailureState>();\n\nfunction linkFailureKey(\n platform: string,\n externalUserId: string | null | undefined,\n): string {\n return `${platform}::${externalUserId ?? \"\"}`;\n}\n\nfunction getLinkFailureState(key: string): LinkFailureState {\n let state = _linkFailureMap.get(key);\n if (!state) {\n state = { failures: [], blockedUntil: 0 };\n _linkFailureMap.set(key, state);\n }\n return state;\n}\n\nfunction isLinkAttemptBlocked(\n platform: string,\n externalUserId: string | null | undefined,\n): { blocked: true; retryAfterMs: number } | { blocked: false } {\n if (!externalUserId) return { blocked: false };\n const key = linkFailureKey(platform, externalUserId);\n const state = _linkFailureMap.get(key);\n if (!state) return { blocked: false };\n const nowMs = Date.now();\n if (state.blockedUntil > nowMs) {\n return { blocked: true, retryAfterMs: state.blockedUntil - nowMs };\n }\n return { blocked: false };\n}\n\nfunction recordLinkFailure(\n platform: string,\n externalUserId: string | null | undefined,\n): void {\n if (!externalUserId) return;\n const key = linkFailureKey(platform, externalUserId);\n const state = getLinkFailureState(key);\n const nowMs = Date.now();\n // Drop expired failure timestamps before counting.\n state.failures = state.failures.filter(\n (ts) => nowMs - ts < LINK_FAIL_WINDOW_MS,\n );\n state.failures.push(nowMs);\n if (state.failures.length >= LINK_FAIL_THRESHOLD) {\n state.blockedUntil = nowMs + LINK_FAIL_BLOCK_MS;\n state.failures = [];\n }\n}\n\nfunction clearLinkFailures(\n platform: string,\n externalUserId: string | null | undefined,\n): void {\n if (!externalUserId) return;\n _linkFailureMap.delete(linkFailureKey(platform, externalUserId));\n}\n\n/**\n * 429-style error returned when /link attempts are rate-limited. The\n * adapter layer can branch on `code === \"LINK_RATE_LIMITED\"` to send a\n * platform-appropriate message back to the user.\n */\nexport class LinkRateLimitError extends Error {\n readonly code = \"LINK_RATE_LIMITED\";\n constructor(public readonly retryAfterMs: number) {\n super(\n `Too many failed link attempts. Try again in ${Math.ceil(retryAfterMs / 60_000)} minute(s).`,\n );\n }\n}\n\nexport interface DispatchApprovalPolicy {\n enabled: boolean;\n approverEmails: string[];\n}\n\nexport interface DispatchDestinationInput {\n id?: string;\n name: string;\n platform: string;\n destination: string;\n threadRef?: string | null;\n notes?: string | null;\n}\n\ntype DispatchApprovalRequest =\n typeof schema.dispatchApprovalRequests.$inferSelect;\n\nexport function currentOwnerEmail(): string {\n const email = getRequestUserEmail();\n if (!email) throw new Error(\"no authenticated user\");\n return email;\n}\n\nexport function currentOrgId(): string | null {\n return getRequestOrgId() || null;\n}\n\n/**\n * Caller-supplied access context for dispatch operations that work by\n * id (destinations, etc.). Looking up a row by id alone is unsafe —\n * UUIDs are not authorization. A row matches the ctx if either the\n * caller owns it or it lives in the caller's active org.\n */\nexport interface DispatchCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\nexport function requireDispatchCtx(): DispatchCtx {\n return { ownerEmail: currentOwnerEmail(), orgId: currentOrgId() };\n}\n\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: DispatchCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction safeJson(value: unknown) {\n return JSON.stringify(value ?? null);\n}\n\nexport async function getApprovalPolicy(): Promise<DispatchApprovalPolicy> {\n const orgId = currentOrgId();\n if (!orgId) return { enabled: false, approverEmails: [] };\n const raw = await getOrgSetting(orgId, APPROVAL_POLICY_KEY);\n return {\n enabled: raw?.enabled === true,\n approverEmails: Array.isArray(raw?.approverEmails)\n ? raw.approverEmails.filter(\n (value): value is string => typeof value === \"string\",\n )\n : [],\n };\n}\n\nasync function applyApprovalPolicy(\n input: DispatchApprovalPolicy,\n actor = currentOwnerEmail(),\n orgId = currentOrgId(),\n) {\n if (!orgId) {\n throw new Error(\n \"Dispatch approval settings require an active organization\",\n );\n }\n await putOrgSetting(orgId, APPROVAL_POLICY_KEY, {\n enabled: input.enabled,\n approverEmails: input.approverEmails,\n });\n await recordAudit({\n action: \"settings.updated\",\n targetType: \"dispatch-settings\",\n targetId: APPROVAL_POLICY_KEY,\n summary: input.enabled\n ? \"Enabled approval flow for durable dispatch changes\"\n : \"Disabled approval flow for durable dispatch changes\",\n metadata: input,\n actor,\n });\n return {\n enabled: input.enabled,\n approverEmails: input.approverEmails,\n };\n}\n\nexport async function setApprovalPolicy(input: DispatchApprovalPolicy) {\n const current = await getApprovalPolicy();\n if (!current.enabled) {\n return applyApprovalPolicy(input);\n }\n return createApprovalRequest({\n changeType: \"approval-policy.update\",\n targetType: \"dispatch-settings\",\n targetId: APPROVAL_POLICY_KEY,\n summary: input.enabled\n ? \"Update dispatch approval policy\"\n : \"Disable dispatch approval policy\",\n payload: input,\n beforeValue: current,\n afterValue: input,\n });\n}\n\nexport async function recordAudit(input: {\n action: string;\n targetType: string;\n targetId?: string | null;\n summary: string;\n metadata?: unknown;\n actor?: string;\n ownerEmail?: string;\n orgId?: string | null;\n}) {\n const db = getDb();\n const timestamp = now();\n await db.insert(schema.dispatchAuditEvents).values({\n id: id(),\n ownerEmail: input.ownerEmail || currentOwnerEmail(),\n orgId: input.orgId !== undefined ? input.orgId : currentOrgId(),\n actor: input.actor || currentOwnerEmail(),\n action: input.action,\n targetType: input.targetType,\n targetId: input.targetId || null,\n summary: input.summary,\n metadata: input.metadata ? safeJson(input.metadata) : null,\n createdAt: timestamp,\n });\n}\n\nexport async function listAuditEvents(limit = 50) {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchAuditEvents)\n .where(\n and(\n eq(schema.dispatchAuditEvents.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchAuditEvents.orgId, orgId)\n : isNull(schema.dispatchAuditEvents.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchAuditEvents.createdAt))\n .limit(limit);\n}\n\nexport async function listDestinations() {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchDestinations.orgId, orgId)\n : isNull(schema.dispatchDestinations.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchDestinations.updatedAt));\n}\n\nexport async function getDestinationById(\n destinationId: string,\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nasync function applyDestinationUpsert(\n input: DispatchDestinationInput,\n actor = currentOwnerEmail(),\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const timestamp = now();\n const destinationId = input.id || id();\n const existing = input.id ? await getDestinationById(input.id, ctx) : null;\n\n if (existing) {\n await db\n .update(schema.dispatchDestinations)\n .set({\n name: input.name,\n platform: input.platform,\n destination: input.destination,\n threadRef: input.threadRef || null,\n notes: input.notes || null,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n );\n } else {\n await db.insert(schema.dispatchDestinations).values({\n id: destinationId,\n ownerEmail: ctx.ownerEmail,\n orgId: ctx.orgId,\n name: input.name,\n platform: input.platform,\n destination: input.destination,\n threadRef: input.threadRef || null,\n notes: input.notes || null,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n }\n\n await recordAudit({\n actor,\n action: existing ? \"destination.updated\" : \"destination.created\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `${existing ? \"Updated\" : \"Created\"} ${input.platform} destination ${input.name}`,\n metadata: input,\n });\n\n return getDestinationById(destinationId, ctx);\n}\n\nasync function applyDestinationDelete(\n destinationId: string,\n actor = currentOwnerEmail(),\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const existing = await getDestinationById(destinationId, ctx);\n if (!existing) {\n throw new Error(\"Destination not found\");\n }\n await db\n .delete(schema.dispatchDestinations)\n .where(\n and(\n eq(schema.dispatchDestinations.id, destinationId),\n ctxScope(schema.dispatchDestinations, ctx),\n ),\n );\n await recordAudit({\n actor,\n action: \"destination.deleted\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `Deleted ${existing.platform} destination ${existing.name}`,\n metadata: existing,\n });\n return existing;\n}\n\nasync function notifyApprovers(requestId: string, summary: string) {\n const policy = await getApprovalPolicy();\n const apiKey = process.env.SENDGRID_API_KEY;\n const from = process.env.SENDGRID_FROM_EMAIL;\n const appUrl = process.env.APP_URL;\n if (!apiKey || !from || !appUrl || policy.approverEmails.length === 0) return;\n\n await fetch(\"https://api.sendgrid.com/v3/mail/send\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n personalizations: [\n {\n to: policy.approverEmails.map((email) => ({ email })),\n subject: \"Dispatch approval requested\",\n },\n ],\n from: { email: from },\n content: [\n {\n type: \"text/plain\",\n value: `${summary}\\n\\nReview it here: ${appUrl}/approvals`,\n },\n ],\n custom_args: { requestId },\n }),\n }).catch(() => {});\n}\n\nexport async function createApprovalRequest(input: {\n changeType: string;\n targetType: string;\n targetId?: string | null;\n summary: string;\n payload: unknown;\n beforeValue?: unknown;\n afterValue?: unknown;\n}) {\n const db = getDb();\n const timestamp = now();\n const requestId = id();\n await db.insert(schema.dispatchApprovalRequests).values({\n id: requestId,\n ownerEmail: currentOwnerEmail(),\n orgId: currentOrgId(),\n changeType: input.changeType,\n targetType: input.targetType,\n targetId: input.targetId || null,\n status: \"pending\",\n summary: input.summary,\n payload: safeJson(input.payload),\n beforeValue:\n input.beforeValue === undefined ? null : safeJson(input.beforeValue),\n afterValue:\n input.afterValue === undefined ? null : safeJson(input.afterValue),\n requestedBy: currentOwnerEmail(),\n reviewedBy: null,\n reviewedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n await recordAudit({\n action: \"approval.requested\",\n targetType: input.targetType,\n targetId: input.targetId || requestId,\n summary: input.summary,\n metadata: input,\n });\n await notifyApprovers(requestId, input.summary);\n return getApprovalRequest(requestId);\n}\n\nexport async function upsertDestination(input: DispatchDestinationInput) {\n const policy = await getApprovalPolicy();\n if (policy.enabled) {\n const existing = input.id ? await getDestinationById(input.id) : null;\n return createApprovalRequest({\n changeType: \"destination.upsert\",\n targetType: \"destination\",\n targetId: input.id || null,\n summary: `${existing ? \"Update\" : \"Create\"} ${input.platform} destination ${input.name}`,\n payload: input,\n beforeValue: existing,\n afterValue: input,\n });\n }\n return applyDestinationUpsert(input);\n}\n\nexport async function deleteDestination(destinationId: string) {\n const policy = await getApprovalPolicy();\n const existing = await getDestinationById(destinationId);\n if (!existing) {\n throw new Error(\"Destination not found\");\n }\n if (policy.enabled) {\n return createApprovalRequest({\n changeType: \"destination.delete\",\n targetType: \"destination\",\n targetId: destinationId,\n summary: `Delete ${existing.platform} destination ${existing.name}`,\n payload: { id: destinationId },\n beforeValue: existing,\n afterValue: null,\n });\n }\n return applyDestinationDelete(destinationId);\n}\n\nexport async function listApprovalRequests() {\n const db = getDb();\n const orgId = currentOrgId();\n return db\n .select()\n .from(schema.dispatchApprovalRequests)\n .where(\n and(\n eq(schema.dispatchApprovalRequests.ownerEmail, currentOwnerEmail()),\n orgId\n ? eq(schema.dispatchApprovalRequests.orgId, orgId)\n : isNull(schema.dispatchApprovalRequests.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchApprovalRequests.updatedAt));\n}\n\nasync function getApprovalRequest(\n requestId: string,\n ctx: DispatchCtx = requireDispatchCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.dispatchApprovalRequests)\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nasync function applyApprovedRequest(request: DispatchApprovalRequest) {\n const payload = JSON.parse(request.payload);\n const requestCtx = {\n ownerEmail: request.ownerEmail,\n orgId: request.orgId,\n };\n if (request.changeType === \"destination.upsert\") {\n return applyDestinationUpsert(\n payload,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"destination.delete\") {\n return applyDestinationDelete(\n payload.id,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"approval-policy.update\") {\n return applyApprovalPolicy(\n payload,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx.orgId,\n );\n }\n if (request.changeType === \"dream-proposal.apply\") {\n const { applyApprovedDreamProposal } = await import(\"./dreams-store.js\");\n return applyApprovedDreamProposal(\n payload.proposalId,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.create\") {\n const { applyWorkspaceResourceCreate } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceCreate(\n payload.input,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-agent-pack.create\") {\n const { applyAgentPackCreate } = await import(\"./agent-pack-store.js\");\n return applyAgentPackCreate(\n payload.inputs,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.update\") {\n const { applyWorkspaceResourceUpdate } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceUpdate(\n payload.id,\n payload.input,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n if (request.changeType === \"workspace-resource.delete\") {\n const { applyWorkspaceResourceDelete } =\n await import(\"./workspace-resources-store.js\");\n return applyWorkspaceResourceDelete(\n payload.id,\n request.reviewedBy || currentOwnerEmail(),\n requestCtx,\n );\n }\n throw new Error(`Unsupported approval request type: ${request.changeType}`);\n}\n\nexport async function approveRequest(requestId: string) {\n const db = getDb();\n const ctx = requireDispatchCtx();\n const request = await getApprovalRequest(requestId, ctx);\n if (!request) throw new Error(\"Approval request not found\");\n\n const timestamp = now();\n const staleApplyingBefore = timestamp - APPROVAL_APPLY_LEASE_MS;\n // Fence the transition on the current status so a concurrent approve can't\n // both win. A crashed worker can leave its lease in \"applying\", so reclaim\n // only a lease that has been idle for the full lease interval.\n const claimed = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"applying\",\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n or(\n eq(schema.dispatchApprovalRequests.status, \"pending\"),\n and(\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n sql`${schema.dispatchApprovalRequests.updatedAt} < ${staleApplyingBefore}`,\n ),\n ),\n ),\n )\n .returning();\n\n if (claimed.length === 0) {\n const current = (await getApprovalRequest(requestId, ctx)) ?? request;\n if (current.status === \"applying\") {\n throw new Error(\"Approval is already being applied\");\n }\n return current;\n }\n\n const applying = claimed[0];\n try {\n await applyApprovedRequest(applying);\n } catch (error) {\n // Applying a request can have succeeded partially before throwing. Do not\n // return it to pending: that would allow an immediate retry to duplicate a\n // non-idempotent effect. Keep the lease until it becomes stale, which\n // serializes any recovery attempt behind the same fencing rule.\n await db\n .update(schema.dispatchApprovalRequests)\n .set({ updatedAt: now() })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n ),\n );\n throw error;\n }\n const [updated] = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"approved\",\n reviewedBy: currentOwnerEmail(),\n reviewedAt: timestamp,\n updatedAt: now(),\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"applying\"),\n ),\n )\n .returning();\n if (!updated) throw new Error(\"Approval request disappeared\");\n await recordAudit({\n action: \"approval.approved\",\n targetType: updated.targetType,\n targetId: requestId,\n summary: `Approved ${updated.summary}`,\n metadata: updated,\n });\n return updated;\n}\n\nexport async function rejectRequest(requestId: string, reason?: string | null) {\n const db = getDb();\n const ctx = requireDispatchCtx();\n const request = await getApprovalRequest(requestId, ctx);\n if (!request) throw new Error(\"Approval request not found\");\n\n const timestamp = now();\n const claimed = await db\n .update(schema.dispatchApprovalRequests)\n .set({\n status: \"rejected\",\n reviewedBy: currentOwnerEmail(),\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.dispatchApprovalRequests.id, requestId),\n ctxScope(schema.dispatchApprovalRequests, ctx),\n eq(schema.dispatchApprovalRequests.status, \"pending\"),\n ),\n )\n .returning();\n\n if (claimed.length === 0) {\n return (await getApprovalRequest(requestId, ctx)) ?? request;\n }\n\n const updated = claimed[0];\n await recordAudit({\n action: \"approval.rejected\",\n targetType: updated.targetType,\n targetId: requestId,\n summary: `Rejected ${updated.summary}`,\n metadata: { request: updated, reason: reason || null },\n });\n return updated;\n}\n\nexport async function createLinkToken(platform: string) {\n const db = getDb();\n const timestamp = now();\n // 16 bytes = 128 bits of entropy. Previous size was 4 bytes (32 bits,\n // ~4.29 billion keyspace) which is brute-forceable in well under an\n // hour given a 7-day expiry and no rate limiting on /link attempts.\n // Old 8-hex-char tokens minted before this change continue to verify\n // until they expire; we don't migrate retroactively. See\n // /tmp/security-audit/07-webhooks.md (H5).\n const token = crypto.randomBytes(16).toString(\"hex\");\n const recordId = id();\n const owner = currentOwnerEmail();\n await db.insert(schema.dispatchLinkTokens).values({\n id: recordId,\n token,\n ownerEmail: owner,\n orgId: currentOrgId(),\n platform,\n createdBy: owner,\n expiresAt: timestamp + 7 * 24 * 60 * 60 * 1000,\n claimedAt: null,\n claimedByExternalUserId: null,\n claimedByExternalUserName: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n await recordAudit({\n action: \"identity.link-token-created\",\n targetType: \"link-token\",\n targetId: recordId,\n summary: `Created ${platform} link token for ${owner}`,\n metadata: { token, platform },\n });\n return {\n token,\n command: `/link ${token}`,\n platform,\n expiresAt: timestamp + 7 * 24 * 60 * 60 * 1000,\n };\n}\n\nexport async function listIdentityState() {\n const db = getDb();\n const owner = currentOwnerEmail();\n const orgId = currentOrgId();\n const filters = and(\n eq(schema.dispatchIdentityLinks.ownerEmail, owner),\n orgId\n ? eq(schema.dispatchIdentityLinks.orgId, orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n );\n const tokenFilters = and(\n eq(schema.dispatchLinkTokens.ownerEmail, owner),\n orgId\n ? eq(schema.dispatchLinkTokens.orgId, orgId)\n : isNull(schema.dispatchLinkTokens.orgId),\n );\n const [links, tokens] = await Promise.all([\n db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(filters)\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt)),\n db\n .select()\n .from(schema.dispatchLinkTokens)\n .where(tokenFilters)\n .orderBy(desc(schema.dispatchLinkTokens.updatedAt)),\n ]);\n return { links, tokens };\n}\n\nexport async function resolveLinkedOwner(\n platform: string,\n externalUserId?: string | null,\n options: {\n orgId?: string | null;\n allowAnyOrgFallback?: boolean;\n } = {},\n) {\n if (!externalUserId) return null;\n const db = getDb();\n const orgId = options.orgId !== undefined ? options.orgId : currentOrgId();\n const rows = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, platform),\n eq(schema.dispatchIdentityLinks.externalUserId, externalUserId),\n orgId\n ? eq(schema.dispatchIdentityLinks.orgId, orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n ),\n )\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt))\n .limit(1);\n if (rows[0]?.ownerEmail) return rows[0].ownerEmail;\n\n if (!options.allowAnyOrgFallback || orgId) return null;\n\n // Webhook processors run outside a normal request/org context. A linked\n // Slack/Telegram identity may still be scoped to an org, so fall back to any\n // org only when every matching link resolves to the same owner.\n const fallbackRows = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, platform),\n eq(schema.dispatchIdentityLinks.externalUserId, externalUserId),\n ),\n )\n .orderBy(desc(schema.dispatchIdentityLinks.updatedAt))\n .limit(25);\n const owners = new Set(fallbackRows.map((row) => row.ownerEmail));\n return owners.size === 1 ? fallbackRows[0]?.ownerEmail || null : null;\n}\n\nexport async function consumeLinkToken(input: {\n platform: string;\n token: string;\n externalUserId?: string | null;\n externalUserName?: string | null;\n}) {\n if (!input.externalUserId) {\n throw new Error(\"Linking requires a platform user id\");\n }\n\n // Rate-limit failed attempts per (platform, externalUserId). Once\n // tripped, all further attempts are short-circuited until the block\n // window passes — including the lookup, so an attacker can't probe\n // for valid tokens during the block.\n const blockState = isLinkAttemptBlocked(input.platform, input.externalUserId);\n if (blockState.blocked) {\n throw new LinkRateLimitError(blockState.retryAfterMs);\n }\n\n const db = getDb();\n const tokenRows = await db\n .select()\n .from(schema.dispatchLinkTokens)\n .where(\n and(\n eq(schema.dispatchLinkTokens.platform, input.platform),\n eq(schema.dispatchLinkTokens.token, input.token),\n ),\n )\n .orderBy(desc(schema.dispatchLinkTokens.createdAt))\n .limit(2);\n if (tokenRows.length > 1) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token is ambiguous. Create a fresh token and retry.\");\n }\n const tokenRow = tokenRows[0];\n if (!tokenRow) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token not found\");\n }\n if (tokenRow.claimedAt) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token has already been claimed\");\n }\n if (tokenRow.expiresAt < now()) {\n recordLinkFailure(input.platform, input.externalUserId);\n throw new Error(\"Link token has expired\");\n }\n\n const timestamp = now();\n const [existing] = await db\n .select()\n .from(schema.dispatchIdentityLinks)\n .where(\n and(\n eq(schema.dispatchIdentityLinks.platform, input.platform),\n eq(schema.dispatchIdentityLinks.externalUserId, input.externalUserId),\n tokenRow.orgId\n ? eq(schema.dispatchIdentityLinks.orgId, tokenRow.orgId)\n : isNull(schema.dispatchIdentityLinks.orgId),\n ),\n )\n .limit(1);\n\n if (existing) {\n await db\n .update(schema.dispatchIdentityLinks)\n .set({\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n externalUserName: input.externalUserName || null,\n linkedBy: tokenRow.createdBy,\n updatedAt: timestamp,\n })\n .where(eq(schema.dispatchIdentityLinks.id, existing.id));\n } else {\n await db.insert(schema.dispatchIdentityLinks).values({\n id: id(),\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n platform: input.platform,\n externalUserId: input.externalUserId,\n externalUserName: input.externalUserName || null,\n linkedBy: tokenRow.createdBy,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n }\n\n await db\n .update(schema.dispatchLinkTokens)\n .set({\n claimedAt: timestamp,\n claimedByExternalUserId: input.externalUserId,\n claimedByExternalUserName: input.externalUserName || null,\n updatedAt: timestamp,\n })\n .where(eq(schema.dispatchLinkTokens.id, tokenRow.id));\n\n // Successful claim — reset the rate-limit budget so subsequent\n // links from this external user start fresh.\n clearLinkFailures(input.platform, input.externalUserId);\n\n await recordAudit({\n actor: tokenRow.createdBy,\n ownerEmail: tokenRow.ownerEmail,\n orgId: tokenRow.orgId,\n action: \"identity.linked\",\n targetType: \"identity-link\",\n targetId: input.externalUserId,\n summary: `Linked ${input.platform} user ${input.externalUserName || input.externalUserId}`,\n metadata: input,\n });\n\n return tokenRow.ownerEmail;\n}\n\nexport async function listOverview() {\n const [destinations, approvals, identities, audit, settings] =\n await Promise.all([\n listDestinations(),\n listApprovalRequests(),\n listIdentityState(),\n listAuditEvents(12),\n getApprovalPolicy(),\n ]);\n\n return {\n counts: {\n destinations: destinations.length,\n pendingApprovals: approvals.filter((item) => item.status === \"pending\")\n .length,\n linkedIdentities: identities.links.length,\n activeTokens: identities.tokens.filter(\n (item) => !item.claimedAt && item.expiresAt > now(),\n ).length,\n },\n recentDestinations: destinations.slice(0, 5),\n recentApprovals: approvals.slice(0, 5),\n recentAudit: audit.slice(0, 8),\n settings,\n };\n}\n"]}
|
|
@@ -73,5 +73,16 @@ export declare function createGrantedDispatchMcpEmbedSession(input: {
|
|
|
73
73
|
expiresAt?: number;
|
|
74
74
|
app: string;
|
|
75
75
|
}>;
|
|
76
|
+
export declare function createWorkspaceSsoEmbedSession(input: {
|
|
77
|
+
app?: string;
|
|
78
|
+
url?: string;
|
|
79
|
+
path?: string;
|
|
80
|
+
chrome?: "full" | "minimal";
|
|
81
|
+
}): Promise<{
|
|
82
|
+
startUrl: string;
|
|
83
|
+
targetPath?: string;
|
|
84
|
+
expiresAt?: number;
|
|
85
|
+
app: string;
|
|
86
|
+
}>;
|
|
76
87
|
export {};
|
|
77
88
|
//# sourceMappingURL=mcp-gateway.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-gateway.d.ts","sourceRoot":"","sources":["../../../src/server/lib/mcp-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,IAAI,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-gateway.d.ts","sourceRoot":"","sources":["../../../src/server/lib/mcp-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA6B5E,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,uBAAuB,CAAC;AA4B/B,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAkCD,KAAK,iCAAiC,GAClC,WAAW,GACX,SAAS,GACT,cAAc,GACd,cAAc,CAAC;AAEnB,KAAK,wBAAwB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,iCAAiC,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,SAAS,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iBAAS,wBAAwB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,GACT,wBAAwB,CAyC1B;AA+XD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IACnD,QAAQ,EAAE,4BAA4B,CAAC;IACvC,IAAI,EAAE,wBAAwB,EAAE,CAAC;CAClC,CAAC,CAcD;AAED,wBAAsB,0BAA0B,IAAI,OAAO,CACzD,wBAAwB,EAAE,CAC3B,CAGA;AAED,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAG1E;AAED,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,wBAAwB,CAAC,CAwBnC;AAgHD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAqCtD;AAED,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,CA+DnC;AAED,wBAAsB,yBAAyB,CAAC,KAAK,EAAE;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,OAAO,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC,CAkDD;AA6MD,wBAAsB,oCAAoC,CAAC,KAAK,EAAE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAWD;AA8ED,wBAAsB,8BAA8B,CAAC,KAAK,EAAE;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAmBD"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { A2AClient, signA2AToken } from "@agent-native/core/a2a";
|
|
2
|
+
import { isFeatureFlagEnabled } from "@agent-native/core/feature-flags";
|
|
2
3
|
import { buildMcpToolName, McpClientManager, } from "@agent-native/core/mcp-client";
|
|
3
4
|
import { getOrgA2ASecret, getOrgDomain } from "@agent-native/core/org";
|
|
4
5
|
import { buildDeepLink, buildEmbedStartPath, createEmbedSessionTicket, getRequestContext, getRequestOrgId, getRequestUserEmail, } from "@agent-native/core/server";
|
|
5
6
|
import { discoverAgents, } from "@agent-native/core/server/agent-discovery";
|
|
7
|
+
import { CANONICAL_WORKSPACE_SSO_APP_ORIGINS, DISPATCH_WORKSPACE_SSO_FLAG, parseWorkspaceSsoAppRegistrations, } from "../../shared/workspace-sso.js";
|
|
8
|
+
import { listWorkspaceApps, } from "./app-creation-store.js";
|
|
6
9
|
import { getDispatchMcpAppAccessSettings, isAppAllowedByMcpAccess, } from "./mcp-access-store.js";
|
|
7
10
|
const DISPATCH_APP_ID = "dispatch";
|
|
8
11
|
const DISPATCH_NAME = "Dispatch";
|
|
@@ -336,6 +339,17 @@ function safeAppOrigin(app) {
|
|
|
336
339
|
return null;
|
|
337
340
|
}
|
|
338
341
|
}
|
|
342
|
+
function isLoopbackOrigin(origin) {
|
|
343
|
+
try {
|
|
344
|
+
const hostname = new URL(origin).hostname;
|
|
345
|
+
return ["localhost", "127.0.0.1", "::1"].includes(hostname);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// coercion-ok: only a previously validated app origin reaches this helper;
|
|
349
|
+
// malformed values are ineligible for the loopback development exception.
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
339
353
|
function appBaseUrl(app) {
|
|
340
354
|
return app.url.replace(/\/+$/, "");
|
|
341
355
|
}
|
|
@@ -441,6 +455,96 @@ export async function resolveGrantedDispatchMcpApp(app) {
|
|
|
441
455
|
}
|
|
442
456
|
return match;
|
|
443
457
|
}
|
|
458
|
+
function workspaceSsoOriginForApp(appId) {
|
|
459
|
+
const canonical = CANONICAL_WORKSPACE_SSO_APP_ORIGINS[appId];
|
|
460
|
+
if (canonical)
|
|
461
|
+
return canonical;
|
|
462
|
+
const custom = parseWorkspaceSsoAppRegistrations(process.env.IDENTITY_SSO_APP_REGISTRY_JSON).find((registration) => registration.appId === appId);
|
|
463
|
+
return custom?.origin ?? null;
|
|
464
|
+
}
|
|
465
|
+
function isWorkspaceSsoCanonicalApp(app) {
|
|
466
|
+
const origin = safeAppOrigin(app);
|
|
467
|
+
if (!origin)
|
|
468
|
+
return false;
|
|
469
|
+
const registeredOrigin = workspaceSsoOriginForApp(app.id);
|
|
470
|
+
if (origin === registeredOrigin)
|
|
471
|
+
return true;
|
|
472
|
+
// The built-in discovery table intentionally points at local dev ports when
|
|
473
|
+
// running outside production. Keep local development usable without ever
|
|
474
|
+
// weakening the production exact-origin check.
|
|
475
|
+
return process.env.NODE_ENV !== "production" && isLoopbackOrigin(origin)
|
|
476
|
+
? Object.prototype.hasOwnProperty.call(CANONICAL_WORKSPACE_SSO_APP_ORIGINS, app.id)
|
|
477
|
+
: false;
|
|
478
|
+
}
|
|
479
|
+
function sameWorkspaceApp(candidate, mounted) {
|
|
480
|
+
if (candidate.id !== mounted.id || !mounted.url)
|
|
481
|
+
return false;
|
|
482
|
+
return candidate.url.replace(/\/+$/, "") === mounted.url.replace(/\/+$/, "");
|
|
483
|
+
}
|
|
484
|
+
async function isEligibleWorkspaceSsoApp(candidate, mountedApps) {
|
|
485
|
+
const origin = safeAppOrigin(candidate);
|
|
486
|
+
if (!origin)
|
|
487
|
+
return false;
|
|
488
|
+
if (isWorkspaceSsoCanonicalApp(candidate))
|
|
489
|
+
return true;
|
|
490
|
+
const customOrigin = workspaceSsoOriginForApp(candidate.id);
|
|
491
|
+
if (customOrigin === origin)
|
|
492
|
+
return true;
|
|
493
|
+
const dispatchOrigin = safeAppOrigin({
|
|
494
|
+
id: DISPATCH_APP_ID,
|
|
495
|
+
name: DISPATCH_NAME,
|
|
496
|
+
description: DISPATCH_DESCRIPTION,
|
|
497
|
+
url: dispatchSelfBaseUrl(),
|
|
498
|
+
color: DISPATCH_COLOR,
|
|
499
|
+
granted: true,
|
|
500
|
+
});
|
|
501
|
+
if (origin !== dispatchOrigin)
|
|
502
|
+
return false;
|
|
503
|
+
return mountedApps.some((mounted) => sameWorkspaceApp(candidate, mounted));
|
|
504
|
+
}
|
|
505
|
+
async function listWorkspaceSsoApps() {
|
|
506
|
+
const [agents, mountedApps] = await Promise.all([
|
|
507
|
+
discoverAgents("dispatch"),
|
|
508
|
+
listWorkspaceApps({ includeAgentCards: false }),
|
|
509
|
+
]);
|
|
510
|
+
const candidates = agents
|
|
511
|
+
.filter((agent) => normalizeAppId(agent.id) !== DISPATCH_APP_ID)
|
|
512
|
+
.map((agent) => ({
|
|
513
|
+
...toAccessibleApp(agent, {
|
|
514
|
+
mode: "all-apps",
|
|
515
|
+
selectedAppIds: [],
|
|
516
|
+
}),
|
|
517
|
+
granted: true,
|
|
518
|
+
}));
|
|
519
|
+
const eligible = [];
|
|
520
|
+
for (const candidate of candidates) {
|
|
521
|
+
if (await isEligibleWorkspaceSsoApp(candidate, mountedApps)) {
|
|
522
|
+
eligible.push(candidate);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return [
|
|
526
|
+
{
|
|
527
|
+
id: DISPATCH_APP_ID,
|
|
528
|
+
name: DISPATCH_NAME,
|
|
529
|
+
description: DISPATCH_DESCRIPTION,
|
|
530
|
+
url: dispatchSelfBaseUrl(),
|
|
531
|
+
color: DISPATCH_COLOR,
|
|
532
|
+
granted: true,
|
|
533
|
+
},
|
|
534
|
+
...eligible,
|
|
535
|
+
];
|
|
536
|
+
}
|
|
537
|
+
async function resolveWorkspaceSsoApp(app) {
|
|
538
|
+
const target = normalizeAppId(app);
|
|
539
|
+
if (!target)
|
|
540
|
+
throw new Error("app is required");
|
|
541
|
+
const apps = await listWorkspaceSsoApps();
|
|
542
|
+
const match = apps.find((candidate) => candidate.id === target || candidate.name.toLowerCase() === target);
|
|
543
|
+
if (!match) {
|
|
544
|
+
throw new Error(`Workspace app "${app}" is not registered for workspace sign-in.`);
|
|
545
|
+
}
|
|
546
|
+
return match;
|
|
547
|
+
}
|
|
444
548
|
export async function askGrantedDispatchMcpApp(app, message, options) {
|
|
445
549
|
const trimmedMessage = message.trim();
|
|
446
550
|
if (!trimmedMessage)
|
|
@@ -653,9 +757,9 @@ async function callTargetCreateEmbedSession(input) {
|
|
|
653
757
|
}
|
|
654
758
|
}
|
|
655
759
|
}
|
|
656
|
-
async function
|
|
760
|
+
async function resolveEmbedTarget(input, options) {
|
|
657
761
|
const explicitApp = input.app?.trim()
|
|
658
|
-
? await
|
|
762
|
+
? await options.resolveApp(input.app)
|
|
659
763
|
: null;
|
|
660
764
|
if (explicitApp && input.path) {
|
|
661
765
|
const path = safeAppPath(input.path);
|
|
@@ -688,12 +792,12 @@ async function resolveDispatchEmbedTarget(input) {
|
|
|
688
792
|
url: `${appBaseUrl(explicitApp)}${path}`,
|
|
689
793
|
};
|
|
690
794
|
}
|
|
691
|
-
const apps = explicitApp ? [explicitApp] : await
|
|
795
|
+
const apps = explicitApp ? [explicitApp] : await options.listApps();
|
|
692
796
|
const target = apps
|
|
693
797
|
.filter((app) => appMatchesUrlPath(app, parsed))
|
|
694
798
|
.sort((a, b) => appPathSpecificity(b) - appPathSpecificity(a))[0];
|
|
695
799
|
if (!target) {
|
|
696
|
-
throw new Error(
|
|
800
|
+
throw new Error(options.urlError);
|
|
697
801
|
}
|
|
698
802
|
const path = safeAppPath(appRelativePath(target, parsed));
|
|
699
803
|
if (!path)
|
|
@@ -701,6 +805,20 @@ async function resolveDispatchEmbedTarget(input) {
|
|
|
701
805
|
assertAppCanOpenPath(target, path);
|
|
702
806
|
return { app: target, path, url: `${appBaseUrl(target)}${path}` };
|
|
703
807
|
}
|
|
808
|
+
async function resolveDispatchEmbedTarget(input) {
|
|
809
|
+
return resolveEmbedTarget(input, {
|
|
810
|
+
resolveApp: resolveGrantedDispatchMcpApp,
|
|
811
|
+
listApps: listGrantedDispatchMcpApps,
|
|
812
|
+
urlError: "Embed URL must belong to an app granted through Dispatch.",
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
async function resolveWorkspaceSsoEmbedTarget(input) {
|
|
816
|
+
return resolveEmbedTarget(input, {
|
|
817
|
+
resolveApp: resolveWorkspaceSsoApp,
|
|
818
|
+
listApps: listWorkspaceSsoApps,
|
|
819
|
+
urlError: "Embed URL must belong to an app registered for Dispatch workspace sign-in.",
|
|
820
|
+
});
|
|
821
|
+
}
|
|
704
822
|
async function createDispatchSelfEmbedSession(input) {
|
|
705
823
|
const ticket = await createEmbedSessionTicket({
|
|
706
824
|
ownerEmail: input.ownerEmail,
|
|
@@ -721,14 +839,22 @@ export async function createGrantedDispatchMcpEmbedSession(input) {
|
|
|
721
839
|
if (!userEmail)
|
|
722
840
|
throw new Error("no authenticated user");
|
|
723
841
|
const target = await resolveDispatchEmbedTarget(input);
|
|
724
|
-
|
|
842
|
+
return createEmbedSessionForResolvedApp({
|
|
843
|
+
ownerEmail: userEmail,
|
|
844
|
+
orgId: getRequestOrgId(),
|
|
845
|
+
target,
|
|
846
|
+
chrome: input.chrome,
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
async function createEmbedSessionForResolvedApp(input) {
|
|
850
|
+
const { ownerEmail, orgId, target, chrome } = input;
|
|
725
851
|
if (target.app.id === DISPATCH_APP_ID) {
|
|
726
852
|
return createDispatchSelfEmbedSession({
|
|
727
|
-
ownerEmail
|
|
853
|
+
ownerEmail,
|
|
728
854
|
orgId,
|
|
729
855
|
path: target.path,
|
|
730
856
|
baseUrl: appBaseUrl(target.app),
|
|
731
|
-
chrome
|
|
857
|
+
chrome,
|
|
732
858
|
});
|
|
733
859
|
}
|
|
734
860
|
const [orgDomain, orgSecret] = orgId
|
|
@@ -741,7 +867,7 @@ export async function createGrantedDispatchMcpEmbedSession(input) {
|
|
|
741
867
|
const usableOrgDomain = typeof orgDomain === "string" && orgDomain.trim().length > 0;
|
|
742
868
|
const useOrgSigning = usableOrgDomain && usableOrgSecret;
|
|
743
869
|
const signedOrgDomain = usableOrgDomain ? orgDomain.trim() : undefined;
|
|
744
|
-
const token = await signA2AToken(
|
|
870
|
+
const token = await signA2AToken(ownerEmail, signedOrgDomain, useOrgSigning ? orgSecret.trim() : undefined, {
|
|
745
871
|
expiresIn: "5m",
|
|
746
872
|
// Prefer the synced org A2A secret when present because first-party
|
|
747
873
|
// production apps do not have to share the same deployment env secret.
|
|
@@ -752,7 +878,7 @@ export async function createGrantedDispatchMcpEmbedSession(input) {
|
|
|
752
878
|
app: target.app,
|
|
753
879
|
token,
|
|
754
880
|
url: target.url,
|
|
755
|
-
chrome
|
|
881
|
+
chrome,
|
|
756
882
|
});
|
|
757
883
|
const parsed = parseMcpToolTextResult(result);
|
|
758
884
|
if (!parsed.startUrl) {
|
|
@@ -768,4 +894,24 @@ export async function createGrantedDispatchMcpEmbedSession(input) {
|
|
|
768
894
|
output.expiresAt = parsed.expiresAt;
|
|
769
895
|
return output;
|
|
770
896
|
}
|
|
897
|
+
export async function createWorkspaceSsoEmbedSession(input) {
|
|
898
|
+
const ownerEmail = getRequestUserEmail();
|
|
899
|
+
if (!ownerEmail)
|
|
900
|
+
throw new Error("no authenticated user");
|
|
901
|
+
const enabled = await isFeatureFlagEnabled(DISPATCH_WORKSPACE_SSO_FLAG, {
|
|
902
|
+
userEmail: ownerEmail,
|
|
903
|
+
userKey: ownerEmail,
|
|
904
|
+
orgId: getRequestOrgId(),
|
|
905
|
+
});
|
|
906
|
+
if (!enabled) {
|
|
907
|
+
throw new Error("Dispatch workspace sign-in is not enabled.");
|
|
908
|
+
}
|
|
909
|
+
const target = await resolveWorkspaceSsoEmbedTarget(input);
|
|
910
|
+
return createEmbedSessionForResolvedApp({
|
|
911
|
+
ownerEmail,
|
|
912
|
+
orgId: getRequestOrgId(),
|
|
913
|
+
target,
|
|
914
|
+
chrome: input.chrome,
|
|
915
|
+
});
|
|
916
|
+
}
|
|
771
917
|
//# sourceMappingURL=mcp-gateway.js.map
|