@diegoaltoworks/chatter 0.12.0 → 0.14.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.
@@ -3,6 +3,6 @@
3
3
  *
4
4
  * Re-exports authentication-related classes and functions.
5
5
  */
6
- export { ApiKeyManager } from "./apikeys";
7
6
  export type { ApiKeyOptions, ApiKeyPayload, VerifyResult } from "./apikeys";
7
+ export { ApiKeyManager } from "./apikeys";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/auth/apikeys.ts
5
+ var import_node_crypto = require("node:crypto");
6
+ var import_jose = require("jose");
7
+ var ApiKeyManager = class {
8
+ constructor(secret) {
9
+ this.secret = secret;
10
+ if (!secret) {
11
+ throw new Error("API key secret is required");
12
+ }
13
+ this.secretBytes = new TextEncoder().encode(secret);
14
+ }
15
+ secret;
16
+ secretBytes;
17
+ /**
18
+ * Create a new API key
19
+ *
20
+ * @param options - API key options
21
+ * @returns JWT token string
22
+ */
23
+ async create(options = {}) {
24
+ const keyId = (0, import_node_crypto.randomUUID)();
25
+ const keyName = options.name || "api-key";
26
+ const expiresIn = options.expiresIn || "365d";
27
+ const expirationMs = this.parseExpiration(expiresIn);
28
+ const expiresAt = new Date(Date.now() + expirationMs);
29
+ const jwt = await new import_jose.SignJWT({
30
+ name: keyName,
31
+ type: "api_key",
32
+ ...options.claims
33
+ }).setProtectedHeader({ alg: "HS256" }).setSubject(keyId).setIssuedAt().setExpirationTime(expiresAt).sign(this.secretBytes);
34
+ return jwt;
35
+ }
36
+ /**
37
+ * Verify an API key
38
+ *
39
+ * @param token - JWT token to verify
40
+ * @returns Verification result with payload if valid
41
+ */
42
+ async verify(token) {
43
+ try {
44
+ const { payload } = await (0, import_jose.jwtVerify)(token, this.secretBytes);
45
+ if (payload.type !== "api_key") {
46
+ return {
47
+ valid: false,
48
+ error: "Token is not an API key"
49
+ };
50
+ }
51
+ return {
52
+ valid: true,
53
+ payload
54
+ };
55
+ } catch (error) {
56
+ return {
57
+ valid: false,
58
+ error: error instanceof Error ? error.message : "Verification failed"
59
+ };
60
+ }
61
+ }
62
+ /**
63
+ * Parse expiration string to milliseconds
64
+ *
65
+ * @param expiresIn - Time string (e.g., "1y", "30d", "12h")
66
+ * @returns Milliseconds
67
+ */
68
+ parseExpiration(expiresIn) {
69
+ const match = expiresIn.match(/^(\d+)([smhdMy])$/);
70
+ if (!match) {
71
+ throw new Error(
72
+ `Invalid expiration format: ${expiresIn}. Supported: s (seconds), m (minutes), h (hours), d (days), M (months), y (years)`
73
+ );
74
+ }
75
+ const value = Number.parseInt(match[1], 10);
76
+ const unit = match[2];
77
+ switch (unit) {
78
+ case "s":
79
+ return value * 1e3;
80
+ case "m":
81
+ return value * 60 * 1e3;
82
+ case "h":
83
+ return value * 60 * 60 * 1e3;
84
+ case "d":
85
+ return value * 24 * 60 * 60 * 1e3;
86
+ case "M":
87
+ return value * 30 * 24 * 60 * 60 * 1e3;
88
+ // Approximate 30 days
89
+ case "y":
90
+ return value * 365 * 24 * 60 * 60 * 1e3;
91
+ // Approximate 365 days
92
+ default:
93
+ throw new Error(`Unknown time unit: ${unit}`);
94
+ }
95
+ }
96
+ /**
97
+ * Get information about a token without verifying signature
98
+ * Useful for debugging
99
+ *
100
+ * @param token - JWT token
101
+ * @returns Decoded payload (unverified)
102
+ */
103
+ decode(token) {
104
+ try {
105
+ const parts = token.split(".");
106
+ if (parts.length !== 3) {
107
+ return null;
108
+ }
109
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
110
+ return payload;
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
115
+ };
116
+
117
+ // bin/create-apikey.ts
118
+ async function main() {
119
+ const args = process.argv.slice(2);
120
+ const options = {};
121
+ for (let i = 0; i < args.length; i++) {
122
+ if (args[i] === "--name" && args[i + 1]) {
123
+ options.name = args[i + 1];
124
+ i++;
125
+ } else if (args[i] === "--expires-in" && args[i + 1]) {
126
+ options.expiresIn = args[i + 1];
127
+ i++;
128
+ } else if (args[i] === "--help" || args[i] === "-h") {
129
+ console.log(`
130
+ Chatter API Key Generator
131
+
132
+ Usage:
133
+ npx chatter create-apikey [options]
134
+
135
+ Options:
136
+ --name <name> Name/label for the API key (default: "api-key")
137
+ --expires-in <time> Expiration time (default: "365d")
138
+ Formats: s=seconds, m=minutes, h=hours, d=days, M=months, y=years
139
+ Examples: 30d, 12h, 1y, 6M
140
+
141
+ Environment:
142
+ CHATTER_SECRET Required. Secret key for signing JWT tokens
143
+
144
+ Examples:
145
+ npx chatter create-apikey --name "mobile-app" --expires-in 365d
146
+ npx chatter create-apikey --name "test-key" --expires-in 1h
147
+ `);
148
+ process.exit(0);
149
+ }
150
+ }
151
+ const secret = process.env.CHATTER_SECRET;
152
+ if (!secret) {
153
+ console.error("\u274C Error: CHATTER_SECRET environment variable is not set");
154
+ console.error("\n Please set it before running this command:");
155
+ console.error(" export CHATTER_SECRET=your-secret-key-here");
156
+ console.error("\n Or prefix the command:");
157
+ console.error(" CHATTER_SECRET=your-secret npx chatter create-apikey\n");
158
+ process.exit(1);
159
+ }
160
+ const manager = new ApiKeyManager(secret);
161
+ const keyName = options.name || "api-key";
162
+ const expiresIn = options.expiresIn || "365d";
163
+ try {
164
+ const apiKey = await manager.create({
165
+ name: keyName,
166
+ expiresIn
167
+ });
168
+ const payload = manager.decode(apiKey);
169
+ if (!payload) {
170
+ throw new Error("Failed to decode generated API key");
171
+ }
172
+ const expiresAt = new Date((payload.exp || 0) * 1e3);
173
+ const issuedAt = new Date((payload.iat || 0) * 1e3);
174
+ console.log("\n\u2705 API Key generated successfully!\n");
175
+ console.log(` Name: ${keyName}`);
176
+ console.log(` ID: ${payload.sub}`);
177
+ console.log(` Issued: ${issuedAt.toISOString()}`);
178
+ console.log(` Expires: ${expiresAt.toISOString()} (${expiresIn})`);
179
+ console.log(`
180
+ API Key:
181
+ ${apiKey}
182
+ `);
183
+ console.log(" Usage:");
184
+ console.log(" curl -X POST https://your-bot.example.com/api/public/chat \\");
185
+ console.log(` -H "x-api-key: ${apiKey.slice(0, 50)}..." \\`);
186
+ console.log(' -H "Content-Type: application/json" \\');
187
+ console.log(` -d '{"message": "Hello"}'`);
188
+ console.log("");
189
+ } catch (error) {
190
+ console.error("\u274C Error creating API key:", error);
191
+ process.exit(1);
192
+ }
193
+ }
194
+ main();
@@ -2,6 +2,6 @@
2
2
  * Client library entry point
3
3
  * Re-exports all client widgets and types
4
4
  */
5
- export { ChatBot, Chat, ChatButton } from "./src";
6
- export type { ChatBotConfig, ChatConfig, ChatButtonConfig, ChatMessage, ChatMode, StreamCallbacks, } from "./src/types";
5
+ export { Chat, ChatBot, ChatButton } from "./src";
6
+ export type { ChatBotConfig, ChatButtonConfig, ChatConfig, ChatMessage, ChatMode, StreamCallbacks, } from "./src/types";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,YAAY,EACV,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,eAAe,GAChB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,eAAe,GAChB,MAAM,aAAa,CAAC"}
@@ -14,5 +14,5 @@ declare global {
14
14
  };
15
15
  }
16
16
  }
