@agent-native/core 0.7.48 → 0.7.50
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/dist/a2a/client.d.ts +6 -2
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +9 -4
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/response-text.d.ts +6 -0
- package/dist/a2a/response-text.d.ts.map +1 -0
- package/dist/a2a/response-text.js +30 -0
- package/dist/a2a/response-text.js.map +1 -0
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +28 -15
- package/dist/a2a/server.js.map +1 -1
- package/dist/deploy/workspace-deploy.d.ts.map +1 -1
- package/dist/deploy/workspace-deploy.js +26 -0
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/integrations/a2a-continuation-marker.d.ts +2 -0
- package/dist/integrations/a2a-continuation-marker.d.ts.map +1 -0
- package/dist/integrations/a2a-continuation-marker.js +2 -0
- package/dist/integrations/a2a-continuation-marker.js.map +1 -0
- package/dist/integrations/a2a-continuation-processor.js +22 -2
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +32 -41
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +11 -6
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +8 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +17 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +2 -22
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/create-server.d.ts.map +1 -1
- package/dist/server/create-server.js +1 -13
- package/dist/server/create-server.js.map +1 -1
- package/dist/server/env-var-writes.d.ts +10 -0
- package/dist/server/env-var-writes.d.ts.map +1 -0
- package/dist/server/env-var-writes.js +18 -0
- package/dist/server/env-var-writes.js.map +1 -0
- package/docs/content/deployment.md +4 -0
- package/package.json +1 -1
package/dist/a2a/client.d.ts
CHANGED
|
@@ -9,11 +9,15 @@ export declare class A2ATaskTimeoutError extends Error {
|
|
|
9
9
|
/**
|
|
10
10
|
* Sign a JWT for A2A cross-app identity verification.
|
|
11
11
|
*
|
|
12
|
-
* Uses
|
|
13
|
-
*
|
|
12
|
+
* Uses an org-level secret by default for direct org-secret workflows. Callers
|
|
13
|
+
* that are doing ordinary hosted cross-app delegation can set
|
|
14
|
+
* `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on
|
|
15
|
+
* every app database having an identical org row. The token contains the
|
|
16
|
+
* caller's email as `sub`, so the receiving app can verify who's calling.
|
|
14
17
|
*/
|
|
15
18
|
export declare function signA2AToken(email: string, orgDomain?: string, orgSecret?: string, options?: {
|
|
16
19
|
expiresIn?: string | number;
|
|
20
|
+
preferGlobalSecret?: boolean;
|
|
17
21
|
}): Promise<string>;
|
|
18
22
|
export declare class A2AClient {
|
|
19
23
|
private baseUrl;
|
package/dist/a2a/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EAGT,OAAO,EACP,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM;CAW9D;AAED
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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"}
|
package/dist/a2a/client.js
CHANGED
|
@@ -17,11 +17,16 @@ export class A2ATaskTimeoutError extends Error {
|
|
|
17
17
|
/**
|
|
18
18
|
* Sign a JWT for A2A cross-app identity verification.
|
|
19
19
|
*
|
|
20
|
-
* Uses
|
|
21
|
-
*
|
|
20
|
+
* Uses an org-level secret by default for direct org-secret workflows. Callers
|
|
21
|
+
* that are doing ordinary hosted cross-app delegation can set
|
|
22
|
+
* `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on
|
|
23
|
+
* every app database having an identical org row. The token contains the
|
|
24
|
+
* caller's email as `sub`, so the receiving app can verify who's calling.
|
|
22
25
|
*/
|
|
23
26
|
export async function signA2AToken(email, orgDomain, orgSecret, options) {
|
|
24
|
-
const secret =
|
|
27
|
+
const secret = options?.preferGlobalSecret
|
|
28
|
+
? process.env.A2A_SECRET || orgSecret
|
|
29
|
+
: orgSecret || process.env.A2A_SECRET;
|
|
25
30
|
if (!secret) {
|
|
26
31
|
throw new Error("No A2A secret available. Set an org-level A2A secret in Team settings, " +
|
|
27
32
|
"or set A2A_SECRET as an environment variable on all apps that need to verify identity.");
|
|
@@ -345,7 +350,7 @@ export async function callAgent(url, text, opts) {
|
|
|
345
350
|
opts?.userEmail &&
|
|
346
351
|
(opts?.orgSecret || process.env.A2A_SECRET)) {
|
|
347
352
|
try {
|
|
348
|
-
apiKey = await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret);
|
|
353
|
+
apiKey = await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret, { preferGlobalSecret: true });
|
|
349
354
|
}
|
|
350
355
|
catch {
|
|
351
356
|
// Fall back to unsigned call
|
package/dist/a2a/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport type {\n AgentCard,\n JsonRpcRequest,\n JsonRpcResponse,\n Message,\n Task,\n} from \"./types.js\";\n\nexport class A2ATaskTimeoutError extends Error {\n readonly taskId: string;\n readonly lastTask: Task;\n readonly lastState: string;\n readonly timeoutMs: number;\n\n constructor(taskId: string, lastTask: Task, timeoutMs: number) {\n const lastState = lastTask.status.state;\n super(\n `A2A task ${taskId} did not complete within ${timeoutMs}ms (last state: ${lastState})`,\n );\n this.name = \"A2ATaskTimeoutError\";\n this.taskId = taskId;\n this.lastTask = lastTask;\n this.lastState = lastState;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Sign a JWT for A2A cross-app identity verification.\n *\n * Uses A2A_SECRET as an HMAC key. The token contains the caller's email\n * as `sub`, so the receiving app can verify who's calling.\n */\nexport async function signA2AToken(\n email: string,\n orgDomain?: string,\n orgSecret?: string,\n options?: { expiresIn?: string | number },\n): Promise<string> {\n const secret = orgSecret || process.env.A2A_SECRET;\n if (!secret) {\n throw new Error(\n \"No A2A secret available. Set an org-level A2A secret in Team settings, \" +\n \"or set A2A_SECRET as an environment variable on all apps that need to verify identity.\",\n );\n }\n\n const appUrl =\n process.env.APP_URL ||\n process.env.BETTER_AUTH_URL ||\n \"http://localhost:3000\";\n\n return new jose.SignJWT({\n sub: email,\n ...(orgDomain ? { org_domain: orgDomain } : {}),\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuer(appUrl)\n .setIssuedAt()\n .setExpirationTime(options?.expiresIn ?? \"15m\")\n .sign(new TextEncoder().encode(secret));\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private apiKey?: string;\n private endpointCandidates: string[] = [];\n private endpointResolved = false;\n private requestTimeoutMs?: number;\n\n constructor(\n baseUrl: string,\n apiKey?: string,\n options?: { requestTimeoutMs?: number },\n ) {\n const normalized = baseUrl.replace(/\\/$/, \"\");\n const explicitEndpoint = splitExplicitA2AEndpoint(normalized);\n this.baseUrl = explicitEndpoint?.baseUrl ?? normalized;\n if (explicitEndpoint) {\n this.endpointCandidates = [explicitEndpoint.endpointUrl];\n this.endpointResolved = true;\n }\n this.apiKey = apiKey;\n this.requestTimeoutMs = options?.requestTimeoutMs;\n }\n\n /**\n * Detect which A2A path the target agent uses.\n * Agent-native apps use /_agent-native/a2a, external agents may use /a2a.\n */\n async resolveEndpoint(): Promise<void> {\n await this.ensureEndpointCandidates();\n if (this.endpointCandidates.length <= 1) return;\n\n for (const endpoint of this.endpointCandidates) {\n try {\n const res = await fetch(endpoint, { method: \"OPTIONS\" });\n if (res.status !== 404 && res.status !== 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n if (res.status === 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n } catch {\n // Try the next candidate.\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) {\n h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async rpc(\n method: string,\n params: Record<string, unknown>,\n ): Promise<JsonRpcResponse> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n };\n\n await this.ensureEndpointCandidates();\n let lastError: Error | null = null;\n\n for (const url of this.endpointCandidates) {\n console.log(`[A2A Client] POST ${url} method=${method}`);\n const startTime = Date.now();\n const res = await this.postJson(url, body);\n console.log(\n `[A2A Client] Response: ${res.status} in ${Date.now() - startTime}ms`,\n );\n\n if (res.ok) {\n this.endpointCandidates = [url];\n return res.json() as Promise<JsonRpcResponse>;\n }\n\n const text = await res.text();\n lastError = new Error(`A2A request failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) {\n throw lastError;\n }\n }\n\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n async getAgentCard(): Promise<AgentCard> {\n const res = await fetch(`${this.baseUrl}/.well-known/agent-card.json`);\n if (!res.ok) {\n throw new Error(`Failed to fetch agent card (${res.status})`);\n }\n return res.json() as Promise<AgentCard>;\n }\n\n async send(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /**\n * If true, ask the server to return the task immediately in `working`\n * state and process the handler in the background. The caller should\n * then poll `getTask(taskId)` until `completed` / `failed` / `canceled`.\n *\n * Use this when you expect the handler may exceed a synchronous\n * serverless request budget.\n */\n async?: boolean;\n },\n ): Promise<Task> {\n const response = await this.rpc(\"message/send\", {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n ...(opts?.async ? { async: true } : {}),\n });\n\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n\n return response.result as Task;\n }\n\n /**\n * Poll for a task by id. Used in async mode after `send({ async: true })`.\n */\n async getTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/get\", { id: taskId });\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n return response.result as Task;\n }\n\n /**\n * Send a message in async mode and poll until the task reaches a terminal\n * state. This is the recommended path on serverless hosts with short\n * function timeouts (Netlify, Vercel) where a synchronous LLM-driven A2A\n * call can exceed the gateway limit.\n *\n * Each individual fetch returns quickly; long-running work happens on the\n * receiving side and is checked via `tasks/get`.\n */\n async sendAndWait(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /** Total time to wait for completion. Default 5 min. */\n timeoutMs?: number;\n /** Poll interval. Default 2s. */\n pollIntervalMs?: number;\n /** Called with each polled task — useful for surfacing progress. */\n onUpdate?: (task: Task) => void;\n },\n ): Promise<Task> {\n const submitted = await this.send(message, {\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n async: true,\n });\n\n const terminalStates = new Set([\"completed\", \"failed\", \"canceled\"]);\n if (terminalStates.has(submitted.status.state)) return submitted;\n\n const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n const pollMs = opts?.pollIntervalMs ?? 2_000;\n const deadline = Date.now() + timeoutMs;\n\n let current = submitted;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, pollMs));\n try {\n current = await this.getTask(submitted.id);\n opts?.onUpdate?.(current);\n } catch (err) {\n // Transient fetch failure — keep polling until the deadline.\n continue;\n }\n if (terminalStates.has(current.status.state)) return current;\n }\n throw new A2ATaskTimeoutError(submitted.id, current, timeoutMs);\n }\n\n async *stream(\n message: Message,\n opts?: { contextId?: string; metadata?: Record<string, unknown> },\n ): AsyncGenerator<Task> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"message/stream\",\n params: {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n },\n };\n\n await this.ensureEndpointCandidates();\n let res: Response | null = null;\n let lastError: Error | null = null;\n for (const candidate of this.endpointCandidates) {\n res = await this.postJson(candidate, body);\n if (res.ok) {\n this.endpointCandidates = [candidate];\n break;\n }\n const text = await res.text();\n lastError = new Error(`A2A stream failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) throw lastError;\n }\n if (!res?.ok) {\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const json = line.slice(6).trim();\n if (!json) continue;\n\n const response: JsonRpcResponse = JSON.parse(json);\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n if (response.result) {\n yield response.result as Task;\n }\n }\n }\n }\n\n private async ensureEndpointCandidates(): Promise<void> {\n if (this.endpointResolved) return;\n this.endpointResolved = true;\n\n const candidates: string[] = [];\n addDefaultEndpointCandidates(candidates, this.baseUrl);\n\n try {\n const card = await this.getAgentCard();\n const cardUrl = normalizeUrl(card.url, this.baseUrl);\n if (cardUrl) {\n const explicitEndpoint = splitExplicitA2AEndpoint(cardUrl);\n if (explicitEndpoint) {\n candidates.unshift(explicitEndpoint.endpointUrl);\n } else {\n addDefaultEndpointCandidates(candidates, cardUrl);\n }\n }\n } catch {\n // Agent cards are discovery hints. Fall back to conventional endpoints.\n }\n\n this.endpointCandidates = unique(candidates);\n }\n\n private async postJson(url: string, body: JsonRpcRequest): Promise<Response> {\n const controller = this.requestTimeoutMs\n ? new AbortController()\n : undefined;\n const timer =\n controller && this.requestTimeoutMs\n ? setTimeout(() => controller.abort(), this.requestTimeoutMs)\n : undefined;\n try {\n return await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(body),\n signal: controller?.signal,\n });\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n}\n\nfunction splitExplicitA2AEndpoint(\n url: string,\n): { baseUrl: string; endpointUrl: string } | null {\n try {\n const parsed = new URL(url);\n const pathname = parsed.pathname.replace(/\\/$/, \"\");\n if (pathname.endsWith(\"/_agent-native/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/_agent-native/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n if (pathname.endsWith(\"/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n } catch {\n // Relative or invalid URLs are handled by the caller's normal fetch path.\n }\n return null;\n}\n\nfunction addDefaultEndpointCandidates(candidates: string[], baseUrl: string) {\n const base = baseUrl.replace(/\\/$/, \"\");\n candidates.push(`${base}/_agent-native/a2a`, `${base}/a2a`);\n}\n\nfunction normalizeUrl(\n value: string | undefined,\n baseUrl: string,\n): string | null {\n if (!value) return null;\n try {\n return new URL(value, `${baseUrl.replace(/\\/$/, \"\")}/`)\n .toString()\n .replace(/\\/$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction shouldTryNextEndpoint(status: number): boolean {\n return status === 404 || status === 405;\n}\n\nfunction unique(values: string[]): string[] {\n return Array.from(new Set(values));\n}\n\n/**\n * One-shot convenience function: send a text message and get a text response.\n *\n * When A2A_SECRET is set and userEmail is provided, outbound calls are signed\n * with a JWT so the receiving app can cryptographically verify the caller's\n * identity (instead of blindly trusting metadata).\n */\nexport async function callAgent(\n url: string,\n text: string,\n opts?: {\n apiKey?: string;\n contextId?: string;\n userEmail?: string;\n orgDomain?: string;\n orgSecret?: string;\n /**\n * Use async/poll instead of a single blocking POST. Recommended for\n * cross-app calls that may exceed a synchronous serverless request budget.\n * Defaults to true so callers get safe behavior out of the box.\n */\n async?: boolean;\n /** Total time to wait for the polled task (default 5 min). */\n timeoutMs?: number;\n },\n): Promise<string> {\n let apiKey = opts?.apiKey;\n\n // Auto-sign with JWT when an A2A secret (org or global) is available and we have a user email\n if (\n !apiKey &&\n opts?.userEmail &&\n (opts?.orgSecret || process.env.A2A_SECRET)\n ) {\n try {\n apiKey = await signA2AToken(\n opts.userEmail,\n opts.orgDomain,\n opts.orgSecret,\n );\n } catch {\n // Fall back to unsigned call\n }\n }\n\n const client = new A2AClient(url, apiKey);\n const metadata: Record<string, unknown> = {};\n if (opts?.userEmail) metadata.userEmail = opts.userEmail;\n if (opts?.orgDomain) metadata.orgDomain = opts.orgDomain;\n\n // Default to async + poll. The receiving A2A server's `_process-task` route\n // runs the handler in a fresh function execution (cross-platform queue\n // pattern), so async mode now works on every host instead of relying on\n // detached promises that get killed on Netlify/Vercel. Callers that\n // explicitly want a single-shot blocking POST can pass `async: false`.\n const useAsync = opts?.async ?? true;\n const message: Message = {\n role: \"user\",\n parts: [{ type: \"text\", text }],\n };\n\n let task: Task;\n if (useAsync) {\n task = await client.sendAndWait(message, {\n contextId: opts?.contextId,\n metadata,\n timeoutMs: opts?.timeoutMs,\n });\n } else {\n task = await client.send(message, {\n contextId: opts?.contextId,\n metadata,\n });\n }\n\n // Extract text from the response\n const responseMessage = task.status.message;\n if (responseMessage) {\n const textParts = responseMessage.parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text);\n return textParts.join(\"\\n\");\n }\n\n return \"\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAS7B,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,MAAM,CAAS;IACf,QAAQ,CAAO;IACf,SAAS,CAAS;IAClB,SAAS,CAAS;IAE3B,YAAY,MAAc,EAAE,QAAc,EAAE,SAAiB;QAC3D,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;QACxC,KAAK,CACH,YAAY,MAAM,4BAA4B,SAAS,mBAAmB,SAAS,GAAG,CACvF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,SAAkB,EAClB,SAAkB,EAClB,OAAuE;IAEvE,MAAM,MAAM,GAAG,OAAO,EAAE,kBAAkB;QACxC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,SAAS;QACrC,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,yEAAyE;YACvE,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,OAAO;QACnB,OAAO,CAAC,GAAG,CAAC,eAAe;QAC3B,uBAAuB,CAAC;IAE1B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;QACtB,GAAG,EAAE,KAAK;QACV,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;SACC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;SACpC,SAAS,CAAC,MAAM,CAAC;SACjB,WAAW,EAAE;SACb,iBAAiB,CAAC,OAAO,EAAE,SAAS,IAAI,KAAK,CAAC;SAC9C,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,OAAO,SAAS;IACZ,OAAO,CAAS;IAChB,MAAM,CAAU;IAChB,kBAAkB,GAAa,EAAE,CAAC;IAClC,gBAAgB,GAAG,KAAK,CAAC;IACzB,gBAAgB,CAAU;IAElC,YACE,OAAe,EACf,MAAe,EACf,OAAuC;QAEvC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,CAAC,OAAO,GAAG,gBAAgB,EAAE,OAAO,IAAI,UAAU,CAAC;QACvD,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAI,CAAC,kBAAkB,GAAG,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;YACzD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO;QAEhD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC/C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBACzD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC7C,IAAI,CAAC,kBAAkB,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACrC,OAAO;gBACT,CAAC;gBACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACvB,IAAI,CAAC,kBAAkB,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACrC,OAAO;gBACT,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,0BAA0B;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAEO,OAAO;QACb,MAAM,CAAC,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;QACzE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAEO,KAAK,CAAC,GAAG,CACf,MAAc,EACd,MAA+B;QAE/B,MAAM,IAAI,GAAmB;YAC3B,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM;YACN,MAAM;SACP,CAAC;QAEF,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QACtC,IAAI,SAAS,GAAiB,IAAI,CAAC;QAEnC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,qBAAqB,GAAG,WAAW,MAAM,EAAE,CAAC,CAAC;YACzD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CACT,0BAA0B,GAAG,CAAC,MAAM,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,CACtE,CAAC;YAEF,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,IAAI,CAAC,kBAAkB,GAAG,CAAC,GAAG,CAAC,CAAC;gBAChC,OAAO,GAAG,CAAC,IAAI,EAA8B,CAAC;YAChD,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,GAAG,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvC,MAAM,SAAS,CAAC;YAClB,CAAC;QACH,CAAC;QAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,8BAA8B,CAAC,CAAC;QACvE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,EAAwB,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,IAAI,CACR,OAAgB,EAChB,IAYC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE;YAC9C,OAAO;YACP,SAAS,EAAE,IAAI,EAAE,SAAS;YAC1B,QAAQ,EAAE,IAAI,EAAE,QAAQ;YACxB,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,cAAc,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAChE,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC,MAAc,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7D,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,cAAc,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAChE,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC,MAAc,CAAC;IACjC,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,WAAW,CACf,OAAgB,EAChB,IASC;QAED,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACzC,SAAS,EAAE,IAAI,EAAE,SAAS;YAC1B,QAAQ,EAAE,IAAI,EAAE,QAAQ;YACxB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;QACpE,IAAI,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAEjE,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,CAAC,GAAG,MAAM,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,EAAE,cAAc,IAAI,KAAK,CAAC;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAExC,IAAI,OAAO,GAAG,SAAS,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAC3C,IAAI,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,6DAA6D;gBAC7D,SAAS;YACX,CAAC;YACD,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,OAAO,CAAC;QAC/D,CAAC;QACD,MAAM,IAAI,mBAAmB,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CACX,OAAgB,EAChB,IAAiE;QAEjE,MAAM,IAAI,GAAmB;YAC3B,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM,EAAE,gBAAgB;YACxB,MAAM,EAAE;gBACN,OAAO;gBACP,SAAS,EAAE,IAAI,EAAE,SAAS;gBAC1B,QAAQ,EAAE,IAAI,EAAE,QAAQ;aACzB;SACF,CAAC;QAEF,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QACtC,IAAI,GAAG,GAAoB,IAAI,CAAC;QAChC,IAAI,SAAS,GAAiB,IAAI,CAAC;QACnC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAChD,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC3C,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,IAAI,CAAC,kBAAkB,GAAG,CAAC,SAAS,CAAC,CAAC;gBACtC,MAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,GAAG,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,MAAM,SAAS,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC;YACb,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAEhB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,CAAC,IAAI;oBAAE,SAAS;gBAEpB,MAAM,QAAQ,GAAoB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACnB,MAAM,IAAI,KAAK,CACb,cAAc,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAChE,CAAC;gBACJ,CAAC;gBACD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACpB,MAAM,QAAQ,CAAC,MAAc,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,wBAAwB;QACpC,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO;QAClC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAE7B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,4BAA4B,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACrD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;gBAC3D,IAAI,gBAAgB,EAAE,CAAC;oBACrB,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,4BAA4B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;QAC1E,CAAC;QAED,IAAI,CAAC,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,GAAW,EAAE,IAAoB;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB;YACtC,CAAC,CAAC,IAAI,eAAe,EAAE;YACvB,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,KAAK,GACT,UAAU,IAAI,IAAI,CAAC,gBAAgB;YACjC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,gBAAgB,CAAC;YAC7D,CAAC,CAAC,SAAS,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE;gBACtB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;gBACvB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC1B,MAAM,EAAE,UAAU,EAAE,MAAM;aAC3B,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF;AAED,SAAS,wBAAwB,CAC/B,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpD,IAAI,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;YACzE,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC7C,WAAW,EAAE,GAAG;aACjB,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;YAC3D,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC7C,WAAW,EAAE,GAAG;aACjB,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,4BAA4B,CAAC,UAAoB,EAAE,OAAe;IACzE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxC,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,YAAY,CACnB,KAAyB,EACzB,OAAe;IAEf,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC;aACpD,QAAQ,EAAE;aACV,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAc;IAC3C,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC;AAC1C,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,IAAY,EACZ,IAcC;IAED,IAAI,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC;IAE1B,8FAA8F;IAC9F,IACE,CAAC,MAAM;QACP,IAAI,EAAE,SAAS;QACf,CAAC,IAAI,EAAE,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAC3C,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,YAAY,CACzB,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,SAAS,EACd,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAC7B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,IAAI,IAAI,EAAE,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACzD,IAAI,IAAI,EAAE,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAEzD,4EAA4E;IAC5E,uEAAuE;IACvE,wEAAwE;IACxE,oEAAoE;IACpE,uEAAuE;IACvE,MAAM,QAAQ,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;IACrC,MAAM,OAAO,GAAY;QACvB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAChC,CAAC;IAEF,IAAI,IAAU,CAAC;IACf,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE;YACvC,SAAS,EAAE,IAAI,EAAE,SAAS;YAC1B,QAAQ;YACR,SAAS,EAAE,IAAI,EAAE,SAAS;SAC3B,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;YAChC,SAAS,EAAE,IAAI,EAAE,SAAS;YAC1B,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED,iCAAiC;IACjC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IAC5C,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK;aACpC,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;aACrE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC","sourcesContent":["import * as jose from \"jose\";\nimport type {\n AgentCard,\n JsonRpcRequest,\n JsonRpcResponse,\n Message,\n Task,\n} from \"./types.js\";\n\nexport class A2ATaskTimeoutError extends Error {\n readonly taskId: string;\n readonly lastTask: Task;\n readonly lastState: string;\n readonly timeoutMs: number;\n\n constructor(taskId: string, lastTask: Task, timeoutMs: number) {\n const lastState = lastTask.status.state;\n super(\n `A2A task ${taskId} did not complete within ${timeoutMs}ms (last state: ${lastState})`,\n );\n this.name = \"A2ATaskTimeoutError\";\n this.taskId = taskId;\n this.lastTask = lastTask;\n this.lastState = lastState;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Sign a JWT for A2A cross-app identity verification.\n *\n * Uses an org-level secret by default for direct org-secret workflows. Callers\n * that are doing ordinary hosted cross-app delegation can set\n * `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on\n * every app database having an identical org row. The token contains the\n * caller's email as `sub`, so the receiving app can verify who's calling.\n */\nexport async function signA2AToken(\n email: string,\n orgDomain?: string,\n orgSecret?: string,\n options?: { expiresIn?: string | number; preferGlobalSecret?: boolean },\n): Promise<string> {\n const secret = options?.preferGlobalSecret\n ? process.env.A2A_SECRET || orgSecret\n : orgSecret || process.env.A2A_SECRET;\n if (!secret) {\n throw new Error(\n \"No A2A secret available. Set an org-level A2A secret in Team settings, \" +\n \"or set A2A_SECRET as an environment variable on all apps that need to verify identity.\",\n );\n }\n\n const appUrl =\n process.env.APP_URL ||\n process.env.BETTER_AUTH_URL ||\n \"http://localhost:3000\";\n\n return new jose.SignJWT({\n sub: email,\n ...(orgDomain ? { org_domain: orgDomain } : {}),\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuer(appUrl)\n .setIssuedAt()\n .setExpirationTime(options?.expiresIn ?? \"15m\")\n .sign(new TextEncoder().encode(secret));\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private apiKey?: string;\n private endpointCandidates: string[] = [];\n private endpointResolved = false;\n private requestTimeoutMs?: number;\n\n constructor(\n baseUrl: string,\n apiKey?: string,\n options?: { requestTimeoutMs?: number },\n ) {\n const normalized = baseUrl.replace(/\\/$/, \"\");\n const explicitEndpoint = splitExplicitA2AEndpoint(normalized);\n this.baseUrl = explicitEndpoint?.baseUrl ?? normalized;\n if (explicitEndpoint) {\n this.endpointCandidates = [explicitEndpoint.endpointUrl];\n this.endpointResolved = true;\n }\n this.apiKey = apiKey;\n this.requestTimeoutMs = options?.requestTimeoutMs;\n }\n\n /**\n * Detect which A2A path the target agent uses.\n * Agent-native apps use /_agent-native/a2a, external agents may use /a2a.\n */\n async resolveEndpoint(): Promise<void> {\n await this.ensureEndpointCandidates();\n if (this.endpointCandidates.length <= 1) return;\n\n for (const endpoint of this.endpointCandidates) {\n try {\n const res = await fetch(endpoint, { method: \"OPTIONS\" });\n if (res.status !== 404 && res.status !== 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n if (res.status === 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n } catch {\n // Try the next candidate.\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) {\n h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async rpc(\n method: string,\n params: Record<string, unknown>,\n ): Promise<JsonRpcResponse> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n };\n\n await this.ensureEndpointCandidates();\n let lastError: Error | null = null;\n\n for (const url of this.endpointCandidates) {\n console.log(`[A2A Client] POST ${url} method=${method}`);\n const startTime = Date.now();\n const res = await this.postJson(url, body);\n console.log(\n `[A2A Client] Response: ${res.status} in ${Date.now() - startTime}ms`,\n );\n\n if (res.ok) {\n this.endpointCandidates = [url];\n return res.json() as Promise<JsonRpcResponse>;\n }\n\n const text = await res.text();\n lastError = new Error(`A2A request failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) {\n throw lastError;\n }\n }\n\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n async getAgentCard(): Promise<AgentCard> {\n const res = await fetch(`${this.baseUrl}/.well-known/agent-card.json`);\n if (!res.ok) {\n throw new Error(`Failed to fetch agent card (${res.status})`);\n }\n return res.json() as Promise<AgentCard>;\n }\n\n async send(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /**\n * If true, ask the server to return the task immediately in `working`\n * state and process the handler in the background. The caller should\n * then poll `getTask(taskId)` until `completed` / `failed` / `canceled`.\n *\n * Use this when you expect the handler may exceed a synchronous\n * serverless request budget.\n */\n async?: boolean;\n },\n ): Promise<Task> {\n const response = await this.rpc(\"message/send\", {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n ...(opts?.async ? { async: true } : {}),\n });\n\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n\n return response.result as Task;\n }\n\n /**\n * Poll for a task by id. Used in async mode after `send({ async: true })`.\n */\n async getTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/get\", { id: taskId });\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n return response.result as Task;\n }\n\n /**\n * Send a message in async mode and poll until the task reaches a terminal\n * state. This is the recommended path on serverless hosts with short\n * function timeouts (Netlify, Vercel) where a synchronous LLM-driven A2A\n * call can exceed the gateway limit.\n *\n * Each individual fetch returns quickly; long-running work happens on the\n * receiving side and is checked via `tasks/get`.\n */\n async sendAndWait(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /** Total time to wait for completion. Default 5 min. */\n timeoutMs?: number;\n /** Poll interval. Default 2s. */\n pollIntervalMs?: number;\n /** Called with each polled task — useful for surfacing progress. */\n onUpdate?: (task: Task) => void;\n },\n ): Promise<Task> {\n const submitted = await this.send(message, {\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n async: true,\n });\n\n const terminalStates = new Set([\"completed\", \"failed\", \"canceled\"]);\n if (terminalStates.has(submitted.status.state)) return submitted;\n\n const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n const pollMs = opts?.pollIntervalMs ?? 2_000;\n const deadline = Date.now() + timeoutMs;\n\n let current = submitted;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, pollMs));\n try {\n current = await this.getTask(submitted.id);\n opts?.onUpdate?.(current);\n } catch (err) {\n // Transient fetch failure — keep polling until the deadline.\n continue;\n }\n if (terminalStates.has(current.status.state)) return current;\n }\n throw new A2ATaskTimeoutError(submitted.id, current, timeoutMs);\n }\n\n async *stream(\n message: Message,\n opts?: { contextId?: string; metadata?: Record<string, unknown> },\n ): AsyncGenerator<Task> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"message/stream\",\n params: {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n },\n };\n\n await this.ensureEndpointCandidates();\n let res: Response | null = null;\n let lastError: Error | null = null;\n for (const candidate of this.endpointCandidates) {\n res = await this.postJson(candidate, body);\n if (res.ok) {\n this.endpointCandidates = [candidate];\n break;\n }\n const text = await res.text();\n lastError = new Error(`A2A stream failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) throw lastError;\n }\n if (!res?.ok) {\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const json = line.slice(6).trim();\n if (!json) continue;\n\n const response: JsonRpcResponse = JSON.parse(json);\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n if (response.result) {\n yield response.result as Task;\n }\n }\n }\n }\n\n private async ensureEndpointCandidates(): Promise<void> {\n if (this.endpointResolved) return;\n this.endpointResolved = true;\n\n const candidates: string[] = [];\n addDefaultEndpointCandidates(candidates, this.baseUrl);\n\n try {\n const card = await this.getAgentCard();\n const cardUrl = normalizeUrl(card.url, this.baseUrl);\n if (cardUrl) {\n const explicitEndpoint = splitExplicitA2AEndpoint(cardUrl);\n if (explicitEndpoint) {\n candidates.unshift(explicitEndpoint.endpointUrl);\n } else {\n addDefaultEndpointCandidates(candidates, cardUrl);\n }\n }\n } catch {\n // Agent cards are discovery hints. Fall back to conventional endpoints.\n }\n\n this.endpointCandidates = unique(candidates);\n }\n\n private async postJson(url: string, body: JsonRpcRequest): Promise<Response> {\n const controller = this.requestTimeoutMs\n ? new AbortController()\n : undefined;\n const timer =\n controller && this.requestTimeoutMs\n ? setTimeout(() => controller.abort(), this.requestTimeoutMs)\n : undefined;\n try {\n return await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(body),\n signal: controller?.signal,\n });\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n}\n\nfunction splitExplicitA2AEndpoint(\n url: string,\n): { baseUrl: string; endpointUrl: string } | null {\n try {\n const parsed = new URL(url);\n const pathname = parsed.pathname.replace(/\\/$/, \"\");\n if (pathname.endsWith(\"/_agent-native/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/_agent-native/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n if (pathname.endsWith(\"/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n } catch {\n // Relative or invalid URLs are handled by the caller's normal fetch path.\n }\n return null;\n}\n\nfunction addDefaultEndpointCandidates(candidates: string[], baseUrl: string) {\n const base = baseUrl.replace(/\\/$/, \"\");\n candidates.push(`${base}/_agent-native/a2a`, `${base}/a2a`);\n}\n\nfunction normalizeUrl(\n value: string | undefined,\n baseUrl: string,\n): string | null {\n if (!value) return null;\n try {\n return new URL(value, `${baseUrl.replace(/\\/$/, \"\")}/`)\n .toString()\n .replace(/\\/$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction shouldTryNextEndpoint(status: number): boolean {\n return status === 404 || status === 405;\n}\n\nfunction unique(values: string[]): string[] {\n return Array.from(new Set(values));\n}\n\n/**\n * One-shot convenience function: send a text message and get a text response.\n *\n * When A2A_SECRET is set and userEmail is provided, outbound calls are signed\n * with a JWT so the receiving app can cryptographically verify the caller's\n * identity (instead of blindly trusting metadata).\n */\nexport async function callAgent(\n url: string,\n text: string,\n opts?: {\n apiKey?: string;\n contextId?: string;\n userEmail?: string;\n orgDomain?: string;\n orgSecret?: string;\n /**\n * Use async/poll instead of a single blocking POST. Recommended for\n * cross-app calls that may exceed a synchronous serverless request budget.\n * Defaults to true so callers get safe behavior out of the box.\n */\n async?: boolean;\n /** Total time to wait for the polled task (default 5 min). */\n timeoutMs?: number;\n },\n): Promise<string> {\n let apiKey = opts?.apiKey;\n\n // Auto-sign with JWT when an A2A secret (org or global) is available and we have a user email\n if (\n !apiKey &&\n opts?.userEmail &&\n (opts?.orgSecret || process.env.A2A_SECRET)\n ) {\n try {\n apiKey = await signA2AToken(\n opts.userEmail,\n opts.orgDomain,\n opts.orgSecret,\n { preferGlobalSecret: true },\n );\n } catch {\n // Fall back to unsigned call\n }\n }\n\n const client = new A2AClient(url, apiKey);\n const metadata: Record<string, unknown> = {};\n if (opts?.userEmail) metadata.userEmail = opts.userEmail;\n if (opts?.orgDomain) metadata.orgDomain = opts.orgDomain;\n\n // Default to async + poll. The receiving A2A server's `_process-task` route\n // runs the handler in a fresh function execution (cross-platform queue\n // pattern), so async mode now works on every host instead of relying on\n // detached promises that get killed on Netlify/Vercel. Callers that\n // explicitly want a single-shot blocking POST can pass `async: false`.\n const useAsync = opts?.async ?? true;\n const message: Message = {\n role: \"user\",\n parts: [{ type: \"text\", text }],\n };\n\n let task: Task;\n if (useAsync) {\n task = await client.sendAndWait(message, {\n contextId: opts?.contextId,\n metadata,\n timeoutMs: opts?.timeoutMs,\n });\n } else {\n task = await client.send(message, {\n contextId: opts?.contextId,\n metadata,\n });\n }\n\n // Extract text from the response\n const responseMessage = task.status.message;\n if (responseMessage) {\n const textParts = responseMessage.parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text);\n return textParts.join(\"\\n\");\n }\n\n return \"\";\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentChatEvent } from "../agent/types.js";
|
|
2
|
+
export interface CollectFinalResponseTextOptions {
|
|
3
|
+
fallbackToPreToolText?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function collectFinalResponseTextFromAgentEvents(events: readonly AgentChatEvent[], options?: CollectFinalResponseTextOptions): string;
|
|
6
|
+
//# sourceMappingURL=response-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-text.d.ts","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,WAAW,+BAA+B;IAC9C,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,OAAO,GAAE,+BAAoC,GAC5C,MAAM,CAsBR"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function collectFinalResponseTextFromAgentEvents(events, options = {}) {
|
|
2
|
+
const fallbackToPreToolText = options.fallbackToPreToolText ?? true;
|
|
3
|
+
let lastToolIdx = -1;
|
|
4
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
5
|
+
const type = events[i].type;
|
|
6
|
+
if (type === "tool_start" || type === "tool_done") {
|
|
7
|
+
lastToolIdx = i;
|
|
8
|
+
break;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const startIdx = lastToolIdx >= 0 ? lastToolIdx + 1 : 0;
|
|
12
|
+
let responseText = collectTextEvents(events, startIdx);
|
|
13
|
+
// Some agents let the final tool output speak for itself. Fall back to all
|
|
14
|
+
// text so callers do not get an empty reply just because no post-tool text
|
|
15
|
+
// was emitted.
|
|
16
|
+
if (!responseText.trim() && lastToolIdx >= 0 && fallbackToPreToolText) {
|
|
17
|
+
responseText = collectTextEvents(events, 0);
|
|
18
|
+
}
|
|
19
|
+
return responseText;
|
|
20
|
+
}
|
|
21
|
+
function collectTextEvents(events, startIdx) {
|
|
22
|
+
let text = "";
|
|
23
|
+
for (let i = startIdx; i < events.length; i++) {
|
|
24
|
+
const event = events[i];
|
|
25
|
+
if (event.type === "text")
|
|
26
|
+
text += event.text;
|
|
27
|
+
}
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=response-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-text.js","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,uCAAuC,CACrD,MAAiC,EACjC,UAA2C,EAAE;IAE7C,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,IAAI,IAAI,CAAC;IACpE,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5B,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAClD,WAAW,GAAG,CAAC,CAAC;YAChB,MAAM;QACR,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,YAAY,GAAG,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEvD,2EAA2E;IAC3E,2EAA2E;IAC3E,eAAe;IACf,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,WAAW,IAAI,CAAC,IAAI,qBAAqB,EAAE,CAAC;QACtE,YAAY,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAiC,EACjC,QAAgB;IAEhB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { AgentChatEvent } from \"../agent/types.js\";\n\nexport interface CollectFinalResponseTextOptions {\n fallbackToPreToolText?: boolean;\n}\n\nexport function collectFinalResponseTextFromAgentEvents(\n events: readonly AgentChatEvent[],\n options: CollectFinalResponseTextOptions = {},\n): string {\n const fallbackToPreToolText = options.fallbackToPreToolText ?? true;\n let lastToolIdx = -1;\n for (let i = events.length - 1; i >= 0; i--) {\n const type = events[i].type;\n if (type === \"tool_start\" || type === \"tool_done\") {\n lastToolIdx = i;\n break;\n }\n }\n\n const startIdx = lastToolIdx >= 0 ? lastToolIdx + 1 : 0;\n let responseText = collectTextEvents(events, startIdx);\n\n // Some agents let the final tool output speak for itself. Fall back to all\n // text so callers do not get an empty reply just because no post-tool text\n // was emitted.\n if (!responseText.trim() && lastToolIdx >= 0 && fallbackToPreToolText) {\n responseText = collectTextEvents(events, 0);\n }\n\n return responseText;\n}\n\nfunction collectTextEvents(\n events: readonly AgentChatEvent[],\n startIdx: number,\n): string {\n let text = \"\";\n for (let i = startIdx; i < events.length; i++) {\n const event = events[i];\n if (event.type === \"text\") text += event.text;\n }\n return text;\n}\n"]}
|
package/dist/a2a/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0J5C;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,GAAG,EACb,MAAM,EAAE,SAAS,EACjB,WAAW,SAAmB,GAC7B,IAAI,CAkNN"}
|
package/dist/a2a/server.js
CHANGED
|
@@ -20,6 +20,12 @@ function warnA2AUnauthOnce() {
|
|
|
20
20
|
console.warn("[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. " +
|
|
21
21
|
"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.");
|
|
22
22
|
}
|
|
23
|
+
function addSecretCandidate(candidates, secret) {
|
|
24
|
+
const trimmed = secret?.trim();
|
|
25
|
+
if (!trimmed || candidates.includes(trimmed))
|
|
26
|
+
return;
|
|
27
|
+
candidates.push(trimmed);
|
|
28
|
+
}
|
|
23
29
|
/**
|
|
24
30
|
* Resolve the audience (`aud`) value to expect in an inbound JWT. We use the
|
|
25
31
|
* receiver's app URL — it's the natural identifier of "who this token was
|
|
@@ -62,25 +68,24 @@ async function verifyA2AToken(authHeader, event) {
|
|
|
62
68
|
catch {
|
|
63
69
|
// Malformed token — fall through to global secret attempt
|
|
64
70
|
}
|
|
65
|
-
// Step 2:
|
|
66
|
-
|
|
71
|
+
// Step 2: Build a small, ordered set of candidate secrets. Tokens minted by
|
|
72
|
+
// current callers prefer the shared A2A_SECRET; older callers may still use
|
|
73
|
+
// an org-level secret. Try both without logging or reflecting secret details.
|
|
74
|
+
const candidateSecrets = [];
|
|
75
|
+
addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);
|
|
67
76
|
if (orgDomainHint) {
|
|
68
77
|
try {
|
|
69
78
|
const { getA2ASecretByDomain } = await import("../org/context.js");
|
|
70
79
|
const orgSecret = await getA2ASecretByDomain(orgDomainHint);
|
|
71
|
-
|
|
72
|
-
secret = orgSecret;
|
|
80
|
+
addSecretCandidate(candidateSecrets, orgSecret);
|
|
73
81
|
}
|
|
74
82
|
catch {
|
|
75
83
|
// DB not ready or column doesn't exist yet — fall through
|
|
76
84
|
}
|
|
77
85
|
}
|
|
78
|
-
|
|
79
|
-
if (!secret)
|
|
80
|
-
secret = process.env.A2A_SECRET;
|
|
81
|
-
if (!secret)
|
|
86
|
+
if (candidateSecrets.length === 0)
|
|
82
87
|
return { email: null, orgDomain: null };
|
|
83
|
-
// Step
|
|
88
|
+
// Step 3: Verify JWT with the candidate secrets.
|
|
84
89
|
//
|
|
85
90
|
// - `audience`: passed only when the token carries an `aud` claim
|
|
86
91
|
// (backward-compat: tokens minted by older `signA2AToken` versions
|
|
@@ -107,15 +112,23 @@ async function verifyA2AToken(authHeader, event) {
|
|
|
107
112
|
unverifiedPayload.iss.length > 0) {
|
|
108
113
|
verifyOptions.issuer = unverifiedPayload.iss;
|
|
109
114
|
}
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
for (const secret of candidateSecrets) {
|
|
116
|
+
try {
|
|
117
|
+
const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(secret), verifyOptions);
|
|
118
|
+
return {
|
|
119
|
+
email: payload.sub ?? null,
|
|
120
|
+
orgDomain: payload.org_domain ?? null,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Try the next candidate without leaking which secret failed.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
115
127
|
}
|
|
116
128
|
catch {
|
|
117
|
-
|
|
129
|
+
// Keep malformed option construction indistinguishable from auth failure.
|
|
118
130
|
}
|
|
131
|
+
return { email: null, orgDomain: null };
|
|
119
132
|
}
|
|
120
133
|
/**
|
|
121
134
|
* Mount A2A protocol endpoints on an H3/Nitro app.
|
package/dist/a2a/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport type { A2AConfig } from \"./types.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Verify an inbound A2A JWT signed with the shared A2A_SECRET.\n * Returns the caller's email (from `sub` claim) if valid, null otherwise.\n */\ninterface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Falls back to undefined when no app URL is configured, in\n * which case the audience check is skipped (backward-compat with tokens\n * minted before the audience claim shipped).\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv);\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\nasync function verifyA2AToken(\n authHeader: string,\n event: any | undefined,\n): Promise<A2ATokenPayload> {\n const token = authHeader.replace(\"Bearer \", \"\");\n\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Look up the org's A2A secret by domain\n let secret: string | undefined;\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n if (orgSecret) secret = orgSecret;\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n\n // Step 3: Fall back to global A2A_SECRET\n if (!secret) secret = process.env.A2A_SECRET;\n if (!secret) return { email: null, orgDomain: null };\n\n // Step 4: Verify JWT with the resolved secret.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n const aud = expectedJwtAudience(event);\n if (aud) verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n return { email: null, orgDomain: null };\n }\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n // Filter out per-user/per-org MCP tools to avoid tenant disclosure.\n // Note: stdio MCP tools loaded from a file-based mcp.config.json are\n // process-wide and don't carry a per-user/per-org prefix, so they\n // remain visible. That's intentional — they're an operator-controlled\n // capability list.\n const filteredSkills = (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id !== \"string\") return true;\n return !id.startsWith(\"mcp__user_\") && !id.startsWith(\"mcp__org_\");\n });\n\n return generateAgentCard({ ...config, skills: filteredSkills }, baseUrl);\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_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?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (process.env.A2A_SECRET) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = !!process.env.A2A_SECRET;\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (authHeader?.startsWith(\"Bearer \")) {\n const tokenPayload = await verifyA2AToken(authHeader, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n const token = authHeader.slice(7);\n if (token !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // If a global secret exists and JWT verification failed, reject after\n // giving the legacy exact-match apiKeyEnv path a chance to succeed.\n if (bearerTokenRejectedByJwt && process.env.A2A_SECRET) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport type { A2AConfig } from \"./types.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Verify an inbound A2A JWT signed with the shared A2A_SECRET.\n * Returns the caller's email (from `sub` claim) if valid, null otherwise.\n */\ninterface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\nfunction addSecretCandidate(\n candidates: string[],\n secret: string | undefined,\n): void {\n const trimmed = secret?.trim();\n if (!trimmed || candidates.includes(trimmed)) return;\n candidates.push(trimmed);\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Falls back to undefined when no app URL is configured, in\n * which case the audience check is skipped (backward-compat with tokens\n * minted before the audience claim shipped).\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv);\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\nasync function verifyA2AToken(\n authHeader: string,\n event: any | undefined,\n): Promise<A2ATokenPayload> {\n const token = authHeader.replace(\"Bearer \", \"\");\n\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Build a small, ordered set of candidate secrets. Tokens minted by\n // current callers prefer the shared A2A_SECRET; older callers may still use\n // an org-level secret. Try both without logging or reflecting secret details.\n const candidateSecrets: string[] = [];\n addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n addSecretCandidate(candidateSecrets, orgSecret);\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n if (candidateSecrets.length === 0) return { email: null, orgDomain: null };\n\n // Step 3: Verify JWT with the candidate secrets.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n const aud = expectedJwtAudience(event);\n if (aud) verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n for (const secret of candidateSecrets) {\n try {\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n // Try the next candidate without leaking which secret failed.\n }\n }\n } catch {\n // Keep malformed option construction indistinguishable from auth failure.\n }\n return { email: null, orgDomain: null };\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n // Filter out per-user/per-org MCP tools to avoid tenant disclosure.\n // Note: stdio MCP tools loaded from a file-based mcp.config.json are\n // process-wide and don't carry a per-user/per-org prefix, so they\n // remain visible. That's intentional — they're an operator-controlled\n // capability list.\n const filteredSkills = (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id !== \"string\") return true;\n return !id.startsWith(\"mcp__user_\") && !id.startsWith(\"mcp__org_\");\n });\n\n return generateAgentCard({ ...config, skills: filteredSkills }, baseUrl);\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_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?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (process.env.A2A_SECRET) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = !!process.env.A2A_SECRET;\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (authHeader?.startsWith(\"Bearer \")) {\n const tokenPayload = await verifyA2AToken(authHeader, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n const token = authHeader.slice(7);\n if (token !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // If a global secret exists and JWT verification failed, reject after\n // giving the legacy exact-match apiKeyEnv path a chance to succeed.\n if (bearerTokenRejectedByJwt && process.env.A2A_SECRET) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-deploy.d.ts","sourceRoot":"","sources":["../../src/deploy/workspace-deploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAK7C,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GAAG,SAAS,CAAC;AAqCnE,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,YAAY,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"workspace-deploy.d.ts","sourceRoot":"","sources":["../../src/deploy/workspace-deploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAK7C,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GAAG,SAAS,CAAC;AAqCnE,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,YAAY,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,IAAI,CAAC,CAmFf"}
|
|
@@ -64,6 +64,7 @@ export async function runWorkspaceDeploy(opts = {}) {
|
|
|
64
64
|
assertNoReservedWorkspaceAppIds(apps);
|
|
65
65
|
const workspaceApps = readWorkspaceAppManifest(workspaceRoot, apps);
|
|
66
66
|
const preset = resolvePreset(opts.preset, rawArgs);
|
|
67
|
+
assertWorkspaceDeployProductionEnv({ buildOnly, preset });
|
|
67
68
|
const distDir = path.join(workspaceRoot, "dist");
|
|
68
69
|
fs.rmSync(distDir, { recursive: true, force: true });
|
|
69
70
|
fs.mkdirSync(distDir, { recursive: true });
|
|
@@ -531,6 +532,31 @@ function resolvePreset(optionPreset, args) {
|
|
|
531
532
|
normalizePreset(process.env.NITRO_PRESET) ??
|
|
532
533
|
"cloudflare_pages");
|
|
533
534
|
}
|
|
535
|
+
function assertWorkspaceDeployProductionEnv(opts) {
|
|
536
|
+
if (!isProductionWorkspaceDeploy(opts))
|
|
537
|
+
return;
|
|
538
|
+
if (process.env.A2A_SECRET?.trim())
|
|
539
|
+
return;
|
|
540
|
+
throw new Error([
|
|
541
|
+
"A2A_SECRET is required for production workspace deploys.",
|
|
542
|
+
"Workspace Slack, webhook, and cross-app A2A work resumes through signed background processors; without A2A_SECRET those production routes return 503.",
|
|
543
|
+
'Set A2A_SECRET in your deploy provider (for example: netlify env:set A2A_SECRET "$(openssl rand -hex 32)") and redeploy.',
|
|
544
|
+
"For local artifact checks, run agent-native deploy --build-only outside the deploy provider environment.",
|
|
545
|
+
].join(" "));
|
|
546
|
+
}
|
|
547
|
+
function isProductionWorkspaceDeploy(opts) {
|
|
548
|
+
if (!opts.buildOnly)
|
|
549
|
+
return true;
|
|
550
|
+
if (opts.preset === "netlify" &&
|
|
551
|
+
process.env.NETLIFY === "true" &&
|
|
552
|
+
process.env.NETLIFY_LOCAL !== "true") {
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
if (opts.preset === "cloudflare_pages" && process.env.CF_PAGES === "1") {
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
534
560
|
function normalizePreset(value) {
|
|
535
561
|
if (!value)
|
|
536
562
|
return null;
|