@rool-dev/sdk 0.11.2 → 0.11.3-dev.029b9ab
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 +143 -10
- package/dist/auth-base.d.ts +100 -0
- package/dist/auth-base.d.ts.map +1 -0
- package/dist/auth-base.js +377 -0
- package/dist/auth-base.js.map +1 -0
- package/dist/auth-browser.d.ts +6 -77
- package/dist/auth-browser.d.ts.map +1 -1
- package/dist/auth-browser.js +32 -328
- package/dist/auth-browser.js.map +1 -1
- package/dist/auth-native.d.ts +50 -0
- package/dist/auth-native.d.ts.map +1 -0
- package/dist/auth-native.js +180 -0
- package/dist/auth-native.js.map +1 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +16 -5
- package/dist/auth.js.map +1 -1
- package/dist/channel.d.ts +1 -4
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +0 -5
- package/dist/channel.js.map +1 -1
- package/dist/client.d.ts +16 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +30 -6
- package/dist/client.js.map +1 -1
- package/dist/graphql.d.ts +9 -5
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +51 -29
- package/dist/graphql.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/rest.d.ts +10 -1
- package/dist/rest.d.ts.map +1 -1
- package/dist/rest.js +30 -0
- package/dist/rest.js.map +1 -1
- package/dist/space.d.ts +21 -10
- package/dist/space.d.ts.map +1 -1
- package/dist/space.js +22 -21
- package/dist/space.js.map +1 -1
- package/dist/subscription.js +1 -1
- package/dist/subscription.js.map +1 -1
- package/dist/types.d.ts +63 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,6 +142,42 @@ if (!authenticated) {
|
|
|
142
142
|
if (!authenticated) throw new Error('Login required');
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
### Native (Capacitor, Cordova, Tauri, ...)
|
|
146
|
+
|
|
147
|
+
Use the native PKCE provider for JS app shells that sign in through an external
|
|
148
|
+
system browser. `login()`/`signup()` open the auth server's `/authorize` page
|
|
149
|
+
via the `openExternal` callback you supply; when the deep link returns, feed it
|
|
150
|
+
to `client.handleAuthRedirect(url)` from your platform's deep-link handler. The
|
|
151
|
+
code is exchanged for a session at `/token` and tokens are stored like the
|
|
152
|
+
browser provider.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { RoolClient, NativePkceAuthProvider } from '@rool-dev/sdk';
|
|
156
|
+
import { Browser } from '@capacitor/browser';
|
|
157
|
+
import { App } from '@capacitor/app';
|
|
158
|
+
|
|
159
|
+
const client = new RoolClient({
|
|
160
|
+
authProvider: new NativePkceAuthProvider({
|
|
161
|
+
redirectUri: 'roolandroidauth://auth/callback', // must match the server allowlist
|
|
162
|
+
defaultProvider: 'google', // 'google' | 'apple'
|
|
163
|
+
openExternal: (url) => Browser.open({ url }),
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Complete sign-in when the OS hands the app its deep link.
|
|
168
|
+
App.addListener('appUrlOpen', async ({ url }) => {
|
|
169
|
+
if (await client.handleAuthRedirect(url)) {
|
|
170
|
+
await Browser.close();
|
|
171
|
+
// Now authenticated — refresh your UI.
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (!(await client.initialize())) {
|
|
176
|
+
// Opens the system browser; completion arrives via the listener above.
|
|
177
|
+
await client.login('My App'); // pass { provider: 'apple' } to override the default
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
145
181
|
### Auth API
|
|
146
182
|
|
|
147
183
|
| Method | Description |
|
|
@@ -150,6 +186,7 @@ if (!authenticated) throw new Error('Login required');
|
|
|
150
186
|
| `login(appName, params?): Promise<void>` | Start login flow. |
|
|
151
187
|
| `signup(appName, params?): Promise<void>` | Start signup flow. |
|
|
152
188
|
| `verify(token): Promise<boolean>` | Complete email verification token flow; returns `false` when the active auth provider does not implement verification. |
|
|
189
|
+
| `handleAuthRedirect(url): Promise<boolean>` | Complete a native PKCE sign-in from a deep-link callback URL. Returns `false` when the active auth provider does not implement it. |
|
|
153
190
|
| `logout(): void` | Clear auth state and close open spaces. |
|
|
154
191
|
| `isAuthenticated(): Promise<boolean>` | Whether credentials are held locally. No network call — a server outage does not read as logged out. |
|
|
155
192
|
| `getAuthUser(): AuthUser` | Return auth identity decoded from the token. |
|
|
@@ -490,16 +527,53 @@ High-level WebDAV methods that validate response status throw `WebDAVError` with
|
|
|
490
527
|
|
|
491
528
|
## Collaboration
|
|
492
529
|
|
|
530
|
+
New members join a space by redeeming an invite. Owners and admins mint invites; the returned `url` contains the secret token and is only available at mint time.
|
|
531
|
+
|
|
493
532
|
```typescript
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
533
|
+
// Shareable invite link
|
|
534
|
+
const invite = await space.createInvite('editor', { expiresInDays: 7 });
|
|
535
|
+
console.log(invite.url);
|
|
536
|
+
|
|
537
|
+
// Email-guarded invite: single-use, locked to that address, sent by mail
|
|
538
|
+
const emailed = await space.createInvite('viewer', { email: 'colleague@example.com' });
|
|
539
|
+
if (emailed.emailStatus !== 'sent') {
|
|
540
|
+
// Mail did not go out (e.g. no mail provider configured) — share emailed.url yourself
|
|
497
541
|
}
|
|
498
542
|
|
|
499
|
-
|
|
543
|
+
// Manage outstanding invites
|
|
544
|
+
const invites = await space.listInvites();
|
|
545
|
+
await space.revokeInvite(invites[0].inviteId);
|
|
546
|
+
|
|
547
|
+
// Change an existing member's role, or remove them
|
|
548
|
+
await space.setUserRole(userId, 'admin');
|
|
549
|
+
await space.removeUser(userId);
|
|
500
550
|
```
|
|
501
551
|
|
|
502
|
-
|
|
552
|
+
On the join page, look up the invite before sign-in and redeem it once authenticated:
|
|
553
|
+
|
|
554
|
+
```typescript
|
|
555
|
+
const preview = await client.previewInvite(token); // no auth required
|
|
556
|
+
console.log(preview.spaceName, preview.role, preview.inviterName);
|
|
557
|
+
|
|
558
|
+
const result = await client.redeemInvite(token);
|
|
559
|
+
console.log(result.spaceId, result.status); // 'joined' | 'upgraded' | 'already_member'
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Invalid, expired, revoked, exhausted, or email-mismatched invites throw `InviteError` with a `code` of `'INVITE_INVALID' | 'INVITE_EXPIRED' | 'INVITE_REVOKED' | 'INVITE_EXHAUSTED' | 'INVITE_EMAIL_MISMATCH'`.
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
import { InviteError } from '@rool-dev/sdk';
|
|
566
|
+
|
|
567
|
+
try {
|
|
568
|
+
await client.redeemInvite(token);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
if (error instanceof InviteError && error.code === 'INVITE_EXPIRED') {
|
|
571
|
+
// Ask for a fresh invite
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Roles (invites grant `admin`, `editor`, or `viewer` — never `owner`):
|
|
503
577
|
|
|
504
578
|
| Role | Capabilities |
|
|
505
579
|
| --- | --- |
|
|
@@ -529,7 +603,8 @@ const client = new RoolClient({
|
|
|
529
603
|
| `getCurrentUser(): Promise<CurrentUser>` | Fetch current user. |
|
|
530
604
|
| `updateCurrentUser(input): Promise<CurrentUser>` | Update `name`, `slug`, or `marketingOptIn`. |
|
|
531
605
|
| `deleteCurrentUser(): Promise<void>` | Mark account for deletion and log out. |
|
|
532
|
-
| `
|
|
606
|
+
| `previewInvite(token): Promise<InvitePreview>` | Look up an invite link without redeeming it. No auth required. |
|
|
607
|
+
| `redeemInvite(token): Promise<InviteRedeemResult>` | Redeem an invite, joining (or upgrading in) its space. |
|
|
533
608
|
| `listSpaces(): Promise<RoolSpaceInfo[]>` | List accessible spaces. |
|
|
534
609
|
| `openSpace(id): Promise<RoolSpace>` | Open/cached live space handle. |
|
|
535
610
|
| `createSpace(name): Promise<RoolSpace>` | Create and open a space. |
|
|
@@ -561,7 +636,7 @@ client.on('error', (error, context) => void 0);
|
|
|
561
636
|
|
|
562
637
|
## RoolSpace API
|
|
563
638
|
|
|
564
|
-
Properties: `id`, `name`, `role`, `
|
|
639
|
+
Properties: `id`, `name`, `role`, `memberCount`, `channels`, `route`, `webdav`.
|
|
565
640
|
|
|
566
641
|
| Method | Description |
|
|
567
642
|
| --- | --- |
|
|
@@ -570,9 +645,11 @@ Properties: `id`, `name`, `role`, `linkAccess`, `memberCount`, `channels`, `rout
|
|
|
570
645
|
| `rename(newName): Promise<void>` | Rename the space. |
|
|
571
646
|
| `delete(): Promise<void>` | Permanently delete the space. |
|
|
572
647
|
| `listUsers(): Promise<SpaceMember[]>` | List collaborators. |
|
|
573
|
-
| `
|
|
648
|
+
| `setUserRole(userId, role): Promise<void>` | Change an existing member's role. |
|
|
574
649
|
| `removeUser(userId): Promise<void>` | Remove collaborator. |
|
|
575
|
-
| `
|
|
650
|
+
| `createInvite(role, options?): Promise<SpaceInviteCreated>` | Mint an invite link; `options` takes `email`, `expiresInDays`, `maxUses`. |
|
|
651
|
+
| `listInvites(): Promise<SpaceInvite[]>` | List currently redeemable invites. |
|
|
652
|
+
| `revokeInvite(inviteId): Promise<boolean>` | Revoke an invite so its link stops working. |
|
|
576
653
|
| `renameChannel(channelId, name): Promise<void>` | Rename a channel. |
|
|
577
654
|
| `deleteChannel(channelId): Promise<void>` | Delete a channel and history. |
|
|
578
655
|
| `exportArchive(): Promise<Blob>` | Export a space archive. |
|
|
@@ -593,7 +670,7 @@ space.on('connectionStateChanged', (state) => void 0);
|
|
|
593
670
|
|
|
594
671
|
## RoolChannel API
|
|
595
672
|
|
|
596
|
-
Properties: `id` (space ID), `name` (space name), `role`, `
|
|
673
|
+
Properties: `id` (space ID), `name` (space name), `role`, `userId`, `channelId`, `channelName`, `conversationId`, `isReadOnly`, `activeLeafId`.
|
|
597
674
|
|
|
598
675
|
| Area | Methods |
|
|
599
676
|
| --- | --- |
|
|
@@ -663,6 +740,62 @@ interface GetObjectsResult {
|
|
|
663
740
|
missing: string[];
|
|
664
741
|
}
|
|
665
742
|
|
|
743
|
+
type InviteRole = 'admin' | 'editor' | 'viewer';
|
|
744
|
+
|
|
745
|
+
interface SpaceInvite {
|
|
746
|
+
inviteId: string;
|
|
747
|
+
spaceId: string;
|
|
748
|
+
role: InviteRole;
|
|
749
|
+
email: string | null;
|
|
750
|
+
createdBy: string;
|
|
751
|
+
createdAt: string;
|
|
752
|
+
expiresAt: string;
|
|
753
|
+
maxUses: number | null;
|
|
754
|
+
useCount: number;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Outcome of the invite email send. Null when no email was involved (open link).
|
|
758
|
+
// The invite is always minted and its `url` is usable regardless of this value;
|
|
759
|
+
// only the email delivery is reflected here.
|
|
760
|
+
// - 'sent': email dispatched
|
|
761
|
+
// - 'not_configured': server has no mail provider (local dev)
|
|
762
|
+
// - 'failed': provider rejected the send
|
|
763
|
+
// - 'cooldown': a recent invite to this same address was already emailed
|
|
764
|
+
// - 'rate_limited': the inviter hit their daily email-invite cap
|
|
765
|
+
// Treat unknown values as not sent.
|
|
766
|
+
type InviteEmailStatus =
|
|
767
|
+
| 'sent'
|
|
768
|
+
| 'not_configured'
|
|
769
|
+
| 'failed'
|
|
770
|
+
| 'cooldown'
|
|
771
|
+
| 'rate_limited'
|
|
772
|
+
| (string & {});
|
|
773
|
+
|
|
774
|
+
interface SpaceInviteCreated {
|
|
775
|
+
inviteId: string;
|
|
776
|
+
spaceId: string;
|
|
777
|
+
role: InviteRole;
|
|
778
|
+
email: string | null;
|
|
779
|
+
expiresAt: string;
|
|
780
|
+
maxUses: number | null;
|
|
781
|
+
url: string; // contains the secret token; only available at mint time
|
|
782
|
+
emailStatus: InviteEmailStatus | null;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
interface InvitePreview {
|
|
786
|
+
spaceId: string;
|
|
787
|
+
spaceName: string;
|
|
788
|
+
role: InviteRole;
|
|
789
|
+
email: string | null;
|
|
790
|
+
inviterName: string | null;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
interface InviteRedeemResult {
|
|
794
|
+
spaceId: string;
|
|
795
|
+
role: RoolUserRole;
|
|
796
|
+
status: 'joined' | 'upgraded' | 'already_member';
|
|
797
|
+
}
|
|
798
|
+
|
|
666
799
|
interface RoolObjectStat {
|
|
667
800
|
path: string;
|
|
668
801
|
modifiedAt: number;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { AuthProvider, AuthUser } from './types.js';
|
|
2
|
+
import { type Logger } from './logger.js';
|
|
3
|
+
export interface BaseTokenAuthConfig {
|
|
4
|
+
/** Auth URL (e.g. https://rool.dev/auth). Injected by RoolClient if omitted. */
|
|
5
|
+
authUrl?: string;
|
|
6
|
+
/** Injected by RoolClient if omitted. */
|
|
7
|
+
logger?: Logger;
|
|
8
|
+
/** Injected by RoolClient if omitted, so auth-state reaches client events. */
|
|
9
|
+
onAuthStateChanged?: (authenticated: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare abstract class BaseTokenAuthProvider implements AuthProvider {
|
|
12
|
+
protected logger: Logger;
|
|
13
|
+
private _authUrl;
|
|
14
|
+
private _onAuthStateChanged;
|
|
15
|
+
private refreshPromise;
|
|
16
|
+
private refreshTimeoutId;
|
|
17
|
+
private boundVisibilityHandler;
|
|
18
|
+
constructor(config?: BaseTokenAuthConfig);
|
|
19
|
+
setAuthUrl(url: string): void;
|
|
20
|
+
setLogger(logger: Logger): void;
|
|
21
|
+
setAuthStateChangedHandler(handler: (authenticated: boolean) => void): void;
|
|
22
|
+
abstract initialize(): boolean;
|
|
23
|
+
abstract login(appName: string, params?: Record<string, string>): Promise<void> | void;
|
|
24
|
+
abstract signup(appName: string, params?: Record<string, string>): Promise<void> | void;
|
|
25
|
+
/**
|
|
26
|
+
* Check if user is currently authenticated.
|
|
27
|
+
*
|
|
28
|
+
* This reports identity (do we hold credentials), NOT server reachability.
|
|
29
|
+
* It deliberately does not perform a network refresh: a backend outage must
|
|
30
|
+
* not read as "logged out". A genuinely invalid/expired refresh token
|
|
31
|
+
* surfaces later as a 401 on first real use, which clears tokens and fires
|
|
32
|
+
* onAuthStateChanged(false) — the only path that ends the session.
|
|
33
|
+
*/
|
|
34
|
+
isAuthenticated(): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Get current access token and rool token, refreshing if expired.
|
|
37
|
+
* Returns undefined if not authenticated.
|
|
38
|
+
*/
|
|
39
|
+
getTokens(): Promise<{
|
|
40
|
+
accessToken: string;
|
|
41
|
+
roolToken: string;
|
|
42
|
+
} | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Get auth identity decoded from JWT token.
|
|
45
|
+
*/
|
|
46
|
+
getAuthUser(): AuthUser;
|
|
47
|
+
/**
|
|
48
|
+
* Complete an email verification flow. Exchanges a verify JWT (from the
|
|
49
|
+
* verification email link) for a fresh token set and signs the user in.
|
|
50
|
+
*/
|
|
51
|
+
verify(token: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Logout - clear all tokens and state.
|
|
54
|
+
*/
|
|
55
|
+
logout(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Destroy auth manager - clear refresh timers and listeners.
|
|
58
|
+
*/
|
|
59
|
+
destroy(): void;
|
|
60
|
+
/** Auth URL without trailing slash */
|
|
61
|
+
protected get authBaseUrl(): string;
|
|
62
|
+
protected notifyAuthState(authenticated: boolean): void;
|
|
63
|
+
/** Persist a fresh token set and (re)arm the background refresh timer. */
|
|
64
|
+
protected acceptTokens(accessToken: string, refreshToken: string | null, roolToken: string | null, expiresAt: number): void;
|
|
65
|
+
/** Arm auto-refresh + visibility re-scheduling. Call from initialize(). */
|
|
66
|
+
protected initBase(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Overridable hook: clear subclass-owned transient state on logout/cancel
|
|
69
|
+
* (e.g. an in-flight OAuth `state` or PKCE verifier). No-op by default.
|
|
70
|
+
*/
|
|
71
|
+
protected clearTransientState(): void;
|
|
72
|
+
protected get storagePrefix(): string;
|
|
73
|
+
/** Build a storage key scoped to this auth endpoint. */
|
|
74
|
+
protected keyFor(name: string): string;
|
|
75
|
+
protected get storageKeys(): {
|
|
76
|
+
readonly access: `${string}access_token`;
|
|
77
|
+
readonly refresh: `${string}refresh_token`;
|
|
78
|
+
readonly rool: `${string}rool_token`;
|
|
79
|
+
readonly expiresAt: `${string}token_expires_at`;
|
|
80
|
+
};
|
|
81
|
+
protected readString(key: string): string | null;
|
|
82
|
+
protected writeString(key: string, value: string): void;
|
|
83
|
+
protected removeString(key: string): void;
|
|
84
|
+
protected scheduleTokenRefresh(): void;
|
|
85
|
+
protected writeTokens(accessToken: string | null, refreshToken: string | null, expiresAt: number | null): void;
|
|
86
|
+
protected writeRoolToken(token: string | null): void;
|
|
87
|
+
protected clearTokens(): void;
|
|
88
|
+
protected readAccessToken(): string | null;
|
|
89
|
+
protected readRoolToken(): string;
|
|
90
|
+
protected readExpiresAt(): number | null;
|
|
91
|
+
/**
|
|
92
|
+
* Get a short hash of the auth URL for scoping storage by endpoint.
|
|
93
|
+
*/
|
|
94
|
+
private get endpointHash();
|
|
95
|
+
private tryRefreshToken;
|
|
96
|
+
private listenForVisibility;
|
|
97
|
+
private cancelScheduledRefresh;
|
|
98
|
+
private decodeAuthUser;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=auth-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-base.d.ts","sourceRoot":"","sources":["../src/auth-base.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAKzD,MAAM,WAAW,mBAAmB;IAChC,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;CACzD;AAED,8BAAsB,qBAAsB,YAAW,YAAY;IAC/D,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,cAAc,CAAiC;IACvD,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,sBAAsB,CAA6B;gBAE/C,MAAM,GAAE,mBAAwB;IAS5C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,0BAA0B,CAAC,OAAO,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAK3E,QAAQ,CAAC,UAAU,IAAI,OAAO;IAC9B,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IACtF,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAEvF;;;;;;;;OAQG;IACG,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAIzC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAiBlF;;OAEG;IACH,WAAW,IAAI,QAAQ;IAMvB;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA4C7C;;OAEG;IACH,MAAM,IAAI,IAAI;IAOd;;OAEG;IACH,OAAO,IAAI,IAAI;IAYf,sCAAsC;IACtC,SAAS,KAAK,WAAW,IAAI,MAAM,CAElC;IAED,SAAS,CAAC,eAAe,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI;IAIvD,0EAA0E;IAC1E,SAAS,CAAC,YAAY,CAClB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GAClB,IAAI;IAMP,2EAA2E;IAC3E,SAAS,CAAC,QAAQ,IAAI,IAAI;IAK1B;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAErC,SAAS,KAAK,aAAa,IAAI,MAAM,CAEpC;IAED,wDAAwD;IACxD,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAItC,SAAS,KAAK,WAAW;;;;;MAQxB;IAED,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQhD,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQvD,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQzC,SAAS,CAAC,oBAAoB,IAAI,IAAI;IAmBtC,SAAS,CAAC,WAAW,CACjB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,GACzB,IAAI;IAoBP,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQpD,SAAS,CAAC,WAAW,IAAI,IAAI;IAK7B,SAAS,CAAC,eAAe,IAAI,MAAM,GAAG,IAAI;IAI1C,SAAS,CAAC,aAAa,IAAI,MAAM;IAIjC,SAAS,CAAC,aAAa,IAAI,MAAM,GAAG,IAAI;IAWxC;;OAEG;IACH,OAAO,KAAK,YAAY,GAQvB;YAEa,eAAe;IAoE7B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,cAAc;CAYzB"}
|