17
- export { ChatBot, Chat, ChatButton };
17
+ export { Chat, ChatBot, ChatButton };
18
18
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/client/src/browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,EAAE;YACP,OAAO,EAAE,OAAO,OAAO,CAAC;YACxB,IAAI,EAAE,OAAO,IAAI,CAAC;YAClB,UAAU,EAAE,OAAO,UAAU,CAAC;SAC/B,CAAC;KACH;CACF;AAWD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/client/src/browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,EAAE;YACP,OAAO,EAAE,OAAO,OAAO,CAAC;YACxB,IAAI,EAAE,OAAO,IAAI,CAAC;YAClB,UAAU,EAAE,OAAO,UAAU,CAAC;SAC/B,CAAC;KACH;CACF;AAWD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -2,8 +2,8 @@
2
2
  * @diegoaltoworks/chatter
3
3
  * Isomorphic TypeScript chatbot client for AI chat API
4
4
  */
5
- export { ChatBot } from "./ChatBot";
6
5
  export { Chat } from "./Chat";
6
+ export { ChatBot } from "./ChatBot";
7
7
  export { ChatButton } from "./ChatButton";
8
- export type { ChatMode, ChatBotConfig, ChatMessage, ChatResponse, StreamCallbacks, ChatConfig, ChatButtonConfig, } from "./types";
8
+ export type { ChatBotConfig, ChatButtonConfig, ChatConfig, ChatMessage, ChatMode, ChatResponse, StreamCallbacks, } from "./types";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EACV,QAAQ,EACR,aAAa,EACb,WAAW,EACX,YAAY,EACZ,eAAe,EACf,UAAU,EACV,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,eAAe,GAChB,MAAM,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"widgets.d.ts","sourceRoot":"","sources":["../../src/core/widgets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,gBAAgB,CA4BxE"}
1
+ {"version":3,"file":"widgets.d.ts","sourceRoot":"","sources":["../../src/core/widgets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAwBxE"}
package/dist/index.d.ts CHANGED
@@ -10,28 +10,27 @@
10
10
  *
11
11
  * @packageDocumentation
12
12
  */
13
- export { createServer } from "./server";
14
- export type { ChatterConfig, ServerDependencies } from "./types";
15
- export { createMCPServer } from "./mcp-server";
16
- export type { MCPServerOptions, MCPTransportMode } from "./mcp-server";
17
- export { VectorStore } from "./core/retrieval";
13
+ export type { ApiKeyOptions, ApiKeyPayload, VerifyResult } from "./auth";
14
+ export { ApiKeyManager } from "./auth";
15
+ export type { ChatBotConfig, ChatButtonConfig, ChatConfig, ChatMessage, ChatMode, StreamCallbacks, } from "./client";
16
+ export { Chat, ChatBot, ChatButton } from "./client";
17
+ export { detectLeakage, scrubOutput } from "./core/guardrails";
18
18
  export { completeOnce, completeStream } from "./core/llm";
19
19
  export { loadKnowledge } from "./core/loaders";
20
20
  export { PromptLoader } from "./core/prompts";
21
- export { detectLeakage, scrubOutput } from "./core/guardrails";
22
- export { createSession, validateSession, getSessionInfo, getActiveSessions, } from "./core/session";
23
- export { ApiKeyManager } from "./auth";
24
- export type { ApiKeyOptions, ApiKeyPayload, VerifyResult } from "./auth";
21
+ export { VectorStore } from "./core/retrieval";
22
+ export { createSession, getActiveSessions, getSessionInfo, validateSession, } from "./core/session";
23
+ export type { MCPServerOptions, MCPTransportMode } from "./mcp-server";
24
+ export { createMCPServer } from "./mcp-server";
25
25
  export { createAuthMiddleware } from "./middleware/auth";
26
- export { createJWTMiddleware } from "./middleware/jwt";
27
26
  export { cors } from "./middleware/cors";
27
+ export { createJWTMiddleware } from "./middleware/jwt";
28
28
  export { createRateLimiter } from "./middleware/ratelimit";
29
29
  export { createReferrerCheck } from "./middleware/referrer";
30
30
  export { createSessionMiddleware } from "./middleware/session";
31
- export { publicRoutes } from "./routes/public";
32
- export { privateRoutes } from "./routes/private";
33
31
  export { demoRoutes } from "./routes/demo";
34
- export { ChatBot, Chat, ChatButton } from "./client";
35
- export type { ChatBotConfig, ChatConfig, ChatButtonConfig, ChatMessage, ChatMode, StreamCallbacks, } from "./client";
36
- export type { BotIdentity, BotBranding, BotChatConfig, KnowledgeDocument, EmbeddingChunk, } from "./types";
32
+ export { privateRoutes } from "./routes/private";
33
+ export { publicRoutes } from "./routes/public";
34
+ export { createServer } from "./server";
35
+ export type { BotBranding, BotChatConfig, BotIdentity, ChatterConfig, EmbeddingChunk, KnowledgeDocument, ServerDependencies, } from "./types";
37
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGjE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGvE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EACL,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EACV,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,eAAe,GAChB,MAAM,UAAU,CAAC;AAGlB,YAAY,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,eAAe,GAChB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,YAAY,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,SAAS,CAAC"}