Skip to main content
Glama
labels.ts4.94 kB
import fs from 'fs'; import path from 'path'; import { getTodoistClient } from '../client'; import { getErrorMessage } from '../../utils'; interface TodoistLabel { id: string; name: string; color: string; order: number; is_favorite: boolean; } interface LabelsResponse { labels: Array<{ id: number; name: string; color: string; order: number; is_favorite: boolean; }>; total_count: number; } // Get all labels function with caching - returns structured data export async function getAllLabels(): Promise< LabelsResponse & { cached_at?: string } > { try { // Cache configuration const CACHE_DIR = '.cache'; const CACHE_FILE = path.join(CACHE_DIR, 'labels.json'); const CACHE_DURATION_MS = 24 * 60 * 60 * 1000; // 1 day // Ensure cache directory exists if (!fs.existsSync(CACHE_DIR)) { fs.mkdirSync(CACHE_DIR, { recursive: true }); } // Check if cache is fresh let isCacheFresh = false; if (fs.existsSync(CACHE_FILE)) { const fileStats = fs.statSync(CACHE_FILE); isCacheFresh = Date.now() - fileStats.mtime.getTime() < CACHE_DURATION_MS; } // Try to read from cache if fresh if (isCacheFresh) { try { const cachedData = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8')); return cachedData; } catch (cacheError) { console.warn( 'Failed to read cache file, falling back to API:', cacheError ); } } // Fetch from API const todoistClient = getTodoistClient(); const response = await todoistClient.get<TodoistLabel[]>('/labels'); const labels = response.data.map((label) => ({ id: parseInt(label.id), name: label.name, color: label.color, order: label.order, is_favorite: label.is_favorite, })); const labelsData = { labels, total_count: labels.length, }; // Create result with cache timestamp const result = { ...labelsData, cached_at: new Date().toISOString(), }; // Write to cache fs.writeFileSync(CACHE_FILE, JSON.stringify(result, null, 2)); return result; } catch (error) { throw new Error(`Failed to get all labels: ${getErrorMessage(error)}`); } } // Get project labels function - returns structured data for labels that start with "PROJECT:" export async function getProjectLabels(): Promise<LabelsResponse> { const todoistClient = getTodoistClient(); try { const response = await todoistClient.get<TodoistLabel[]>('/labels'); const projectLabels = response.data .filter((label) => label.name.startsWith('PROJECT:')) .map((label) => ({ id: parseInt(label.id), name: label.name, color: label.color, order: label.order, is_favorite: label.is_favorite, })); return { labels: projectLabels, total_count: projectLabels.length, }; } catch (error) { throw new Error(`Failed to get project labels: ${getErrorMessage(error)}`); } } // Get context labels function - returns structured data for labels that start with "context:" export async function getContextLabels(): Promise<LabelsResponse> { const todoistClient = getTodoistClient(); try { const response = await todoistClient.get<TodoistLabel[]>('/labels'); const contextLabels = response.data .filter((label) => label.name.startsWith('context:')) .map((label) => ({ id: parseInt(label.id), name: label.name, color: label.color, order: label.order, is_favorite: label.is_favorite, })); return { labels: contextLabels, total_count: contextLabels.length, }; } catch (error) { throw new Error(`Failed to get context labels: ${getErrorMessage(error)}`); } } // Create project label function - creates a new label with "PROJECT: " prefix export async function createProjectLabel(projectName: string): Promise<{ id: number; name: string; color: string; order: number; is_favorite: boolean; }> { const todoistClient = getTodoistClient(); try { // Validate that the project name starts with "PROJECT: " if (!projectName.startsWith('PROJECT: ')) { throw new Error('Project label name must start with "PROJECT: "'); } if (!todoistClient.post) { throw new Error('POST method not available on Todoist client'); } const response = await todoistClient.post<TodoistLabel>('/labels', { name: projectName, color: 'charcoal', }); return { id: parseInt(response.data.id), name: response.data.name, color: response.data.color, order: response.data.order, is_favorite: response.data.is_favorite, }; } catch (error) { throw new Error( `Failed to create project label: ${getErrorMessage(error)}` ); } } // Export types for testing export type { TodoistLabel, LabelsResponse };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bkotos/todoist-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server