@thewhateverapp/tile-sdk 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 The Whatever App
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,582 @@
1
+ # @thewhateverapp/tile-sdk
2
+
3
+ > ⚠️ **Beta Release (v0.0.1)**: This package is in early preview. Requires integration with The Whatever App parent window (thewhatever.app). Use for development and testing.
4
+
5
+ SDK for building interactive tiles on The Whatever App platform. Provides secure parent-tile communication, authentication, storage, and more.
6
+
7
+ ## Features
8
+
9
+ - **🔐 Authentication**: OAuth-like permission system for accessing user data
10
+ - **💾 Storage**: Parent-managed persistent storage (100KB per tile)
11
+ - **📋 Clipboard**: Secure clipboard access with user permission
12
+ - **🔄 Navigation**: Navigate to full page or open external URLs
13
+ - **📊 Analytics**: Track events and user interactions
14
+ - **🎨 React Hooks**: Easy-to-use React hooks and components
15
+ - **🔒 Security**: Sandboxed iframe with validated message bridge
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @thewhateverapp/tile-sdk
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### React Component
26
+
27
+ ```tsx
28
+ import { TileProvider, useTile } from '@thewhateverapp/tile-sdk/react';
29
+
30
+ function MyTileApp() {
31
+ return (
32
+ <TileProvider fallback={<div>Loading...</div>}>
33
+ <TileContent />
34
+ </TileProvider>
35
+ );
36
+ }
37
+
38
+ function TileContent() {
39
+ const tile = useTile();
40
+
41
+ const handleClick = async () => {
42
+ // Navigate to full page
43
+ tile.navigateToPage();
44
+
45
+ // Track event
46
+ tile.trackEvent('button_click', { action: 'open_page' });
47
+ };
48
+
49
+ return (
50
+ <div className="w-full h-full">
51
+ <h1>My Tile</h1>
52
+ <button onClick={handleClick}>Open Full App</button>
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### Vanilla JavaScript
59
+
60
+ ```javascript
61
+ import { getTileBridge } from '@thewhateverapp/tile-sdk';
62
+
63
+ const bridge = getTileBridge();
64
+
65
+ // Wait for bridge to be ready
66
+ await bridge.waitForReady();
67
+
68
+ // Use bridge APIs
69
+ bridge.navigateToPage();
70
+ bridge.trackEvent('page_view', { page: 'home' });
71
+ ```
72
+
73
+ ## Authentication
74
+
75
+ The tile SDK implements an OAuth-like permission system where apps start with minimal access (user ID only) and must request additional permissions.
76
+
77
+ ### Permission Scopes
78
+
79
+ - **`id`** - User's internal ID (always granted)
80
+ - **`profile`** - Username, avatar, display name
81
+ - **`email`** - Email address
82
+ - **`wallet`** - Connected wallet addresses
83
+ - **`analytics:read`** - View user's analytics
84
+ - **`analytics:write`** - Track analytics (auto-granted)
85
+ - **`storage:read`** - Read user's storage (auto-granted)
86
+ - **`storage:write`** - Write to storage (auto-granted)
87
+
88
+ ### Request User Authentication
89
+
90
+ ```tsx
91
+ const tile = useTile();
92
+
93
+ // Request user with specific scopes
94
+ const handleLogin = async () => {
95
+ const user = await tile.auth.getUser({
96
+ scopes: ['profile', 'email'],
97
+ reason: 'We need your email to send you updates'
98
+ });
99
+
100
+ if (user) {
101
+ console.log('User granted access:', user);
102
+ // { id, username, email, scopes }
103
+ } else {
104
+ console.log('User denied permission');
105
+ }
106
+ };
107
+ ```
108
+
109
+ ### Get Current User
110
+
111
+ ```tsx
112
+ const tile = useTile();
113
+
114
+ // Get current user (if already authenticated)
115
+ const user = await tile.auth.getCurrentUser();
116
+
117
+ if (user) {
118
+ console.log(`Hello, ${user.username || 'User'}!`);
119
+ }
120
+ ```
121
+
122
+ ### Request Additional Scopes
123
+
124
+ ```tsx
125
+ const tile = useTile();
126
+
127
+ // Later in the app, request wallet access
128
+ const handleConnectWallet = async () => {
129
+ const granted = await tile.auth.requestScopes(['wallet']);
130
+
131
+ if (granted) {
132
+ const user = await tile.auth.getCurrentUser();
133
+ console.log('Wallet addresses:', user.walletAddresses);
134
+ }
135
+ };
136
+ ```
137
+
138
+ ## Storage
139
+
140
+ Tiles get 100KB of persistent storage managed by the parent window.
141
+
142
+ ```tsx
143
+ const tile = useTile();
144
+
145
+ // Store data
146
+ await tile.storage.set('user_preferences', {
147
+ theme: 'dark',
148
+ notifications: true
149
+ });
150
+
151
+ // Retrieve data
152
+ const prefs = await tile.storage.get('user_preferences');
153
+ console.log('Theme:', prefs.theme);
154
+ ```
155
+
156
+ ## Clipboard
157
+
158
+ Clipboard access requires user permission (one-time prompt).
159
+
160
+ ```tsx
161
+ const tile = useTile();
162
+
163
+ const handleCopy = async () => {
164
+ try {
165
+ await tile.clipboard.write('Hello from my tile!');
166
+ console.log('Copied to clipboard!');
167
+ } catch (error) {
168
+ console.error('User denied clipboard access');
169
+ }
170
+ };
171
+ ```
172
+
173
+ ## Navigation
174
+
175
+ ### Navigate to Full Page
176
+
177
+ ```tsx
178
+ const tile = useTile();
179
+
180
+ // Opens the full page view of your app
181
+ tile.navigateToPage();
182
+ ```
183
+
184
+ ### Open External URL
185
+
186
+ ```tsx
187
+ const tile = useTile();
188
+
189
+ // Opens URL with user confirmation
190
+ tile.openUrl('https://example.com', '_blank');
191
+ ```
192
+
193
+ ## Analytics
194
+
195
+ Track user events and interactions.
196
+
197
+ ```tsx
198
+ const tile = useTile();
199
+
200
+ // Track custom event
201
+ tile.trackEvent('button_click', {
202
+ button: 'subscribe',
203
+ location: 'header'
204
+ });
205
+
206
+ // Track page view
207
+ tile.trackEvent('page_view', { page: 'home' });
208
+ ```
209
+
210
+ ## Configuration
211
+
212
+ Access tile configuration from parent.
213
+
214
+ ```tsx
215
+ const tile = useTile();
216
+
217
+ if (tile.config) {
218
+ console.log('App ID:', tile.config.appId);
219
+ console.log('Position:', tile.config.position);
220
+ console.log('Theme:', tile.config.theme);
221
+ }
222
+ ```
223
+
224
+ ## Advanced: Using TileBridge Directly
225
+
226
+ For non-React apps or advanced use cases:
227
+
228
+ ```typescript
229
+ import { getTileBridge } from '@thewhateverapp/tile-sdk';
230
+
231
+ const bridge = getTileBridge();
232
+
233
+ // Wait for ready
234
+ const config = await bridge.waitForReady();
235
+
236
+ // Listen for events
237
+ bridge.on('theme:change', (theme) => {
238
+ console.log('Theme changed:', theme);
239
+ });
240
+
241
+ // Request resize (max 512x512)
242
+ bridge.requestResize(400, 300);
243
+
244
+ // Get user with auth
245
+ const user = await bridge.getUser({
246
+ scopes: ['profile'],
247
+ reason: 'Show your name'
248
+ });
249
+
250
+ // Storage operations
251
+ await bridge.setStorage('key', { data: 'value' });
252
+ const data = await bridge.getStorage('key');
253
+
254
+ // Navigate
255
+ bridge.navigateToPage();
256
+ bridge.openUrl('https://example.com');
257
+
258
+ // Track events
259
+ bridge.trackEvent('custom_event', { foo: 'bar' });
260
+
261
+ // Clipboard
262
+ await bridge.writeToClipboard('text to copy');
263
+ ```
264
+
265
+ ## Security Model
266
+
267
+ ### Sandboxed Iframe
268
+
269
+ All tiles run in sandboxed iframes with strict policies:
270
+
271
+ ```html
272
+ <iframe
273
+ sandbox="allow-scripts allow-pointer-lock"
274
+ referrerpolicy="no-referrer"
275
+ allow="clipboard-read; clipboard-write"
276
+ />
277
+ ```
278
+
279
+ ### Origin Validation
280
+
281
+ All messages are validated against the parent origin:
282
+ - Production: `https://thewhatever.app`
283
+ - Development: `http://localhost:3000`
284
+
285
+ ### Permission System
286
+
287
+ - Apps start with **minimal access** (user ID only)
288
+ - Additional permissions require **explicit user consent**
289
+ - Users can **revoke permissions** anytime in settings
290
+ - Permission grants are **audited** for security
291
+
292
+ ## Best Practices
293
+
294
+ ### 1. Request Minimal Scopes
295
+
296
+ ❌ Bad:
297
+ ```typescript
298
+ await tile.auth.getUser({
299
+ scopes: ['profile', 'email', 'wallet']
300
+ });
301
+ ```
302
+
303
+ ✅ Good:
304
+ ```typescript
305
+ // Start minimal
306
+ await tile.auth.getUser({
307
+ scopes: ['profile']
308
+ });
309
+
310
+ // Request more later when needed
311
+ await tile.auth.requestScopes(['email']);
312
+ ```
313
+
314
+ ### 2. Explain Why
315
+
316
+ ```typescript
317
+ await tile.auth.getUser({
318
+ scopes: ['email'],
319
+ reason: 'Send you order confirmation'
320
+ });
321
+ ```
322
+
323
+ ### 3. Handle Denials Gracefully
324
+
325
+ ```typescript
326
+ const user = await tile.auth.getUser({ scopes: ['email'] });
327
+
328
+ if (!user || !user.email) {
329
+ // Provide alternative flow
330
+ return <ManualEmailInput />;
331
+ }
332
+ ```
333
+
334
+ ### 4. Check Scopes Before Using
335
+
336
+ ```typescript
337
+ const user = await tile.auth.getCurrentUser();
338
+
339
+ if (user?.scopes.includes('email')) {
340
+ sendEmail(user.email);
341
+ } else {
342
+ console.log('Email permission not granted');
343
+ }
344
+ ```
345
+
346
+ ## API Reference
347
+
348
+ ### `useTile()` Hook
349
+
350
+ Returns the tile context with all available methods.
351
+
352
+ **Returns**: `TileContextValue`
353
+
354
+ ### `TileContextValue`
355
+
356
+ ```typescript
357
+ interface TileContextValue {
358
+ config: TileConfig | null;
359
+ bridge: TileBridge;
360
+ isReady: boolean;
361
+
362
+ // Navigation
363
+ navigateToPage: () => void;
364
+ openUrl: (url: string, target?: '_blank' | '_self') => void;
365
+
366
+ // Analytics
367
+ trackEvent: (eventName: string, data?: any) => void;
368
+
369
+ // Storage
370
+ storage: {
371
+ get: (key: string) => Promise<any>;
372
+ set: (key: string, value: any) => Promise<void>;
373
+ };
374
+
375
+ // Clipboard
376
+ clipboard: {
377
+ write: (text: string) => Promise<void>;
378
+ };
379
+
380
+ // Authentication
381
+ auth: {
382
+ getUser: (options?: {
383
+ scopes?: string[];
384
+ reason?: string;
385
+ }) => Promise<UserContext | null>;
386
+ requestScopes: (scopes: string[]) => Promise<boolean>;
387
+ getCurrentUser: () => Promise<UserContext | null>;
388
+ };
389
+ }
390
+ ```
391
+
392
+ ### `TileConfig`
393
+
394
+ ```typescript
395
+ interface TileConfig {
396
+ appId: string;
397
+ position: { row: number; col: number };
398
+ tileUrl: string;
399
+ apiEndpoint?: string;
400
+ theme?: 'light' | 'dark';
401
+ debug?: boolean;
402
+ }
403
+ ```
404
+
405
+ ### `UserContext`
406
+
407
+ ```typescript
408
+ interface UserContext {
409
+ authenticated: boolean;
410
+ userId: string;
411
+ scopes: string[];
412
+
413
+ // Only if 'profile' scope granted
414
+ username?: string;
415
+ avatar?: string;
416
+ displayName?: string;
417
+
418
+ // Only if 'email' scope granted
419
+ email?: string;
420
+
421
+ // Only if 'wallet' scope granted
422
+ walletAddresses?: string[];
423
+ }
424
+ ```
425
+
426
+ ## Examples
427
+
428
+ ### Example: Simple Counter Tile
429
+
430
+ ```tsx
431
+ import { TileProvider, useTile } from '@thewhateverapp/tile-sdk/react';
432
+ import { useState, useEffect } from 'react';
433
+
434
+ function CounterTile() {
435
+ return (
436
+ <TileProvider>
437
+ <Counter />
438
+ </TileProvider>
439
+ );
440
+ }
441
+
442
+ function Counter() {
443
+ const tile = useTile();
444
+ const [count, setCount] = useState(0);
445
+
446
+ // Load count from storage on mount
447
+ useEffect(() => {
448
+ tile.storage.get('count').then(savedCount => {
449
+ if (savedCount !== undefined) setCount(savedCount);
450
+ });
451
+ }, []);
452
+
453
+ // Save count to storage when it changes
454
+ useEffect(() => {
455
+ tile.storage.set('count', count);
456
+ }, [count]);
457
+
458
+ const increment = () => {
459
+ setCount(c => c + 1);
460
+ tile.trackEvent('counter_increment', { value: count + 1 });
461
+ };
462
+
463
+ return (
464
+ <div className="flex flex-col items-center justify-center h-full">
465
+ <h1 className="text-4xl font-bold">{count}</h1>
466
+ <button onClick={increment} className="mt-4 px-6 py-2 bg-blue-500">
467
+ Increment
468
+ </button>
469
+ <button onClick={() => tile.navigateToPage()} className="mt-2">
470
+ View Full App
471
+ </button>
472
+ </div>
473
+ );
474
+ }
475
+ ```
476
+
477
+ ### Example: User Profile Tile
478
+
479
+ ```tsx
480
+ import { TileProvider, useTile } from '@thewhateverapp/tile-sdk/react';
481
+ import { useState, useEffect } from 'react';
482
+
483
+ function ProfileTile() {
484
+ return (
485
+ <TileProvider>
486
+ <Profile />
487
+ </TileProvider>
488
+ );
489
+ }
490
+
491
+ function Profile() {
492
+ const tile = useTile();
493
+ const [user, setUser] = useState(null);
494
+
495
+ const handleLogin = async () => {
496
+ const userData = await tile.auth.getUser({
497
+ scopes: ['profile', 'email'],
498
+ reason: 'Display your profile information'
499
+ });
500
+
501
+ if (userData) {
502
+ setUser(userData);
503
+ tile.trackEvent('user_logged_in');
504
+ }
505
+ };
506
+
507
+ if (!user) {
508
+ return (
509
+ <div className="flex items-center justify-center h-full">
510
+ <button onClick={handleLogin} className="px-6 py-3 bg-purple-500">
511
+ Sign In
512
+ </button>
513
+ </div>
514
+ );
515
+ }
516
+
517
+ return (
518
+ <div className="p-4">
519
+ <img src={user.avatar} className="w-16 h-16 rounded-full" />
520
+ <h2 className="text-xl font-bold mt-2">{user.username}</h2>
521
+ {user.email && <p className="text-gray-600">{user.email}</p>}
522
+ <button onClick={() => tile.navigateToPage()} className="mt-4">
523
+ View Full Profile
524
+ </button>
525
+ </div>
526
+ );
527
+ }
528
+ ```
529
+
530
+ ## TypeScript Support
531
+
532
+ Full TypeScript support with type definitions included.
533
+
534
+ ```typescript
535
+ import type {
536
+ TileContextValue,
537
+ TileConfig,
538
+ UserContext,
539
+ TileBridge
540
+ } from '@thewhateverapp/tile-sdk';
541
+ ```
542
+
543
+ ## Development
544
+
545
+ ### Local Testing
546
+
547
+ ```bash
548
+ # Install dependencies
549
+ npm install
550
+
551
+ # Build
552
+ npm run build
553
+
554
+ # Run type checking
555
+ npm run typecheck
556
+
557
+ # Lint
558
+ npm run lint
559
+ ```
560
+
561
+ ### Testing with Parent
562
+
563
+ To test your tile locally, you'll need the parent window running:
564
+
565
+ ```bash
566
+ # In parent project
567
+ npm run dev
568
+
569
+ # Your tile will be loaded at:
570
+ # http://localhost:3000/tile/[your-app-id]
571
+ ```
572
+
573
+ ## Resources
574
+
575
+ - [Platform Documentation](https://thewhatever.app/docs)
576
+ - [Authentication Guide](https://thewhatever.app/docs/auth)
577
+ - [Security Best Practices](https://thewhatever.app/docs/security)
578
+ - [Example Apps](https://github.com/thewhateverapp/examples)
579
+
580
+ ## License
581
+
582
+ Proprietary - All rights reserved
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Secure message bridge for tile-parent communication
3
+ * This runs inside the iframe (tile side)
4
+ */
5
+ export interface TileMessage {
6
+ type: string;
7
+ payload?: any;
8
+ id?: string;
9
+ timestamp?: number;
10
+ }
11
+ export interface TileConfig {
12
+ appId: string;
13
+ position: {
14
+ row: number;
15
+ col: number;
16
+ };
17
+ tileUrl: string;
18
+ apiEndpoint?: string;
19
+ theme?: 'light' | 'dark';
20
+ debug?: boolean;
21
+ }
22
+ export declare class TileBridge {
23
+ private config;
24
+ private messageQueue;
25
+ private responseHandlers;
26
+ private eventHandlers;
27
+ private ready;
28
+ private parentOrigin;
29
+ constructor(expectedOrigin?: string);
30
+ private initialize;
31
+ private handleMessage;
32
+ private handleConfig;
33
+ private handleResponse;
34
+ private handleEvent;
35
+ private sendToParent;
36
+ /**
37
+ * Request to navigate to full page view
38
+ */
39
+ navigateToPage(): void;
40
+ /**
41
+ * Request to open a URL (with user confirmation)
42
+ */
43
+ openUrl(url: string, target?: '_blank' | '_self'): void;
44
+ /**
45
+ * Send analytics event
46
+ */
47
+ trackEvent(eventName: string, data?: any): void;
48
+ /**
49
+ * Request clipboard write (requires user permission)
50
+ */
51
+ writeToClipboard(text: string): Promise<void>;
52
+ /**
53
+ * Store data in parent's storage (limited to 100KB per tile)
54
+ */
55
+ setStorage(key: string, value: any): Promise<void>;
56
+ /**
57
+ * Get data from parent's storage
58
+ */
59
+ getStorage(key: string): Promise<any>;
60
+ /**
61
+ * Request resize (within limits)
62
+ */
63
+ requestResize(width: number, height: number): void;
64
+ /**
65
+ * Request user authentication with specific scopes
66
+ */
67
+ getUser(options?: {
68
+ scopes?: string[];
69
+ reason?: string;
70
+ }): Promise<any>;
71
+ /**
72
+ * Request additional permission scopes
73
+ */
74
+ requestScopes(scopes: string[]): Promise<boolean>;
75
+ /**
76
+ * Get current authenticated user (if available)
77
+ */
78
+ getCurrentUser(): Promise<any>;
79
+ /**
80
+ * Subscribe to events from parent
81
+ */
82
+ on(event: string, handler: (data: any) => void): () => void;
83
+ /**
84
+ * Get tile configuration
85
+ */
86
+ getConfig(): TileConfig | null;
87
+ /**
88
+ * Check if ready
89
+ */
90
+ isReady(): boolean;
91
+ /**
92
+ * Wait for ready state
93
+ */
94
+ waitForReady(): Promise<TileConfig>;
95
+ private emitEvent;
96
+ private generateId;
97
+ private isDevelopment;
98
+ }
99
+ export declare function getTileBridge(): TileBridge;
100
+ //# sourceMappingURL=TileBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TileBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/TileBridge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,OAAO,CAAC,aAAa,CAAoD;IACzE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAS;gBAEjB,cAAc,GAAE,MAAkC;IAW9D,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAsBpB;;OAEG;IACI,cAAc,IAAI,IAAI;IAO7B;;OAEG;IACI,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,QAAQ,GAAG,OAAkB,GAAG,IAAI;IAOxE;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAOtD;;OAEG;IACU,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B1D;;OAEG;IACU,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B/D;;OAEG;IACU,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAoBlD;;OAEG;IACI,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAWzD;;OAEG;IACU,OAAO,CAAC,OAAO,CAAC,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,GAAG,CAAC;IAiChB;;OAEG;IACU,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IA8B9D;;OAEG;IACU,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAuB3C;;OAEG;IACI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI;IAgBlE;;OAEG;IACI,SAAS,IAAI,UAAU,GAAG,IAAI;IAIrC;;OAEG;IACI,OAAO,IAAI,OAAO;IAIzB;;OAEG;IACU,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC;IAehD,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,aAAa;CAKtB;AAKD,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}