@sogni-ai/sogni-client 3.4.0-alpha.1 → 4.0.0-alpha.2

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/Account/CurrentAccount.d.ts +2 -4
  3. package/dist/Account/CurrentAccount.js +4 -9
  4. package/dist/Account/CurrentAccount.js.map +1 -1
  5. package/dist/Account/index.d.ts +2 -30
  6. package/dist/Account/index.js +36 -49
  7. package/dist/Account/index.js.map +1 -1
  8. package/dist/Account/types.d.ts +11 -0
  9. package/dist/ApiClient/WebSocketClient/index.d.ts +1 -1
  10. package/dist/ApiClient/WebSocketClient/index.js +1 -10
  11. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  12. package/dist/ApiClient/index.d.ts +12 -5
  13. package/dist/ApiClient/index.js +17 -31
  14. package/dist/ApiClient/index.js.map +1 -1
  15. package/dist/index.d.ts +23 -0
  16. package/dist/index.js +48 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/AuthManager/AuthManagerBase.d.ts +25 -0
  19. package/dist/lib/AuthManager/AuthManagerBase.js +14 -0
  20. package/dist/lib/AuthManager/AuthManagerBase.js.map +1 -0
  21. package/dist/lib/AuthManager/CookieAuthManager.d.ts +15 -0
  22. package/dist/lib/AuthManager/CookieAuthManager.js +53 -0
  23. package/dist/lib/AuthManager/CookieAuthManager.js.map +1 -0
  24. package/dist/lib/AuthManager/TokenAuthManager.d.ts +41 -0
  25. package/dist/lib/{AuthManager.js → AuthManager/TokenAuthManager.js} +96 -60
  26. package/dist/lib/AuthManager/TokenAuthManager.js.map +1 -0
  27. package/dist/lib/AuthManager/index.d.ts +5 -0
  28. package/dist/lib/AuthManager/index.js +11 -0
  29. package/dist/lib/AuthManager/index.js.map +1 -0
  30. package/dist/lib/RestClient.d.ts +1 -1
  31. package/dist/lib/RestClient.js +6 -2
  32. package/dist/lib/RestClient.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/Account/CurrentAccount.ts +5 -12
  35. package/src/Account/index.ts +34 -48
  36. package/src/Account/types.ts +12 -0
  37. package/src/ApiClient/WebSocketClient/index.ts +2 -11
  38. package/src/ApiClient/index.ts +35 -31
  39. package/src/index.ts +63 -9
  40. package/src/lib/AuthManager/AuthManagerBase.ts +37 -0
  41. package/src/lib/AuthManager/CookieAuthManager.ts +40 -0
  42. package/src/lib/{AuthManager.ts → AuthManager/TokenAuthManager.ts} +97 -77
  43. package/src/lib/AuthManager/index.ts +8 -0
  44. package/src/lib/RestClient.ts +7 -10
  45. package/dist/lib/AuthManager.d.ts +0 -51
  46. package/dist/lib/AuthManager.js.map +0 -1
@@ -1,100 +1,117 @@
1
- import { decodeToken, decodeRefreshToken } from './utils';
2
- import { ApiError, ApiErrorResponse } from '../ApiClient';
3
- import { Logger } from './DefaultLogger';
4
- import isNodejs from './isNodejs';
1
+ import { decodeToken, decodeRefreshToken } from '../utils';
2
+ import { ApiError, ApiErrorResponse } from '../../ApiClient';
3
+ import { Logger } from '../DefaultLogger';
4
+ import isNodejs from '../isNodejs';
5
5
  import Cookie from 'js-cookie';
6
- import TypedEventEmitter from './TypedEventEmitter';
6
+ import AuthManagerBase from './AuthManagerBase';
7
+ import { ClientOptions } from 'ws';
7
8
 
8
9
  /**
9
- * Tokens object, containing the token and refresh token
10
- * @typedef {Object} Tokens
11
- * @property {string} [token] - The JWT token. Optonal, if missing it will be retrieved from the server
10
+ * Token object, containing the token and refresh token
11
+ * @property {string} token - The JWT token
12
12
  * @property {string} refreshToken - The refresh token
13
13
  */
