@okrlinkhub/agent-bridge 0.2.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +132 -122
  2. package/dist/cli/init.d.ts +3 -0
  3. package/dist/cli/init.d.ts.map +1 -0
  4. package/dist/cli/init.js +108 -0
  5. package/dist/cli/init.js.map +1 -0
  6. package/dist/client/index.d.ts +54 -262
  7. package/dist/client/index.d.ts.map +1 -1
  8. package/dist/client/index.js +188 -539
  9. package/dist/client/index.js.map +1 -1
  10. package/dist/component/_generated/api.d.ts +4 -8
  11. package/dist/component/_generated/api.d.ts.map +1 -1
  12. package/dist/component/_generated/api.js.map +1 -1
  13. package/dist/component/_generated/component.d.ts +75 -257
  14. package/dist/component/_generated/component.d.ts.map +1 -1
  15. package/dist/component/agentBridgeUtils.d.ts +9 -0
  16. package/dist/component/agentBridgeUtils.d.ts.map +1 -0
  17. package/dist/component/agentBridgeUtils.js +36 -0
  18. package/dist/component/agentBridgeUtils.js.map +1 -0
  19. package/dist/component/agents.d.ts +30 -0
  20. package/dist/component/agents.d.ts.map +1 -0
  21. package/dist/component/agents.js +124 -0
  22. package/dist/component/agents.js.map +1 -0
  23. package/dist/component/gateway.d.ts +46 -51
  24. package/dist/component/gateway.d.ts.map +1 -1
  25. package/dist/component/gateway.js +176 -227
  26. package/dist/component/gateway.js.map +1 -1
  27. package/dist/component/permissions.d.ts +30 -84
  28. package/dist/component/permissions.d.ts.map +1 -1
  29. package/dist/component/permissions.js +80 -203
  30. package/dist/component/permissions.js.map +1 -1
  31. package/dist/component/schema.d.ts +58 -223
  32. package/dist/component/schema.d.ts.map +1 -1
  33. package/dist/component/schema.js +32 -126
  34. package/dist/component/schema.js.map +1 -1
  35. package/dist/react/index.d.ts +2 -2
  36. package/dist/react/index.d.ts.map +1 -1
  37. package/dist/react/index.js +2 -3
  38. package/dist/react/index.js.map +1 -1
  39. package/package.json +3 -2
  40. package/src/cli/init.ts +124 -0
  41. package/src/client/index.test.ts +147 -0
  42. package/src/client/index.ts +310 -790
  43. package/src/component/_generated/api.ts +4 -8
  44. package/src/component/_generated/component.ts +75 -310
  45. package/src/component/agentBridgeUtils.ts +56 -0
  46. package/src/component/agents.ts +138 -0
  47. package/src/component/gateway.ts +213 -279
  48. package/src/component/permissions.ts +89 -259
  49. package/src/component/schema.ts +34 -146
  50. package/src/react/index.ts +5 -6
  51. package/dist/component/channels.d.ts +0 -83
  52. package/dist/component/channels.d.ts.map +0 -1
  53. package/dist/component/channels.js +0 -288
  54. package/dist/component/channels.js.map +0 -1
  55. package/dist/component/circuitBreaker.d.ts +0 -73
  56. package/dist/component/circuitBreaker.d.ts.map +0 -1
  57. package/dist/component/circuitBreaker.js +0 -216
  58. package/dist/component/circuitBreaker.js.map +0 -1
  59. package/dist/component/provisioning.d.ts +0 -87
  60. package/dist/component/provisioning.d.ts.map +0 -1
  61. package/dist/component/provisioning.js +0 -343
  62. package/dist/component/provisioning.js.map +0 -1
  63. package/dist/component/registry.d.ts +0 -46
  64. package/dist/component/registry.d.ts.map +0 -1
  65. package/dist/component/registry.js +0 -121
  66. package/dist/component/registry.js.map +0 -1
  67. package/src/component/channels.ts +0 -374
  68. package/src/component/circuitBreaker.ts +0 -250
  69. package/src/component/provisioning.ts +0 -402
  70. package/src/component/registry.ts +0 -152
