@teamphnx/sduiapi 0.1.4

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 (43) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +248 -0
  3. package/dist/auth/webUntisAuth.d.ts +3 -0
  4. package/dist/auth/webUntisAuth.d.ts.map +1 -0
  5. package/dist/auth/webUntisAuth.js +202 -0
  6. package/dist/auth/webUntisAuth.js.map +1 -0
  7. package/dist/client.d.ts +22 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +192 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/constants.d.ts +9 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +10 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/errors.d.ts +5 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +9 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.d.ts +5 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +4 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/src/index.d.ts +2 -0
  24. package/dist/src/index.d.ts.map +1 -0
  25. package/dist/src/index.js +4 -0
  26. package/dist/src/index.js.map +1 -0
  27. package/dist/types.d.ts +42 -0
  28. package/dist/types.d.ts.map +1 -0
  29. package/dist/types.js +2 -0
  30. package/dist/types.js.map +1 -0
  31. package/dist/utils/logging.d.ts +3 -0
  32. package/dist/utils/logging.d.ts.map +1 -0
  33. package/dist/utils/logging.js +11 -0
  34. package/dist/utils/logging.js.map +1 -0
  35. package/dist/utils/parsers.d.ts +4 -0
  36. package/dist/utils/parsers.d.ts.map +1 -0
  37. package/dist/utils/parsers.js +20 -0
  38. package/dist/utils/parsers.js.map +1 -0
  39. package/dist/utils/url.d.ts +3 -0
  40. package/dist/utils/url.d.ts.map +1 -0
  41. package/dist/utils/url.js +13 -0
  42. package/dist/utils/url.js.map +1 -0
  43. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # SduiAPI
