@daisyintel/whatsapp-cloud-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # WhatsApp Cloud API MCP Server
2
+
3
+ TypeScript MCP server that exposes WhatsApp Cloud API admin and messaging tools over `stdio` and runs an HTTP webhook endpoint for verification and inbound event intake.
4
+
5
+ ## Environment
6
+
7
+ Set these variables before starting the server:
8
+
9
+ ```powershell
10
+ $env:WHATSAPP_ACCESS_TOKEN="..."
11
+ $env:WHATSAPP_API_VERSION="v23.0"
12
+ $env:WHATSAPP_BUSINESS_ID="..."
13
+ $env:WHATSAPP_WABA_ID="..."
14
+ $env:WHATSAPP_PHONE_NUMBER_ID="..."
15
+ $env:WHATSAPP_VERIFY_TOKEN="..."
16
+ $env:META_APP_SECRET="..."
17
+ $env:PORT="3000"
18
+ $env:WHATSAPP_ALLOW_UNSIGNED_WEBHOOKS="false"
19
+ ```
20
+
21
+ `WHATSAPP_BUSINESS_ID`, `WHATSAPP_WABA_ID`, and `WHATSAPP_PHONE_NUMBER_ID` are optional if you want to discover them via the MCP tools first.
22
+
23
+ ## Package Commands
24
+
25
+ After building or installing the package, these CLI commands are available:
26
+
27
+ - `whatsapp-cloud-mcp` starts the MCP server
28
+ - `whatsapp-cloud-mcp-inspect` starts MCP Inspector against the packaged server automatically
29
+
30
+ If you publish this package, users can run:
31
+
32
+ ```powershell
33
+ npx --package @daisy/whatsapp-cloud-mcp whatsapp-cloud-mcp
34
+ npx --package @daisy/whatsapp-cloud-mcp whatsapp-cloud-mcp-inspect
35
+ ```
36
+
37
+ The most practical local equivalents in this repo are:
38
+
39
+ ```powershell
40
+ npm install
41
+ npm run build
42
+ npm start
43
+ npm run inspect
44
+ ```
45
+
46
+ ## Scripts
47
+
48
+ ```powershell
49
+ npm install
50
+ npm run build
51
+ npm test
52
+ npm start
53
+ npm run inspect
54
+ npm run inspect:dev
55
+ ```
56
+
57
+ ## MCP Inspector
58
+
59
+ The packaged inspector command starts the server under MCP Inspector automatically.
60
+
61
+ - `npm run inspect` launches Inspector against the built package server
62
+ - `npm run inspect:dev` launches Inspector directly against `src/index.ts`
63
+ - `whatsapp-cloud-mcp-inspect` does the same as the packaged built-server flow
64
+
65
+ Inspector opens a local UI, usually at `http://localhost:6274`, and proxies to the spawned MCP server. Before starting it, set the same WhatsApp environment variables shown above in your shell.
66
+
67
+ The installed Inspector version requires Node `>=22.7.5`. This machine is already compatible.
68
+
69
+ If you want a reusable client/server config, copy `mcp.json.example` to `mcp.json` and replace the placeholder env values.
70
+
71
+ ## Webhook routes
72
+
73
+ - `GET /health`
74
+ - `GET /webhook`
75
+ - `POST /webhook`
76
+
77
+ ## MCP transports
78
+
79
+ - `stdio` via the main MCP server process
80
+ - `streamable-http` at `http://127.0.0.1:3000/mcp`
81
+ - `sse` at `http://127.0.0.1:3000/sse` with POST messages to `http://127.0.0.1:3000/messages`
82
+
83
+ ## Testing with MCP Inspector
84
+
85
+ To test the current `stdio` transport in Inspector:
86
+
87
+ ```powershell
88
+ $env:WHATSAPP_ACCESS_TOKEN="..."
89
+ $env:WHATSAPP_VERIFY_TOKEN="..."
90
+ npm run inspect:dev
91
+ ```
92
+
93
+ To test the HTTP transports:
94
+
95
+ 1. Start the server with `npm run dev`
96
+ 2. Open MCP Inspector
97
+ 3. Choose:
98
+ - `streamable-http` with `http://127.0.0.1:3000/mcp`
99
+ - `sse` with `http://127.0.0.1:3000/sse`
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { createRequire } from "node:module";
6
+ const require = createRequire(import.meta.url);
7
+ const currentDir = dirname(fileURLToPath(import.meta.url));
8
+ const serverBinPath = join(currentDir, "server.js");
9
+ const inspectorPackagePath = require.resolve("@modelcontextprotocol/inspector/package.json");
10
+ const inspectorCliPath = join(dirname(inspectorPackagePath), "cli", "build", "cli.js");
11
+ const child = spawn(process.execPath, [inspectorCliPath, process.execPath, serverBinPath, ...process.argv.slice(2)], {
12
+ stdio: "inherit",
13
+ env: process.env
14
+ });
15
+ child.on("exit", (code, signal) => {
16
+ if (signal) {
17
+ process.kill(process.pid, signal);
18
+ return;
19
+ }
20
+ process.exit(code ?? 0);
21
+ });
22
+ child.on("error", (error) => {
23
+ console.error(error instanceof Error ? error.message : error);
24
+ process.exit(1);
25
+ });
26
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../src/bin/inspect.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACpD,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC;AAC7F,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAEvF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,gBAAgB,EAAE,OAAO,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;IACnH,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,CAAC;AAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;IAChC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import "../index.js";
3
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/bin/server.ts"],"names":[],"mappings":";AACA,OAAO,aAAa,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { config as loadDotEnv } from "dotenv";
2
+ loadDotEnv();
3
+ const DEFAULT_API_VERSION = "v23.0";
4
+ const DEFAULT_PORT = 3000;
5
+ const DEFAULT_MAX_WEBHOOK_EVENTS = 100;
6
+ function parseIntWithDefault(rawValue, fallback, label) {
7
+ if (!rawValue) {
8
+ return fallback;
9
+ }
10
+ const parsed = Number.parseInt(rawValue, 10);
11
+ if (Number.isNaN(parsed) || parsed <= 0) {
12
+ throw new Error(`Invalid ${label}: expected a positive integer.`);
13
+ }
14
+ return parsed;
15
+ }
16
+ function parseBoolean(rawValue) {
17
+ return rawValue === "true" || rawValue === "1";
18
+ }
19
+ export function loadConfig(env = process.env) {
20
+ const accessToken = env.WHATSAPP_ACCESS_TOKEN;
21
+ if (!accessToken) {
22
+ throw new Error("WHATSAPP_ACCESS_TOKEN is required.");
23
+ }
24
+ return {
25
+ accessToken,
26
+ apiVersion: env.WHATSAPP_API_VERSION ?? DEFAULT_API_VERSION,
27
+ businessId: env.WHATSAPP_BUSINESS_ID ?? env.BUSINESS_ID,
28
+ wabaId: env.WHATSAPP_WABA_ID ?? env.WAB_ID,
29
+ phoneNumberId: env.WHATSAPP_PHONE_NUMBER_ID ?? env.PHONE_ID,
30
+ verifyToken: env.WHATSAPP_VERIFY_TOKEN,
31
+ appSecret: env.META_APP_SECRET,
32
+ port: parseIntWithDefault(env.PORT, DEFAULT_PORT, "PORT"),
33
+ maxWebhookEvents: parseIntWithDefault(env.WHATSAPP_MAX_WEBHOOK_EVENTS, DEFAULT_MAX_WEBHOOK_EVENTS, "WHATSAPP_MAX_WEBHOOK_EVENTS"),
34
+ allowUnsignedWebhooks: parseBoolean(env.WHATSAPP_ALLOW_UNSIGNED_WEBHOOKS)
35
+ };
36
+ }
37
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG9C,UAAU,EAAE,CAAC;AAEb,MAAM,mBAAmB,GAAG,OAAO,CAAC;AACpC,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAEvC,SAAS,mBAAmB,CAAC,QAA4B,EAAE,QAAgB,EAAE,KAAa;IACxF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,WAAW,KAAK,gCAAgC,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,QAA4B;IAChD,OAAO,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,GAAG,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,WAAW,GAAG,GAAG,CAAC,qBAAqB,CAAC;IAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO;QACL,WAAW;QACX,UAAU,EAAE,GAAG,CAAC,oBAAoB,IAAI,mBAAmB;QAC3D,UAAU,EAAE,GAAG,CAAC,oBAAoB,IAAI,GAAG,CAAC,WAAW;QACvD,MAAM,EAAE,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,MAAM;QAC1C,aAAa,EAAE,GAAG,CAAC,wBAAwB,IAAI,GAAG,CAAC,QAAQ;QAC3D,WAAW,EAAE,GAAG,CAAC,qBAAqB;QACtC,SAAS,EAAE,GAAG,CAAC,eAAe;QAC9B,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC;QACzD,gBAAgB,EAAE,mBAAmB,CACnC,GAAG,CAAC,2BAA2B,EAC/B,0BAA0B,EAC1B,6BAA6B,CAC9B;QACD,qBAAqB,EAAE,YAAY,CAAC,GAAG,CAAC,gCAAgC,CAAC;KAC1E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ export class InMemoryWebhookEventStore {
2
+ maxEvents;
3
+ events = [];
4
+ constructor(maxEvents) {
5
+ this.maxEvents = maxEvents;
6
+ }
7
+ add(events) {
8
+ for (const event of events) {
9
+ this.events.unshift(event);
10
+ }
11
+ if (this.events.length > this.maxEvents) {
12
+ this.events.length = this.maxEvents;
13
+ }
14
+ }
15
+ list(limit = 20) {
16
+ return this.events.slice(0, limit);
17
+ }
18
+ clear() {
19
+ this.events.length = 0;
20
+ }
21
+ }
22
+ //# sourceMappingURL=eventStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventStore.js","sourceRoot":"","sources":["../../src/eventStore.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,yBAAyB;IAGP;IAFZ,MAAM,GAA6B,EAAE,CAAC;IAEvD,YAA6B,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;IAElD,GAAG,CAAC,MAAgC;QAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC;QACtC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,GAAG,EAAE;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,114 @@
1
+ export class GraphRequestError extends Error {
2
+ endpoint;
3
+ status;
4
+ requestId;
5
+ graphError;
6
+ constructor(message, endpoint, status, requestId, graphError) {
7
+ super(message);
8
+ this.endpoint = endpoint;
9
+ this.status = status;
10
+ this.requestId = requestId;
11
+ this.graphError = graphError;
12
+ this.name = "GraphRequestError";
13
+ }
14
+ }
15
+ function buildUrl(config, path, query) {
16
+ const sanitizedPath = path.startsWith("/") ? path.slice(1) : path;
17
+ const url = new URL(`https://graph.facebook.com/${config.apiVersion}/${sanitizedPath}`);
18
+ for (const [key, value] of Object.entries(query ?? {})) {
19
+ if (value !== undefined) {
20
+ url.searchParams.set(key, String(value));
21
+ }
22
+ }
23
+ return url;
24
+ }
25
+ async function parseErrorBody(response) {
26
+ let body;
27
+ try {
28
+ body = await response.json();
29
+ }
30
+ catch {
31
+ body = undefined;
32
+ }
33
+ const root = typeof body === "object" && body !== null ? body : undefined;
34
+ const graphError = root?.error;
35
+ const normalized = typeof graphError === "object" && graphError !== null ? graphError : undefined;
36
+ return {
37
+ message: typeof normalized?.message === "string"
38
+ ? normalized.message
39
+ : `Graph API request failed with status ${response.status}.`,
40
+ type: typeof normalized?.type === "string" ? normalized.type : undefined,
41
+ code: typeof normalized?.code === "number" ? normalized.code : undefined,
42
+ errorSubcode: typeof normalized?.error_subcode === "number" ? normalized.error_subcode : undefined,
43
+ fbtraceId: typeof normalized?.fbtrace_id === "string" ? normalized.fbtrace_id : undefined,
44
+ details: body
45
+ };
46
+ }
47
+ export class WhatsAppGraphClient {
48
+ config;
49
+ fetchImpl;
50
+ constructor(config, fetchImpl = fetch) {
51
+ this.config = config;
52
+ this.fetchImpl = fetchImpl;
53
+ }
54
+ async request(options) {
55
+ const url = buildUrl(this.config, options.path, options.query);
56
+ const endpoint = url.toString();
57
+ const headers = new Headers(options.headers ?? {});
58
+ headers.set("Authorization", `Bearer ${this.config.accessToken}`);
59
+ let body;
60
+ if (options.formData) {
61
+ body = options.formData;
62
+ }
63
+ else if (options.body !== undefined) {
64
+ headers.set("Content-Type", "application/json");
65
+ body = JSON.stringify(options.body);
66
+ }
67
+ const response = await this.fetchImpl(endpoint, {
68
+ method: options.method ?? "GET",
69
+ headers,
70
+ body
71
+ });
72
+ const requestId = response.headers.get("x-fb-request-id") ?? undefined;
73
+ if (!response.ok) {
74
+ const graphError = await parseErrorBody(response);
75
+ throw new GraphRequestError(graphError.message, endpoint, response.status, requestId, graphError);
76
+ }
77
+ if (response.status === 204) {
78
+ return undefined;
79
+ }
80
+ return (await response.json());
81
+ }
82
+ async safeRequest(options) {
83
+ const url = buildUrl(this.config, options.path, options.query);
84
+ const endpoint = url.toString();
85
+ try {
86
+ const data = await this.request(options);
87
+ return {
88
+ ok: true,
89
+ endpoint,
90
+ data
91
+ };
92
+ }
93
+ catch (error) {
94
+ if (error instanceof GraphRequestError) {
95
+ return {
96
+ ok: false,
97
+ endpoint: error.endpoint,
98
+ status: error.status,
99
+ requestId: error.requestId,
100
+ error: error.graphError ?? { message: error.message }
101
+ };
102
+ }
103
+ return {
104
+ ok: false,
105
+ endpoint,
106
+ error: {
107
+ message: error instanceof Error ? error.message : "Unknown Graph API error.",
108
+ details: error
109
+ }
110
+ };
111
+ }
112
+ }
113
+ }
114
+ //# sourceMappingURL=graphClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphClient.js","sourceRoot":"","sources":["../../src/graphClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { loadConfig } from "./config.js";
3
+ import { InMemoryWebhookEventStore } from "./eventStore.js";
4
+ import { WhatsAppGraphClient } from "./graphClient.js";
5
+ import { createWhatsAppMcpServer } from "./tools.js";
6
+ import { startHttpServer } from "./webhook.js";
7
+ async function main() {
8
+ const config = loadConfig();
9
+ const eventStore = new InMemoryWebhookEventStore(config.maxWebhookEvents);
10
+ const client = new WhatsAppGraphClient(config);
11
+ const createMcpServer = () => createWhatsAppMcpServer(client, config, eventStore);
12
+ const httpServer = await startHttpServer(config, eventStore, createMcpServer);
13
+ console.error(`HTTP server listening on port ${config.port}`);
14
+ console.error(`MCP streamable HTTP endpoint: http://127.0.0.1:${config.port}/mcp`);
15
+ console.error(`MCP SSE endpoint: http://127.0.0.1:${config.port}/sse`);
16
+ console.error(`Webhook endpoint: http://127.0.0.1:${config.port}/webhook`);
17
+ const stdioServer = createMcpServer();
18
+ const transport = new StdioServerTransport();
19
+ await stdioServer.connect(transport);
20
+ const shutdown = async () => {
21
+ await new Promise((resolve, reject) => {
22
+ httpServer.close((error) => {
23
+ if (error) {
24
+ reject(error);
25
+ return;
26
+ }
27
+ resolve();
28
+ });
29
+ });
30
+ process.exit(0);
31
+ };
32
+ process.on("SIGINT", () => void shutdown());
33
+ process.on("SIGTERM", () => void shutdown());
34
+ }
35
+ main().catch((error) => {
36
+ console.error(error instanceof Error ? error.stack : error);
37
+ process.exit(1);
38
+ });
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,yBAAyB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE/C,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAElF,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IAC9E,OAAO,CAAC,KAAK,CAAC,iCAAiC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,KAAK,CAAC,kDAAkD,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;IACnF,OAAO,CAAC,KAAK,CAAC,sCAAsC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,sCAAsC,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC;IAE3E,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACzB,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,KAAK,CAAC,CAAC;oBACd,OAAO;gBACT,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}