14
- export interface Tokens {
15
- token?: string;
14
+ export interface TokenAuthData {
15
+ token: string;
16
16
  refreshToken: string;
17
17
  }
18
18
 
19
- export type AuthUpdatedEvent =
20
- | { token: string; refreshToken: string; walletAddress: string }
21
- | { token: null; refreshToken: null; walletAddress: null };
22
-
23
- interface AuthManagerEvents {
24
- updated: AuthUpdatedEvent;
25
- refreshFailed: ApiErrorResponse;
26
- }
27
-
28
- class AuthManager extends TypedEventEmitter<AuthManagerEvents> {
19
+ class TokenAuthManager extends AuthManagerBase<TokenAuthData | null> {
29
20
  private _token?: string;
30
21
  private _tokenExpiresAt: Date = new Date(0);
31
22
  private _refreshToken?: string;
32
23
  private _refreshTokenExpiresAt: Date = new Date(0);
33
- private _logger: Logger;
34
24
  private _baseUrl: string;
35
- private _walletAddress?: string;
36
25
  private _renewTokenPromise?: Promise<string>;
37
26
 
38
27
  constructor(baseUrl: string, logger: Logger) {
39
- super();
40
- this._logger = logger;
28
+ super(logger);
41
29
  this._baseUrl = baseUrl;
42
30
  }
43
31
 
44
- get refreshToken() {
45
- return this._refreshToken;
46
- }
47
-
48
- get walletAddress() {
49
- return this._walletAddress;
50
- }
51
-
52
32
  get isAuthenticated() {
53
33
  return !!this._refreshToken && this._refreshTokenExpiresAt > new Date();
54
34
  }
55
35
 
56
- private _updateCookies() {
57
- if (isNodejs) {
58
- return;
59
- }
60
- const token = this._token;
61
- if (token) {
62
- Cookie.set('authorization', token, {
63
- domain: '.sogni.ai',
64
- expires: 1
65
- });
66
- } else {
67
- Cookie.remove('authorization', {
68
- domain: '.sogni.ai'
69
- });
36
+ async backup() {
37
+ if (this._token && this._refreshToken) {
38
+ return { token: this._token, refreshToken: this._refreshToken };
70
39
  }
40
+ return null;
71
41
  }
72
42
 
73
- async setTokens({ refreshToken, token }: { refreshToken: string; token?: string }) {
43
+ async authenticate({ refreshToken, token }: TokenAuthData) {
44
+ // If there is a token, and it is not expired, authenticate with it
74
45
  if (token) {
75
- this._updateTokens({ token, refreshToken });
76
- return;
46
+ const { expiresAt } = decodeToken(token);
47
+ if (expiresAt > new Date()) {
48
+ this._updateTokens({ token, refreshToken });
49
+ this.emit('updated', true);
50
+ return;
51
+ }
77
52
  }
53
+ // If token is expired, try to renew it with the refresh token
78
54
  this._refreshToken = refreshToken;
79
55
  const { expiresAt: refreshExpiresAt } = decodeRefreshToken(refreshToken);
80
56
  this._refreshTokenExpiresAt = refreshExpiresAt;
81
- await this.renewToken();
57
+ await this._renewTokenSafe();
58
+ this.emit('updated', true);
82
59
  }
83
60
 
84
- async getToken(): Promise<string | undefined> {
61
+ clear() {
62
+ // Prevent duplicate events
63
+ if (!this._token && !this._refreshToken) {
64
+ return;
65
+ }
66
+ this._refreshToken = undefined;
67
+ this._refreshTokenExpiresAt = new Date(0);
68
+ this._token = undefined;
69
+ this._tokenExpiresAt = new Date(0);
70
+ this.emit('updated', false);
71
+ }
72
+
73
+ async authenticateRequest(option: RequestInit): Promise<RequestInit> {
85
74
  //If there is a token, and it is not expired, return it
75
+ if (this._token && this._tokenExpiresAt > new Date()) {
76
+ return { ...option, headers: { ...option.headers, Authorization: this._token } };
77
+ }
78
+ //If there is no refresh token, return undefined, to make unauthorized requests
79
+ if (!this._refreshToken) {
80
+ return option;
81
+ }
82
+ //If there is a refresh token, try to renew the token
83
+ const token = await this._renewTokenSafe();
84
+ return { ...option, headers: { ...option.headers, Authorization: token } };
85
+ }
86
+
87
+ async socketOptions(): Promise<ClientOptions | undefined> {
88
+ if (!isNodejs) {
89
+ return undefined;
90
+ }
91
+ const token = await this._getToken();
92
+ if (!token) {
93
+ return undefined;
94
+ }
95
+ return {
96
+ headers: {
97
+ Authorization: token
98
+ }
99
+ };
100
+ }
101
+
102
+ private async _getToken() {
86
103
  if (this._token && this._tokenExpiresAt > new Date()) {
87
104
  return this._token;
88
105
  }
89
106
  //If there is no refresh token, return undefined, to make unauthorized requests
90
107
  if (!this._refreshToken) {
91
- return;
108
+ return undefined;
92
109
  }
93
110
  //If there is a refresh token, try to renew the token
94
- return this.renewToken();
111
+ return this._renewTokenSafe();
95
112
  }
96
113
 
97
- async renewToken(): Promise<string> {
114
+ private async _renewTokenSafe(): Promise<string> {
98
115
  if (this._renewTokenPromise) {
99
116
  return this._renewTokenPromise;
100
117
  }
@@ -105,33 +122,41 @@ class AuthManager extends TypedEventEmitter<AuthManagerEvents> {
105
122
  return this._renewTokenPromise;
106
123
  }
107
124
 
108
- clear() {
109
- // Prevent duplicate events
110
- if (!this._token && !this._refreshToken) {
111
- return;
112
- }
113
- this._refreshToken = undefined;
114
- this._refreshTokenExpiresAt = new Date(0);
115
- this._token = undefined;
116
- this._tokenExpiresAt = new Date(0);
117
- this._walletAddress = undefined;
118
- this.emit('updated', { token: null, refreshToken: null, walletAddress: null });
119
- }
120
-
121
125
  private _updateTokens({ token, refreshToken }: { token: string; refreshToken: string }) {
122
126
  // Prevent duplicate events
123
127
  if (this._token === token && this._refreshToken === refreshToken) {
124
128
  return;
125
129
  }
126
130
  this._token = token;
127
- const { expiresAt, walletAddress } = decodeToken(token);
128
- this._walletAddress = walletAddress;
131
+ const { expiresAt } = decodeToken(token);
129
132
  this._tokenExpiresAt = expiresAt;
130
133
  this._refreshToken = refreshToken;
131
134
  const { expiresAt: refreshExpiresAt } = decodeRefreshToken(refreshToken);
132
135
  this._refreshTokenExpiresAt = refreshExpiresAt;
133
136
  this._updateCookies();
134
- this.emit('updated', { token, refreshToken, walletAddress });
137
+ this.emit('updated', true);
138
+ }
139
+
140
+ /**
141
+ * This is a fallback for browsers, where we can't set headers on WebSocket requests.
142
+ * Normally a browser should use CookieAuthManager
143
+ * @private
144
+ */
145
+ private _updateCookies() {
146
+ if (isNodejs) {
147
+ return;
148
+ }
149
+ const token = this._token;
150
+ if (token) {
151
+ Cookie.set('authorization', token, {
152
+ domain: '.sogni.ai',
153
+ expires: 1
154
+ });
155
+ } else {
156
+ Cookie.remove('authorization', {
157
+ domain: '.sogni.ai'
158
+ });
159
+ }
135
160
  }
136
161
 
137
162
  private async _renewToken(): Promise<string> {
@@ -150,16 +175,11 @@ class AuthManager extends TypedEventEmitter<AuthManagerEvents> {
150
175
  try {
151
176
  responseData = await response.json();
152
177
  } catch (e) {
153
- this.emit('refreshFailed', {
154
- status: 'error',
155
- errorCode: 0,
156
- message: 'Failed to parse response'
157
- });
178
+ this.clear();
158
179
  this._logger.error('Failed to parse response:', e);
159
180
  throw new Error('Failed to parse response');
160
181
  }
161
182
  if (!response.ok) {
162
- this.emit('refreshFailed', responseData);
163
183
  this.clear();
164
184
  throw new ApiError(response.status, responseData as ApiErrorResponse);
165
185
  }
@@ -169,4 +189,4 @@ class AuthManager extends TypedEventEmitter<AuthManagerEvents> {
169
189
  }
170
190
  }
171
191
 
172
- export default AuthManager;
192
+ export default TokenAuthManager;
@@ -0,0 +1,8 @@
1
+ import CookieAuthManager from './CookieAuthManager';
2
+ import TokenAuthManager, { TokenAuthData } from './TokenAuthManager';
3
+
4
+ export type { TokenAuthData };
5
+
6
+ export { CookieAuthManager, TokenAuthManager };
7
+
8
+ export type AuthManager = CookieAuthManager | TokenAuthManager;
@@ -2,7 +2,7 @@ import { ApiError, ApiErrorResponse } from '../ApiClient';
2
2
  import TypedEventEmitter, { EventMap } from './TypedEventEmitter';
3
3
  import { JSONValue } from '../types/json';
4
4
  import { Logger } from './DefaultLogger';
5
- import AuthManager from './AuthManager';
5
+ import { AuthManager } from './AuthManager';
6
6
 
7
7
  class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
8
8
  readonly baseUrl: string;
@@ -29,15 +29,8 @@ class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
29
29
  }
30
30
 
31
31
  private async request<T = JSONValue>(url: string, options: RequestInit = {}): Promise<T> {
32
- const token = await this.auth.getToken();
33
- return fetch(url, {
34
- ...options,
35
- credentials: 'include',
36
- headers: {
37
- ...(options.headers || {}),
38
- ...(token ? { Authorization: token } : {})
39
- }
40
- }).then((r) => this.processResponse(r) as T);
32
+ const init = await this.auth.authenticateRequest(options);
33
+ return fetch(url, init).then((r) => this.processResponse(r) as T);
41
34
  }
42
35
 
43
36
  private async processResponse(response: Response): Promise<JSONValue> {
@@ -48,6 +41,10 @@ class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
48
41
  this._logger.error('Failed to parse response:', e);
49
42
  throw new Error('Failed to parse response');
50
43
  }
44
+ // 401 means that the client instance is not authenticated, so we clear the authentication
45
+ if (response.status === 401 && this.auth.isAuthenticated) {
46
+ this.auth.clear();
47
+ }
51
48
  if (!response.ok) {
52
49
  throw new ApiError(response.status, responseData as ApiErrorResponse);
53
50
  }
@@ -1,51 +0,0 @@
1
- import { ApiErrorResponse } from '../ApiClient';
2
- import { Logger } from './DefaultLogger';
3
- import TypedEventEmitter from './TypedEventEmitter';
4
- /**
5
- * Tokens object, containing the token and refresh token
6
- * @typedef {Object} Tokens
7
- * @property {string} [token] - The JWT token. Optonal, if missing it will be retrieved from the server
8
- * @property {string} refreshToken - The refresh token
9
- */
10
- export interface Tokens {
11
- token?: string;
12
- refreshToken: string;
13
- }
14
- export type AuthUpdatedEvent = {
15
- token: string;
16
- refreshToken: string;
17
- walletAddress: string;
18
- } | {
19
- token: null;
20
- refreshToken: null;
21
- walletAddress: null;
22
- };
23
- interface AuthManagerEvents {
24
- updated: AuthUpdatedEvent;
25
- refreshFailed: ApiErrorResponse;
26
- }
27
- declare class AuthManager extends TypedEventEmitter<AuthManagerEvents> {
28
- private _token?;
29
- private _tokenExpiresAt;
30
- private _refreshToken?;
31
- private _refreshTokenExpiresAt;
32
- private _logger;
33
- private _baseUrl;
34
- private _walletAddress?;
35
- private _renewTokenPromise?;
36
- constructor(baseUrl: string, logger: Logger);
37
- get refreshToken(): string | undefined;
38
- get walletAddress(): string | undefined;
39
- get isAuthenticated(): boolean;
40
- private _updateCookies;
41
- setTokens({ refreshToken, token }: {
42
- refreshToken: string;
43
- token?: string;
44
- }): Promise<void>;
45
- getToken(): Promise<string | undefined>;
46
- renewToken(): Promise<string>;
47
- clear(): void;
48
- private _updateTokens;
49
- private _renewToken;
50
- }
51
- export default AuthManager;
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthManager.js","sourceRoot":"","sources":["../../src/lib/AuthManager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,mCAA0D;AAC1D,4CAA0D;AAE1D,0DAAkC;AAClC,0DAA+B;AAC/B,4EAAoD;AAsBpD,MAAM,WAAY,SAAQ,2BAAoC;IAU5D,YAAY,OAAe,EAAE,MAAc;QACzC,KAAK,EAAE,CAAC;QATF,oBAAe,GAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpC,2BAAsB,GAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QAQjD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,IAAI,eAAe;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,sBAAsB,GAAG,IAAI,IAAI,EAAE,CAAC;IAC1E,CAAC;IAEO,cAAc;QACpB,IAAI,kBAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,KAAK,EAAE,CAAC;YACV,mBAAM,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE;gBACjC,MAAM,EAAE,WAAW;gBACnB,OAAO,EAAE,CAAC;aACX,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,mBAAM,CAAC,MAAM,CAAC,eAAe,EAAE;gBAC7B,MAAM,EAAE,WAAW;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEK,SAAS;6DAAC,EAAE,YAAY,EAAE,KAAK,EAA4C;YAC/E,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;YAClC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,IAAA,0BAAkB,EAAC,YAAY,CAAC,CAAC;YACzE,IAAI,CAAC,sBAAsB,GAAG,gBAAgB,CAAC;YAC/C,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC;KAAA;IAEK,QAAQ;;YACZ,uDAAuD;YACvD,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC,MAAM,CAAC;YACrB,CAAC;YACD,+EAA+E;YAC/E,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACxB,OAAO;YACT,CAAC;YACD,qDAAqD;YACrD,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;QAC3B,CAAC;KAAA;IAEK,UAAU;;YACd,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC,kBAAkB,CAAC;YACjC,CAAC;YACD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE;gBACnC,IAAI,CAAC,kBAAkB,GAAG,SAAS,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,kBAAkB,CAAC;QACjC,CAAC;KAAA;IAED,KAAK;QACH,2BAA2B;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,sBAAsB,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,CAAC,eAAe,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACjF,CAAC;IAEO,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAA2C;QACpF,2BAA2B;QAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;YACjE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,IAAA,mBAAW,EAAC,KAAK,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,IAAA,0BAAkB,EAAC,YAAY,CAAC,CAAC;QACzE,IAAI,CAAC,sBAAsB,GAAG,gBAAgB,CAAC;QAC/C,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,CAAC;IAC/D,CAAC;IAEa,WAAW;;YACvB,IAAI,IAAI,CAAC,sBAAsB,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC3E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;aAC3D,CAAC,CAAC;YACH,IAAI,YAAiB,CAAC;YACtB,IAAI,CAAC;gBACH,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACvC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;oBACzB,MAAM,EAAE,OAAO;oBACf,SAAS,EAAE,CAAC;oBACZ,OAAO,EAAE,0BAA0B;iBACpC,CAAC,CAAC;gBACH,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,CAAC,CAAC,CAAC;gBACnD,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;gBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,MAAM,IAAI,oBAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAgC,CAAC,CAAC;YACxE,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC;YAClD,IAAI,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC,MAAO,CAAC;QACtB,CAAC;KAAA;CACF;AAED,kBAAe,WAAW,CAAC"}