@yungho/noclaw-channel 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,109 @@
1
+ # @yungho/noclaw-channel
2
+
3
+ NoClaw Channel Server — WebSocket IPC bridge that connects external chat platforms (WeChat, Telegram) to [NoClaw](https://github.com/noclaw/noclaw) for Obsidian.
4
+
5
+ ## How It Works
6
+
7
+ ```
8
+ Phone (WeChat/Telegram)
9
+ ↕ HTTP Long Polling
10
+ @noclaw/channel (this package)
11
+ ↕ WebSocket (ws://127.0.0.1:8123)
12
+ NoClaw Plugin (Obsidian)
13
+ ```
14
+
15
+ The Channel Server runs as a standalone Node.js process. It handles communication with external chat platforms and bridges messages to the NoClaw Obsidian plugin via WebSocket.
16
+
17
+ ## Requirements
18
+
19
+ - **Node.js** >= 18
20
+ - **NoClaw** plugin installed in Obsidian
21
+
22
+ ## Installation
23
+
24
+ ### Option A — npx (no install required)
25
+
26
+ ```bash
27
+ npx @yungho/noclaw-channel start
28
+ ```
29
+
30
+ ### Option B — global install (recommended for daily use)
31
+
32
+ ```bash
33
+ npm i -g @yungho/noclaw-channel
34
+ noclaw-channel start
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Start the server
40
+
41
+ ```bash
42
+ # Default (ws://127.0.0.1:8123)
43
+ noclaw-channel start
44
+
45
+ # Custom port
46
+ noclaw-channel start --port=9000
47
+
48
+ # Custom host
49
+ noclaw-channel start --host=0.0.0.0
50
+ ```
51
+
52
+ ### Other commands
53
+
54
+ ```bash
55
+ noclaw-channel status # Check if server is running
56
+ noclaw-channel stop # Stop the server
57
+ noclaw-channel setup # Interactive configuration wizard
58
+ ```
59
+
60
+ ## Connecting to NoClaw
61
+
62
+ 1. Start the Channel Server in your terminal
63
+ 2. Open Obsidian → Settings → NoClaw → Chat Channels
64
+ 3. Enable "Chat Channels"
65
+ 4. Click "Connect"
66
+ 5. For WeChat: scan the QR code shown in the terminal
67
+
68
+ ## Supported Platforms
69
+
70
+ | Platform | Status | Auth Method |
71
+ |----------|--------|-------------|
72
+ | WeChat | ✅ Working | QR Code (ClawBot ilink API) |
73
+ | Telegram | 🔜 Planned | Bot Token |
74
+
75
+ ## Configuration
76
+
77
+ The server stores its config at `~/.noclaw/channel-config.json`:
78
+
79
+ ```json
80
+ {
81
+ "port": 8123,
82
+ "host": "127.0.0.1",
83
+ "logLevel": "info",
84
+ "wechat": {
85
+ "enabled": true,
86
+ "permissions": {
87
+ "chat": "all",
88
+ "executeTools": true,
89
+ "permissionRelay": true,
90
+ "adminUsers": []
91
+ }
92
+ },
93
+ "telegram": {
94
+ "enabled": false,
95
+ "botToken": "",
96
+ "allowedUsers": [],
97
+ "permissions": {
98
+ "chat": "whitelist",
99
+ "executeTools": true,
100
+ "permissionRelay": true,
101
+ "adminUsers": []
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ## License
108
+
109
+ Apache-2.0
package/bin/cli.js ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { ChannelServer } from '../dist/server/ChannelServer.js';
4
+ import { ConfigManager } from '../dist/config/ConfigManager.js';
5
+ import { Logger } from '../dist/utils/Logger.js';
6
+
7
+ const loggerWrapper = new Logger();
8
+ const logger = loggerWrapper.getPinoLogger();
9
+
10
+ program
11
+ .name('noclaw-channel')
12
+ .description('NoClaw Channel Server - WebSocket IPC bridge for external chat platforms')
13
+ .version('0.1.0');
14
+
15
+ program
16
+ .command('start')
17
+ .description('Start the channel server')
18
+ .option('--port <port>', 'WebSocket port (default: 8123)', '8123')
19
+ .option('--host <host>', 'WebSocket host (default: 127.0.0.1)', '127.0.0.1')
20
+ .option('--background', 'Run as background process', false)
21
+ .action(async (options) => {
22
+ try {
23
+ const config = new ConfigManager();
24
+ const server = new ChannelServer(config, logger);
25
+
26
+ await server.start({
27
+ port: parseInt(options.port),
28
+ host: options.host,
29
+ background: options.background
30
+ });
31
+
32
+ logger.info('Channel server started successfully');
33
+ } catch (error) {
34
+ logger.error('Failed to start server:', error);
35
+ process.exit(1);
36
+ }
37
+ });
38
+
39
+ program
40
+ .command('stop')
41
+ .description('Stop the channel server')
42
+ .action(async () => {
43
+ try {
44
+ const config = new ConfigManager();
45
+ await config.stopChannel();
46
+ logger.info('Channel server stopped');
47
+ } catch (error) {
48
+ logger.error('Failed to stop server:', error);
49
+ process.exit(1);
50
+ }
51
+ });
52
+
53
+ program
54
+ .command('status')
55
+ .description('Check the status of the channel server')
56
+ .action(async () => {
57
+ try {
58
+ const config = new ConfigManager();
59
+ const status = await config.getStatus();
60
+ logger.info('Channel server status:', status);
61
+ } catch (error) {
62
+ logger.error('Failed to get status:', error);
63
+ process.exit(1);
64
+ }
65
+ });
66
+
67
+ program
68
+ .command('setup')
69
+ .description('Setup the channel server configuration')
70
+ .action(async () => {
71
+ try {
72
+ const config = new ConfigManager();
73
+ await config.interactiveSetup();
74
+ logger.info('Setup completed successfully');
75
+ } catch (error) {
76
+ logger.error('Setup failed:', error);
77
+ process.exit(1);
78
+ }
79
+ });
80
+
81
+ program.parse();
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Telegram Channel Implementation
3
+ *
4
+ * Uses Telegram Bot API for message communication.
5
+ * This is a placeholder implementation for future use.
6
+ */
7
+ import { IChannel, IpcMessage, TelegramConfig, ChannelStatus, ChannelCapabilities, MediaObject } from '../types.js';
8
+ import pino from 'pino';
9
+ export declare class TelegramChannel implements IChannel {
10
+ private readonly baseUrl;
11
+ private config;
12
+ private logger;
13
+ private status;
14
+ private pollingInterval?;
15
+ private messageCallback?;
16
+ private statusCallbacks;
17
+ private qrCodeCallbacks;
18
+ private lastUpdateId;
19
+ private readonly POLLING_INTERVAL;
20
+ constructor(config: TelegramConfig, logger: pino.Logger);
21
+ connect(): Promise<void>;
22
+ disconnect(): Promise<void>;
23
+ send(text: string, contextToken: string, media?: MediaObject[]): Promise<void>;
24
+ onMessage(callback: (msg: IpcMessage) => void): void;
25
+ getStatus(): ChannelStatus;
26
+ getCapabilities(): ChannelCapabilities;
27
+ onStatusChange(callback: (status: ChannelStatus) => void): void;
28
+ requestQrCode(): void;
29
+ onQrCode(callback: (qrCodeUrl: string) => void): void;
30
+ /**
31
+ * Start polling for incoming messages
32
+ */
33
+ private startMessagePolling;
34
+ /**
35
+ * Stop all polling
36
+ */
37
+ private stopPolling;
38
+ /**
39
+ * Send text message
40
+ */
41
+ private sendMessage;
42
+ /**
43
+ * Send photo
44
+ */
45
+ private sendPhoto;
46
+ /**
47
+ * Make HTTP request to Telegram API
48
+ */
49
+ private makeRequest;
50
+ /**
51
+ * Update connection status
52
+ */
53
+ private setStatus;
54
+ /**
55
+ * Notify listeners about QR code
56
+ */
57
+ private notifyQrCode;
58
+ }
59
+ //# sourceMappingURL=TelegramChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelegramChannel.d.ts","sourceRoot":"","sources":["../../src/channels/TelegramChannel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,IAAI,MAAM,MAAM,CAAC;AAqCxB,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,eAAe,CAAC,CAA4B;IACpD,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;gBAE7B,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM;IAMjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpF,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAIpD,SAAS,IAAI,aAAa;IAI1B,eAAe,IAAI,mBAAmB;IAUtC,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAI/D,aAAa,IAAI,IAAI;IAKrB,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIrD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA+C3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;YACW,WAAW;IAyBzB;;OAEG;YACW,SAAS;IA2BvB;;OAEG;YACW,WAAW;IAYzB;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;OAEG;IACH,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Telegram Channel Implementation
3
+ *
4
+ * Uses Telegram Bot API for message communication.
5
+ * This is a placeholder implementation for future use.
6
+ */
7
+ export class TelegramChannel {
8
+ baseUrl;
9
+ config;
10
+ logger;
11
+ status = 'disconnected';
12
+ pollingInterval;
13
+ messageCallback;
14
+ statusCallbacks = new Set();
15
+ qrCodeCallbacks = new Set();
16
+ lastUpdateId = 0;
17
+ POLLING_INTERVAL = 2000; // 2 seconds
18
+ constructor(config, logger) {
19
+ this.config = config;
20
+ this.baseUrl = `https://api.telegram.org/bot${config.botToken}`;
21
+ this.logger = logger.child({ channel: 'telegram' });
22
+ }
23
+ async connect() {
24
+ if (!this.config.enabled) {
25
+ this.logger.warn('Telegram channel is disabled in config');
26
+ return;
27
+ }
28
+ this.setStatus('connecting');
29
+ try {
30
+ // Test token by making a request
31
+ const response = await this.makeRequest('/getUpdates', {
32
+ method: 'GET',
33
+ });
34
+ if (!response.ok) {
35
+ throw new Error('Invalid bot token or API error');
36
+ }
37
+ this.startMessagePolling();
38
+ this.setStatus('connected');
39
+ this.logger.info('Connected to Telegram Bot API');
40
+ }
41
+ catch (error) {
42
+ this.logger.error({ error }, 'Failed to connect to Telegram');
43
+ this.setStatus('error');
44
+ throw error;
45
+ }
46
+ }
47
+ async disconnect() {
48
+ this.stopPolling();
49
+ this.setStatus('disconnected');
50
+ this.logger.info('Disconnected from Telegram');
51
+ }
52
+ async send(text, contextToken, media) {
53
+ try {
54
+ const chatId = contextToken.replace('tg_', '');
55
+ if (media && media.length > 0) {
56
+ // Send media first
57
+ for (const item of media) {
58
+ if (item.type === 'image') {
59
+ await this.sendPhoto(chatId, item.data, text);
60
+ break; // Only send first image for now
61
+ }
62
+ }
63
+ }
64
+ else {
65
+ // Send text message
66
+ await this.sendMessage(chatId, text);
67
+ }
68
+ this.logger.debug({ chatId, textLength: text.length }, 'Message sent to Telegram');
69
+ }
70
+ catch (error) {
71
+ this.logger.error({ error, contextToken }, 'Failed to send message to Telegram');
72
+ throw error;
73
+ }
74
+ }
75
+ onMessage(callback) {
76
+ this.messageCallback = callback;
77
+ }
78
+ getStatus() {
79
+ return this.status;
80
+ }
81
+ getCapabilities() {
82
+ return {
83
+ textMessaging: true,
84
+ mediaSharing: true,
85
+ permissionRelay: true,
86
+ richFormatting: true,
87
+ webhooks: false,
88
+ };
89
+ }
90
+ onStatusChange(callback) {
91
+ this.statusCallbacks.add(callback);
92
+ }
93
+ requestQrCode() {
94
+ // Telegram uses bot token, not QR code
95
+ this.logger.info('Telegram uses bot token authentication, no QR code');
96
+ }
97
+ onQrCode(callback) {
98
+ this.qrCodeCallbacks.add(callback);
99
+ }
100
+ /**
101
+ * Start polling for incoming messages
102
+ */
103
+ startMessagePolling() {
104
+ this.stopPolling(); // Clear any existing polling
105
+ this.pollingInterval = setInterval(async () => {
106
+ try {
107
+ const response = await this.makeRequest(`/getUpdates?offset=${this.lastUpdateId}`, {
108
+ method: 'GET',
109
+ });
110
+ if (response.result && response.result.length > 0) {
111
+ this.logger.debug({ messageCount: response.result.length }, 'Received messages from Telegram');
112
+ for (const update of response.result) {
113
+ // Update last update ID
114
+ this.lastUpdateId = update.update_id;
115
+ // Emit message to callback
116
+ if (update.message?.text) {
117
+ this.messageCallback?.({
118
+ type: 'MSG_IN',
119
+ platform: 'telegram',
120
+ content: update.message.text,
121
+ contextToken: `tg_${update.message.chat.id}`,
122
+ userId: String(update.message.from.id),
123
+ metadata: {
124
+ timestamp: Date.now(),
125
+ platform: 'telegram',
126
+ userId: String(update.message.from.id),
127
+ messageId: String(update.message.message_id),
128
+ },
129
+ });
130
+ }
131
+ }
132
+ }
133
+ }
134
+ catch (error) {
135
+ this.logger.error({ error }, 'Error polling for messages');
136
+ // Don't stop polling on error, just log it
137
+ }
138
+ }, this.POLLING_INTERVAL);
139
+ }
140
+ /**
141
+ * Stop all polling
142
+ */
143
+ stopPolling() {
144
+ if (this.pollingInterval) {
145
+ clearInterval(this.pollingInterval);
146
+ this.pollingInterval = undefined;
147
+ }
148
+ }
149
+ /**
150
+ * Send text message
151
+ */
152
+ async sendMessage(chatId, text) {
153
+ const url = `${this.baseUrl}/sendMessage`;
154
+ const body = JSON.stringify({
155
+ chat_id: parseInt(chatId),
156
+ text,
157
+ });
158
+ const response = await fetch(url, {
159
+ method: 'POST',
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ },
163
+ body,
164
+ });
165
+ if (!response.ok) {
166
+ throw new Error(`Failed to send message: ${response.statusText}`);
167
+ }
168
+ const data = await response.json();
169
+ if (!data.ok) {
170
+ throw new Error('Failed to send message');
171
+ }
172
+ }
173
+ /**
174
+ * Send photo
175
+ */
176
+ async sendPhoto(chatId, photoData, caption) {
177
+ const url = `${this.baseUrl}/sendPhoto`;
178
+ const formData = new FormData();
179
+ formData.append('chat_id', chatId);
180
+ const buffer = Buffer.from(photoData, 'base64');
181
+ const blob = new Blob([buffer], { type: 'image/jpeg' });
182
+ formData.append('photo', blob, 'photo.jpg');
183
+ if (caption) {
184
+ formData.append('caption', caption);
185
+ }
186
+ const response = await fetch(url, {
187
+ method: 'POST',
188
+ body: formData,
189
+ });
190
+ if (!response.ok) {
191
+ throw new Error(`Failed to send photo: ${response.statusText}`);
192
+ }
193
+ const data = await response.json();
194
+ if (!data.ok) {
195
+ throw new Error('Failed to send photo');
196
+ }
197
+ }
198
+ /**
199
+ * Make HTTP request to Telegram API
200
+ */
201
+ async makeRequest(endpoint, options) {
202
+ const url = `${this.baseUrl}${endpoint}`;
203
+ const response = await fetch(url, options);
204
+ if (!response.ok) {
205
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
206
+ }
207
+ return await response.json();
208
+ }
209
+ /**
210
+ * Update connection status
211
+ */
212
+ setStatus(status) {
213
+ this.status = status;
214
+ this.statusCallbacks.forEach((callback) => callback(status));
215
+ }
216
+ /**
217
+ * Notify listeners about QR code
218
+ */
219
+ notifyQrCode(qrCodeUrl) {
220
+ this.qrCodeCallbacks.forEach((callback) => callback(qrCodeUrl));
221
+ }
222
+ }
223
+ //# sourceMappingURL=TelegramChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelegramChannel.js","sourceRoot":"","sources":["../../src/channels/TelegramChannel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * WeChat Channel Implementation
3
+ *
4
+ * Uses WeChat's official ClawBot ilink API for safe, official integration
5
+ * without risk of account suspension.
6
+ */
7
+ import { IChannel, IpcMessage, WechatConfig, ChannelStatus, ChannelCapabilities, MediaObject } from '../types.js';
8
+ import pino from 'pino';
9
+ export declare class WechatChannel implements IChannel {
10
+ private readonly baseUrl;
11
+ private readonly defaultBaseUrl;
12
+ private botToken?;
13
+ private config;
14
+ private logger;
15
+ private status;
16
+ private pollingInterval?;
17
+ private qrCodePollingInterval?;
18
+ private messageCallback?;
19
+ private statusCallbacks;
20
+ private qrCodeCallbacks;
21
+ private lastQrCodeUrl?;
22
+ private lastUpdateId;
23
+ private readonly POLLING_INTERVAL;
24
+ private readonly QR_CODE_POLLING_INTERVAL;
25
+ private readonly LONG_POLLING_TIMEOUT;
26
+ constructor(config: WechatConfig, logger: pino.Logger);
27
+ connect(): Promise<void>;
28
+ disconnect(): Promise<void>;
29
+ send(text: string, contextToken: string, media?: MediaObject[]): Promise<void>;
30
+ onMessage(callback: (msg: IpcMessage) => void): void;
31
+ getStatus(): ChannelStatus;
32
+ getCapabilities(): ChannelCapabilities;
33
+ onStatusChange(callback: (status: ChannelStatus) => void): void;
34
+ requestQrCode(): void;
35
+ onQrCode(callback: (qrCodeUrl: string) => void): void;
36
+ /**
37
+ * Authenticate with WeChat using QR code
38
+ */
39
+ private authenticateWithQrCode;
40
+ /**
41
+ * Poll for QR code scan status
42
+ */
43
+ private pollQrCodeStatus;
44
+ /**
45
+ * Start polling for incoming messages
46
+ */
47
+ private startMessagePolling;
48
+ /**
49
+ * Stop all polling
50
+ */
51
+ private stopPolling;
52
+ /**
53
+ * Make HTTP request to WeChat API
54
+ */
55
+ private makeRequest;
56
+ /**
57
+ * Update connection status
58
+ */
59
+ private setStatus;
60
+ /**
61
+ * Notify listeners about QR code
62
+ */
63
+ private notifyQrCode;
64
+ }
65
+ //# sourceMappingURL=WechatChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WechatChannel.d.ts","sourceRoot":"","sources":["../../src/channels/WechatChannel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClH,OAAO,IAAI,MAAM,MAAM,CAAC;AA8BxB,qBAAa,aAAc,YAAW,QAAQ;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6C;IAC5E,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,qBAAqB,CAAC,CAAiB;IAC/C,OAAO,CAAC,eAAe,CAAC,CAA4B;IACpD,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAQ;IACjD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;gBAElC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM;IAS/C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BpF,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAIpD,SAAS,IAAI,aAAa;IAI1B,eAAe,IAAI,mBAAmB;IAUtC,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAI/D,aAAa,IAAI,IAAI;IAQrB,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIrD;;OAEG;YACW,sBAAsB;IAqBpC;;OAEG;YACW,gBAAgB;IA+D9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;YACW,WAAW;IAgCzB;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;OAEG;IACH,OAAO,CAAC,YAAY;CAGrB"}