2
+
3
+ TypeScript SDUI API client with WebUntis login support.
4
+
5
+ DISCLAIMER: An independent, open-source project – not connected to or supported by WebUntis, Untis GmbH or Sdui GmbH.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install sduiapi
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { SduiClient } from 'sduiapi';
17
+
18
+ const client = await SduiClient.authenticateWithWebUntis({
19
+ schoolSlink: 'example-school',
20
+ username: process.env.SDUI_USERNAME ?? '',
21
+ password: process.env.SDUI_PASSWORD ?? '',
22
+ });
23
+
24
+ const me = await client.getCurrentUser();
25
+ console.log(me);
26
+ ```
27
+
28
+ ## Public API
29
+
30
+ ### `SduiClient.authenticateWithWebUntis(credentials, options?)`
31
+
32
+ Creates an authenticated client by running the full SDUI <-> WebUntis bridge flow.
33
+
34
+ ### `SduiClient.fromAccessToken(accessToken)`
35
+
36
+ Creates a client when you already have a bearer token.
37
+
38
+ ### `client.request(config)`
39
+
40
+ Sends any request to the SDUI API using the authenticated HTTP instance.
41
+
42
+ ### `client.getCurrentUser()`
43
+
44
+ Convenience helper for `GET /v1/users/self`.
45
+
46
+ ### `client.getUserNews(userId, options?)`
47
+
48
+ Convenience helper for `GET /v1/users/:userId/feed/news`.
49
+
50
+ ```ts
51
+ const news = await client.getUserNews('user-id-placeholder', {
52
+ page: 2,
53
+ search: 'announcement',
54
+ });
55
+ ```
56
+
57
+ Options:
58
+
59
+ - `page` (default: `1`)
60
+ - `search` (default: `''`)
61
+
62
+ ### `client.getUserChats(userId, options?)`
63
+
64
+ Convenience helper for `GET /v1/users/:userId/channels/chats`.
65
+
66
+ ```ts
67
+ const chats = await client.getUserChats('user-id-placeholder', {
68
+ page: 2,
69
+ search: '',
70
+ limit: 10,
71
+ });
72
+ ```
73
+
74
+ Options:
75
+
76
+ - `page` (default: `1`)
77
+ - `search` (default: `''`)
78
+ - `limit` (default: `10`)
79
+
80
+ ### `client.getChatMessages(chatId, options?)`
81
+
82
+ Convenience helper for `GET /v1/channels/chats/:chatId/messages`.
83
+
84
+ ```ts
85
+ const messages = await client.getChatMessages('chat-id-placeholder', {
86
+ page: 1,
87
+ });
88
+ ```
89
+
90
+ Options:
91
+
92
+ - `page` (default: `1`)
93
+
94
+ ### `client.getMessageReaders(chatId, messageUuid, options?)`
95
+
96
+ Convenience helper for `GET /v1/channels/chats/:chatId/messages/:messageUuid/readers`.
97
+
98
+ ```ts
99
+ const readers = await client.getMessageReaders(
100
+ 'readers-chat-id-placeholder',
101
+ 'readers-message-uuid-placeholder',
102
+ {
103
+ page: 1,
104
+ search: '',
105
+ },
106
+ );
107
+ ```
108
+
109
+ Options:
110
+
111
+ - `page` (default: `1`)
112
+ - `search` (default: `''`)
113
+
114
+ ### `client.markChatAsRead(chatId, payload?)`
115
+
116
+ Convenience helper for `POST /v1/channels/chats/:chatId/read`.
117
+
118
+ ```ts
119
+ const result = await client.markChatAsRead('read-chat-id-placeholder', {});
120
+ ```
121
+
122
+ `payload` defaults to `{}` and is forwarded as JSON body.
123
+
124
+ ### `client.sendChatMessage(chatId, payload)`
125
+
126
+ Convenience helper for `POST /v1/channels/chats/:chatId/messages`.
127
+
128
+ ```ts
129
+ const sent = await client.sendChatMessage('message-chat-id-placeholder', {
130
+ content: '.',
131
+ });
132
+ ```
133
+
134
+ `payload.content` is required.
135
+ The payload is sent as `multipart/form-data`, and extra payload keys are forwarded as additional form fields.
136
+
137
+ ### `client.replyToChatMessage(chatId, replyUuid, payload)`
138
+
139
+ Convenience helper for replying via `POST /v1/channels/chats/:chatId/messages` with `reply_uuid`.
140
+
141
+ ```ts
142
+ const sentReply = await client.replyToChatMessage(
143
+ 'message-chat-id-placeholder',
144
+ 'message-uuid-placeholder',
145
+ {
146
+ content: 'Hallo',
147
+ },
148
+ );
149
+ ```
150
+
151
+ ### `client.deleteChatMessage(chatId, messageUuid)`
152
+
153
+ Convenience helper for `DELETE /v1/channels/chats/:chatId/messages/:messageUuid`.
154
+
155
+ ```ts
156
+ const result = await client.deleteChatMessage(
157
+ 'message-chat-id-placeholder',
158
+ 'message-uuid-placeholder',
159
+ );
160
+ ```
161
+
162
+ ### `client.getChannelUsers(channelId)`
163
+
164
+ Convenience helper for `GET /v1/channels/:channelId/users`.
165
+
166
+ ```ts
167
+ const users = await client.getChannelUsers('channel-id-placeholder');
168
+ ```
169
+
170
+ ### `authenticateWithWebUntis(credentials, options?)`
171
+
172
+ Lower-level function that returns:
173
+
174
+ ```ts
175
+ {
176
+ accessToken: string;
177
+ http: AxiosInstance;
178
+ }
179
+ ```
180
+
181
+ ## Error Handling
182
+
183
+ Authentication failures throw `SduiAuthError` with an optional `context` object for debugging.
184
+
185
+ ```ts
186
+ import { SduiAuthError, SduiClient } from 'sduiapi';
187
+
188
+ try {
189
+ await SduiClient.authenticateWithWebUntis({
190
+ schoolSlink: 'example-school',
191
+ username: '...',
192
+ password: '...',
193
+ });
194
+ } catch (error) {
195
+ if (error instanceof SduiAuthError) {
196
+ console.error(error.message, error.context);
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## Logging
202
+
203
+ Pass `logger` in options to get structured auth progress events.
204
+
205
+ ```ts
206
+ import { SduiClient } from 'sduiapi';
207
+
208
+ await SduiClient.authenticateWithWebUntis(
209
+ {
210
+ schoolSlink: 'example-school',
211
+ username: '...',
212
+ password: '...',
213
+ },
214
+ {
215
+ logger: (event) => {
216
+ console.log(
217
+ `[${event.step}] ${event.message}`,
218
+ event.details ?? {},
219
+ );
220
+ },
221
+ },
222
+ );
223
+ ```
224
+
225
+ ## Testing
226
+
227
+ ```bash
228
+ npm test
229
+ ```
230
+
231
+ The tests use mocked HTTP responses, so they do not call SDUI or WebUntis servers.
232
+
233
+ ### Live SDUI integration test (optional)
234
+
235
+ Create a local .env file (you can copy .env.example):
236
+
237
+ SDUI_LIVE_TEST=true
238
+ SDUI_SCHOOL_SLINK=example-school
239
+ SDUI_USERNAME=your_webuntis_username
240
+ SDUI_PASSWORD=your_webuntis_password
241
+
242
+ Run the real integration test:
243
+
244
+ ```bash
245
+ npm run test:live
246
+ ```
247
+
248
+ If SDUI_LIVE_TEST is false, or credentials are missing, the live authentication test is skipped.
@@ -0,0 +1,3 @@
1
+ import type { AuthenticateWithWebUntisOptions, SduiAuthResult, WebUntisCredentials } from '../types.js';
2
+ export declare function authenticateWithWebUntis(credentials: WebUntisCredentials, options?: AuthenticateWithWebUntisOptions): Promise<SduiAuthResult>;
3
+ //# sourceMappingURL=webUntisAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webUntisAuth.d.ts","sourceRoot":"","sources":["../../src/auth/webUntisAuth.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACR,+BAA+B,EAC/B,cAAc,EACd,mBAAmB,EACtB,MAAM,aAAa,CAAC;AAkHrB,wBAAsB,wBAAwB,CAC1C,WAAW,EAAE,mBAAmB,EAChC,OAAO,GAAE,+BAAoC,GAC9C,OAAO,CAAC,cAAc,CAAC,CAmPzB"}
@@ -0,0 +1,202 @@
1
+ import axios, {} from 'axios';
2
+ import { wrapper } from 'axios-cookiejar-support';
3
+ import { CookieJar } from 'tough-cookie';
4
+ import { DEFAULT_REDIRECT_HOP_LIMIT, DEFAULT_REQUEST_HEADERS, DEFAULT_USER_AGENT, SDUI_API_BASE_URL, SDUI_IDP_RETURN_URL, } from '../constants.js';
5
+ import { SduiAuthError } from '../errors.js';
6
+ import { emitLog } from '../utils/logging.js';
7
+ import { extractCsrfToken, extractMetaRefreshUrl, maskSecret, } from '../utils/parsers.js';
8
+ import { buildSduiAuthorizeUrl, resolveRedirectUrl } from '../utils/url.js';
9
+ function createBrowserLikeHttpClient(userAgent) {
10
+ const cookieJar = new CookieJar();
11
+ return wrapper(axios.create({
12
+ maxRedirects: 10,
13
+ validateStatus: () => true,
14
+ jar: cookieJar,
15
+ withCredentials: true,
16
+ headers: {
17
+ ...DEFAULT_REQUEST_HEADERS,
18
+ 'User-Agent': userAgent,
19
+ },
20
+ }));
21
+ }
22
+ function getFinalResponseUrl(response) {
23
+ const req = response.request;
24
+ return req?.res?.responseUrl ?? null;
25
+ }
26
+ function readLocationHeader(response) {
27
+ const location = response.headers.location;
28
+ if (typeof location === 'string') {
29
+ return location;
30
+ }
31
+ if (Array.isArray(location) && typeof location[0] === 'string') {
32
+ return location[0];
33
+ }
34
+ return null;
35
+ }
36
+ function isRedirectStatus(statusCode) {
37
+ return [301, 302, 303, 307, 308].includes(statusCode);
38
+ }
39
+ async function followUntilSduiCallback(http, startUrl, hopLimit, logger) {
40
+ let nextUrl = startUrl;
41
+ for (let hop = 1; hop <= hopLimit; hop += 1) {
42
+ const response = await http.get(nextUrl, {
43
+ maxRedirects: 0,
44
+ responseType: 'text',
45
+ validateStatus: () => true,
46
+ });
47
+ const location = readLocationHeader(response);
48
+ emitLog(logger, 'callback.redirect', 'Following redirect during callback resolution.', {
49
+ hop,
50
+ statusCode: response.status,
51
+ hasLocation: Boolean(location),
52
+ });
53
+ if (!location || !isRedirectStatus(response.status)) {
54
+ return null;
55
+ }
56
+ const resolvedUrl = resolveRedirectUrl(nextUrl, location);
57
+ if (resolvedUrl.startsWith('https://sdui.app/')) {
58
+ return resolvedUrl;
59
+ }
60
+ nextUrl = resolvedUrl;
61
+ }
62
+ return null;
63
+ }
64
+ export async function authenticateWithWebUntis(credentials, options = {}) {
65
+ const schoolSlink = credentials.schoolSlink.trim();
66
+ const username = credentials.username.trim();
67
+ const password = credentials.password;
68
+ if (!schoolSlink || !username || !password) {
69
+ throw new SduiAuthError('schoolSlink, username and password are required.');
70
+ }
71
+ const redirectHopLimit = options.redirectHopLimit ?? DEFAULT_REDIRECT_HOP_LIMIT;
72
+ if (redirectHopLimit < 1) {
73
+ throw new SduiAuthError('redirectHopLimit must be at least 1.');
74
+ }
75
+ const userAgent = options.userAgent ?? DEFAULT_USER_AGENT;
76
+ const http = createBrowserLikeHttpClient(userAgent);
77
+ emitLog(options.logger, 'school.lookup', 'Looking up school configuration.', { schoolSlink });
78
+ const schoolResponse = await http.get(`${SDUI_API_BASE_URL}/v1/find-schools`, {
79
+ params: { slink: schoolSlink },
80
+ });
81
+ const idpUri = schoolResponse.data?.data?.meta?.external_identity_providers?.[0]
82
+ ?.uri ?? null;
83
+ if (!idpUri) {
84
+ throw new SduiAuthError('Unable to resolve identity provider URL for school.', {
85
+ schoolSlink,
86
+ statusCode: schoolResponse.status,
87
+ });
88
+ }
89
+ const authorizeUrl = buildSduiAuthorizeUrl(idpUri, schoolSlink);
90
+ emitLog(options.logger, 'idp.bridge', 'Triggering SDUI SSO bridge.');
91
+ const idpResponse = await http.get(authorizeUrl, {
92
+ responseType: 'text',
93
+ });
94
+ const webUntisInitUrl = extractMetaRefreshUrl(idpResponse.data);
95
+ if (!webUntisInitUrl) {
96
+ throw new SduiAuthError('Failed to read WebUntis URL from IDP response.');
97
+ }
98
+ emitLog(options.logger, 'idp.meta-refresh', 'Resolved meta refresh target.', {
99
+ webUntisInitUrl,
100
+ });
101
+ const loginPageResponse = await http.get(webUntisInitUrl, {
102
+ responseType: 'text',
103
+ });
104
+ const csrfToken = extractCsrfToken(loginPageResponse.data);
105
+ if (!csrfToken) {
106
+ throw new SduiAuthError('Could not extract csrfToken from WebUntis page.');
107
+ }
108
+ emitLog(options.logger, 'webuntis.csrf', 'Extracted WebUntis CSRF token.', {
109
+ csrfToken: maskSecret(csrfToken),
110
+ });
111
+ const loginPageUrl = getFinalResponseUrl(loginPageResponse) ?? webUntisInitUrl;
112
+ const parsedLoginPageUrl = new URL(loginPageUrl);
113
+ const webUntisBaseUrl = `${parsedLoginPageUrl.protocol}//${parsedLoginPageUrl.host}`;
114
+ const schoolFromLoginUrl = parsedLoginPageUrl.searchParams.get('school') ?? schoolSlink;
115
+ const loginFormPayload = new URLSearchParams({
116
+ school: schoolFromLoginUrl,
117
+ j_username: username,
118
+ j_password: password,
119
+ });
120
+ emitLog(options.logger, 'webuntis.login', 'Submitting WebUntis credentials.', {
121
+ webUntisBaseUrl,
122
+ username,
123
+ });
124
+ const loginResponse = await http.post(`${webUntisBaseUrl}/WebUntis/j_spring_security_check`, loginFormPayload.toString(), {
125
+ headers: {
126
+ 'Content-Type': 'application/x-www-form-urlencoded',
127
+ 'X-Requested-With': 'XMLHttpRequest',
128
+ },
129
+ maxRedirects: 0,
130
+ validateStatus: () => true,
131
+ });
132
+ emitLog(options.logger, 'webuntis.login.done', 'WebUntis login request finished.', {
133
+ statusCode: loginResponse.status,
134
+ });
135
+ const sduiCallbackUrl = await followUntilSduiCallback(http, webUntisInitUrl, redirectHopLimit, options.logger);
136
+ if (!sduiCallbackUrl) {
137
+ throw new SduiAuthError('WebUntis did not redirect to SDUI callback URL. Credentials may be invalid or flow changed.');
138
+ }
139
+ const callbackUrl = new URL(sduiCallbackUrl);
140
+ const code1 = callbackUrl.searchParams.get('code');
141
+ const state1 = callbackUrl.searchParams.get('state');
142
+ if (!code1 || !state1) {
143
+ throw new SduiAuthError('Missing code/state in SDUI callback URL.', {
144
+ callbackUrl: sduiCallbackUrl,
145
+ });
146
+ }
147
+ emitLog(options.logger, 'idp.exchange.1', 'Exchanging first SDUI bridge code.', {
148
+ code: maskSecret(code1),
149
+ });
150
+ const idpExchangeResponse = await http.get(SDUI_IDP_RETURN_URL, {
151
+ params: {
152
+ code: code1,
153
+ state: state1,
154
+ },
155
+ maxRedirects: 0,
156
+ validateStatus: () => true,
157
+ });
158
+ const ssoVerifyLocation = readLocationHeader(idpExchangeResponse);
159
+ if (!isRedirectStatus(idpExchangeResponse.status) || !ssoVerifyLocation) {
160
+ throw new SduiAuthError('Failed to exchange code at SDUI identity bridge.', {
161
+ statusCode: idpExchangeResponse.status,
162
+ });
163
+ }
164
+ const ssoVerifyUrl = resolveRedirectUrl(SDUI_IDP_RETURN_URL, ssoVerifyLocation);
165
+ const code2 = new URL(ssoVerifyUrl).searchParams.get('code');
166
+ if (!code2) {
167
+ throw new SduiAuthError('Missing code in SSO verify redirect URL.', {
168
+ ssoVerifyUrl,
169
+ });
170
+ }
171
+ emitLog(options.logger, 'idp.exchange.2', 'Exchanging second code for API token.', {
172
+ code: maskSecret(code2),
173
+ });
174
+ const tokenResponse = await http.post(`${SDUI_API_BASE_URL}/v1/auth/login-idm`, {
175
+ code: code2,
176
+ slink: schoolSlink,
177
+ });
178
+ const accessToken = tokenResponse.data?.data?.access_token ??
179
+ tokenResponse.data?.access_token;
180
+ if (!accessToken) {
181
+ throw new SduiAuthError('Token exchange succeeded but no access token was returned.', {
182
+ statusCode: tokenResponse.status,
183
+ responseBody: tokenResponse.data,
184
+ });
185
+ }
186
+ emitLog(options.logger, 'auth.success', 'Authentication completed.', {
187
+ accessToken: maskSecret(accessToken),
188
+ });
189
+ const authenticatedHttp = axios.create({
190
+ baseURL: SDUI_API_BASE_URL,
191
+ headers: {
192
+ Accept: 'application/json',
193
+ Authorization: `Bearer ${accessToken}`,
194
+ 'User-Agent': userAgent,
195
+ },
196
+ });
197
+ return {
198
+ accessToken,
199
+ http: authenticatedHttp,
200
+ };
201
+ }
202
+ //# sourceMappingURL=webUntisAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webUntisAuth.js","sourceRoot":"","sources":["../../src/auth/webUntisAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type AxiosInstance, type AxiosRequestConfig } from 'axios';
2
+ import type { AuthenticateWithWebUntisOptions, GetChatMessagesOptions, GetMessageReadersOptions, GetUserChatsOptions, GetUserNewsOptions, MarkChatAsReadPayload, SendChatMessagePayload, WebUntisCredentials } from './types.js';
3
+ export declare class SduiClient {
4
+ readonly accessToken: string;
5
+ private readonly http;
6
+ private constructor();
7
+ static authenticateWithWebUntis(credentials: WebUntisCredentials, options?: AuthenticateWithWebUntisOptions): Promise<SduiClient>;
8
+ static fromAccessToken(accessToken: string, userAgent?: string): SduiClient;
9
+ request<T>(config: AxiosRequestConfig): Promise<T>;
10
+ getCurrentUser<T = unknown>(): Promise<T>;
11
+ getUserNews<T = unknown>(userId: string | number, options?: GetUserNewsOptions): Promise<T>;
12
+ getUserChats<T = unknown>(userId: string | number, options?: GetUserChatsOptions): Promise<T>;
13
+ getChatMessages<T = unknown>(chatId: string | number, options?: GetChatMessagesOptions): Promise<T>;
14
+ getMessageReaders<T = unknown>(chatId: string | number, messageUuid: string | number, options?: GetMessageReadersOptions): Promise<T>;
15
+ markChatAsRead<T = unknown>(chatId: string | number, payload?: MarkChatAsReadPayload): Promise<T>;
16
+ sendChatMessage<T = unknown>(chatId: string | number, payload: SendChatMessagePayload): Promise<T>;
17
+ replyToChatMessage<T = unknown>(chatId: string | number, replyUuid: string | number, payload: SendChatMessagePayload): Promise<T>;
18
+ deleteChatMessage<T = unknown>(chatId: string | number, messageUuid: string | number): Promise<T>;
19
+ getChannelUsers<T = unknown>(channelId: string | number): Promise<T>;
20
+ getHttpClient(): AxiosInstance;
21
+ }
22
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAG3E,OAAO,KAAK,EACR,+BAA+B,EAC/B,sBAAsB,EACtB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACtB,MAAM,YAAY,CAAC;AAEpB,qBAAa,UAAU;IACnB,SAAgB,WAAW,EAAE,MAAM,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IAErC,OAAO;WAKa,wBAAwB,CACxC,WAAW,EAAE,mBAAmB,EAChC,OAAO,GAAE,+BAAoC,GAC9C,OAAO,CAAC,UAAU,CAAC;WAQR,eAAe,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA2B,GACvC,UAAU;IAaA,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IAKlD,cAAc,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;IAOzC,WAAW,CAAC,CAAC,GAAG,OAAO,EAChC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,CAAC,CAAC;IAuBA,YAAY,CAAC,CAAC,GAAG,OAAO,EACjC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,CAAC,CAAC;IA6BA,eAAe,CAAC,CAAC,GAAG,OAAO,EACpC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,sBAA2B,GACrC,OAAO,CAAC,CAAC,CAAC;IAoBA,iBAAiB,CAAC,CAAC,GAAG,OAAO,EACtC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,OAAO,GAAE,wBAA6B,GACvC,OAAO,CAAC,CAAC,CAAC;IA4BA,cAAc,CAAC,CAAC,GAAG,OAAO,EACnC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,qBAA0B,GACpC,OAAO,CAAC,CAAC,CAAC;IAaA,eAAe,CAAC,CAAC,GAAG,OAAO,EACpC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,CAAC,CAAC;IA8BA,kBAAkB,CAAC,CAAC,GAAG,OAAO,EACvC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,CAAC,CAAC;IAYA,iBAAiB,CAAC,CAAC,GAAG,OAAO,EACtC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,WAAW,EAAE,MAAM,GAAG,MAAM,GAC7B,OAAO,CAAC,CAAC,CAAC;IAiBA,eAAe,CAAC,CAAC,GAAG,OAAO,EACpC,SAAS,EAAE,MAAM,GAAG,MAAM,GAC3B,OAAO,CAAC,CAAC,CAAC;IAYN,aAAa,IAAI,aAAa;CAGxC"}