ticktick-mcp 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/README.md +112 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1156 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +228 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +415 -0
- package/dist/oauth.js.map +1 -0
- package/dist/sdk/client.d.ts +280 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +388 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/errors.d.ts +92 -0
- package/dist/sdk/errors.d.ts.map +1 -0
- package/dist/sdk/errors.js +187 -0
- package/dist/sdk/errors.js.map +1 -0
- package/dist/sdk/index.d.ts +38 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +46 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/types.d.ts +308 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +28 -0
- package/dist/sdk/types.js.map +1 -0
- package/package.json +51 -0
package/dist/oauth.js
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TickTick OAuth Helper Module
|
|
3
|
+
*
|
|
4
|
+
* Handles OAuth 2.0 authentication flow for TickTick API:
|
|
5
|
+
* - Building authorization URLs
|
|
6
|
+
* - Token exchange (authorization code -> access token)
|
|
7
|
+
* - Token refresh
|
|
8
|
+
* - File-based token storage
|
|
9
|
+
*/
|
|
10
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Constants
|
|
16
|
+
// =============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* OAuth URLs for different regions.
|
|
19
|
+
*/
|
|
20
|
+
const OAUTH_URLS = {
|
|
21
|
+
global: {
|
|
22
|
+
authorize: "https://ticktick.com/oauth/authorize",
|
|
23
|
+
token: "https://ticktick.com/oauth/token",
|
|
24
|
+
},
|
|
25
|
+
china: {
|
|
26
|
+
authorize: "https://dida365.com/oauth/authorize",
|
|
27
|
+
token: "https://dida365.com/oauth/token",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Default scopes for TickTick OAuth.
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_SCOPES = ["tasks:read", "tasks:write"];
|
|
34
|
+
/**
|
|
35
|
+
* Default token storage path.
|
|
36
|
+
*/
|
|
37
|
+
const DEFAULT_TOKEN_PATH = join(homedir(), ".ticktick-mcp", "tokens.json");
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// OAuth Helper Class
|
|
40
|
+
// =============================================================================
|
|
41
|
+
/**
|
|
42
|
+
* TickTick OAuth Helper
|
|
43
|
+
*
|
|
44
|
+
* Provides methods for handling the OAuth 2.0 flow with TickTick.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const oauth = new TickTickOAuth({
|
|
49
|
+
* clientId: 'your-client-id',
|
|
50
|
+
* clientSecret: 'your-client-secret',
|
|
51
|
+
* redirectUri: 'http://localhost:8000/callback',
|
|
52
|
+
* region: 'global',
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Generate authorization URL
|
|
56
|
+
* const { url, state } = oauth.getAuthorizationUrl();
|
|
57
|
+
*
|
|
58
|
+
* // After user authorizes, exchange code for tokens
|
|
59
|
+
* const tokens = await oauth.exchangeCode(authorizationCode);
|
|
60
|
+
*
|
|
61
|
+
* // Later, refresh the tokens
|
|
62
|
+
* const newTokens = await oauth.refreshToken(tokens.refresh_token);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export class TickTickOAuth {
|
|
66
|
+
config;
|
|
67
|
+
tokenPath;
|
|
68
|
+
oauthUrls;
|
|
69
|
+
/**
|
|
70
|
+
* Create a new TickTick OAuth helper.
|
|
71
|
+
*
|
|
72
|
+
* @param config - OAuth configuration
|
|
73
|
+
* @param tokenPath - Optional custom path for token storage
|
|
74
|
+
*/
|
|
75
|
+
constructor(config, tokenPath) {
|
|
76
|
+
this.config = config;
|
|
77
|
+
this.tokenPath = tokenPath ?? DEFAULT_TOKEN_PATH;
|
|
78
|
+
this.oauthUrls = OAUTH_URLS[config.region ?? "global"];
|
|
79
|
+
}
|
|
80
|
+
// ===========================================================================
|
|
81
|
+
// Authorization URL
|
|
82
|
+
// ===========================================================================
|
|
83
|
+
/**
|
|
84
|
+
* Generate the authorization URL for initiating OAuth flow.
|
|
85
|
+
*
|
|
86
|
+
* @param scopes - Optional array of scopes (defaults to tasks:read tasks:write)
|
|
87
|
+
* @param state - Optional state parameter for CSRF protection (auto-generated if not provided)
|
|
88
|
+
* @returns The authorization URL and the state parameter
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const { url, state } = oauth.getAuthorizationUrl();
|
|
93
|
+
* // Redirect user to url
|
|
94
|
+
* // Store state to verify in callback
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
getAuthorizationUrl(scopes, state) {
|
|
98
|
+
const finalState = state ?? generateRandomState();
|
|
99
|
+
const finalScopes = scopes ?? DEFAULT_SCOPES;
|
|
100
|
+
const params = new URLSearchParams({
|
|
101
|
+
client_id: this.config.clientId,
|
|
102
|
+
redirect_uri: this.config.redirectUri,
|
|
103
|
+
response_type: "code",
|
|
104
|
+
scope: finalScopes.join(" "),
|
|
105
|
+
state: finalState,
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
url: `${this.oauthUrls.authorize}?${params.toString()}`,
|
|
109
|
+
state: finalState,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// ===========================================================================
|
|
113
|
+
// Token Exchange
|
|
114
|
+
// ===========================================================================
|
|
115
|
+
/**
|
|
116
|
+
* Exchange an authorization code for access and refresh tokens.
|
|
117
|
+
*
|
|
118
|
+
* @param code - The authorization code from the OAuth callback
|
|
119
|
+
* @returns The token response
|
|
120
|
+
* @throws Error if the token exchange fails
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* // After user is redirected back with ?code=xxx
|
|
125
|
+
* const tokens = await oauth.exchangeCode(code);
|
|
126
|
+
* console.log(`Access token: ${tokens.access_token}`);
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async exchangeCode(code) {
|
|
130
|
+
const body = new URLSearchParams({
|
|
131
|
+
client_id: this.config.clientId,
|
|
132
|
+
client_secret: this.config.clientSecret,
|
|
133
|
+
code,
|
|
134
|
+
grant_type: "authorization_code",
|
|
135
|
+
redirect_uri: this.config.redirectUri,
|
|
136
|
+
});
|
|
137
|
+
const response = await fetch(this.oauthUrls.token, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: {
|
|
140
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
141
|
+
},
|
|
142
|
+
body: body.toString(),
|
|
143
|
+
});
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
const errorText = await response.text();
|
|
146
|
+
let errorMessage = `Token exchange failed: HTTP ${response.status}`;
|
|
147
|
+
try {
|
|
148
|
+
const errorJson = JSON.parse(errorText);
|
|
149
|
+
if (errorJson.error_description) {
|
|
150
|
+
errorMessage = `Token exchange failed: ${errorJson.error_description}`;
|
|
151
|
+
}
|
|
152
|
+
else if (errorJson.error) {
|
|
153
|
+
errorMessage = `Token exchange failed: ${errorJson.error}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Use default error message
|
|
158
|
+
}
|
|
159
|
+
throw new Error(errorMessage);
|
|
160
|
+
}
|
|
161
|
+
const tokens = (await response.json());
|
|
162
|
+
return tokens;
|
|
163
|
+
}
|
|
164
|
+
// ===========================================================================
|
|
165
|
+
// Token Refresh
|
|
166
|
+
// ===========================================================================
|
|
167
|
+
/**
|
|
168
|
+
* Refresh an expired access token using the refresh token.
|
|
169
|
+
*
|
|
170
|
+
* @param refreshToken - The refresh token
|
|
171
|
+
* @returns The new token response
|
|
172
|
+
* @throws Error if the token refresh fails
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const newTokens = await oauth.refreshToken(storedToken.refreshToken);
|
|
177
|
+
* await oauth.storeToken(newTokens);
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
async refreshToken(refreshToken) {
|
|
181
|
+
const body = new URLSearchParams({
|
|
182
|
+
client_id: this.config.clientId,
|
|
183
|
+
client_secret: this.config.clientSecret,
|
|
184
|
+
refresh_token: refreshToken,
|
|
185
|
+
grant_type: "refresh_token",
|
|
186
|
+
});
|
|
187
|
+
const response = await fetch(this.oauthUrls.token, {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: {
|
|
190
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
191
|
+
},
|
|
192
|
+
body: body.toString(),
|
|
193
|
+
});
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
const errorText = await response.text();
|
|
196
|
+
let errorMessage = `Token refresh failed: HTTP ${response.status}`;
|
|
197
|
+
try {
|
|
198
|
+
const errorJson = JSON.parse(errorText);
|
|
199
|
+
if (errorJson.error_description) {
|
|
200
|
+
errorMessage = `Token refresh failed: ${errorJson.error_description}`;
|
|
201
|
+
}
|
|
202
|
+
else if (errorJson.error) {
|
|
203
|
+
errorMessage = `Token refresh failed: ${errorJson.error}`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Use default error message
|
|
208
|
+
}
|
|
209
|
+
throw new Error(errorMessage);
|
|
210
|
+
}
|
|
211
|
+
const tokens = (await response.json());
|
|
212
|
+
return tokens;
|
|
213
|
+
}
|
|
214
|
+
// ===========================================================================
|
|
215
|
+
// Token Storage
|
|
216
|
+
// ===========================================================================
|
|
217
|
+
/**
|
|
218
|
+
* Store tokens to the file system.
|
|
219
|
+
*
|
|
220
|
+
* @param tokens - The token response to store
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const tokens = await oauth.exchangeCode(code);
|
|
225
|
+
* await oauth.storeToken(tokens);
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
async storeToken(tokens) {
|
|
229
|
+
const storedToken = {
|
|
230
|
+
accessToken: tokens.access_token,
|
|
231
|
+
refreshToken: tokens.refresh_token,
|
|
232
|
+
expiresAt: Date.now() + tokens.expires_in * 1000,
|
|
233
|
+
tokenType: tokens.token_type,
|
|
234
|
+
storedAt: Date.now(),
|
|
235
|
+
};
|
|
236
|
+
// Ensure directory exists
|
|
237
|
+
const dir = dirname(this.tokenPath);
|
|
238
|
+
if (!existsSync(dir)) {
|
|
239
|
+
await mkdir(dir, { recursive: true });
|
|
240
|
+
}
|
|
241
|
+
await writeFile(this.tokenPath, JSON.stringify(storedToken, null, 2), {
|
|
242
|
+
encoding: "utf-8",
|
|
243
|
+
mode: 0o600, // Only owner can read/write
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Load stored tokens from the file system.
|
|
248
|
+
*
|
|
249
|
+
* @returns The stored token data, or null if not found
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* const storedToken = await oauth.loadToken();
|
|
254
|
+
* if (storedToken && !oauth.isTokenExpired(storedToken)) {
|
|
255
|
+
* // Use the token
|
|
256
|
+
* }
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
async loadToken() {
|
|
260
|
+
if (!existsSync(this.tokenPath)) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const content = await readFile(this.tokenPath, { encoding: "utf-8" });
|
|
265
|
+
const storedToken = JSON.parse(content);
|
|
266
|
+
return storedToken;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Clear stored tokens from the file system.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* await oauth.clearToken();
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
async clearToken() {
|
|
281
|
+
if (existsSync(this.tokenPath)) {
|
|
282
|
+
await writeFile(this.tokenPath, "", { encoding: "utf-8" });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Check if a stored token is expired.
|
|
287
|
+
*
|
|
288
|
+
* @param storedToken - The stored token to check
|
|
289
|
+
* @param bufferSeconds - Buffer time before actual expiration (default: 60 seconds)
|
|
290
|
+
* @returns True if the token is expired or will expire within the buffer time
|
|
291
|
+
*/
|
|
292
|
+
isTokenExpired(storedToken, bufferSeconds = 60) {
|
|
293
|
+
const bufferMs = bufferSeconds * 1000;
|
|
294
|
+
return Date.now() >= storedToken.expiresAt - bufferMs;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get authentication status.
|
|
298
|
+
*
|
|
299
|
+
* @returns The current authentication status
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const status = await oauth.getAuthStatus();
|
|
304
|
+
* if (status.isAuthenticated && !status.isExpired) {
|
|
305
|
+
* console.log(`Token expires in ${status.expiresIn} seconds`);
|
|
306
|
+
* }
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
async getAuthStatus() {
|
|
310
|
+
const storedToken = await this.loadToken();
|
|
311
|
+
if (!storedToken) {
|
|
312
|
+
return {
|
|
313
|
+
isAuthenticated: false,
|
|
314
|
+
isExpired: true,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const isExpired = this.isTokenExpired(storedToken);
|
|
318
|
+
const expiresAt = new Date(storedToken.expiresAt).toISOString();
|
|
319
|
+
const expiresIn = isExpired
|
|
320
|
+
? 0
|
|
321
|
+
: Math.floor((storedToken.expiresAt - Date.now()) / 1000);
|
|
322
|
+
return {
|
|
323
|
+
isAuthenticated: true,
|
|
324
|
+
isExpired,
|
|
325
|
+
expiresAt,
|
|
326
|
+
expiresIn,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Get a valid access token, refreshing if necessary.
|
|
331
|
+
*
|
|
332
|
+
* This method will:
|
|
333
|
+
* 1. Load the stored token
|
|
334
|
+
* 2. If expired or about to expire, refresh it
|
|
335
|
+
* 3. Return the valid access token
|
|
336
|
+
*
|
|
337
|
+
* @returns The valid access token
|
|
338
|
+
* @throws Error if no token is stored or refresh fails
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* const accessToken = await oauth.getValidAccessToken();
|
|
343
|
+
* // Use accessToken for API requests
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
async getValidAccessToken() {
|
|
347
|
+
const storedToken = await this.loadToken();
|
|
348
|
+
if (!storedToken) {
|
|
349
|
+
throw new Error("Not authenticated. Please complete the OAuth flow first.");
|
|
350
|
+
}
|
|
351
|
+
// Check if token needs refresh (with 60 second buffer)
|
|
352
|
+
if (this.isTokenExpired(storedToken)) {
|
|
353
|
+
try {
|
|
354
|
+
const newTokens = await this.refreshToken(storedToken.refreshToken);
|
|
355
|
+
await this.storeToken(newTokens);
|
|
356
|
+
return newTokens.access_token;
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
throw new Error(`Failed to refresh token: ${error instanceof Error ? error.message : String(error)}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return storedToken.accessToken;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Get the token storage path.
|
|
366
|
+
*/
|
|
367
|
+
getTokenPath() {
|
|
368
|
+
return this.tokenPath;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// =============================================================================
|
|
372
|
+
// Helper Functions
|
|
373
|
+
// =============================================================================
|
|
374
|
+
/**
|
|
375
|
+
* Generate a random state string for CSRF protection.
|
|
376
|
+
*/
|
|
377
|
+
function generateRandomState() {
|
|
378
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
379
|
+
let result = "";
|
|
380
|
+
const randomValues = new Uint8Array(32);
|
|
381
|
+
crypto.getRandomValues(randomValues);
|
|
382
|
+
for (const value of randomValues) {
|
|
383
|
+
result += chars[value % chars.length];
|
|
384
|
+
}
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Create an OAuth helper from environment variables.
|
|
389
|
+
*
|
|
390
|
+
* Expected environment variables:
|
|
391
|
+
* - TICKTICK_CLIENT_ID
|
|
392
|
+
* - TICKTICK_CLIENT_SECRET
|
|
393
|
+
* - TICKTICK_REDIRECT_URI (optional, defaults to http://localhost:8000/callback)
|
|
394
|
+
* - TICKTICK_REGION (optional, defaults to "global")
|
|
395
|
+
* - TICKTICK_TOKEN_PATH (optional, defaults to ~/.ticktick-mcp/tokens.json)
|
|
396
|
+
*
|
|
397
|
+
* @returns A configured TickTickOAuth instance
|
|
398
|
+
* @throws Error if required environment variables are not set
|
|
399
|
+
*/
|
|
400
|
+
export function createOAuthFromEnv() {
|
|
401
|
+
const clientId = process.env.TICKTICK_CLIENT_ID;
|
|
402
|
+
const clientSecret = process.env.TICKTICK_CLIENT_SECRET;
|
|
403
|
+
if (!clientId || !clientSecret) {
|
|
404
|
+
throw new Error("Missing required environment variables: TICKTICK_CLIENT_ID and TICKTICK_CLIENT_SECRET must be set");
|
|
405
|
+
}
|
|
406
|
+
const config = {
|
|
407
|
+
clientId,
|
|
408
|
+
clientSecret,
|
|
409
|
+
redirectUri: process.env.TICKTICK_REDIRECT_URI ?? "http://localhost:8000/callback",
|
|
410
|
+
region: process.env.TICKTICK_REGION ?? "global",
|
|
411
|
+
};
|
|
412
|
+
const tokenPath = process.env.TICKTICK_TOKEN_PATH;
|
|
413
|
+
return new TickTickOAuth(config, tokenPath);
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAmDlC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE;QACN,SAAS,EAAE,sCAAsC;QACjD,KAAK,EAAE,kCAAkC;KAC1C;IACD,KAAK,EAAE;QACL,SAAS,EAAE,qCAAqC;QAChD,KAAK,EAAE,iCAAiC;KACzC;CACO,CAAC;AAEX;;GAEG;AACH,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;AAE3E,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,aAAa;IACP,MAAM,CAAc;IACpB,SAAS,CAAS;IAClB,SAAS,CAAuC;IAEjE;;;;;OAKG;IACH,YAAY,MAAmB,EAAE,SAAkB;QACjD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,kBAAkB,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,8EAA8E;IAC9E,oBAAoB;IACpB,8EAA8E;IAE9E;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CACjB,MAAiB,EACjB,KAAc;QAEd,MAAM,UAAU,GAAG,KAAK,IAAI,mBAAmB,EAAE,CAAC;QAClD,MAAM,WAAW,GAAG,MAAM,IAAI,cAAc,CAAC;QAE7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACrC,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5B,KAAK,EAAE,UAAU;SAClB,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE;YACvD,KAAK,EAAE,UAAU;SAClB,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,iBAAiB;IACjB,8EAA8E;IAE9E;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,YAAY,CAAC,IAAY;QAC7B,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;YAC/B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YACvC,IAAI;YACJ,UAAU,EAAE,oBAAoB;YAChC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;SACtC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;aACpD;YACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,YAAY,GAAG,+BAA+B,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpE,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAGrC,CAAC;gBACF,IAAI,SAAS,CAAC,iBAAiB,EAAE,CAAC;oBAChC,YAAY,GAAG,0BAA0B,SAAS,CAAC,iBAAiB,EAAE,CAAC;gBACzE,CAAC;qBAAM,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;oBAC3B,YAAY,GAAG,0BAA0B,SAAS,CAAC,KAAK,EAAE,CAAC;gBAC7D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkB,CAAC;QACxD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,8EAA8E;IAC9E,gBAAgB;IAChB,8EAA8E;IAE9E;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;YAC/B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YACvC,aAAa,EAAE,YAAY;YAC3B,UAAU,EAAE,eAAe;SAC5B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;aACpD;YACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,YAAY,GAAG,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAAC;YACnE,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAGrC,CAAC;gBACF,IAAI,SAAS,CAAC,iBAAiB,EAAE,CAAC;oBAChC,YAAY,GAAG,yBAAyB,SAAS,CAAC,iBAAiB,EAAE,CAAC;gBACxE,CAAC;qBAAM,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;oBAC3B,YAAY,GAAG,yBAAyB,SAAS,CAAC,KAAK,EAAE,CAAC;gBAC5D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkB,CAAC;QACxD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,8EAA8E;IAC9E,gBAAgB;IAChB,8EAA8E;IAE9E;;;;;;;;;;OAUG;IACH,KAAK,CAAC,UAAU,CAAC,MAAqB;QACpC,MAAM,WAAW,GAAgB;YAC/B,WAAW,EAAE,MAAM,CAAC,YAAY;YAChC,YAAY,EAAE,MAAM,CAAC,aAAa;YAClC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI;YAChD,SAAS,EAAE,MAAM,CAAC,UAAU;YAC5B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QAEF,0BAA0B;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;YACpE,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,KAAK,EAAE,4BAA4B;SAC1C,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACtE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;YACvD,OAAO,WAAW,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,cAAc,CAAC,WAAwB,EAAE,aAAa,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,SAAS,GAAG,QAAQ,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,aAAa;QACjB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAE3C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,eAAe,EAAE,KAAK;gBACtB,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChE,MAAM,SAAS,GAAG,SAAS;YACzB,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QAE5D,OAAO;YACL,eAAe,EAAE,IAAI;YACrB,SAAS;YACT,SAAS;YACT,SAAS;SACV,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,mBAAmB;QACvB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAE3C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;gBACpE,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;gBACjC,OAAO,SAAS,CAAC,YAAY,CAAC;YAChC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC,WAAW,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAED,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;GAEG;AACH,SAAS,mBAAmB;IAC1B,MAAM,KAAK,GACT,gEAAgE,CAAC;IACnE,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAExD,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,mGAAmG,CACpG,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAgB;QAC1B,QAAQ;QACR,YAAY;QACZ,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,gCAAgC;QACvE,MAAM,EAAG,OAAO,CAAC,GAAG,CAAC,eAA0B,IAAI,QAAQ;KAC5D,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAElD,OAAO,IAAI,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC"}
|