aamp-sdk 0.1.5

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,43 @@
1
+ # @byted-meego/aamp-sdk
2
+
3
+ Node.js SDK for connecting agents and services to AAMP.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @byted-meego/aamp-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { AampClient } from '@byted-meego/aamp-sdk'
15
+
16
+ const client = new AampClient({
17
+ email: 'agent@example.com',
18
+ jmapToken: '<base64(email:password)>',
19
+ jmapUrl: 'http://localhost:3000/jmap',
20
+ smtpHost: 'localhost',
21
+ smtpPort: 587,
22
+ smtpPassword: '<smtp-password>',
23
+ rejectUnauthorized: false,
24
+ })
25
+
26
+ client.on('task.dispatch', async (task) => {
27
+ await client.sendResult({
28
+ to: task.from,
29
+ taskId: task.taskId,
30
+ status: 'completed',
31
+ output: 'done',
32
+ inReplyTo: task.messageId,
33
+ })
34
+ })
35
+
36
+ await client.connect()
37
+ ```
38
+
39
+ ## Exports
40
+
41
+ - `AampClient`
42
+ - `JmapPushClient`
43
+ - protocol types such as `TaskDispatch`, `TaskResult`, and `TaskHelp`
@@ -0,0 +1,91 @@
1
+ /**
2
+ * AampClient — Main SDK entry point
3
+ *
4
+ * Combines JMAP WebSocket Push (receive) + SMTP (send) into a single client.
5
+ *
6
+ * Usage:
7
+ *
8
+ * ```typescript
9
+ * const client = new AampClient({
10
+ * email: 'codereviewer-abc@aamp.example.com',
11
+ * jmapToken: '<base64-token>',
12
+ * jmapUrl: 'http://localhost:8080',
13
+ * smtpHost: 'localhost',
14
+ * smtpPort: 587,
15
+ * smtpPassword: 'agent-smtp-password',
16
+ * })
17
+ *
18
+ * // Listen for incoming tasks
19
+ * client.on('task.dispatch', async (task) => {
20
+ * const result = await doWork(task)
21
+ * await client.sendResult({
22
+ * to: task.from,
23
+ * taskId: task.taskId,
24
+ * status: 'completed',
25
+ * output: result,
26
+ * })
27
+ * })
28
+ *
29
+ * await client.connect()
30
+ * ```
31
+ */
32
+ import { EventEmitter } from 'events';
33
+ import type { AampClientConfig, AampClientEvents, SendTaskOptions, SendResultOptions, SendHelpOptions } from './types.js';
34
+ export declare class AampClient extends EventEmitter {
35
+ private jmapClient;
36
+ private smtpSender;
37
+ private readonly config;
38
+ constructor(config: AampClientConfig);
39
+ on<K extends keyof AampClientEvents>(event: K, listener: AampClientEvents[K]): this;
40
+ once<K extends keyof AampClientEvents>(event: K, listener: AampClientEvents[K]): this;
41
+ off<K extends keyof AampClientEvents>(event: K, listener: AampClientEvents[K]): this;
42
+ /**
43
+ * Connect to JMAP and start listening for tasks
44
+ */
45
+ connect(): Promise<void>;
46
+ /**
47
+ * Disconnect and clean up
48
+ */
49
+ disconnect(): void;
50
+ /**
51
+ * Returns true if the JMAP connection is active
52
+ */
53
+ isConnected(): boolean;
54
+ isUsingPollingFallback(): boolean;
55
+ /**
56
+ * Send a task.dispatch email to an agent.
57
+ * Returns the generated taskId and the SMTP Message-ID.
58
+ * Store messageId → taskId in Redis/DB to support In-Reply-To thread routing
59
+ * for human replies that arrive without X-AAMP headers.
60
+ */
61
+ sendTask(opts: SendTaskOptions): Promise<{
62
+ taskId: string;
63
+ messageId: string;
64
+ }>;
65
+ /**
66
+ * Send a task.result email (agent → system/dispatcher)
67
+ */
68
+ sendResult(opts: SendResultOptions): Promise<void>;
69
+ /**
70
+ * Send a task.help email when the agent needs human assistance
71
+ */
72
+ sendHelp(opts: SendHelpOptions): Promise<void>;
73
+ /**
74
+ * Download a blob (attachment) by its JMAP blobId.
75
+ * Use this to retrieve attachment content from received TaskDispatch or TaskResult messages.
76
+ * Returns the raw binary content as a Buffer.
77
+ */
78
+ downloadBlob(blobId: string, filename?: string): Promise<Buffer>;
79
+ /**
80
+ * Reconcile recent mailbox contents via JMAP HTTP to catch messages missed by
81
+ * a flaky WebSocket path. Safe to call periodically; duplicate processing is
82
+ * suppressed by the JMAP push client.
83
+ */
84
+ reconcileRecentEmails(limit?: number): Promise<number>;
85
+ /**
86
+ * Verify SMTP connectivity
87
+ */
88
+ verifySmtp(): Promise<boolean>;
89
+ get email(): string;
90
+ }
91
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAGrC,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAMhB,eAAe,EACf,iBAAiB,EACjB,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,MAAM,EAAE,gBAAgB;IAkF3B,EAAE,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAC1C,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC5B,IAAI;IAIE,IAAI,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAC5C,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC5B,IAAI;IAIE,GAAG,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAC3C,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC5B,IAAI;IAQP;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB,sBAAsB,IAAI,OAAO;IAQjC;;;;;OAKG;IACG,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAIrF;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAItE;;;;OAIG;IACG,qBAAqB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAIpC,IAAI,KAAK,IAAI,MAAM,CAElB;CACF"}
package/dist/client.js ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * AampClient — Main SDK entry point
3
+ *
4
+ * Combines JMAP WebSocket Push (receive) + SMTP (send) into a single client.
5
+ *
6
+ * Usage:
7
+ *
8
+ * ```typescript
9
+ * const client = new AampClient({
10
+ * email: 'codereviewer-abc@aamp.example.com',
11
+ * jmapToken: '<base64-token>',
12
+ * jmapUrl: 'http://localhost:8080',
13
+ * smtpHost: 'localhost',
14
+ * smtpPort: 587,
15
+ * smtpPassword: 'agent-smtp-password',
16
+ * })
17
+ *
18
+ * // Listen for incoming tasks
19
+ * client.on('task.dispatch', async (task) => {
20
+ * const result = await doWork(task)
21
+ * await client.sendResult({
22
+ * to: task.from,
23
+ * taskId: task.taskId,
24
+ * status: 'completed',
25
+ * output: result,
26
+ * })
27
+ * })
28
+ *
29
+ * await client.connect()
30
+ * ```
31
+ */
32
+ import { EventEmitter } from 'events';
33
+ import { JmapPushClient } from './jmap-push.js';
34
+ import { SmtpSender } from './smtp-sender.js';
35
+ export class AampClient extends EventEmitter {
36
+ jmapClient;
37
+ smtpSender;
38
+ config;
39
+ constructor(config) {
40
+ super();
41
+ this.config = config;
42
+ // Decode JMAP token (format: base64(email:password))
43
+ let password;
44
+ try {
45
+ const decoded = Buffer.from(config.jmapToken, 'base64').toString('utf-8');
46
+ const colonIdx = decoded.indexOf(':');
47
+ if (colonIdx < 0)
48
+ throw new Error('Invalid jmapToken format: expected base64(email:password)');
49
+ password = decoded.slice(colonIdx + 1);
50
+ if (!password)
51
+ throw new Error('Invalid jmapToken: empty password');
52
+ }
53
+ catch (err) {
54
+ if (err instanceof Error && err.message.startsWith('Invalid jmapToken'))
55
+ throw err;
56
+ throw new Error(`Failed to decode jmapToken: ${err.message}`);
57
+ }
58
+ this.jmapClient = new JmapPushClient({
59
+ email: config.email,
60
+ password: password ?? config.smtpPassword,
61
+ jmapUrl: config.jmapUrl,
62
+ reconnectInterval: config.reconnectInterval ?? 5000,
63
+ rejectUnauthorized: config.rejectUnauthorized,
64
+ });
65
+ this.smtpSender = new SmtpSender({
66
+ host: config.smtpHost,
67
+ port: config.smtpPort ?? 587,
68
+ user: config.email,
69
+ password: config.smtpPassword,
70
+ httpBaseUrl: config.httpSendBaseUrl ?? config.jmapUrl,
71
+ authToken: config.jmapToken,
72
+ rejectUnauthorized: config.rejectUnauthorized,
73
+ });
74
+ // Forward JMAP events to this emitter
75
+ this.jmapClient.on('task.dispatch', (task) => {
76
+ this.emit('task.dispatch', task);
77
+ });
78
+ this.jmapClient.on('task.result', (result) => {
79
+ this.emit('task.result', result);
80
+ });
81
+ this.jmapClient.on('task.help', (help) => {
82
+ this.emit('task.help', help);
83
+ });
84
+ this.jmapClient.on('task.ack', (ack) => {
85
+ this.emit('task.ack', ack);
86
+ });
87
+ // Auto-ACK: when a task.dispatch is received, automatically send an ACK back
88
+ this.jmapClient.on('_autoAck', async ({ to, taskId, messageId }) => {
89
+ try {
90
+ await this.smtpSender.sendAck({ to, taskId, inReplyTo: messageId });
91
+ }
92
+ catch (err) {
93
+ console.warn(`[AAMP] Failed to send ACK for task ${taskId}: ${err.message}`);
94
+ }
95
+ });
96
+ this.jmapClient.on('reply', (reply) => {
97
+ this.emit('reply', reply);
98
+ });
99
+ this.jmapClient.on('connected', () => {
100
+ this.emit('connected');
101
+ });
102
+ this.jmapClient.on('disconnected', (reason) => {
103
+ this.emit('disconnected', reason);
104
+ });
105
+ this.jmapClient.on('error', (err) => {
106
+ this.emit('error', err);
107
+ });
108
+ }
109
+ // =====================================================
110
+ // Type-safe event emitter methods
111
+ // =====================================================
112
+ on(event, listener) {
113
+ return super.on(event, listener);
114
+ }
115
+ once(event, listener) {
116
+ return super.once(event, listener);
117
+ }
118
+ off(event, listener) {
119
+ return super.off(event, listener);
120
+ }
121
+ // =====================================================
122
+ // Lifecycle
123
+ // =====================================================
124
+ /**
125
+ * Connect to JMAP and start listening for tasks
126
+ */
127
+ async connect() {
128
+ await this.jmapClient.start();
129
+ }
130
+ /**
131
+ * Disconnect and clean up
132
+ */
133
+ disconnect() {
134
+ this.jmapClient.stop();
135
+ this.smtpSender.close();
136
+ }
137
+ /**
138
+ * Returns true if the JMAP connection is active
139
+ */
140
+ isConnected() {
141
+ return this.jmapClient.isConnected();
142
+ }
143
+ isUsingPollingFallback() {
144
+ return this.jmapClient.isUsingPollingFallback();
145
+ }
146
+ // =====================================================
147
+ // Sending
148
+ // =====================================================
149
+ /**
150
+ * Send a task.dispatch email to an agent.
151
+ * Returns the generated taskId and the SMTP Message-ID.
152
+ * Store messageId → taskId in Redis/DB to support In-Reply-To thread routing
153
+ * for human replies that arrive without X-AAMP headers.
154
+ */
155
+ async sendTask(opts) {
156
+ return this.smtpSender.sendTask(opts);
157
+ }
158
+ /**
159
+ * Send a task.result email (agent → system/dispatcher)
160
+ */
161
+ async sendResult(opts) {
162
+ return this.smtpSender.sendResult(opts);
163
+ }
164
+ /**
165
+ * Send a task.help email when the agent needs human assistance
166
+ */
167
+ async sendHelp(opts) {
168
+ return this.smtpSender.sendHelp(opts);
169
+ }
170
+ /**
171
+ * Download a blob (attachment) by its JMAP blobId.
172
+ * Use this to retrieve attachment content from received TaskDispatch or TaskResult messages.
173
+ * Returns the raw binary content as a Buffer.
174
+ */
175
+ async downloadBlob(blobId, filename) {
176
+ return this.jmapClient.downloadBlob(blobId, filename);
177
+ }
178
+ /**
179
+ * Reconcile recent mailbox contents via JMAP HTTP to catch messages missed by
180
+ * a flaky WebSocket path. Safe to call periodically; duplicate processing is
181
+ * suppressed by the JMAP push client.
182
+ */
183
+ async reconcileRecentEmails(limit) {
184
+ return this.jmapClient.reconcileRecentEmails(limit);
185
+ }
186
+ /**
187
+ * Verify SMTP connectivity
188
+ */
189
+ async verifySmtp() {
190
+ return this.smtpSender.verify();
191
+ }
192
+ get email() {
193
+ return this.config.email;
194
+ }
195
+ }
196
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @byted-meego/aamp-sdk — Node.js SDK for AAMP Service
3
+ *
4
+ * Main exports:
5
+ * - AampClient: combined JMAP push receiver + SMTP sender
6
+ * - parseAampHeaders: parse AAMP headers from raw email headers
7
+ * - Types
8
+ */
9
+ export { AampClient } from './client.js';
10
+ export { parseAampHeaders, normalizeHeaders, buildDispatchHeaders, buildResultHeaders, buildHelpHeaders, buildAckHeaders } from './parser.js';
11
+ export { JmapPushClient } from './jmap-push.js';
12
+ export { SmtpSender } from './smtp-sender.js';
13
+ export type { AampIntent, TaskStatus, AampAttachment, ReceivedAttachment, StructuredResultField, TaskDispatch, TaskResult, TaskHelp, TaskAck, HumanReply, AampMessage, AampClientConfig, AampClientEvents, SendTaskOptions, SendResultOptions, SendHelpOptions, } from './types.js';
14
+ export { AAMP_HEADER } from './types.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7I,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,YAAY,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,OAAO,EACP,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @byted-meego/aamp-sdk — Node.js SDK for AAMP Service
3
+ *
4
+ * Main exports:
5
+ * - AampClient: combined JMAP push receiver + SMTP sender
6
+ * - parseAampHeaders: parse AAMP headers from raw email headers
7
+ * - Types
8
+ */
9
+ export { AampClient } from './client.js';
10
+ export { parseAampHeaders, normalizeHeaders, buildDispatchHeaders, buildResultHeaders, buildHelpHeaders, buildAckHeaders } from './parser.js';
11
+ export { JmapPushClient } from './jmap-push.js';
12
+ export { SmtpSender } from './smtp-sender.js';
13
+ export { AAMP_HEADER } from './types.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7I,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAsB7C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * JMAP WebSocket Push Client
3
+ *
4
+ * Connects to Stalwart's JMAP WebSocket endpoint and subscribes to
5
+ * Email StateChange events. When a new email arrives in the agent's
6
+ * mailbox, fetches it via JMAP and emits the parsed AAMP headers.
7
+ *
8
+ * Protocol: RFC 8887 (JMAP over WebSocket)
9
+ * Ref: https://www.rfc-editor.org/rfc/rfc8887
10
+ */
11
+ import { EventEmitter } from 'events';
12
+ export declare class JmapPushClient extends EventEmitter {
13
+ private ws;
14
+ private session;
15
+ private reconnectTimer;
16
+ private pollTimer;
17
+ private pingTimer;
18
+ private readonly seenMessageIds;
19
+ private connected;
20
+ private pollingActive;
21
+ private running;
22
+ private connecting;
23
+ /** JMAP Email state — tracks processed position; null = not yet initialized */
24
+ private emailState;
25
+ private readonly startedAtMs;
26
+ private readonly email;
27
+ private readonly password;
28
+ private readonly jmapUrl;
29
+ private readonly reconnectInterval;
30
+ private readonly rejectUnauthorized;
31
+ private readonly pingIntervalMs;
32
+ constructor(opts: {
33
+ email: string;
34
+ password: string;
35
+ jmapUrl: string;
36
+ reconnectInterval?: number;
37
+ /** Whether to reject unauthorized TLS certificates (default: true) */
38
+ rejectUnauthorized?: boolean;
39
+ });
40
+ /**
41
+ * Start the JMAP Push listener
42
+ */
43
+ start(): Promise<void>;
44
+ /**
45
+ * Stop the JMAP Push listener
46
+ */
47
+ stop(): void;
48
+ private getAuthHeader;
49
+ /**
50
+ * Fetch the JMAP session object
51
+ */
52
+ private fetchSession;
53
+ /**
54
+ * Perform a JMAP API call
55
+ */
56
+ private jmapCall;
57
+ /**
58
+ * Initialize emailState by fetching the current state without loading any emails.
59
+ * Called on first connect so we only process emails that arrive AFTER this point.
60
+ */
61
+ private initEmailState;
62
+ /**
63
+ * Fetch only emails created since `sinceState` using Email/changes.
64
+ * Updates `this.emailState` to the new state after fetching.
65
+ * Returns [] and resets state if the server cannot calculate changes (state too old).
66
+ */
67
+ private fetchEmailsSince;
68
+ /**
69
+ * Process a received email.
70
+ *
71
+ * Priority:
72
+ * 1. If X-AAMP-Intent is present → emit typed AAMP event (task.dispatch / task.result / task.help)
73
+ * 2. If In-Reply-To is present → emit 'reply' event so the application layer can
74
+ * resolve the thread (inReplyTo → taskId via Redis/DB) and handle human replies.
75
+ * 3. Otherwise → ignore (not an AAMP-related email)
76
+ */
77
+ private processEmail;
78
+ private fetchRecentEmails;
79
+ private shouldProcessBootstrapEmail;
80
+ /**
81
+ * Connect to JMAP WebSocket
82
+ */
83
+ private connect;
84
+ private startPingHeartbeat;
85
+ private stopPingHeartbeat;
86
+ private handleStateChange;
87
+ private scheduleReconnect;
88
+ isConnected(): boolean;
89
+ isUsingPollingFallback(): boolean;
90
+ private stopPolling;
91
+ private startPolling;
92
+ /**
93
+ * Download a blob (attachment) by its JMAP blobId.
94
+ * Returns the raw binary content as a Buffer.
95
+ */
96
+ downloadBlob(blobId: string, filename?: string): Promise<Buffer>;
97
+ /**
98
+ * Actively reconcile recent mailbox contents via JMAP HTTP.
99
+ * Useful as a safety net when the WebSocket stays "connected"
100
+ * but a notification is missed by an intermediate layer.
101
+ */
102
+ reconcileRecentEmails(limit?: number): Promise<number>;
103
+ }
104
+ //# sourceMappingURL=jmap-push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jmap-push.d.ts","sourceRoot":"","sources":["../src/jmap-push.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAoDrC,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoB;IACnD,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,UAAU,CAAQ;IAC1B,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IAEzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAO;gBAE1B,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,sEAAsE;QACtE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAC7B;IASD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;OAEG;IACH,IAAI,IAAI,IAAI;IAuBZ,OAAO,CAAC,aAAa;IAKrB;;OAEG;YACW,YAAY;IAa1B;;OAEG;YACW,QAAQ;IA+BtB;;;OAGG;YACW,cAAc;IAU5B;;;;OAIG;YACW,gBAAgB;IA+C9B;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;YAsFN,iBAAiB;IAuC/B,OAAO,CAAC,2BAA2B;IAOnC;;OAEG;YACW,OAAO;IAoHrB,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,iBAAiB;YAOX,iBAAiB;IA0B/B,OAAO,CAAC,iBAAiB;IAWzB,WAAW,IAAI,OAAO;IAItB,sBAAsB,IAAI,OAAO;IAIjC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,YAAY;IAsDpB;;;OAGG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiEtE;;;;OAIG;IACG,qBAAqB,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC;CA2DzD"}