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/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":"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"}