package/README.md CHANGED
@@ -1,181 +1,191 @@
1
- # Convex Agent Bridge
1
+ # Convex Agent Bridge (Config-First)
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@okrlinkhub%2Fagent-bridge.svg)](https://badge.fury.io/js/@okrlinkhub%2Fagent-bridge)
4
4
 
5
- A Convex component that acts as a **Security Gateway** between external AI agents
6
- (e.g. OpenClaw on Railway) and your Convex app's functions. It provides:
5
+ `@okrlinkhub/agent-bridge` espone un gateway HTTP per agenti esterni con approccio **config-first**:
7
6
 
8
- - **Function Handle Registry**: Register which of your app's functions agents can call
9
- - **Dynamic Permissions**: Pattern-based access control (e.g. `"okr:read*"` -> allow)
10
- - **Distributed Provisioning**: Token-based agent registration with self-service onboarding
11
- - **Audit Logging**: Full access log of all agent interactions
12
- - **HTTP Gateway**: Single endpoint for agents to call registered functions securely
7
+ - dichiari le funzioni Convex esposte in un solo file;
8
+ - configuri i permessi in batch solo su quelle funzioni;
9
+ - non modifichi query/mutation/action Convex esistenti.
13
10
 
14
- Found a bug? Feature request?
15
- [File it here](https://github.com/okrlinkhub/agent-bridge/issues).
16
-
17
- ## Installation
11
+ ## Installazione
18
12
 
19
13
  ```sh
20
14
  npm install @okrlinkhub/agent-bridge
21
15
  ```
22
16
 
23
- Add the component to your `convex/convex.config.ts`:
17
+ ## Setup rapido
18
+
19
+ ### 1) Inizializza i file nel consumer
20
+
21
+ ```sh
22
+ npx @okrlinkhub/agent-bridge init
23
+ ```
24
+
25
+ Questo genera:
26
+
27
+ - `agent-bridge.config.ts`
28
+ - `convex/agentBridge.ts`
29
+
30
+ ### 2) Abilita il componente in `convex/convex.config.ts`
24
31
 
25
32
  ```ts
26
- // convex/convex.config.ts
27
33
  import { defineApp } from "convex/server";
28
34
  import agentBridge from "@okrlinkhub/agent-bridge/convex.config.js";
29
35
 
30
36
  const app = defineApp();
31
37
  app.use(agentBridge);
32
-
33
38
  export default app;
34
39
  ```
35
40
 
36
- ## Quick Start
41
+ ### 3) Monta le route in `convex/http.ts`
37
42
 
38
- ### 1. Initialize the client
43
+ ```ts
44
+ import { httpRouter } from "convex/server";
45
+ import { registerAgentBridgeRoutes } from "./agentBridge";
46
+
47
+ const http = httpRouter();
48
+ registerAgentBridgeRoutes(http);
49
+ export default http;
50
+ ```
51
+
52
+ Se vuoi usare il flusso multi-app gestito dal bridge, passa anche la service key:
39
53
 
40
54
  ```ts
41
- // convex/agentBridge.ts
42
- import { AgentBridge } from "@okrlinkhub/agent-bridge";
43
- import { components } from "./_generated/api";
44
-
45
- export const bridge = new AgentBridge(components.agentBridge, {
46
- appName: "my-app",
47
- defaultPermissions: [
48
- { pattern: "myapp:read*", permission: "allow" },
49
- { pattern: "myapp:write*", permission: "rate_limited", rateLimitConfig: { requestsPerHour: 50, tokenBudget: 50000 } },
50
- { pattern: "*", permission: "deny" },
51
- ],
55
+ registerRoutes(http, components.agentBridge, bridgeConfig, {
56
+ pathPrefix: "/agent",
57
+ serviceKey:
58
+ (globalThis as { process?: { env?: Record<string, string> } }).process?.env
59
+ ?.AGENT_BRIDGE_SERVICE_KEY,
52
60
  });
53
61
  ```
54
62
 
55
- ### 2. Register functions that agents can call
63
+ ### 4) Configura funzioni esposte in `agent-bridge.config.ts`
56
64
 
57
65
  ```ts
58
- import { mutation } from "./_generated/server";
59
- import { createFunctionHandle } from "convex/server";
60
- import { api } from "./_generated/api";
61
- import { bridge } from "./agentBridge";
62
-
63
- export const setup = mutation({
64
- args: {},
65
- returns: v.null(),
66
- handler: async (ctx) => {
67
- await bridge.configure(ctx);
68
-
69
- const handle = await createFunctionHandle(api.myFunctions.getItems);
70
- await bridge.registerFunction(ctx, {
71
- name: "myapp:getItems",
72
- handle,
73
- type: "query",
74
- description: "List all items",
75
- });
76
-
77
- return null;
66
+ import { api } from "./convex/_generated/api";
67
+ import { defineAgentBridgeConfig } from "@okrlinkhub/agent-bridge";
68
+
69
+ export default defineAgentBridgeConfig({
70
+ functions: {
71
+ "cart.calculatePrice": { ref: api.cart.calculatePrice, type: "query" },
72
+ "cart.applyDiscount": { ref: api.cart.applyDiscount, type: "mutation" },
73
+ "okr.create": { ref: api.okr.create, type: "mutation" },
74
+ },
75
+ metadata: {
76
+ "cart.calculatePrice": {
77
+ description: "Calcola prezzo totale",
78
+ riskLevel: "low",
79
+ category: "commerce",
80
+ },
78
81
  },
79
82
  });
80
83
  ```
81
84
 
82
- ### 3. Mount HTTP routes
85
+ ## Endpoint HTTP esposti
83
86
 
84
- ```ts
85
- // convex/http.ts
86
- import { httpRouter } from "convex/server";
87
- import { registerRoutes } from "@okrlinkhub/agent-bridge";
88
- import { components } from "./_generated/api";
87
+ - `POST /agent/execute`
88
+ - `GET /agent/functions`
89
89
 
90
- const http = httpRouter();
90
+ ### `POST /agent/execute`
91
91
 
92
- // Exposes:
93
- // POST /agent-bridge/execute -- Gateway for agent function calls
94
- // POST /agent-bridge/provision -- Agent self-provisioning
95
- // GET /agent-bridge/health -- Health check
96
- registerRoutes(http, components.agentBridge, {
97
- appName: "my-app",
98
- });
92
+ Header richiesti (una delle due modalita):
99
93
 
100
- export default http;
101
- ```
94
+ - Legacy:
95
+ - `X-Agent-API-Key: <api-key>`
96
+ - Service-to-bridge (consigliato per OpenClaw multi-app):
97
+ - `X-Agent-Service-Key: <shared-service-secret>`
98
+ - `X-Agent-App: <app-key>` (es. `crm`, `billing`)
102
99
 
103
- ### 4. Generate a provisioning token (admin)
100
+ Body richiesto:
104
101
 
105
- ```ts
106
- export const generateToken = mutation({
107
- args: { email: v.string(), department: v.string() },
108
- handler: async (ctx, args) => {
109
- // Authenticate admin here
110
- return await bridge.generateProvisioningToken(ctx, {
111
- employeeEmail: args.email,
112
- department: args.department,
113
- createdBy: "admin@company.com",
114
- });
115
- },
116
- });
102
+ ```json
103
+ {
104
+ "functionKey": "cart.calculatePrice",
105
+ "args": { "cartId": "..." }
106
+ }
117
107
  ```
118
108
 
119
- ## How It Works
109
+ Risposta:
110
+
111
+ - successo: `{ "success": true, "result": ... }`
112
+ - errore: `{ "success": false, "error": "..." }`
120
113
 
121
- ### Agent Provisioning Flow
114
+ Codici principali: `401`, `403`, `404`, `429`, `500`.
122
115
 
123
- 1. **IT Admin** generates a Provisioning Token (APT) via the `generateProvisioningToken` method
124
- 2. **Employee** uses the APT to self-register on an app by calling `POST /agent-bridge/provision`
125
- 3. The component creates an agent record and returns an `instanceToken` (valid 24h)
126
- 4. The agent uses the `instanceToken` for all subsequent function calls
116
+ ## Setup OpenClaw multi-app (semplice su Railway)
127
117
 
128
- ### Function Execution Flow
118
+ Per un solo servizio OpenClaw che gestisce piu applicativi:
129
119
 
130
- 1. Agent sends `POST /agent-bridge/execute` with `{ instanceToken, functionName, args }`
131
- 2. The gateway validates the token, checks permissions via pattern matching
132
- 3. If authorized, executes the registered function handle and returns the result
133
- 4. All access attempts are logged to the audit table
120
+ 1. In Railway imposta solo:
121
+ - `AGENT_BRIDGE_SERVICE_KEY=<secret-unico>`
122
+ 2. In Convex registra un agente per app con `appKey` univoco:
123
+ - `crm`, `billing`, `warehouse`, ecc.
124
+ 3. OpenClaw invia per ogni chiamata:
125
+ - `X-Agent-Service-Key` (sempre uguale)
126
+ - `X-Agent-App` (varia per app target)
134
127
 
135
- ### Permission Pattern Matching
128
+ Puoi generare una service key con l'helper del package:
136
129
 
137
- Permissions use glob-style patterns with `*` wildcards:
130
+ ```ts
131
+ import { generateAgentBridgeServiceKey } from "@okrlinkhub/agent-bridge";
132
+
133
+ const serviceKey = generateAgentBridgeServiceKey(); // es: abs_live_<random>
134
+ ```
135
+
136
+ Vantaggi:
137
+ - controllo e debugging centralizzati nel bridge Convex;
138
+ - nessun invio multiplo di API key nelle request;
139
+ - rotazione e policy per app gestite nel bridge.
140
+
141
+ ## Gestione agenti e permessi
138
142
 
139
- | Pattern | Matches |
140
- |---------|---------|
141
- | `*` | Everything (catch-all) |
142
- | `okr:*` | All OKR functions |
143
- | `okr:read*` | `okr:readObjectives`, `okr:readKeyResults`, etc. |
144
- | `okr:createObjective` | Only this specific function |
143
+ Mutation/query del componente disponibili in `components.agentBridge`:
145
144
 
146
- More specific patterns take priority over wildcards. Default behavior when no pattern matches: **deny**.
145
+ - `agents.createAgent`
146
+ - `agents.updateAgent`
147
+ - `agents.rotateApiKey`
148
+ - `agents.listAgents`
149
+ - `gateway.authorizeByAppKey`
150
+ - `permissions.setAgentPermissions` (batch)
151
+ - `permissions.listAgentPermissions`
152
+ - `permissions.setFunctionOverrides` (batch)
153
+ - `permissions.listFunctionOverrides`
154
+ - `gateway.queryAccessLog`
147
155
 
148
- ## API Reference
156
+ ### Esempio permessi batch
149
157
 
150
- ### `AgentBridge` class
158
+ ```ts
159
+ await ctx.runMutation(components.agentBridge.permissions.setAgentPermissions, {
160
+ agentId,
161
+ rules: [
162
+ { pattern: "cart.*", permission: "allow" },
163
+ {
164
+ pattern: "okr.create",
165
+ permission: "rate_limited",
166
+ rateLimitConfig: { requestsPerHour: 60, tokenBudget: 50000 },
167
+ },
168
+ ],
169
+ availableFunctionKeys: Object.keys(config.functions),
170
+ });
171
+ ```
151
172
 
152
- | Method | Description |
153
- |--------|-------------|
154
- | `configure(ctx)` | Initialize component configuration |
155
- | `registerFunction(ctx, fn)` | Register a callable function |
156
- | `registerFunctions(ctx, fns)` | Bulk register functions |
157
- | `unregisterFunction(ctx, name)` | Remove a function |
158
- | `listFunctions(ctx)` | List registered functions |
159
- | `generateProvisioningToken(ctx, opts)` | Create an APT (admin) |
160
- | `listAgents(ctx)` | List registered agents |
161
- | `revokeAgent(ctx, opts)` | Revoke an agent globally |
162
- | `revokeAppInstance(ctx, opts)` | Revoke a specific app instance |
163
- | `setPermission(ctx, opts)` | Set/update a permission |
164
- | `removePermission(ctx, opts)` | Remove a permission |
165
- | `listPermissions(ctx, agentId)` | List agent permissions |
166
- | `queryAccessLog(ctx, opts)` | Query audit logs |
173
+ ## Migrazione 0.2 -> next major
167
174
 
168
- ### `registerRoutes(http, component, config)`
175
+ Breaking changes principali:
169
176
 
170
- Registers HTTP endpoints on the host app's router:
177
+ - rimosso il flusso provisioning token/instance token;
178
+ - rimossa la registrazione runtime delle funzioni via `createFunctionHandle`;
179
+ - rimosso l’uso della classe `AgentBridge` legacy.
171
180
 
172
- - `POST /agent-bridge/execute` -- Execute a registered function
173
- - `POST /agent-bridge/provision` -- Agent self-provisioning
174
- - `GET /agent-bridge/health` -- Health check
181
+ Nuovo flusso:
175
182
 
176
- See [example/convex/example.ts](./example/convex/example.ts) for a complete working example.
183
+ 1. config funzioni in `agent-bridge.config.ts`;
184
+ 2. auth via `X-Agent-API-Key` (legacy) oppure `X-Agent-Service-Key + X-Agent-App` (multi-app);
185
+ 3. policy in batch via mutation del componente;
186
+ 4. log centralizzato in `agentLogs`.
177
187
 
178
- ## Development
188
+ ## Sviluppo locale
179
189
 
180
190
  ```sh
181
191
  npm i
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":""}
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ import { access, mkdir, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ const cwd = process.cwd();
5
+ async function exists(targetPath) {
6
+ try {
7
+ await access(targetPath);
8
+ return true;
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ }
14
+ async function writeIfMissing(relativePath, content) {
15
+ const absolutePath = path.join(cwd, relativePath);
16
+ if (await exists(absolutePath)) {
17
+ return "skipped";
18
+ }
19
+ await mkdir(path.dirname(absolutePath), { recursive: true });
20
+ await writeFile(absolutePath, content, "utf8");
21
+ return "created";
22
+ }
23
+ const configTemplate = `import { api } from "./convex/_generated/api";
24
+ import { defineAgentBridgeConfig } from "@okrlinkhub/agent-bridge";
25
+
26
+ export default defineAgentBridgeConfig({
27
+ functions: {
28
+ "cart.calculatePrice": {
29
+ ref: api.cart.calculatePrice,
30
+ type: "query",
31
+ },
32
+ "cart.applyDiscount": {
33
+ ref: api.cart.applyDiscount,
34
+ type: "mutation",
35
+ },
36
+ },
37
+ metadata: {
38
+ "cart.calculatePrice": {
39
+ description: "Calcola il prezzo totale del carrello",
40
+ riskLevel: "low",
41
+ category: "commerce",
42
+ },
43
+ },
44
+ });
45
+ `;
46
+ const bridgeHttpTemplate = `import { registerRoutes } from "@okrlinkhub/agent-bridge";
47
+ import { components } from "./_generated/api";
48
+ import config from "../agent-bridge.config";
49
+
50
+ export function registerAgentBridgeRoutes(
51
+ http: Parameters<typeof registerRoutes>[0],
52
+ ) {
53
+ registerRoutes(http, components.agentBridge, config, {
54
+ pathPrefix: "/agent",
55
+ serviceKey:
56
+ (globalThis as { process?: { env?: Record<string, string> } }).process?.env
57
+ ?.AGENT_BRIDGE_SERVICE_KEY,
58
+ });
59
+ }
60
+ `;
61
+ const integrationNotes = `
62
+ [agent-bridge] Init completed.
63
+
64
+ Next steps:
65
+ 1) Add component in convex/convex.config.ts:
66
+
67
+ import { defineApp } from "convex/server";
68
+ import agentBridge from "@okrlinkhub/agent-bridge/convex.config.js";
69
+
70
+ const app = defineApp();
71
+ app.use(agentBridge);
72
+ export default app;
73
+
74
+ 2) Mount routes in convex/http.ts:
75
+
76
+ import { httpRouter } from "convex/server";
77
+ import { registerAgentBridgeRoutes } from "./agentBridge";
78
+
79
+ const http = httpRouter();
80
+ registerAgentBridgeRoutes(http);
81
+ export default http;
82
+
83
+ 3) Create agents and permissions with component mutations:
84
+ - components.agentBridge.agents.createAgent
85
+ - components.agentBridge.permissions.setAgentPermissions
86
+ - components.agentBridge.permissions.setFunctionOverrides
87
+
88
+ 4) For multi-app OpenClaw deployments, set one service secret in Railway:
89
+ - AGENT_BRIDGE_SERVICE_KEY=<shared-secret>
90
+ - OpenClaw sends X-Agent-Service-Key and X-Agent-App headers
91
+ - Bridge resolves app -> agent internally (keep legacy X-Agent-API-Key for compatibility)
92
+ `;
93
+ async function main() {
94
+ const commandArg = process.argv[2];
95
+ if (commandArg && commandArg !== "init") {
96
+ console.error(`[agent-bridge] Unknown command "${commandArg}".`);
97
+ console.error("Usage: npx @okrlinkhub/agent-bridge init");
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+ const configResult = await writeIfMissing("agent-bridge.config.ts", configTemplate);
102
+ const bridgeResult = await writeIfMissing("convex/agentBridge.ts", bridgeHttpTemplate);
103
+ console.log(`[agent-bridge] agent-bridge.config.ts: ${configResult === "created" ? "created" : "skipped (already exists)"}`);
104
+ console.log(`[agent-bridge] convex/agentBridge.ts: ${bridgeResult === "created" ? "created" : "skipped (already exists)"}`);
105
+ console.log(integrationNotes.trim());
106
+ }
107
+ void main();
108
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;AAE1B,KAAK,UAAU,MAAM,CAAC,UAAkB;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,YAAoB,EACpB,OAAe;IAEf,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAClD,IAAI,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBtB,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;CAc1B,CAAC;AAEF,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BxB,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,UAAU,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,mCAAmC,UAAU,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,wBAAwB,EAAE,cAAc,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,CAAC;IAEvF,OAAO,CAAC,GAAG,CACT,0CAA0C,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,0BAA0B,EAAE,CAChH,CAAC;IACF,OAAO,CAAC,GAAG,CACT,yCAAyC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,0BAA0B,EAAE,CAC/G,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}