@agent-native/core 0.7.22 → 0.7.24
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 +2 -2
- package/dist/a2a/client.d.ts +10 -4
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +16 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +20 -17
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/cli/create.d.ts +3 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +33 -32
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +23 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts +3 -0
- package/dist/cli/workspace-dev.d.ts.map +1 -0
- package/dist/cli/workspace-dev.js +323 -0
- package/dist/cli/workspace-dev.js.map +1 -0
- package/dist/cli/workspacify.d.ts +3 -3
- package/dist/cli/workspacify.js +4 -4
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +10 -9
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/components/ui/tooltip.d.ts +8 -0
- package/dist/client/components/ui/tooltip.d.ts.map +1 -0
- package/dist/client/components/ui/tooltip.js +11 -0
- package/dist/client/components/ui/tooltip.js.map +1 -0
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +21 -17
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +13 -11
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/deploy/workspace-core.d.ts +1 -1
- package/dist/deploy/workspace-core.d.ts.map +1 -1
- package/dist/deploy/workspace-core.js +14 -11
- package/dist/deploy/workspace-core.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts +10 -0
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -0
- package/dist/integrations/a2a-continuation-processor.js +150 -0
- package/dist/integrations/a2a-continuation-processor.js.map +1 -0
- package/dist/integrations/a2a-continuations-store.d.ts +41 -0
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -0
- package/dist/integrations/a2a-continuations-store.js +214 -0
- package/dist/integrations/a2a-continuations-store.js.map +1 -0
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +4 -1
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +52 -0
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/types.d.ts +5 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +6 -0
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +69 -15
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +22 -16
- package/dist/org/handlers.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +91 -30
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +17 -105
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agents-bundle.js +1 -1
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +29 -120
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +1 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +7 -5
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/framework-request-handler.js +1 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +1 -8
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +321 -152
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/request-context.d.ts +14 -3
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +3 -0
- package/dist/server/request-context.js.map +1 -1
- package/dist/templates/default/_gitignore +2 -0
- package/dist/templates/workspace-core/AGENTS.md +18 -71
- package/dist/templates/workspace-core/package.json +2 -20
- package/dist/templates/workspace-core/src/client/index.ts +2 -26
- package/dist/templates/workspace-core/src/index.ts +1 -21
- package/dist/templates/workspace-core/src/server/index.ts +3 -22
- package/dist/templates/workspace-root/.prettierignore +19 -0
- package/dist/templates/workspace-root/README.md +17 -20
- package/dist/templates/workspace-root/_gitignore +8 -0
- package/dist/templates/workspace-root/package.json +8 -4
- package/dist/templates/workspace-root/pnpm-workspace.yaml +5 -2
- package/dist/vite/agents-bundle-plugin.js +2 -2
- package/dist/vite/agents-bundle-plugin.js.map +1 -1
- package/docs/content/authentication.md +3 -5
- package/docs/content/multi-app-workspace.md +38 -50
- package/package.json +1 -1
- package/src/templates/default/_gitignore +2 -0
- package/src/templates/workspace-core/AGENTS.md +18 -71
- package/src/templates/workspace-core/package.json +2 -20
- package/src/templates/workspace-core/src/client/index.ts +2 -26
- package/src/templates/workspace-core/src/index.ts +1 -21
- package/src/templates/workspace-core/src/server/index.ts +3 -22
- package/src/templates/workspace-root/.prettierignore +19 -0
- package/src/templates/workspace-root/README.md +17 -20
- package/src/templates/workspace-root/_gitignore +8 -0
- package/src/templates/workspace-root/package.json +8 -4
- package/src/templates/workspace-root/pnpm-workspace.yaml +5 -2
- package/dist/templates/default/.claude/settings.json +0 -100
- package/dist/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
- package/dist/templates/workspace-core/actions/company-directory.ts +0 -38
- package/dist/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
- package/dist/templates/workspace-core/src/credentials.ts +0 -67
- package/dist/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
- package/dist/templates/workspace-core/src/server/auth-plugin.ts +0 -35
- package/dist/templates/workspace-core/styles/tokens.css +0 -22
- package/dist/templates/workspace-root/scripts/workspace-dev.ts +0 -377
- package/src/templates/default/.claude/settings.json +0 -100
- package/src/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
- package/src/templates/workspace-core/actions/company-directory.ts +0 -38
- package/src/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
- package/src/templates/workspace-core/src/credentials.ts +0 -67
- package/src/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
- package/src/templates/workspace-core/src/server/auth-plugin.ts +0 -35
- package/src/templates/workspace-core/styles/tokens.css +0 -22
- package/src/templates/workspace-root/scripts/workspace-dev.ts +0 -377
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { createError, getHeader, readRawBody } from \"h3\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\n\n/** Slack's max message length */\nconst SLACK_MAX_LENGTH = 4000;\n\n/**\n * Create a Slack platform adapter.\n *\n * Required env vars:\n * - SLACK_BOT_TOKEN — Bot user OAuth token (xoxb-...)\n * - SLACK_SIGNING_SECRET — Used to verify webhook signatures\n *\n * Optional env vars:\n * - SLACK_ALLOWED_TEAM_IDS — Comma-separated list of Slack workspace\n * `team_id` values (e.g. \"T012ABCDEF,T034GHIJKL\") that this deployment\n * accepts events from. Strongly recommended in multi-tenant deployments\n * to prevent cross-workspace event injection (H1 in the webhook audit):\n * the global `SLACK_SIGNING_SECRET` is the same key for every workspace\n * the app is installed to, so without an allowlist any installed\n * workspace can drive the agent. When unset the adapter accepts events\n * from any workspace — fine for single-tenant dev, unsafe for prod.\n * - SLACK_ALLOWED_API_APP_IDS — Comma-separated list of Slack app IDs\n * (`api_app_id`) to additionally pin events to. Useful when the same\n * signing secret rotation surfaces multiple app installs.\n */\nexport function slackAdapter(): PlatformAdapter {\n return {\n platform: \"slack\",\n label: \"Slack\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"SLACK_BOT_TOKEN\",\n label: \"Slack Bot Token\",\n required: true,\n helpText:\n \"In your Slack app's left nav: OAuth & Permissions → Bot User OAuth Token (starts with `xoxb-`).\",\n },\n {\n key: \"SLACK_SIGNING_SECRET\",\n label: \"Slack Signing Secret\",\n required: true,\n helpText:\n \"In your Slack app's left nav: Basic Information → App Credentials → Signing Secret.\",\n },\n ];\n },\n\n async handleVerification(\n event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Slack sends url_verification when first setting up the webhook.\n // readRawBodyCached caches the raw bytes on event.context.__rawBody so\n // subsequent verifyWebhook + parseIncomingMessage calls re-use them\n // without re-stringifying a parsed body (M2 in the audit).\n const body = await readRawBodyCached(event);\n try {\n const parsed = JSON.parse(body);\n if (parsed.type === \"url_verification\") {\n return { handled: true, response: { challenge: parsed.challenge } };\n }\n } catch {}\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const signingSecret = process.env.SLACK_SIGNING_SECRET;\n if (!signingSecret) return false;\n\n const signature = getHeader(event, \"x-slack-signature\");\n const timestamp = getHeader(event, \"x-slack-request-timestamp\");\n if (!signature || !timestamp) return false;\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(timestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) return false;\n\n const body = await readRawBodyCached(event);\n const crypto = await import(\"node:crypto\");\n const basestring = `v0:${timestamp}:${body}`;\n const expectedSignature =\n \"v0=\" +\n crypto\n .createHmac(\"sha256\", signingSecret)\n .update(basestring)\n .digest(\"hex\");\n\n // Timing-safe comparison\n try {\n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature),\n );\n } catch {\n return false;\n }\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const raw = await readRawBodyCached(event);\n let payload: any;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n\n // H1 (webhook audit): cross-workspace event injection. The global\n // SLACK_SIGNING_SECRET is the same key for every workspace this Slack\n // app is installed to — without a per-tenant allowlist any installed\n // workspace can drive the agent. We enforce SLACK_ALLOWED_TEAM_IDS\n // here AFTER the signature has already been verified by the webhook\n // handler, so this is purely a tenant-isolation gate (not a forgery\n // defense). When unset in production we surface a one-time warning\n // recommending it be configured.\n enforceWorkspaceAllowlist(payload);\n\n // Handle Events API wrapper\n if (payload.type === \"event_callback\") {\n const e = payload.event;\n if (!e) return null;\n\n // Ignore bot messages\n if (e.bot_id || e.subtype === \"bot_message\") return null;\n // Ignore message edits and deletes\n if (e.subtype === \"message_changed\" || e.subtype === \"message_deleted\")\n return null;\n\n // Handle both direct messages and app_mentions\n const text = e.text?.trim();\n if (!text) return null;\n\n // Remove bot mention from text (e.g., \"<@U123> do something\" → \"do something\")\n const cleanText = text.replace(/<@[A-Z0-9]+>/g, \"\").trim();\n if (!cleanText) return null;\n\n // Thread ID: use thread_ts if in a thread, otherwise message ts\n const threadTs = e.thread_ts || e.ts;\n const externalThreadId = `${e.channel}:${threadTs}`;\n\n return {\n platform: \"slack\",\n externalThreadId,\n text: cleanText,\n senderName: e.user,\n senderId: e.user,\n platformContext: {\n channelId: e.channel,\n threadTs: threadTs,\n messageTs: e.ts,\n teamId: payload.team_id,\n eventId: payload.event_id,\n },\n timestamp: Math.floor(parseFloat(e.ts) * 1000),\n };\n }\n\n return null;\n },\n\n async postProcessingPlaceholder(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null> {\n // No placeholder reply in the thread — Slack's native assistant\n // status bar (\"agent-native is thinking…\", below the composer) is the\n // loading affordance. A second visible \"Working on it…\" reply was\n // redundant and added an extra chunk that we then had to overwrite.\n // We just set the native status and return null so sendResponse posts\n // the final reply as a fresh message.\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) return null;\n\n const channelId = incoming.platformContext.channelId as string;\n const threadTs = incoming.platformContext.threadTs as string;\n if (!channelId || !threadTs) return null;\n\n // Best-effort: flip the native AI-assistant \"is thinking…\" status bar\n // in the channel input area. Requires `assistant:write` scope on the\n // app — otherwise silently no-ops.\n setSlackAssistantStatus(token, channelId, threadTs, \"is thinking…\");\n return null;\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void> {\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) {\n console.error(\"[slack] SLACK_BOT_TOKEN not configured\");\n return;\n }\n\n const channelId = context.platformContext.channelId as string;\n const threadTs = context.platformContext.threadTs as string;\n const blocks = (message.platformContext as any)?.blocks as\n | unknown[]\n | undefined;\n const placeholderRef = opts?.placeholderRef;\n\n // Block-rich path: split text into chunks but render the FIRST chunk as\n // blocks (so we keep the in-place edit + button) and any overflow as\n // plain follow-up posts. The vast majority of replies fit in one block.\n const chunks = splitMessage(message.text, SLACK_MAX_LENGTH);\n const firstChunk = chunks[0] ?? \"\";\n const restChunks = chunks.slice(1);\n\n const finalBlocks =\n blocks ??\n buildResponseBlocks(firstChunk, {\n threadDeepLinkUrl: (message.platformContext as any)\n ?.threadDeepLinkUrl,\n });\n\n const baseBody: Record<string, unknown> = {\n channel: channelId,\n text: firstChunk,\n blocks: finalBlocks,\n unfurl_links: false,\n unfurl_media: false,\n mrkdwn: true,\n };\n\n try {\n if (placeholderRef) {\n // Replace the \"thinking…\" placeholder in place.\n const res = await fetch(\"https://slack.com/api/chat.update\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ ...baseBody, ts: placeholderRef }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n error?: string;\n };\n if (!data.ok) {\n console.error(\"[slack] chat.update error:\", data.error);\n // Fall back to a fresh post so the user still sees a reply\n await postFresh(token, channelId, threadTs, baseBody);\n }\n } else {\n await postFresh(token, channelId, threadTs, baseBody);\n }\n\n // Clear the AI-assistant \"is thinking…\" status now that we've\n // delivered the final answer. Empty status clears it.\n if (threadTs) {\n setSlackAssistantStatus(token, channelId, threadTs, \"\");\n }\n\n // Overflow chunks (rare) — post as plain follow-ups in the same thread\n for (const chunk of restChunks) {\n await postFresh(token, channelId, threadTs, {\n channel: channelId,\n text: chunk,\n unfurl_links: false,\n unfurl_media: false,\n mrkdwn: true,\n });\n }\n } catch (err) {\n console.error(\"[slack] Failed to send message:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) {\n console.error(\"[slack] SLACK_BOT_TOKEN not configured\");\n return;\n }\n\n const chunks = splitMessage(message.text, SLACK_MAX_LENGTH);\n for (const chunk of chunks) {\n const body: Record<string, unknown> = {\n channel: target.destination,\n text: chunk,\n };\n if (target.threadRef) body.thread_ts = target.threadRef;\n\n try {\n const res = await fetch(\"https://slack.com/api/chat.postMessage\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = (await res.json()) as { ok: boolean; error?: string };\n if (!data.ok) {\n throw new Error(data.error || \"chat.postMessage failed\");\n }\n } catch (err) {\n console.error(\"[slack] Failed to send proactive message:\", err);\n throw err;\n }\n }\n },\n\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage {\n return {\n text: markdownToSlackMrkdwn(text),\n platformContext: opts?.threadDeepLinkUrl\n ? { threadDeepLinkUrl: opts.threadDeepLinkUrl }\n : {},\n };\n },\n\n async getStatus(baseUrl?: string): Promise<IntegrationStatus> {\n const hasToken = !!process.env.SLACK_BOT_TOKEN;\n const hasSecret = !!process.env.SLACK_SIGNING_SECRET;\n const configured = hasToken && hasSecret;\n\n return {\n platform: \"slack\",\n label: \"Slack\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasToken,\n hasSecret,\n },\n error: !configured\n ? \"Set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in your environment\"\n : undefined,\n };\n },\n };\n}\n\n/**\n * Parse a comma-separated env var into a Set of trimmed, non-empty values.\n * Returns null when the env var is unset or empty (so callers can\n * distinguish \"no allowlist configured\" from \"empty allowlist\").\n */\nfunction parseAllowlistEnv(name: string): Set<string> | null {\n const raw = process.env[name];\n if (!raw) return null;\n const values = raw\n .split(\",\")\n .map((v) => v.trim())\n .filter((v) => v.length > 0);\n if (values.length === 0) return null;\n return new Set(values);\n}\n\nlet _missingAllowlistWarned = false;\n\n/**\n * Enforce that an incoming Slack event comes from an allowlisted workspace.\n *\n * H1 in the webhook audit: the framework uses a SINGLE global\n * SLACK_SIGNING_SECRET for every workspace the Slack app is installed to,\n * so a valid signature alone doesn't prove the request belongs to the\n * tenant the deployment intends to serve. This helper layers a per-tenant\n * allowlist on top of signature verification.\n *\n * Behavior:\n * - If `SLACK_ALLOWED_TEAM_IDS` is set: reject any payload whose\n * `team_id` isn't in the list.\n * - If `SLACK_ALLOWED_API_APP_IDS` is set: also reject payloads whose\n * `api_app_id` isn't in the list (bot apps can be installed under the\n * same Slack app id across multiple workspaces — pinning both keeps\n * the surface tight when team_id allows multiple workspaces).\n * - If neither is set AND `NODE_ENV === \"production\"`: log a one-time\n * warning recommending the env var be configured. Continue (preserves\n * existing behavior to avoid breaking single-tenant prod deployments\n * that have always run without an allowlist).\n * - If neither is set in dev / single-tenant: accept (current behavior).\n *\n * Throws an h3 401 error when an allowlisted-but-mismatched payload is\n * received, which the integrations plugin surfaces to the caller as\n * \"Unrecognized Slack workspace\" without enqueuing the event.\n */\nfunction enforceWorkspaceAllowlist(payload: any): void {\n const teamId =\n typeof payload?.team_id === \"string\" ? payload.team_id : undefined;\n const apiAppId =\n typeof payload?.api_app_id === \"string\" ? payload.api_app_id : undefined;\n\n const allowedTeamIds = parseAllowlistEnv(\"SLACK_ALLOWED_TEAM_IDS\");\n const allowedAppIds = parseAllowlistEnv(\"SLACK_ALLOWED_API_APP_IDS\");\n\n if (allowedTeamIds) {\n if (!teamId || !allowedTeamIds.has(teamId)) {\n throw createError({\n statusCode: 401,\n statusMessage: \"Unrecognized Slack workspace\",\n });\n }\n }\n\n if (allowedAppIds) {\n if (!apiAppId || !allowedAppIds.has(apiAppId)) {\n throw createError({\n statusCode: 401,\n statusMessage: \"Unrecognized Slack workspace\",\n });\n }\n }\n\n if (\n !allowedTeamIds &&\n !allowedAppIds &&\n process.env.NODE_ENV === \"production\" &&\n !_missingAllowlistWarned\n ) {\n _missingAllowlistWarned = true;\n console.warn(\n \"[slack] SLACK_ALLOWED_TEAM_IDS not set in production — accepting events from any workspace whose signature matches SLACK_SIGNING_SECRET. \" +\n \"Set SLACK_ALLOWED_TEAM_IDS to a comma-separated list of allowed team_id values to prevent cross-workspace event injection (H1 in the webhook audit).\",\n );\n }\n}\n\n/**\n * Read the raw request body as a string and cache on the event context.\n *\n * This MUST read raw bytes from the request stream — never `JSON.stringify`\n * a parsed body, because Slack's HMAC is computed over the exact bytes Slack\n * sent. Re-stringifying a parsed object loses key ordering, whitespace, and\n * Unicode-escape choices, so the signature check would silently fail for\n * legitimate requests (M2 in the webhook security audit).\n *\n * h3 v2's body stream is consume-once, so we cache the raw string on the\n * event context after the first read. All call sites (handleVerification,\n * verifyWebhook, parseIncomingMessage) MUST go through this helper.\n */\nasync function readRawBodyCached(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n // h3's readRawBody returns the bytes Slack actually sent, defaulting to\n // utf8-decoded. Returns undefined for empty bodies — we coerce to \"\" so\n // the HMAC check can proceed deterministically.\n const raw = (await readRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n\n/** Split a message into chunks that fit within the platform's limit */\nfunction splitMessage(text: string, maxLength: number): string[] {\n if (text.length <= maxLength) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n // Try to split at a newline\n let splitIdx = remaining.lastIndexOf(\"\\n\", maxLength);\n if (splitIdx <= 0) {\n // Try to split at a space\n splitIdx = remaining.lastIndexOf(\" \", maxLength);\n }\n if (splitIdx <= 0) {\n splitIdx = maxLength;\n }\n chunks.push(remaining.slice(0, splitIdx));\n remaining = remaining.slice(splitIdx).trimStart();\n }\n return chunks;\n}\n\n/** Hard cap on input length we feed to the regex-based mrkdwn converter.\n * L2 in the webhook audit: `\\*\\*(.+?)\\*\\*` with the `s` flag on a long\n * string of asterisks can exhibit super-linear backtracking. Slack\n * itself caps message bodies at 4000 chars (SLACK_MAX_LENGTH); we cap\n * the input here at 10x that as a defensive bound for any caller that\n * passes a longer rendering source through this helper before chunking. */\nconst MRKDWN_MAX_LENGTH = 40_000;\n\n/**\n * Convert standard markdown to Slack's mrkdwn dialect.\n * - `[text](url)` → `<url|text>`\n * - `**bold**` → `*bold*` (Slack uses single asterisks for bold)\n *\n * Inputs longer than MRKDWN_MAX_LENGTH are truncated before the regex\n * pass to bound worst-case backtracking on pathological input (L2 in the\n * webhook audit).\n */\nfunction markdownToSlackMrkdwn(text: string): string {\n const bounded =\n text.length > MRKDWN_MAX_LENGTH ? text.slice(0, MRKDWN_MAX_LENGTH) : text;\n return (\n bounded\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"<$2|$1>\")\n // Bounded character class instead of `.+?` with the `s` flag — caps\n // each bold span at 5000 chars so an attacker can't construct a\n // pathological \"**\" sequence that exhibits super-linear backtracking.\n // Newlines are allowed because `[^*]` excludes only the asterisk\n // itself, so multi-line bold spans still match.\n .replace(/\\*\\*([^*]{1,5000})\\*\\*/g, \"*$1*\")\n );\n}\n\n/**\n * Optionally set Slack's native AI-assistant status indicator (the small\n * \"is thinking…\" line under the message composer) for an app configured\n * with the `assistant:write` scope. Pure best-effort — fails silently for\n * apps that aren't set up as AI assistants.\n */\nfunction setSlackAssistantStatus(\n token: string,\n channelId: string,\n threadTs: string,\n status: string,\n): void {\n fetch(\"https://slack.com/api/assistant.threads.setStatus\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n channel_id: channelId,\n thread_ts: threadTs,\n status,\n }),\n }).catch(() => {});\n}\n\n/**\n * Block Kit payload for the final answer. We avoid auto-unfurl previews by\n * separating the deep-link out into a button instead of inlining it as a\n * `<url|text>` markdown link in the section body — that's what was producing\n * the giant \"Agent-Native Dispatch\" card in every thread reply.\n */\nfunction buildResponseBlocks(\n text: string,\n opts: { threadDeepLinkUrl?: string },\n): unknown[] {\n const blocks: any[] = [\n {\n type: \"section\",\n text: { type: \"mrkdwn\", text: text || \"_(no response)_\" },\n },\n ];\n if (opts.threadDeepLinkUrl) {\n blocks.push({\n type: \"actions\",\n elements: [\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Open thread\", emoji: true },\n url: opts.threadDeepLinkUrl,\n action_id: \"open_dispatch_thread\",\n },\n ],\n });\n }\n return blocks;\n}\n\n/**\n * Post a fresh message to a thread. Used as the placeholder-fallback path\n * (e.g. when chat.update fails) and for follow-up overflow chunks.\n */\nasync function postFresh(\n token: string,\n channelId: string,\n threadTs: string | undefined,\n body: Record<string, unknown>,\n): Promise<void> {\n const payload: Record<string, unknown> = {\n ...body,\n channel: channelId,\n };\n if (threadTs && !payload.thread_ts) payload.thread_ts = threadTs;\n const res = await fetch(\"https://slack.com/api/chat.postMessage\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n const data = (await res.json()) as { ok: boolean; error?: string };\n if (!data.ok) {\n console.error(\"[slack] chat.postMessage error:\", data.error);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { createError, getHeader, readRawBody } from \"h3\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\n\n/** Slack's max message length */\nconst SLACK_MAX_LENGTH = 4000;\n\n/**\n * Create a Slack platform adapter.\n *\n * Required env vars:\n * - SLACK_BOT_TOKEN — Bot user OAuth token (xoxb-...)\n * - SLACK_SIGNING_SECRET — Used to verify webhook signatures\n *\n * Optional env vars:\n * - SLACK_ALLOWED_TEAM_IDS — Comma-separated list of Slack workspace\n * `team_id` values (e.g. \"T012ABCDEF,T034GHIJKL\") that this deployment\n * accepts events from. Strongly recommended in multi-tenant deployments\n * to prevent cross-workspace event injection (H1 in the webhook audit):\n * the global `SLACK_SIGNING_SECRET` is the same key for every workspace\n * the app is installed to, so without an allowlist any installed\n * workspace can drive the agent. When unset the adapter accepts events\n * from any workspace — fine for single-tenant dev, unsafe for prod.\n * - SLACK_ALLOWED_API_APP_IDS — Comma-separated list of Slack app IDs\n * (`api_app_id`) to additionally pin events to. Useful when the same\n * signing secret rotation surfaces multiple app installs.\n */\nexport function slackAdapter(): PlatformAdapter {\n return {\n platform: \"slack\",\n label: \"Slack\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"SLACK_BOT_TOKEN\",\n label: \"Slack Bot Token\",\n required: true,\n helpText:\n \"In your Slack app's left nav: OAuth & Permissions → Bot User OAuth Token (starts with `xoxb-`).\",\n },\n {\n key: \"SLACK_SIGNING_SECRET\",\n label: \"Slack Signing Secret\",\n required: true,\n helpText:\n \"In your Slack app's left nav: Basic Information → App Credentials → Signing Secret.\",\n },\n ];\n },\n\n async handleVerification(\n event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Slack sends url_verification when first setting up the webhook.\n // readRawBodyCached caches the raw bytes on event.context.__rawBody so\n // subsequent verifyWebhook + parseIncomingMessage calls re-use them\n // without re-stringifying a parsed body (M2 in the audit).\n const body = await readRawBodyCached(event);\n try {\n const parsed = JSON.parse(body);\n if (parsed.type === \"url_verification\") {\n // Slack's URL verifier expects the raw challenge value in the\n // response body. Returning JSON works for some clients but the app\n // settings verifier rejects it as not matching the challenge.\n return { handled: true, response: parsed.challenge };\n }\n } catch {}\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const signingSecret = process.env.SLACK_SIGNING_SECRET;\n if (!signingSecret) return false;\n\n const signature = getHeader(event, \"x-slack-signature\");\n const timestamp = getHeader(event, \"x-slack-request-timestamp\");\n if (!signature || !timestamp) return false;\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(timestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) return false;\n\n const body = await readRawBodyCached(event);\n const crypto = await import(\"node:crypto\");\n const basestring = `v0:${timestamp}:${body}`;\n const expectedSignature =\n \"v0=\" +\n crypto\n .createHmac(\"sha256\", signingSecret)\n .update(basestring)\n .digest(\"hex\");\n\n // Timing-safe comparison\n try {\n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature),\n );\n } catch {\n return false;\n }\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const raw = await readRawBodyCached(event);\n let payload: any;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n\n // H1 (webhook audit): cross-workspace event injection. The global\n // SLACK_SIGNING_SECRET is the same key for every workspace this Slack\n // app is installed to — without a per-tenant allowlist any installed\n // workspace can drive the agent. We enforce SLACK_ALLOWED_TEAM_IDS\n // here AFTER the signature has already been verified by the webhook\n // handler, so this is purely a tenant-isolation gate (not a forgery\n // defense). When unset in production we surface a one-time warning\n // recommending it be configured.\n enforceWorkspaceAllowlist(payload);\n\n // Handle Events API wrapper\n if (payload.type === \"event_callback\") {\n const e = payload.event;\n if (!e) return null;\n\n // Ignore bot messages\n if (e.bot_id || e.subtype === \"bot_message\") return null;\n // Ignore message edits and deletes\n if (e.subtype === \"message_changed\" || e.subtype === \"message_deleted\")\n return null;\n\n // Handle both direct messages and app_mentions\n const text = e.text?.trim();\n if (!text) return null;\n\n // Remove bot mention from text (e.g., \"<@U123> do something\" → \"do something\")\n const cleanText = text.replace(/<@[A-Z0-9]+>/g, \"\").trim();\n if (!cleanText) return null;\n\n // Thread ID: use thread_ts if in a thread, otherwise message ts\n const threadTs = e.thread_ts || e.ts;\n const externalThreadId = `${e.channel}:${threadTs}`;\n\n return {\n platform: \"slack\",\n externalThreadId,\n text: cleanText,\n senderName: e.user,\n senderId: e.user,\n platformContext: {\n channelId: e.channel,\n threadTs: threadTs,\n messageTs: e.ts,\n teamId: payload.team_id,\n eventId: payload.event_id,\n },\n timestamp: Math.floor(parseFloat(e.ts) * 1000),\n };\n }\n\n return null;\n },\n\n async postProcessingPlaceholder(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null> {\n // No placeholder reply in the thread — Slack's native assistant\n // status bar (\"agent-native is thinking…\", below the composer) is the\n // loading affordance. A second visible \"Working on it…\" reply was\n // redundant and added an extra chunk that we then had to overwrite.\n // We just set the native status and return null so sendResponse posts\n // the final reply as a fresh message.\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) return null;\n\n const channelId = incoming.platformContext.channelId as string;\n const threadTs = incoming.platformContext.threadTs as string;\n if (!channelId || !threadTs) return null;\n\n // Best-effort: flip the native AI-assistant \"is thinking…\" status bar\n // in the channel input area. Requires `assistant:write` scope on the\n // app — otherwise silently no-ops.\n setSlackAssistantStatus(token, channelId, threadTs, \"is thinking…\");\n return null;\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void> {\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) {\n console.error(\"[slack] SLACK_BOT_TOKEN not configured\");\n return;\n }\n\n const channelId = context.platformContext.channelId as string;\n const threadTs = context.platformContext.threadTs as string;\n const blocks = (message.platformContext as any)?.blocks as\n | unknown[]\n | undefined;\n const placeholderRef = opts?.placeholderRef;\n\n // Block-rich path: split text into chunks but render the FIRST chunk as\n // blocks (so we keep the in-place edit + button) and any overflow as\n // plain follow-up posts. The vast majority of replies fit in one block.\n const chunks = splitMessage(message.text, SLACK_MAX_LENGTH);\n const firstChunk = chunks[0] ?? \"\";\n const restChunks = chunks.slice(1);\n\n const finalBlocks =\n blocks ??\n buildResponseBlocks(firstChunk, {\n threadDeepLinkUrl: (message.platformContext as any)\n ?.threadDeepLinkUrl,\n });\n\n const baseBody: Record<string, unknown> = {\n channel: channelId,\n text: firstChunk,\n blocks: finalBlocks,\n unfurl_links: false,\n unfurl_media: false,\n mrkdwn: true,\n };\n\n try {\n if (placeholderRef) {\n // Replace the \"thinking…\" placeholder in place.\n const res = await fetch(\"https://slack.com/api/chat.update\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ ...baseBody, ts: placeholderRef }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n error?: string;\n };\n if (!data.ok) {\n console.error(\"[slack] chat.update error:\", data.error);\n // Fall back to a fresh post so the user still sees a reply\n await postFresh(token, channelId, threadTs, baseBody);\n }\n } else {\n await postFresh(token, channelId, threadTs, baseBody);\n }\n\n // Clear the AI-assistant \"is thinking…\" status now that we've\n // delivered the final answer. Empty status clears it.\n if (threadTs) {\n setSlackAssistantStatus(token, channelId, threadTs, \"\");\n }\n\n // Overflow chunks (rare) — post as plain follow-ups in the same thread\n for (const chunk of restChunks) {\n await postFresh(token, channelId, threadTs, {\n channel: channelId,\n text: chunk,\n unfurl_links: false,\n unfurl_media: false,\n mrkdwn: true,\n });\n }\n } catch (err) {\n console.error(\"[slack] Failed to send message:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const token = process.env.SLACK_BOT_TOKEN;\n if (!token) {\n console.error(\"[slack] SLACK_BOT_TOKEN not configured\");\n return;\n }\n\n const chunks = splitMessage(message.text, SLACK_MAX_LENGTH);\n for (const chunk of chunks) {\n const body: Record<string, unknown> = {\n channel: target.destination,\n text: chunk,\n };\n if (target.threadRef) body.thread_ts = target.threadRef;\n\n try {\n const res = await fetch(\"https://slack.com/api/chat.postMessage\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = (await res.json()) as { ok: boolean; error?: string };\n if (!data.ok) {\n throw new Error(data.error || \"chat.postMessage failed\");\n }\n } catch (err) {\n console.error(\"[slack] Failed to send proactive message:\", err);\n throw err;\n }\n }\n },\n\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage {\n return {\n text: markdownToSlackMrkdwn(text),\n platformContext: opts?.threadDeepLinkUrl\n ? { threadDeepLinkUrl: opts.threadDeepLinkUrl }\n : {},\n };\n },\n\n async getStatus(baseUrl?: string): Promise<IntegrationStatus> {\n const hasToken = !!process.env.SLACK_BOT_TOKEN;\n const hasSecret = !!process.env.SLACK_SIGNING_SECRET;\n const configured = hasToken && hasSecret;\n\n return {\n platform: \"slack\",\n label: \"Slack\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasToken,\n hasSecret,\n },\n error: !configured\n ? \"Set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in your environment\"\n : undefined,\n };\n },\n };\n}\n\n/**\n * Parse a comma-separated env var into a Set of trimmed, non-empty values.\n * Returns null when the env var is unset or empty (so callers can\n * distinguish \"no allowlist configured\" from \"empty allowlist\").\n */\nfunction parseAllowlistEnv(name: string): Set<string> | null {\n const raw = process.env[name];\n if (!raw) return null;\n const values = raw\n .split(\",\")\n .map((v) => v.trim())\n .filter((v) => v.length > 0);\n if (values.length === 0) return null;\n return new Set(values);\n}\n\nlet _missingAllowlistWarned = false;\n\n/**\n * Enforce that an incoming Slack event comes from an allowlisted workspace.\n *\n * H1 in the webhook audit: the framework uses a SINGLE global\n * SLACK_SIGNING_SECRET for every workspace the Slack app is installed to,\n * so a valid signature alone doesn't prove the request belongs to the\n * tenant the deployment intends to serve. This helper layers a per-tenant\n * allowlist on top of signature verification.\n *\n * Behavior:\n * - If `SLACK_ALLOWED_TEAM_IDS` is set: reject any payload whose\n * `team_id` isn't in the list.\n * - If `SLACK_ALLOWED_API_APP_IDS` is set: also reject payloads whose\n * `api_app_id` isn't in the list (bot apps can be installed under the\n * same Slack app id across multiple workspaces — pinning both keeps\n * the surface tight when team_id allows multiple workspaces).\n * - If neither is set AND `NODE_ENV === \"production\"`: log a one-time\n * warning recommending the env var be configured. Continue (preserves\n * existing behavior to avoid breaking single-tenant prod deployments\n * that have always run without an allowlist).\n * - If neither is set in dev / single-tenant: accept (current behavior).\n *\n * Throws an h3 401 error when an allowlisted-but-mismatched payload is\n * received, which the integrations plugin surfaces to the caller as\n * \"Unrecognized Slack workspace\" without enqueuing the event.\n */\nfunction enforceWorkspaceAllowlist(payload: any): void {\n const teamId =\n typeof payload?.team_id === \"string\" ? payload.team_id : undefined;\n const apiAppId =\n typeof payload?.api_app_id === \"string\" ? payload.api_app_id : undefined;\n\n const allowedTeamIds = parseAllowlistEnv(\"SLACK_ALLOWED_TEAM_IDS\");\n const allowedAppIds = parseAllowlistEnv(\"SLACK_ALLOWED_API_APP_IDS\");\n\n if (allowedTeamIds) {\n if (!teamId || !allowedTeamIds.has(teamId)) {\n throw createError({\n statusCode: 401,\n statusMessage: \"Unrecognized Slack workspace\",\n });\n }\n }\n\n if (allowedAppIds) {\n if (!apiAppId || !allowedAppIds.has(apiAppId)) {\n throw createError({\n statusCode: 401,\n statusMessage: \"Unrecognized Slack workspace\",\n });\n }\n }\n\n if (\n !allowedTeamIds &&\n !allowedAppIds &&\n process.env.NODE_ENV === \"production\" &&\n !_missingAllowlistWarned\n ) {\n _missingAllowlistWarned = true;\n console.warn(\n \"[slack] SLACK_ALLOWED_TEAM_IDS not set in production — accepting events from any workspace whose signature matches SLACK_SIGNING_SECRET. \" +\n \"Set SLACK_ALLOWED_TEAM_IDS to a comma-separated list of allowed team_id values to prevent cross-workspace event injection (H1 in the webhook audit).\",\n );\n }\n}\n\n/**\n * Read the raw request body as a string and cache on the event context.\n *\n * This MUST read raw bytes from the request stream — never `JSON.stringify`\n * a parsed body, because Slack's HMAC is computed over the exact bytes Slack\n * sent. Re-stringifying a parsed object loses key ordering, whitespace, and\n * Unicode-escape choices, so the signature check would silently fail for\n * legitimate requests (M2 in the webhook security audit).\n *\n * h3 v2's body stream is consume-once, so we cache the raw string on the\n * event context after the first read. All call sites (handleVerification,\n * verifyWebhook, parseIncomingMessage) MUST go through this helper.\n */\nasync function readRawBodyCached(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n // h3's readRawBody returns the bytes Slack actually sent, defaulting to\n // utf8-decoded. Returns undefined for empty bodies — we coerce to \"\" so\n // the HMAC check can proceed deterministically.\n const raw = (await readRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n\n/** Split a message into chunks that fit within the platform's limit */\nfunction splitMessage(text: string, maxLength: number): string[] {\n if (text.length <= maxLength) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n // Try to split at a newline\n let splitIdx = remaining.lastIndexOf(\"\\n\", maxLength);\n if (splitIdx <= 0) {\n // Try to split at a space\n splitIdx = remaining.lastIndexOf(\" \", maxLength);\n }\n if (splitIdx <= 0) {\n splitIdx = maxLength;\n }\n chunks.push(remaining.slice(0, splitIdx));\n remaining = remaining.slice(splitIdx).trimStart();\n }\n return chunks;\n}\n\n/** Hard cap on input length we feed to the regex-based mrkdwn converter.\n * L2 in the webhook audit: `\\*\\*(.+?)\\*\\*` with the `s` flag on a long\n * string of asterisks can exhibit super-linear backtracking. Slack\n * itself caps message bodies at 4000 chars (SLACK_MAX_LENGTH); we cap\n * the input here at 10x that as a defensive bound for any caller that\n * passes a longer rendering source through this helper before chunking. */\nconst MRKDWN_MAX_LENGTH = 40_000;\n\n/**\n * Convert standard markdown to Slack's mrkdwn dialect.\n * - `[text](url)` → `<url|text>`\n * - `**bold**` → `*bold*` (Slack uses single asterisks for bold)\n *\n * Inputs longer than MRKDWN_MAX_LENGTH are truncated before the regex\n * pass to bound worst-case backtracking on pathological input (L2 in the\n * webhook audit).\n */\nfunction markdownToSlackMrkdwn(text: string): string {\n const bounded =\n text.length > MRKDWN_MAX_LENGTH ? text.slice(0, MRKDWN_MAX_LENGTH) : text;\n return (\n bounded\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"<$2|$1>\")\n // Bounded character class instead of `.+?` with the `s` flag — caps\n // each bold span at 5000 chars so an attacker can't construct a\n // pathological \"**\" sequence that exhibits super-linear backtracking.\n // Newlines are allowed because `[^*]` excludes only the asterisk\n // itself, so multi-line bold spans still match.\n .replace(/\\*\\*([^*]{1,5000})\\*\\*/g, \"*$1*\")\n );\n}\n\n/**\n * Optionally set Slack's native AI-assistant status indicator (the small\n * \"is thinking…\" line under the message composer) for an app configured\n * with the `assistant:write` scope. Pure best-effort — fails silently for\n * apps that aren't set up as AI assistants.\n */\nfunction setSlackAssistantStatus(\n token: string,\n channelId: string,\n threadTs: string,\n status: string,\n): void {\n fetch(\"https://slack.com/api/assistant.threads.setStatus\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n channel_id: channelId,\n thread_ts: threadTs,\n status,\n }),\n }).catch(() => {});\n}\n\n/**\n * Block Kit payload for the final answer. We avoid auto-unfurl previews by\n * separating the deep-link out into a button instead of inlining it as a\n * `<url|text>` markdown link in the section body — that's what was producing\n * the giant \"Agent-Native Dispatch\" card in every thread reply.\n */\nfunction buildResponseBlocks(\n text: string,\n opts: { threadDeepLinkUrl?: string },\n): unknown[] {\n const blocks: any[] = [\n {\n type: \"section\",\n text: { type: \"mrkdwn\", text: text || \"_(no response)_\" },\n },\n ];\n if (opts.threadDeepLinkUrl) {\n blocks.push({\n type: \"actions\",\n elements: [\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Open thread\", emoji: true },\n url: opts.threadDeepLinkUrl,\n action_id: \"open_dispatch_thread\",\n },\n ],\n });\n }\n return blocks;\n}\n\n/**\n * Post a fresh message to a thread. Used as the placeholder-fallback path\n * (e.g. when chat.update fails) and for follow-up overflow chunks.\n */\nasync function postFresh(\n token: string,\n channelId: string,\n threadTs: string | undefined,\n body: Record<string, unknown>,\n): Promise<void> {\n const payload: Record<string, unknown> = {\n ...body,\n channel: channelId,\n };\n if (threadTs && !payload.thread_ts) payload.thread_ts = threadTs;\n const res = await fetch(\"https://slack.com/api/chat.postMessage\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n const data = (await res.json()) as { ok: boolean; error?: string };\n if (!data.ok) {\n console.error(\"[slack] chat.postMessage error:\", data.error);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/integrations/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,yBAAyB,EAE1B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/integrations/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AAiCpB,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAoH9D;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,CAAC,EAAE,yBAAyB,GAClC,cAAc,CAoiBhB;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,gBAA6B,CAAC"}
|
|
@@ -16,11 +16,22 @@ import { googleDocsAdapter } from "./adapters/google-docs.js";
|
|
|
16
16
|
import { emailAdapter } from "./adapters/email.js";
|
|
17
17
|
import { startGoogleDocsPoller, handlePushNotification, } from "./google-docs-poller.js";
|
|
18
18
|
import { startPendingTasksRetryJob } from "./pending-tasks-retry-job.js";
|
|
19
|
+
import { processA2AContinuationById, processDueA2AContinuations, } from "./a2a-continuation-processor.js";
|
|
19
20
|
import { resourceGetByPath, SHARED_OWNER } from "../resources/store.js";
|
|
20
21
|
import { getTaskQueueStats } from "./task-queue-stats.js";
|
|
21
22
|
import { getSession } from "../server/auth.js";
|
|
22
23
|
import { getOrgContext } from "../org/context.js";
|
|
23
24
|
import { withConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
25
|
+
let a2aContinuationRetryInterval = null;
|
|
26
|
+
function startA2AContinuationRetryJob(adapters) {
|
|
27
|
+
if (a2aContinuationRetryInterval)
|
|
28
|
+
return;
|
|
29
|
+
a2aContinuationRetryInterval = setInterval(() => {
|
|
30
|
+
processDueA2AContinuations({ adapters }).catch((err) => {
|
|
31
|
+
console.error("[integrations] A2A continuation retry job failed:", err);
|
|
32
|
+
});
|
|
33
|
+
}, 60_000);
|
|
34
|
+
}
|
|
24
35
|
// ─── Google Pub/Sub OIDC verifier (for Drive changes.watch push) ────────────
|
|
25
36
|
// Cache Google's public keys for OIDC verification. jose handles TTL +
|
|
26
37
|
// refresh internally — same pattern as templates/mail/.../gmail/push.post.ts.
|
|
@@ -314,6 +325,7 @@ export function createIntegrationsPlugin(options) {
|
|
|
314
325
|
actions,
|
|
315
326
|
model,
|
|
316
327
|
apiKey: getApiKey(),
|
|
328
|
+
engine: options?.engine,
|
|
317
329
|
ownerEmail: task.ownerEmail,
|
|
318
330
|
});
|
|
319
331
|
await markTaskCompleted(taskId);
|
|
@@ -332,6 +344,41 @@ export function createIntegrationsPlugin(options) {
|
|
|
332
344
|
return { error: "Internal task failed" };
|
|
333
345
|
}
|
|
334
346
|
}));
|
|
347
|
+
// ─── Process deferred A2A continuation ──────────────────────────
|
|
348
|
+
// POST /_agent-native/integrations/process-a2a-continuation
|
|
349
|
+
// Internal endpoint invoked when call-agent timed out inside an
|
|
350
|
+
// integration processor but the remote A2A task kept running.
|
|
351
|
+
h3.use(`${P}/process-a2a-continuation`, defineEventHandler(async (event) => {
|
|
352
|
+
if (getMethod(event) !== "POST") {
|
|
353
|
+
setResponseStatus(event, 405);
|
|
354
|
+
return { error: "Method not allowed" };
|
|
355
|
+
}
|
|
356
|
+
const body = (await readBody(event));
|
|
357
|
+
const continuationId = body?.continuationId;
|
|
358
|
+
if (!continuationId) {
|
|
359
|
+
setResponseStatus(event, 400);
|
|
360
|
+
return { error: "continuationId required" };
|
|
361
|
+
}
|
|
362
|
+
if (!process.env.A2A_SECRET) {
|
|
363
|
+
if (process.env.NODE_ENV === "production") {
|
|
364
|
+
setResponseStatus(event, 503);
|
|
365
|
+
return {
|
|
366
|
+
error: "A2A_SECRET not configured — internal token signing is required to process A2A continuations in production.",
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
const tok = extractBearerToken(getRequestHeader(event, "authorization"));
|
|
372
|
+
if (!tok || !verifyInternalToken(continuationId, tok)) {
|
|
373
|
+
setResponseStatus(event, 401);
|
|
374
|
+
return { error: "Invalid or expired internal token" };
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
await processA2AContinuationById(continuationId, {
|
|
378
|
+
adapters: adapterMap,
|
|
379
|
+
});
|
|
380
|
+
return { ok: true, continuationId };
|
|
381
|
+
}));
|
|
335
382
|
// ─── Per-platform catch-all ───────────────────────────────────
|
|
336
383
|
// Handles: webhook, status, enable, disable, setup for each platform
|
|
337
384
|
h3.use(`${P}`, defineEventHandler(async (event) => {
|
|
@@ -348,6 +395,9 @@ export function createIntegrationsPlugin(options) {
|
|
|
348
395
|
// Already handled by the dedicated /process-task route above
|
|
349
396
|
if (parts[0] === "process-task")
|
|
350
397
|
return;
|
|
398
|
+
// Already handled by the dedicated /process-a2a-continuation route above
|
|
399
|
+
if (parts[0] === "process-a2a-continuation")
|
|
400
|
+
return;
|
|
351
401
|
const platform = parts[0];
|
|
352
402
|
const action = parts[1]; // webhook, status, enable, disable, setup
|
|
353
403
|
if (!platform) {
|
|
@@ -469,6 +519,7 @@ export function createIntegrationsPlugin(options) {
|
|
|
469
519
|
actions,
|
|
470
520
|
model,
|
|
471
521
|
apiKey: getApiKey(),
|
|
522
|
+
engine: options?.engine,
|
|
472
523
|
ownerEmail: owner,
|
|
473
524
|
beforeProcess: options?.beforeProcess,
|
|
474
525
|
incoming,
|
|
@@ -537,6 +588,7 @@ export function createIntegrationsPlugin(options) {
|
|
|
537
588
|
startPendingTasksRetryJob({
|
|
538
589
|
webhookBaseUrl: process.env.WEBHOOK_BASE_URL,
|
|
539
590
|
});
|
|
591
|
+
startA2AContinuationRetryJob(adapterMap);
|
|
540
592
|
// ─── Start Google Docs poller/push ────────────────────────────
|
|
541
593
|
if (adapterMap.has("google-docs")) {
|
|
542
594
|
// Defer startup slightly so the server is fully ready
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/integrations/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineEventHandler, setResponseStatus, getMethod } from \"h3\";\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport type {\n PlatformAdapter,\n IntegrationsPluginOptions,\n IntegrationStatus,\n} from \"./types.js\";\nimport { handleWebhook, processIntegrationTask } from \"./webhook-handler.js\";\nimport { DEFAULT_MODEL } from \"../agent/default-model.js\";\nimport {\n claimPendingTask,\n getPendingTask,\n markTaskCompleted,\n markTaskFailed,\n} from \"./pending-tasks-store.js\";\nimport { extractBearerToken, verifyInternalToken } from \"./internal-token.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getRequestHeader } from \"h3\";\nimport { getIntegrationConfig, saveIntegrationConfig } from \"./config-store.js\";\nimport { slackAdapter } from \"./adapters/slack.js\";\nimport { telegramAdapter } from \"./adapters/telegram.js\";\nimport { whatsappAdapter } from \"./adapters/whatsapp.js\";\nimport { googleDocsAdapter } from \"./adapters/google-docs.js\";\nimport { emailAdapter } from \"./adapters/email.js\";\nimport {\n startGoogleDocsPoller,\n handlePushNotification,\n} from \"./google-docs-poller.js\";\nimport { startPendingTasksRetryJob } from \"./pending-tasks-retry-job.js\";\nimport { resourceGetByPath, SHARED_OWNER } from \"../resources/store.js\";\nimport { getTaskQueueStats } from \"./task-queue-stats.js\";\nimport { getSession } from \"../server/auth.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\n// ─── Google Pub/Sub OIDC verifier (for Drive changes.watch push) ────────────\n// Cache Google's public keys for OIDC verification. jose handles TTL +\n// refresh internally — same pattern as templates/mail/.../gmail/push.post.ts.\n// Used to verify Google Pub/Sub push notifications carry a valid bearer token\n// signed by a configured service account. Without this, the webhook is wide\n// open to anonymous callers who can force a Drive sync (H7 in the audit).\nconst GOOGLE_JWKS = createRemoteJWKSet(\n new URL(\"https://www.googleapis.com/oauth2/v3/certs\"),\n);\nconst GOOGLE_ISSUERS = [\"https://accounts.google.com\", \"accounts.google.com\"];\n\n/**\n * Verify a Pub/Sub OIDC bearer token. Throws on any verification failure.\n * Requires GOOGLE_DOCS_PUSH_AUDIENCE and GOOGLE_DOCS_PUSH_SIGNER_EMAIL to be\n * set; if either is missing in production, the webhook handler refuses the\n * request entirely (so a misconfigured deployment fails closed, surfacing in\n * Pub/Sub's delivery metrics).\n */\nasync function verifyGoogleDocsPushToken(authHeader: string): Promise<void> {\n if (!authHeader.startsWith(\"Bearer \")) {\n throw new Error(\"missing bearer token\");\n }\n const token = authHeader.slice(7);\n const audience = process.env.GOOGLE_DOCS_PUSH_AUDIENCE;\n if (!audience) {\n throw new Error(\"GOOGLE_DOCS_PUSH_AUDIENCE not configured\");\n }\n const { payload } = await jwtVerify(token, GOOGLE_JWKS, {\n issuer: GOOGLE_ISSUERS,\n audience,\n });\n if (payload.email_verified !== true) {\n throw new Error(\"email_verified claim is not true\");\n }\n // Pin to a specific service account — without this, any Google-issued\n // token with the right audience could trigger a Drive sync.\n const expectedSigner = process.env.GOOGLE_DOCS_PUSH_SIGNER_EMAIL;\n if (!expectedSigner) {\n throw new Error(\"GOOGLE_DOCS_PUSH_SIGNER_EMAIL not configured\");\n }\n if (payload.email !== expectedSigner) {\n throw new Error(`unexpected signer: ${String(payload.email)}`);\n }\n}\n\n/** Built-in adapters, instantiated lazily */\nfunction getDefaultAdapters(): PlatformAdapter[] {\n return [\n slackAdapter(),\n telegramAdapter(),\n whatsappAdapter(),\n googleDocsAdapter(),\n emailAdapter(),\n ];\n}\n\n/**\n * Load resources for the integration agent's system prompt.\n * Mirrors the pattern from agent-chat-plugin.ts.\n */\nasync function loadResourcesForPrompt(owner: string): Promise<string> {\n const resourceNames = [\"AGENTS.md\", \"LEARNINGS.md\"];\n const sections: string[] = [];\n\n for (const name of resourceNames) {\n try {\n const shared = await resourceGetByPath(SHARED_OWNER, name);\n if (shared?.content?.trim()) {\n sections.push(\n `<resource name=\"${name}\" scope=\"shared\">\\n${shared.content.trim()}\\n</resource>`,\n );\n }\n } catch {}\n\n if (owner !== SHARED_OWNER) {\n try {\n const personal = await resourceGetByPath(owner, name);\n if (personal?.content?.trim()) {\n sections.push(\n `<resource name=\"${name}\" scope=\"personal\">\\n${personal.content.trim()}\\n</resource>`,\n );\n }\n } catch {}\n }\n }\n\n if (sections.length === 0) return \"\";\n return (\n \"\\n\\nThe following resources contain template-specific instructions and user context.\\n\\n\" +\n sections.join(\"\\n\\n\")\n );\n}\n\nconst INTEGRATION_SYSTEM_PROMPT = `You are an AI agent responding via a messaging platform integration (Slack, Telegram, WhatsApp, etc.).\n\nYou have the same capabilities as the web chat agent. Use your tools to help the user.\n\nKeep responses concise — messaging platforms have character limits and users expect shorter replies than in a web interface. Use markdown sparingly (bold and lists are fine, but avoid complex formatting that may not render well on all platforms).\n\nIf a task requires many steps, summarize what you did rather than streaming every detail.`;\n\n/**\n * Creates a Nitro plugin that mounts messaging platform integration webhook routes.\n *\n * Routes:\n * POST /_agent-native/integrations/:platform/webhook — receive platform webhooks\n * GET /_agent-native/integrations/status — all integrations status\n * GET /_agent-native/integrations/:platform/status — single platform status\n * POST /_agent-native/integrations/:platform/enable — enable integration\n * POST /_agent-native/integrations/:platform/disable — disable integration\n * POST /_agent-native/integrations/:platform/setup — platform-specific setup\n */\nexport function createIntegrationsPlugin(\n options?: IntegrationsPluginOptions,\n): NitroPluginDef {\n return async (nitroApp: any) => {\n const adapters = options?.adapters ?? getDefaultAdapters();\n const adapterMap = new Map<string, PlatformAdapter>();\n for (const adapter of adapters) {\n adapterMap.set(adapter.platform, adapter);\n }\n\n const model = options?.model ?? DEFAULT_MODEL;\n // Read the API key at REQUEST time, not plugin-init time. On Netlify\n // Lambda the plugin module loads in a context where env vars from the\n // site's runtime config may not yet be populated, so capturing at\n // init can leave us with an empty string forever. The getter\n // re-resolves on every webhook so freshly-set secrets work without\n // a redeploy.\n const getApiKey = () =>\n options?.apiKey ?? process.env.ANTHROPIC_API_KEY ?? \"\";\n\n // Build the system prompt\n const baseSystemPrompt = options?.systemPrompt ?? INTEGRATION_SYSTEM_PROMPT;\n\n // Resolve actions — auto-include call-agent so the integration agent can\n // delegate to other A2A apps, matching the behavior of the agent-chat plugin.\n const localActions = options?.actions ?? {};\n let callAgentEntry: Record<string, unknown> = {};\n try {\n const mod = await import(\"../scripts/call-agent.js\");\n callAgentEntry = {\n \"call-agent\": {\n tool: mod.tool,\n run: (args: Record<string, string>, context: unknown) =>\n mod.run(args, context as any, options?.appId),\n },\n };\n } catch {\n // call-agent script not available — skip\n }\n const actions = {\n ...localActions,\n ...callAgentEntry,\n } as typeof localActions;\n\n const h3 = getH3App(nitroApp);\n const P = `${FRAMEWORK_ROUTE_PREFIX}/integrations`;\n\n async function requireSession(event: any): Promise<boolean> {\n const session = await getSession(event).catch(() => null);\n if (session?.email) return true;\n setResponseStatus(event, 401);\n return false;\n }\n\n /**\n * Gate destructive integration writes (enable/disable, setup,\n * setIntegrationConfig…) behind an org-owner/admin check.\n *\n * `integration_configs` is keyed `(platform, config_key)` with no\n * owner column in the PRIMARY KEY — so this row is effectively\n * deployment-wide. Any signed-in user toggling /enable or /disable\n * would otherwise affect every other user (a regular org member could\n * disable Slack/email org-wide, write a malicious allowlist for\n * inbound email, etc.). This check enforces that only owners and\n * admins of the user's active org may mutate integration config.\n *\n * Solo / no-org sessions (i.e. ctx.orgId == null) are allowed — that's\n * the local-dev / single-user case where there's no privilege gradient\n * to enforce. The deployment is single-tenant by definition there.\n *\n * Returns an `{ ok: true }` on pass, or `{ ok: false, error }` with the\n * status already set on the event. The error string lines up with the\n * status code (401 → \"unauthorized\"; 403 → admin-required message).\n */\n async function checkOrgAdmin(\n event: any,\n ): Promise<{ ok: true } | { ok: false; error: string }> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { ok: false, error: \"unauthorized\" };\n }\n const ctx = await getOrgContext(event).catch(() => null);\n // Solo (no org membership) — single-tenant flow, allow.\n if (!ctx?.orgId) return { ok: true };\n if (ctx.role === \"owner\" || ctx.role === \"admin\") return { ok: true };\n setResponseStatus(event, 403);\n return {\n ok: false,\n error:\n \"Only organization owners and admins can mutate integration config\",\n };\n }\n\n // ─── Status endpoint (all integrations) ───────────────────────\n h3.use(\n `${P}/status`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n const baseUrl = getBaseUrl(event);\n const statuses: IntegrationStatus[] = [];\n for (const adapter of adapters) {\n const status = await adapter.getStatus(baseUrl);\n const config = await getIntegrationConfig(adapter.platform);\n status.enabled = !!config?.configData?.enabled;\n status.webhookUrl = `${baseUrl}${P}/${adapter.platform}/webhook`;\n if (!status.requiredEnvKeys) {\n try {\n status.requiredEnvKeys = adapter.getRequiredEnvKeys();\n } catch {\n status.requiredEnvKeys = [];\n }\n }\n statuses.push(status);\n }\n return statuses;\n }),\n );\n\n // ─── Task queue status (observability) ───────────────────────\n // GET /_agent-native/integrations/task-queue/status\n // Returns counts + recent failures for the integration_pending_tasks\n // queue. Requires a normal session — this exposes operational data, not\n // platform secrets. If the queue table doesn't exist yet (no inbound\n // webhook has been processed), returns zeroed stats rather than 500.\n h3.use(\n `${P}/task-queue/status`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n try {\n return await getTaskQueueStats();\n } catch (err: any) {\n setResponseStatus(event, 500);\n return { error: err?.message ?? String(err) };\n }\n }),\n );\n\n // ─── Process pending task (cross-platform task queue) ────────\n // POST /_agent-native/integrations/process-task\n // Internal endpoint invoked via fire-and-forget self-webhook from the\n // public webhook handler. Auth: HMAC bearer signed with A2A_SECRET.\n // Each invocation runs the agent loop in a fresh function execution.\n h3.use(\n `${P}/process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: string };\n const taskId = body?.taskId;\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // Auth: HMAC token bound to the task id.\n //\n // In production we MUST require A2A_SECRET — a publicly-callable\n // process-task endpoint lets attackers re-trigger any queued task\n // by guessing or sniffing its id (C3 in the webhook security audit).\n // The atomic SQL claim only prevents *double*-processing, not the\n // first attacker-driven processing.\n //\n // In dev we keep the loose posture so contributors don't have to\n // configure A2A_SECRET to play with the integration locally.\n if (!process.env.A2A_SECRET) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A_SECRET not configured — internal token signing is required to process integration tasks in production.\",\n };\n }\n // Dev: fall through unsigned (the atomic claim still gates double-processing).\n } else {\n const tok = extractBearerToken(\n getRequestHeader(event, \"authorization\"),\n );\n if (!tok || !verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired internal token\" };\n }\n }\n\n // Atomic claim: only one invocation gets to process this task\n const task = await claimPendingTask(taskId);\n if (!task) {\n setResponseStatus(event, 200);\n return { ok: true, skipped: \"already-claimed-or-missing\" };\n }\n\n try {\n const adapter = adapterMap.get(task.platform);\n if (!adapter) {\n await markTaskFailed(taskId, `Unknown platform: ${task.platform}`);\n setResponseStatus(event, 404);\n return { error: \"Unknown platform\" };\n }\n const resources = await loadResourcesForPrompt(task.ownerEmail);\n await processIntegrationTask(task, {\n adapter,\n systemPrompt: baseSystemPrompt + resources,\n actions,\n model,\n apiKey: getApiKey(),\n ownerEmail: task.ownerEmail,\n });\n await markTaskCompleted(taskId);\n return { ok: true, taskId };\n } catch (err: any) {\n await markTaskFailed(\n taskId,\n err?.message\n ? String(err.message).slice(0, 1000)\n : \"processor failed\",\n );\n // Log the detail server-side; never return the raw error message\n // to the caller. Raw messages have leaked DB error codes, schema\n // names, and stack hints in the past (L3 in the webhook security\n // audit). Sentry / log providers still see the full error.\n console.error(\"[integrations] process-task failure:\", err);\n setResponseStatus(event, 500);\n return { error: \"Internal task failed\" };\n }\n }),\n );\n\n // ─── Per-platform catch-all ───────────────────────────────────\n // Handles: webhook, status, enable, disable, setup for each platform\n h3.use(\n `${P}`,\n defineEventHandler(async (event) => {\n const method = getMethod(event);\n // event.path is stripped to the remainder after the mount prefix\n const raw = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n const parts = raw.split(\"/\").filter(Boolean);\n\n // Already handled by the dedicated /status route above\n if (parts[0] === \"status\" && parts.length === 1) return;\n // Already handled by the dedicated /task-queue/status route above\n if (parts[0] === \"task-queue\") return;\n // Already handled by the dedicated /process-task route above\n if (parts[0] === \"process-task\") return;\n\n const platform = parts[0];\n const action = parts[1]; // webhook, status, enable, disable, setup\n\n if (!platform) {\n setResponseStatus(event, 404);\n return { error: \"Platform required\" };\n }\n\n const adapter = adapterMap.get(platform);\n if (!adapter) {\n setResponseStatus(event, 404);\n return { error: `Unknown platform: ${platform}` };\n }\n\n // Set params for handlers that read them\n if (event.context) {\n event.context.params = {\n ...event.context.params,\n platform,\n };\n }\n\n // ─── GET /:platform/status ─────────────────────────────\n if (action === \"status\" && method === \"GET\") {\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n const baseUrl = getBaseUrl(event);\n const status = await adapter.getStatus(baseUrl);\n const config = await getIntegrationConfig(platform);\n status.enabled = !!config?.configData?.enabled;\n status.webhookUrl = `${baseUrl}${P}/${platform}/webhook`;\n if (!status.requiredEnvKeys) {\n try {\n status.requiredEnvKeys = adapter.getRequiredEnvKeys();\n } catch {\n status.requiredEnvKeys = [];\n }\n }\n return status;\n }\n\n // ─── POST /:platform/webhook ───────────────────────────\n if (action === \"webhook\" && method === \"POST\") {\n // Google Docs push notifications bypass the normal webhook flow —\n // they're opaque \"something changed\" pings, not message payloads.\n // We MUST verify the Pub/Sub OIDC token here. Without it, anyone\n // could POST any body to this URL and force a Drive changes pull\n // (H7 in the webhook security audit).\n if (platform === \"google-docs\") {\n const audience = process.env.GOOGLE_DOCS_PUSH_AUDIENCE;\n if (!audience) {\n if (process.env.NODE_ENV === \"production\") {\n // Fail closed in prod so a misconfigured deployment surfaces\n // in Pub/Sub's delivery metrics rather than silently\n // accepting anonymous requests.\n setResponseStatus(event, 503);\n return {\n ok: false,\n error:\n \"google-docs push endpoint disabled (audience not configured)\",\n };\n }\n // Dev: keep the loose posture so contributors can play with the\n // integration locally without configuring Pub/Sub.\n handlePushNotification().catch((err) => {\n console.error(\"[google-docs] Push handler error:\", err);\n });\n return \"ok\";\n }\n const authHeader = getRequestHeader(event, \"authorization\") || \"\";\n try {\n await verifyGoogleDocsPushToken(authHeader);\n } catch (err: any) {\n console.warn(\n `[google-docs] OIDC verify failed: ${err?.message ?? String(err)}`,\n );\n setResponseStatus(event, 401);\n return { ok: false, error: \"unauthorized\" };\n }\n handlePushNotification().catch((err) => {\n console.error(\"[google-docs] Push handler error:\", err);\n });\n return \"ok\";\n }\n\n // Handle platform verification challenges (e.g. Slack url_verification)\n // before checking enable state or parsing the message.\n const verification = await adapter.handleVerification(event);\n if (verification.handled) {\n return verification.response ?? \"ok\";\n }\n\n const config = await getIntegrationConfig(platform);\n if (!config?.configData?.enabled) {\n setResponseStatus(event, 404);\n return { error: `Integration ${platform} is not enabled` };\n }\n\n // Verify the webhook signature BEFORE parsing. We pre-parse the\n // body here (so handleWebhook can skip its second readBody, which\n // hangs on streaming providers), and that means handleWebhook's\n // own verifyWebhook step is bypassed. Without this call anyone\n // could POST a forged Slack/Telegram/email payload.\n const isValid = await adapter.verifyWebhook(event);\n if (!isValid) {\n setResponseStatus(event, 401);\n return { error: \"Invalid webhook signature\" };\n }\n\n const incoming = await adapter.parseIncomingMessage(event);\n if (!incoming) {\n setResponseStatus(event, 200);\n return \"ok\";\n }\n let owner = `integration@${platform}`;\n if (options?.resolveOwner) {\n try {\n owner = await options.resolveOwner(incoming);\n } catch (err) {\n console.error(\n `[integrations] resolveOwner failed, using default:`,\n err,\n );\n }\n }\n const resources = await loadResourcesForPrompt(owner);\n const systemPrompt = baseSystemPrompt + resources;\n const result = await handleWebhook(event, {\n adapter,\n systemPrompt,\n actions,\n model,\n apiKey: getApiKey(),\n ownerEmail: owner,\n beforeProcess: options?.beforeProcess,\n incoming,\n });\n setResponseStatus(event, result.status);\n return result.body;\n }\n\n // ─── POST /:platform/enable ────────────────────────────\n if (action === \"enable\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n // Stamp the org-admin who toggled this so downstream code can\n // tell who is responsible — useful for audit logs even though\n // the row itself remains deployment-wide.\n const session = await getSession(event).catch(() => null);\n await saveIntegrationConfig(\n platform,\n { enabled: true },\n \"default\",\n session?.email,\n );\n return { ok: true, platform, enabled: true };\n }\n\n // ─── POST /:platform/disable ───────────────────────────\n if (action === \"disable\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n const session = await getSession(event).catch(() => null);\n await saveIntegrationConfig(\n platform,\n { enabled: false },\n \"default\",\n session?.email,\n );\n return { ok: true, platform, enabled: false };\n }\n\n // ─── POST /:platform/setup ─────────────────────────────\n if (action === \"setup\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n if (platform === \"telegram\") {\n const baseUrl = getBaseUrl(event);\n const webhookUrl = `${baseUrl}${P}/telegram/webhook`;\n const token = process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n setResponseStatus(event, 400);\n return { error: \"TELEGRAM_BOT_TOKEN not configured\" };\n }\n try {\n const res = await fetch(\n `https://api.telegram.org/bot${token}/setWebhook`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: webhookUrl }),\n },\n );\n const data = await res.json();\n return { ok: true, platform, webhookUrl, result: data };\n } catch (err: any) {\n setResponseStatus(event, 500);\n return { error: err.message };\n }\n }\n return { ok: true, platform, message: \"No setup required\" };\n }\n\n setResponseStatus(event, 404);\n return { error: \"Not found\" };\n }),\n );\n\n // ─── Start pending-tasks retry sweeper ────────────────────────\n // Sweeps the integration_pending_tasks queue every 60s and re-fires the\n // processor for any tasks that got stuck (initial dispatch lost or\n // processor killed mid-flight). No-ops gracefully if the queue table\n // hasn't been created yet on this deployment.\n startPendingTasksRetryJob({\n webhookBaseUrl: process.env.WEBHOOK_BASE_URL,\n });\n\n // ─── Start Google Docs poller/push ────────────────────────────\n if (adapterMap.has(\"google-docs\")) {\n // Defer startup slightly so the server is fully ready\n setTimeout(() => {\n // We don't know the base URL at plugin init time — it depends on\n // the incoming request. For push mode, the webhook URL needs to be\n // resolved. We pass it as a special option; the poller will attempt\n // to register a watch when the first request reveals the base URL,\n // or use the WEBHOOK_BASE_URL env var if set.\n const baseUrl = process.env.WEBHOOK_BASE_URL;\n const webhookUrl = baseUrl\n ? `${withConfiguredAppBasePath(baseUrl)}${P}/google-docs/webhook`\n : undefined;\n\n startGoogleDocsPoller({\n systemPrompt: baseSystemPrompt,\n actions,\n model,\n apiKey: getApiKey(),\n ownerEmail: \"integration@google-docs\",\n webhookUrl,\n });\n }, 2000);\n }\n\n if (process.env.DEBUG)\n console.log(\n `[integrations] Mounted integration routes for: ${adapters.map((a) => a.platform).join(\", \")}`,\n );\n };\n}\n\n/**\n * Default integrations plugin — auto-mounts all adapters.\n */\nexport const defaultIntegrationsPlugin = createIntegrationsPlugin();\n\n/** Extract base URL from the request */\nfunction getBaseUrl(event: any): string {\n try {\n const headers = event.node?.req?.headers || event.headers || {};\n const getHeader = (name: string) =>\n typeof headers.get === \"function\"\n ? headers.get(name)\n : (headers as Record<string, string>)[name];\n const proto = getHeader(\"x-forwarded-proto\") || \"http\";\n const host = getHeader(\"host\") || \"localhost:3000\";\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\"http://localhost:3000\");\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/integrations/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineEventHandler, setResponseStatus, getMethod } from \"h3\";\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport type {\n PlatformAdapter,\n IntegrationsPluginOptions,\n IntegrationStatus,\n} from \"./types.js\";\nimport { handleWebhook, processIntegrationTask } from \"./webhook-handler.js\";\nimport { DEFAULT_MODEL } from \"../agent/default-model.js\";\nimport {\n claimPendingTask,\n getPendingTask,\n markTaskCompleted,\n markTaskFailed,\n} from \"./pending-tasks-store.js\";\nimport { extractBearerToken, verifyInternalToken } from \"./internal-token.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getRequestHeader } from \"h3\";\nimport { getIntegrationConfig, saveIntegrationConfig } from \"./config-store.js\";\nimport { slackAdapter } from \"./adapters/slack.js\";\nimport { telegramAdapter } from \"./adapters/telegram.js\";\nimport { whatsappAdapter } from \"./adapters/whatsapp.js\";\nimport { googleDocsAdapter } from \"./adapters/google-docs.js\";\nimport { emailAdapter } from \"./adapters/email.js\";\nimport {\n startGoogleDocsPoller,\n handlePushNotification,\n} from \"./google-docs-poller.js\";\nimport { startPendingTasksRetryJob } from \"./pending-tasks-retry-job.js\";\nimport {\n processA2AContinuationById,\n processDueA2AContinuations,\n} from \"./a2a-continuation-processor.js\";\nimport { resourceGetByPath, SHARED_OWNER } from \"../resources/store.js\";\nimport { getTaskQueueStats } from \"./task-queue-stats.js\";\nimport { getSession } from \"../server/auth.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nlet a2aContinuationRetryInterval: ReturnType<typeof setInterval> | null = null;\n\nfunction startA2AContinuationRetryJob(\n adapters: Map<string, PlatformAdapter>,\n): void {\n if (a2aContinuationRetryInterval) return;\n a2aContinuationRetryInterval = setInterval(() => {\n processDueA2AContinuations({ adapters }).catch((err) => {\n console.error(\"[integrations] A2A continuation retry job failed:\", err);\n });\n }, 60_000);\n}\n\n// ─── Google Pub/Sub OIDC verifier (for Drive changes.watch push) ────────────\n// Cache Google's public keys for OIDC verification. jose handles TTL +\n// refresh internally — same pattern as templates/mail/.../gmail/push.post.ts.\n// Used to verify Google Pub/Sub push notifications carry a valid bearer token\n// signed by a configured service account. Without this, the webhook is wide\n// open to anonymous callers who can force a Drive sync (H7 in the audit).\nconst GOOGLE_JWKS = createRemoteJWKSet(\n new URL(\"https://www.googleapis.com/oauth2/v3/certs\"),\n);\nconst GOOGLE_ISSUERS = [\"https://accounts.google.com\", \"accounts.google.com\"];\n\n/**\n * Verify a Pub/Sub OIDC bearer token. Throws on any verification failure.\n * Requires GOOGLE_DOCS_PUSH_AUDIENCE and GOOGLE_DOCS_PUSH_SIGNER_EMAIL to be\n * set; if either is missing in production, the webhook handler refuses the\n * request entirely (so a misconfigured deployment fails closed, surfacing in\n * Pub/Sub's delivery metrics).\n */\nasync function verifyGoogleDocsPushToken(authHeader: string): Promise<void> {\n if (!authHeader.startsWith(\"Bearer \")) {\n throw new Error(\"missing bearer token\");\n }\n const token = authHeader.slice(7);\n const audience = process.env.GOOGLE_DOCS_PUSH_AUDIENCE;\n if (!audience) {\n throw new Error(\"GOOGLE_DOCS_PUSH_AUDIENCE not configured\");\n }\n const { payload } = await jwtVerify(token, GOOGLE_JWKS, {\n issuer: GOOGLE_ISSUERS,\n audience,\n });\n if (payload.email_verified !== true) {\n throw new Error(\"email_verified claim is not true\");\n }\n // Pin to a specific service account — without this, any Google-issued\n // token with the right audience could trigger a Drive sync.\n const expectedSigner = process.env.GOOGLE_DOCS_PUSH_SIGNER_EMAIL;\n if (!expectedSigner) {\n throw new Error(\"GOOGLE_DOCS_PUSH_SIGNER_EMAIL not configured\");\n }\n if (payload.email !== expectedSigner) {\n throw new Error(`unexpected signer: ${String(payload.email)}`);\n }\n}\n\n/** Built-in adapters, instantiated lazily */\nfunction getDefaultAdapters(): PlatformAdapter[] {\n return [\n slackAdapter(),\n telegramAdapter(),\n whatsappAdapter(),\n googleDocsAdapter(),\n emailAdapter(),\n ];\n}\n\n/**\n * Load resources for the integration agent's system prompt.\n * Mirrors the pattern from agent-chat-plugin.ts.\n */\nasync function loadResourcesForPrompt(owner: string): Promise<string> {\n const resourceNames = [\"AGENTS.md\", \"LEARNINGS.md\"];\n const sections: string[] = [];\n\n for (const name of resourceNames) {\n try {\n const shared = await resourceGetByPath(SHARED_OWNER, name);\n if (shared?.content?.trim()) {\n sections.push(\n `<resource name=\"${name}\" scope=\"shared\">\\n${shared.content.trim()}\\n</resource>`,\n );\n }\n } catch {}\n\n if (owner !== SHARED_OWNER) {\n try {\n const personal = await resourceGetByPath(owner, name);\n if (personal?.content?.trim()) {\n sections.push(\n `<resource name=\"${name}\" scope=\"personal\">\\n${personal.content.trim()}\\n</resource>`,\n );\n }\n } catch {}\n }\n }\n\n if (sections.length === 0) return \"\";\n return (\n \"\\n\\nThe following resources contain template-specific instructions and user context.\\n\\n\" +\n sections.join(\"\\n\\n\")\n );\n}\n\nconst INTEGRATION_SYSTEM_PROMPT = `You are an AI agent responding via a messaging platform integration (Slack, Telegram, WhatsApp, etc.).\n\nYou have the same capabilities as the web chat agent. Use your tools to help the user.\n\nKeep responses concise — messaging platforms have character limits and users expect shorter replies than in a web interface. Use markdown sparingly (bold and lists are fine, but avoid complex formatting that may not render well on all platforms).\n\nIf a task requires many steps, summarize what you did rather than streaming every detail.`;\n\n/**\n * Creates a Nitro plugin that mounts messaging platform integration webhook routes.\n *\n * Routes:\n * POST /_agent-native/integrations/:platform/webhook — receive platform webhooks\n * GET /_agent-native/integrations/status — all integrations status\n * GET /_agent-native/integrations/:platform/status — single platform status\n * POST /_agent-native/integrations/:platform/enable — enable integration\n * POST /_agent-native/integrations/:platform/disable — disable integration\n * POST /_agent-native/integrations/:platform/setup — platform-specific setup\n */\nexport function createIntegrationsPlugin(\n options?: IntegrationsPluginOptions,\n): NitroPluginDef {\n return async (nitroApp: any) => {\n const adapters = options?.adapters ?? getDefaultAdapters();\n const adapterMap = new Map<string, PlatformAdapter>();\n for (const adapter of adapters) {\n adapterMap.set(adapter.platform, adapter);\n }\n\n const model = options?.model ?? DEFAULT_MODEL;\n // Read the API key at REQUEST time, not plugin-init time. On Netlify\n // Lambda the plugin module loads in a context where env vars from the\n // site's runtime config may not yet be populated, so capturing at\n // init can leave us with an empty string forever. The getter\n // re-resolves on every webhook so freshly-set secrets work without\n // a redeploy.\n const getApiKey = () =>\n options?.apiKey ?? process.env.ANTHROPIC_API_KEY ?? \"\";\n\n // Build the system prompt\n const baseSystemPrompt = options?.systemPrompt ?? INTEGRATION_SYSTEM_PROMPT;\n\n // Resolve actions — auto-include call-agent so the integration agent can\n // delegate to other A2A apps, matching the behavior of the agent-chat plugin.\n const localActions = options?.actions ?? {};\n let callAgentEntry: Record<string, unknown> = {};\n try {\n const mod = await import(\"../scripts/call-agent.js\");\n callAgentEntry = {\n \"call-agent\": {\n tool: mod.tool,\n run: (args: Record<string, string>, context: unknown) =>\n mod.run(args, context as any, options?.appId),\n },\n };\n } catch {\n // call-agent script not available — skip\n }\n const actions = {\n ...localActions,\n ...callAgentEntry,\n } as typeof localActions;\n\n const h3 = getH3App(nitroApp);\n const P = `${FRAMEWORK_ROUTE_PREFIX}/integrations`;\n\n async function requireSession(event: any): Promise<boolean> {\n const session = await getSession(event).catch(() => null);\n if (session?.email) return true;\n setResponseStatus(event, 401);\n return false;\n }\n\n /**\n * Gate destructive integration writes (enable/disable, setup,\n * setIntegrationConfig…) behind an org-owner/admin check.\n *\n * `integration_configs` is keyed `(platform, config_key)` with no\n * owner column in the PRIMARY KEY — so this row is effectively\n * deployment-wide. Any signed-in user toggling /enable or /disable\n * would otherwise affect every other user (a regular org member could\n * disable Slack/email org-wide, write a malicious allowlist for\n * inbound email, etc.). This check enforces that only owners and\n * admins of the user's active org may mutate integration config.\n *\n * Solo / no-org sessions (i.e. ctx.orgId == null) are allowed — that's\n * the local-dev / single-user case where there's no privilege gradient\n * to enforce. The deployment is single-tenant by definition there.\n *\n * Returns an `{ ok: true }` on pass, or `{ ok: false, error }` with the\n * status already set on the event. The error string lines up with the\n * status code (401 → \"unauthorized\"; 403 → admin-required message).\n */\n async function checkOrgAdmin(\n event: any,\n ): Promise<{ ok: true } | { ok: false; error: string }> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { ok: false, error: \"unauthorized\" };\n }\n const ctx = await getOrgContext(event).catch(() => null);\n // Solo (no org membership) — single-tenant flow, allow.\n if (!ctx?.orgId) return { ok: true };\n if (ctx.role === \"owner\" || ctx.role === \"admin\") return { ok: true };\n setResponseStatus(event, 403);\n return {\n ok: false,\n error:\n \"Only organization owners and admins can mutate integration config\",\n };\n }\n\n // ─── Status endpoint (all integrations) ───────────────────────\n h3.use(\n `${P}/status`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n const baseUrl = getBaseUrl(event);\n const statuses: IntegrationStatus[] = [];\n for (const adapter of adapters) {\n const status = await adapter.getStatus(baseUrl);\n const config = await getIntegrationConfig(adapter.platform);\n status.enabled = !!config?.configData?.enabled;\n status.webhookUrl = `${baseUrl}${P}/${adapter.platform}/webhook`;\n if (!status.requiredEnvKeys) {\n try {\n status.requiredEnvKeys = adapter.getRequiredEnvKeys();\n } catch {\n status.requiredEnvKeys = [];\n }\n }\n statuses.push(status);\n }\n return statuses;\n }),\n );\n\n // ─── Task queue status (observability) ───────────────────────\n // GET /_agent-native/integrations/task-queue/status\n // Returns counts + recent failures for the integration_pending_tasks\n // queue. Requires a normal session — this exposes operational data, not\n // platform secrets. If the queue table doesn't exist yet (no inbound\n // webhook has been processed), returns zeroed stats rather than 500.\n h3.use(\n `${P}/task-queue/status`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n try {\n return await getTaskQueueStats();\n } catch (err: any) {\n setResponseStatus(event, 500);\n return { error: err?.message ?? String(err) };\n }\n }),\n );\n\n // ─── Process pending task (cross-platform task queue) ────────\n // POST /_agent-native/integrations/process-task\n // Internal endpoint invoked via fire-and-forget self-webhook from the\n // public webhook handler. Auth: HMAC bearer signed with A2A_SECRET.\n // Each invocation runs the agent loop in a fresh function execution.\n h3.use(\n `${P}/process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: string };\n const taskId = body?.taskId;\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // Auth: HMAC token bound to the task id.\n //\n // In production we MUST require A2A_SECRET — a publicly-callable\n // process-task endpoint lets attackers re-trigger any queued task\n // by guessing or sniffing its id (C3 in the webhook security audit).\n // The atomic SQL claim only prevents *double*-processing, not the\n // first attacker-driven processing.\n //\n // In dev we keep the loose posture so contributors don't have to\n // configure A2A_SECRET to play with the integration locally.\n if (!process.env.A2A_SECRET) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A_SECRET not configured — internal token signing is required to process integration tasks in production.\",\n };\n }\n // Dev: fall through unsigned (the atomic claim still gates double-processing).\n } else {\n const tok = extractBearerToken(\n getRequestHeader(event, \"authorization\"),\n );\n if (!tok || !verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired internal token\" };\n }\n }\n\n // Atomic claim: only one invocation gets to process this task\n const task = await claimPendingTask(taskId);\n if (!task) {\n setResponseStatus(event, 200);\n return { ok: true, skipped: \"already-claimed-or-missing\" };\n }\n\n try {\n const adapter = adapterMap.get(task.platform);\n if (!adapter) {\n await markTaskFailed(taskId, `Unknown platform: ${task.platform}`);\n setResponseStatus(event, 404);\n return { error: \"Unknown platform\" };\n }\n const resources = await loadResourcesForPrompt(task.ownerEmail);\n await processIntegrationTask(task, {\n adapter,\n systemPrompt: baseSystemPrompt + resources,\n actions,\n model,\n apiKey: getApiKey(),\n engine: options?.engine,\n ownerEmail: task.ownerEmail,\n });\n await markTaskCompleted(taskId);\n return { ok: true, taskId };\n } catch (err: any) {\n await markTaskFailed(\n taskId,\n err?.message\n ? String(err.message).slice(0, 1000)\n : \"processor failed\",\n );\n // Log the detail server-side; never return the raw error message\n // to the caller. Raw messages have leaked DB error codes, schema\n // names, and stack hints in the past (L3 in the webhook security\n // audit). Sentry / log providers still see the full error.\n console.error(\"[integrations] process-task failure:\", err);\n setResponseStatus(event, 500);\n return { error: \"Internal task failed\" };\n }\n }),\n );\n\n // ─── Process deferred A2A continuation ──────────────────────────\n // POST /_agent-native/integrations/process-a2a-continuation\n // Internal endpoint invoked when call-agent timed out inside an\n // integration processor but the remote A2A task kept running.\n h3.use(\n `${P}/process-a2a-continuation`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { continuationId?: string };\n const continuationId = body?.continuationId;\n if (!continuationId) {\n setResponseStatus(event, 400);\n return { error: \"continuationId required\" };\n }\n\n if (!process.env.A2A_SECRET) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A_SECRET not configured — internal token signing is required to process A2A continuations in production.\",\n };\n }\n } else {\n const tok = extractBearerToken(\n getRequestHeader(event, \"authorization\"),\n );\n if (!tok || !verifyInternalToken(continuationId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired internal token\" };\n }\n }\n\n await processA2AContinuationById(continuationId, {\n adapters: adapterMap,\n });\n return { ok: true, continuationId };\n }),\n );\n\n // ─── Per-platform catch-all ───────────────────────────────────\n // Handles: webhook, status, enable, disable, setup for each platform\n h3.use(\n `${P}`,\n defineEventHandler(async (event) => {\n const method = getMethod(event);\n // event.path is stripped to the remainder after the mount prefix\n const raw = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n const parts = raw.split(\"/\").filter(Boolean);\n\n // Already handled by the dedicated /status route above\n if (parts[0] === \"status\" && parts.length === 1) return;\n // Already handled by the dedicated /task-queue/status route above\n if (parts[0] === \"task-queue\") return;\n // Already handled by the dedicated /process-task route above\n if (parts[0] === \"process-task\") return;\n // Already handled by the dedicated /process-a2a-continuation route above\n if (parts[0] === \"process-a2a-continuation\") return;\n\n const platform = parts[0];\n const action = parts[1]; // webhook, status, enable, disable, setup\n\n if (!platform) {\n setResponseStatus(event, 404);\n return { error: \"Platform required\" };\n }\n\n const adapter = adapterMap.get(platform);\n if (!adapter) {\n setResponseStatus(event, 404);\n return { error: `Unknown platform: ${platform}` };\n }\n\n // Set params for handlers that read them\n if (event.context) {\n event.context.params = {\n ...event.context.params,\n platform,\n };\n }\n\n // ─── GET /:platform/status ─────────────────────────────\n if (action === \"status\" && method === \"GET\") {\n if (!(await requireSession(event))) return { error: \"unauthorized\" };\n const baseUrl = getBaseUrl(event);\n const status = await adapter.getStatus(baseUrl);\n const config = await getIntegrationConfig(platform);\n status.enabled = !!config?.configData?.enabled;\n status.webhookUrl = `${baseUrl}${P}/${platform}/webhook`;\n if (!status.requiredEnvKeys) {\n try {\n status.requiredEnvKeys = adapter.getRequiredEnvKeys();\n } catch {\n status.requiredEnvKeys = [];\n }\n }\n return status;\n }\n\n // ─── POST /:platform/webhook ───────────────────────────\n if (action === \"webhook\" && method === \"POST\") {\n // Google Docs push notifications bypass the normal webhook flow —\n // they're opaque \"something changed\" pings, not message payloads.\n // We MUST verify the Pub/Sub OIDC token here. Without it, anyone\n // could POST any body to this URL and force a Drive changes pull\n // (H7 in the webhook security audit).\n if (platform === \"google-docs\") {\n const audience = process.env.GOOGLE_DOCS_PUSH_AUDIENCE;\n if (!audience) {\n if (process.env.NODE_ENV === \"production\") {\n // Fail closed in prod so a misconfigured deployment surfaces\n // in Pub/Sub's delivery metrics rather than silently\n // accepting anonymous requests.\n setResponseStatus(event, 503);\n return {\n ok: false,\n error:\n \"google-docs push endpoint disabled (audience not configured)\",\n };\n }\n // Dev: keep the loose posture so contributors can play with the\n // integration locally without configuring Pub/Sub.\n handlePushNotification().catch((err) => {\n console.error(\"[google-docs] Push handler error:\", err);\n });\n return \"ok\";\n }\n const authHeader = getRequestHeader(event, \"authorization\") || \"\";\n try {\n await verifyGoogleDocsPushToken(authHeader);\n } catch (err: any) {\n console.warn(\n `[google-docs] OIDC verify failed: ${err?.message ?? String(err)}`,\n );\n setResponseStatus(event, 401);\n return { ok: false, error: \"unauthorized\" };\n }\n handlePushNotification().catch((err) => {\n console.error(\"[google-docs] Push handler error:\", err);\n });\n return \"ok\";\n }\n\n // Handle platform verification challenges (e.g. Slack url_verification)\n // before checking enable state or parsing the message.\n const verification = await adapter.handleVerification(event);\n if (verification.handled) {\n return verification.response ?? \"ok\";\n }\n\n const config = await getIntegrationConfig(platform);\n if (!config?.configData?.enabled) {\n setResponseStatus(event, 404);\n return { error: `Integration ${platform} is not enabled` };\n }\n\n // Verify the webhook signature BEFORE parsing. We pre-parse the\n // body here (so handleWebhook can skip its second readBody, which\n // hangs on streaming providers), and that means handleWebhook's\n // own verifyWebhook step is bypassed. Without this call anyone\n // could POST a forged Slack/Telegram/email payload.\n const isValid = await adapter.verifyWebhook(event);\n if (!isValid) {\n setResponseStatus(event, 401);\n return { error: \"Invalid webhook signature\" };\n }\n\n const incoming = await adapter.parseIncomingMessage(event);\n if (!incoming) {\n setResponseStatus(event, 200);\n return \"ok\";\n }\n let owner = `integration@${platform}`;\n if (options?.resolveOwner) {\n try {\n owner = await options.resolveOwner(incoming);\n } catch (err) {\n console.error(\n `[integrations] resolveOwner failed, using default:`,\n err,\n );\n }\n }\n const resources = await loadResourcesForPrompt(owner);\n const systemPrompt = baseSystemPrompt + resources;\n const result = await handleWebhook(event, {\n adapter,\n systemPrompt,\n actions,\n model,\n apiKey: getApiKey(),\n engine: options?.engine,\n ownerEmail: owner,\n beforeProcess: options?.beforeProcess,\n incoming,\n });\n setResponseStatus(event, result.status);\n return result.body;\n }\n\n // ─── POST /:platform/enable ────────────────────────────\n if (action === \"enable\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n // Stamp the org-admin who toggled this so downstream code can\n // tell who is responsible — useful for audit logs even though\n // the row itself remains deployment-wide.\n const session = await getSession(event).catch(() => null);\n await saveIntegrationConfig(\n platform,\n { enabled: true },\n \"default\",\n session?.email,\n );\n return { ok: true, platform, enabled: true };\n }\n\n // ─── POST /:platform/disable ───────────────────────────\n if (action === \"disable\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n const session = await getSession(event).catch(() => null);\n await saveIntegrationConfig(\n platform,\n { enabled: false },\n \"default\",\n session?.email,\n );\n return { ok: true, platform, enabled: false };\n }\n\n // ─── POST /:platform/setup ─────────────────────────────\n if (action === \"setup\" && method === \"POST\") {\n const adminCheck = await checkOrgAdmin(event);\n if (adminCheck.ok === false) return { error: adminCheck.error };\n if (platform === \"telegram\") {\n const baseUrl = getBaseUrl(event);\n const webhookUrl = `${baseUrl}${P}/telegram/webhook`;\n const token = process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n setResponseStatus(event, 400);\n return { error: \"TELEGRAM_BOT_TOKEN not configured\" };\n }\n try {\n const res = await fetch(\n `https://api.telegram.org/bot${token}/setWebhook`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: webhookUrl }),\n },\n );\n const data = await res.json();\n return { ok: true, platform, webhookUrl, result: data };\n } catch (err: any) {\n setResponseStatus(event, 500);\n return { error: err.message };\n }\n }\n return { ok: true, platform, message: \"No setup required\" };\n }\n\n setResponseStatus(event, 404);\n return { error: \"Not found\" };\n }),\n );\n\n // ─── Start pending-tasks retry sweeper ────────────────────────\n // Sweeps the integration_pending_tasks queue every 60s and re-fires the\n // processor for any tasks that got stuck (initial dispatch lost or\n // processor killed mid-flight). No-ops gracefully if the queue table\n // hasn't been created yet on this deployment.\n startPendingTasksRetryJob({\n webhookBaseUrl: process.env.WEBHOOK_BASE_URL,\n });\n startA2AContinuationRetryJob(adapterMap);\n\n // ─── Start Google Docs poller/push ────────────────────────────\n if (adapterMap.has(\"google-docs\")) {\n // Defer startup slightly so the server is fully ready\n setTimeout(() => {\n // We don't know the base URL at plugin init time — it depends on\n // the incoming request. For push mode, the webhook URL needs to be\n // resolved. We pass it as a special option; the poller will attempt\n // to register a watch when the first request reveals the base URL,\n // or use the WEBHOOK_BASE_URL env var if set.\n const baseUrl = process.env.WEBHOOK_BASE_URL;\n const webhookUrl = baseUrl\n ? `${withConfiguredAppBasePath(baseUrl)}${P}/google-docs/webhook`\n : undefined;\n\n startGoogleDocsPoller({\n systemPrompt: baseSystemPrompt,\n actions,\n model,\n apiKey: getApiKey(),\n ownerEmail: \"integration@google-docs\",\n webhookUrl,\n });\n }, 2000);\n }\n\n if (process.env.DEBUG)\n console.log(\n `[integrations] Mounted integration routes for: ${adapters.map((a) => a.platform).join(\", \")}`,\n );\n };\n}\n\n/**\n * Default integrations plugin — auto-mounts all adapters.\n */\nexport const defaultIntegrationsPlugin = createIntegrationsPlugin();\n\n/** Extract base URL from the request */\nfunction getBaseUrl(event: any): string {\n try {\n const headers = event.node?.req?.headers || event.headers || {};\n const getHeader = (name: string) =>\n typeof headers.get === \"function\"\n ? headers.get(name)\n : (headers as Record<string, string>)[name];\n const proto = getHeader(\"x-forwarded-proto\") || \"http\";\n const host = getHeader(\"host\") || \"localhost:3000\";\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\"http://localhost:3000\");\n }\n}\n"]}
|
|
@@ -160,6 +160,11 @@ export interface IntegrationsPluginOptions {
|
|
|
160
160
|
model?: string;
|
|
161
161
|
/** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */
|
|
162
162
|
apiKey?: string;
|
|
163
|
+
/** Agent engine to use. Defaults to the same engine resolver as web chat. */
|
|
164
|
+
engine?: import("../agent/engine/types.js").AgentEngine | string | {
|
|
165
|
+
name: string;
|
|
166
|
+
config: Record<string, unknown>;
|
|
167
|
+
};
|
|
163
168
|
/**
|
|
164
169
|
* Resolve which owner should receive personal resource context and own the
|
|
165
170
|
* created chat thread for an incoming platform message.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { EnvKeyConfig } from \"../server/create-server.js\";\n\n/**\n * Normalized incoming message from any messaging platform.\n */\nexport interface IncomingMessage {\n /** Platform identifier (e.g., \"slack\", \"telegram\", \"whatsapp\") */\n platform: string;\n /** Platform-specific thread/conversation identifier */\n externalThreadId: string;\n /** Message text content */\n text: string;\n /** Display name of the sender */\n senderName?: string;\n /** Verified sender email, when the platform can provide one */\n senderEmail?: string;\n /** Platform-specific sender ID */\n senderId?: string;\n /** Raw platform-specific context needed for routing responses */\n platformContext: Record<string, unknown>;\n /** Message timestamp (epoch ms) */\n timestamp: number;\n}\n\n/**\n * Outgoing message to send back to a messaging platform.\n */\nexport interface OutgoingMessage {\n /** Text content of the response */\n text: string;\n /** Platform-specific payload (e.g., Slack blocks, Telegram parse_mode) */\n platformContext: Record<string, unknown>;\n}\n\n/**\n * Proactive outbound message target for a platform.\n * Used when the agent needs to send to a saved destination instead of replying\n * to the current inbound thread.\n */\nexport interface OutboundTarget {\n /** Canonical platform-specific destination id (channel, chat, thread, etc.) */\n destination: string;\n /** Optional thread reference when the destination supports threading */\n threadRef?: string | null;\n /** Optional fallback display label */\n label?: string;\n}\n\n/**\n * Connection status for a platform integration.\n */\nexport interface IntegrationStatus {\n platform: string;\n /** Human-readable label (e.g., \"Slack\", \"Telegram\") */\n label: string;\n /** Whether the integration is explicitly enabled */\n enabled: boolean;\n /** Whether all required credentials are configured */\n configured: boolean;\n /** Platform-specific details (workspace name, bot username, etc.) */\n details?: Record<string, unknown>;\n /** Error message if something is wrong */\n error?: string;\n /** The webhook URL that should be configured in the platform */\n webhookUrl?: string;\n /** The full list of env keys (required + optional) the adapter recognizes,\n * including UI hints. Surfaced on the integrations status endpoint so the\n * frontend can render fields without hard-coding them per platform. */\n requiredEnvKeys?: import(\"../server/create-server.js\").EnvKeyConfig[];\n}\n\n/**\n * Platform adapter interface — implement this for each messaging platform.\n *\n * Each adapter handles the platform-specific concerns:\n * - Webhook verification (HMAC signatures, challenge responses)\n * - Message parsing (platform events → normalized IncomingMessage)\n * - Response formatting (agent text → platform-specific format)\n * - Response delivery (POST back to platform API)\n */\nexport interface PlatformAdapter {\n /** Unique platform identifier */\n readonly platform: string;\n /** Human-readable label */\n readonly label: string;\n\n /** Env keys this adapter needs (tokens, secrets, etc.) */\n getRequiredEnvKeys(): EnvKeyConfig[];\n\n /**\n * Handle platform-specific verification challenges.\n * For example, Slack sends a `url_verification` event when setting up.\n * Return `{ handled: true, response }` to short-circuit the webhook handler.\n */\n handleVerification(event: H3Event): Promise<{\n handled: boolean;\n response?: unknown;\n }>;\n\n /**\n * Validate the webhook request signature.\n * Returns true if the request is authentic.\n */\n verifyWebhook(event: H3Event): Promise<boolean>;\n\n /**\n * Parse the webhook payload into a normalized IncomingMessage.\n * Return null to silently ignore the event (bot messages, edits, etc.).\n */\n parseIncomingMessage(event: H3Event): Promise<IncomingMessage | null>;\n\n /**\n * Send the agent's response back to the messaging platform.\n *\n * If `opts.placeholderRef` is provided (returned earlier by\n * `postProcessingPlaceholder`), adapters that support in-place edits should\n * update that placeholder message rather than posting a new one. Adapters\n * without an \"update message\" API can ignore the ref and post fresh.\n */\n sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void>;\n\n /**\n * Optionally post a \"working on it…\" placeholder message immediately when a\n * webhook arrives, before the agent loop runs. Adapters that support\n * in-place message edits (Slack via `chat.update`, etc.) return an opaque\n * `placeholderRef` that the webhook flow threads through to `sendResponse`\n * so the same message is updated with the final answer once ready.\n *\n * Adapters without edit support should leave this undefined; the webhook\n * handler will skip the placeholder step entirely.\n */\n postProcessingPlaceholder?(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null>;\n\n /**\n * Send a proactive outbound message to a platform destination. Adapters that\n * only support direct replies can omit this.\n */\n sendMessageToTarget?(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void>;\n\n /**\n * Format plain agent response text into a platform-appropriate message.\n * Handles markdown conversion, message splitting for length limits, etc.\n *\n * `opts.threadDeepLinkUrl`, when present, is a URL back to the originating\n * thread in the dispatch UI. Adapters that support rich blocks should\n * render this as a button (Slack); adapters that don't may inline it as a\n * link or simply omit it.\n */\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage;\n\n /** Return current connection/configuration status for the settings UI. */\n getStatus(baseUrl?: string): Promise<IntegrationStatus>;\n}\n\n/**\n * Options for the integrations plugin.\n */\nexport interface IntegrationsPluginOptions {\n /** App identifier used by call-agent to prevent self-calls (e.g. \"dispatch\"). */\n appId?: string;\n /** Platform adapters to enable. Default: all built-in adapters with configured env keys. */\n adapters?: PlatformAdapter[];\n /** System prompt for the agent (same as agent-chat). Inherited from agent-chat plugin if not set. */\n systemPrompt?: string;\n /** Actions registry (same as agent-chat). */\n actions?: Record<string, import(\"../agent/production-agent.js\").ActionEntry>;\n /** Model to use. Default: claude-sonnet-4-6 */\n model?: string;\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */\n apiKey?: string;\n /**\n * Resolve which owner should receive personal resource context and own the\n * created chat thread for an incoming platform message.\n */\n resolveOwner?: (incoming: IncomingMessage) => string | Promise<string>;\n /**\n * Optional preprocessor for inbound platform messages. Can intercept special\n * commands (such as `/link`) before the agent loop runs.\n */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { EnvKeyConfig } from \"../server/create-server.js\";\n\n/**\n * Normalized incoming message from any messaging platform.\n */\nexport interface IncomingMessage {\n /** Platform identifier (e.g., \"slack\", \"telegram\", \"whatsapp\") */\n platform: string;\n /** Platform-specific thread/conversation identifier */\n externalThreadId: string;\n /** Message text content */\n text: string;\n /** Display name of the sender */\n senderName?: string;\n /** Verified sender email, when the platform can provide one */\n senderEmail?: string;\n /** Platform-specific sender ID */\n senderId?: string;\n /** Raw platform-specific context needed for routing responses */\n platformContext: Record<string, unknown>;\n /** Message timestamp (epoch ms) */\n timestamp: number;\n}\n\n/**\n * Outgoing message to send back to a messaging platform.\n */\nexport interface OutgoingMessage {\n /** Text content of the response */\n text: string;\n /** Platform-specific payload (e.g., Slack blocks, Telegram parse_mode) */\n platformContext: Record<string, unknown>;\n}\n\n/**\n * Proactive outbound message target for a platform.\n * Used when the agent needs to send to a saved destination instead of replying\n * to the current inbound thread.\n */\nexport interface OutboundTarget {\n /** Canonical platform-specific destination id (channel, chat, thread, etc.) */\n destination: string;\n /** Optional thread reference when the destination supports threading */\n threadRef?: string | null;\n /** Optional fallback display label */\n label?: string;\n}\n\n/**\n * Connection status for a platform integration.\n */\nexport interface IntegrationStatus {\n platform: string;\n /** Human-readable label (e.g., \"Slack\", \"Telegram\") */\n label: string;\n /** Whether the integration is explicitly enabled */\n enabled: boolean;\n /** Whether all required credentials are configured */\n configured: boolean;\n /** Platform-specific details (workspace name, bot username, etc.) */\n details?: Record<string, unknown>;\n /** Error message if something is wrong */\n error?: string;\n /** The webhook URL that should be configured in the platform */\n webhookUrl?: string;\n /** The full list of env keys (required + optional) the adapter recognizes,\n * including UI hints. Surfaced on the integrations status endpoint so the\n * frontend can render fields without hard-coding them per platform. */\n requiredEnvKeys?: import(\"../server/create-server.js\").EnvKeyConfig[];\n}\n\n/**\n * Platform adapter interface — implement this for each messaging platform.\n *\n * Each adapter handles the platform-specific concerns:\n * - Webhook verification (HMAC signatures, challenge responses)\n * - Message parsing (platform events → normalized IncomingMessage)\n * - Response formatting (agent text → platform-specific format)\n * - Response delivery (POST back to platform API)\n */\nexport interface PlatformAdapter {\n /** Unique platform identifier */\n readonly platform: string;\n /** Human-readable label */\n readonly label: string;\n\n /** Env keys this adapter needs (tokens, secrets, etc.) */\n getRequiredEnvKeys(): EnvKeyConfig[];\n\n /**\n * Handle platform-specific verification challenges.\n * For example, Slack sends a `url_verification` event when setting up.\n * Return `{ handled: true, response }` to short-circuit the webhook handler.\n */\n handleVerification(event: H3Event): Promise<{\n handled: boolean;\n response?: unknown;\n }>;\n\n /**\n * Validate the webhook request signature.\n * Returns true if the request is authentic.\n */\n verifyWebhook(event: H3Event): Promise<boolean>;\n\n /**\n * Parse the webhook payload into a normalized IncomingMessage.\n * Return null to silently ignore the event (bot messages, edits, etc.).\n */\n parseIncomingMessage(event: H3Event): Promise<IncomingMessage | null>;\n\n /**\n * Send the agent's response back to the messaging platform.\n *\n * If `opts.placeholderRef` is provided (returned earlier by\n * `postProcessingPlaceholder`), adapters that support in-place edits should\n * update that placeholder message rather than posting a new one. Adapters\n * without an \"update message\" API can ignore the ref and post fresh.\n */\n sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void>;\n\n /**\n * Optionally post a \"working on it…\" placeholder message immediately when a\n * webhook arrives, before the agent loop runs. Adapters that support\n * in-place message edits (Slack via `chat.update`, etc.) return an opaque\n * `placeholderRef` that the webhook flow threads through to `sendResponse`\n * so the same message is updated with the final answer once ready.\n *\n * Adapters without edit support should leave this undefined; the webhook\n * handler will skip the placeholder step entirely.\n */\n postProcessingPlaceholder?(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null>;\n\n /**\n * Send a proactive outbound message to a platform destination. Adapters that\n * only support direct replies can omit this.\n */\n sendMessageToTarget?(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void>;\n\n /**\n * Format plain agent response text into a platform-appropriate message.\n * Handles markdown conversion, message splitting for length limits, etc.\n *\n * `opts.threadDeepLinkUrl`, when present, is a URL back to the originating\n * thread in the dispatch UI. Adapters that support rich blocks should\n * render this as a button (Slack); adapters that don't may inline it as a\n * link or simply omit it.\n */\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage;\n\n /** Return current connection/configuration status for the settings UI. */\n getStatus(baseUrl?: string): Promise<IntegrationStatus>;\n}\n\n/**\n * Options for the integrations plugin.\n */\nexport interface IntegrationsPluginOptions {\n /** App identifier used by call-agent to prevent self-calls (e.g. \"dispatch\"). */\n appId?: string;\n /** Platform adapters to enable. Default: all built-in adapters with configured env keys. */\n adapters?: PlatformAdapter[];\n /** System prompt for the agent (same as agent-chat). Inherited from agent-chat plugin if not set. */\n systemPrompt?: string;\n /** Actions registry (same as agent-chat). */\n actions?: Record<string, import(\"../agent/production-agent.js\").ActionEntry>;\n /** Model to use. Default: claude-sonnet-4-6 */\n model?: string;\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */\n apiKey?: string;\n /** Agent engine to use. Defaults to the same engine resolver as web chat. */\n engine?:\n | import(\"../agent/engine/types.js\").AgentEngine\n | string\n | {\n name: string;\n config: Record<string, unknown>;\n };\n /**\n * Resolve which owner should receive personal resource context and own the\n * created chat thread for an incoming platform message.\n */\n resolveOwner?: (incoming: IncomingMessage) => string | Promise<string>;\n /**\n * Optional preprocessor for inbound platform messages. Can intercept special\n * commands (such as `/link`) before the agent loop runs.\n */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n"]}
|