Skip to main content
Glama
todos.ts7.65 kB
import { SidvyApiClient } from './client.js' import { Todo, ApiResponse, CreateTodoRequest, UpdateTodoRequest, DeleteTodoRequest, DeleteTodoResponse, ListTodosParams, } from '../types.js' export class TodosApi { constructor(private client: SidvyApiClient) {} /** * List todos with optional filtering and pagination */ async listTodos(params: ListTodosParams = {}): Promise<ApiResponse<Todo[]>> { const queryParams: Record<string, any> = {} if (params.page !== undefined) queryParams.page = params.page if (params.limit !== undefined) queryParams.limit = params.limit if (params.workspaceId !== undefined) queryParams.workspaceId = params.workspaceId if (params.noteId !== undefined) queryParams.noteId = params.noteId if (params.completed !== undefined) queryParams.completed = params.completed if (params.isDeleted !== undefined) queryParams.isDeleted = params.isDeleted if (params.search !== undefined) queryParams.search = params.search if (params.sort !== undefined) queryParams.sort = params.sort return this.client.get<Todo[]>('/todo', queryParams) } /** * Get todos for a specific note */ async getTodosForNote(noteId: string, workspaceId?: string): Promise<ApiResponse<Todo[]>> { return this.listTodos({ noteId, workspaceId, sort: 'createdAt:asc', }) } /** * Get pending (incomplete) todos */ async getPendingTodos(workspaceId?: string, limit?: number): Promise<ApiResponse<Todo[]>> { return this.listTodos({ workspaceId, completed: false, limit, sort: 'createdAt:desc', }) } /** * Get completed todos */ async getCompletedTodos(workspaceId?: string, limit?: number): Promise<ApiResponse<Todo[]>> { return this.listTodos({ workspaceId, completed: true, limit, sort: 'completedAt:desc', }) } /** * Get recently completed todos */ async getRecentlyCompleted( workspaceId?: string, limit: number = 10, ): Promise<ApiResponse<Todo[]>> { return this.getCompletedTodos(workspaceId, limit) } /** * Search todos by text */ async searchTodos(query: string, workspaceId?: string): Promise<ApiResponse<Todo[]>> { return this.listTodos({ search: query, workspaceId, sort: 'updatedAt:desc', }) } /** * Get a specific todo by ID */ async getTodoById(todoId: string, workspaceId?: string): Promise<ApiResponse<Todo | null>> { const response = await this.listTodos({ workspaceId, limit: 100, }) if (!this.client.isSuccessResponse(response)) { return response } const todo = response.data.find((t) => t.id === todoId) return { success: true, data: todo || null, } } /** * Create a new todo */ async createTodo(todoData: CreateTodoRequest): Promise<ApiResponse<Todo>> { return this.client.post<Todo>('/todo', todoData) } /** * Update an existing todo */ async updateTodo(todoData: UpdateTodoRequest): Promise<ApiResponse<Todo>> { return this.client.put<Todo>('/todo', todoData) } /** * Delete a todo (soft delete) */ async deleteTodo(todoData: DeleteTodoRequest): Promise<ApiResponse<DeleteTodoResponse>> { return this.client.delete<DeleteTodoResponse>('/todo', todoData) } /** * Toggle todo completion status */ async toggleTodo(todoId: string): Promise<ApiResponse<Todo>> { const todoResponse = await this.getTodoById(todoId) if (!this.client.isSuccessResponse(todoResponse) || !todoResponse.data) { return todoResponse as ApiResponse<Todo> } const todo = todoResponse.data return this.updateTodo({ todoId, completed: !todo.completed, }) } /** * Mark todo as completed */ async completeTodo(todoId: string): Promise<ApiResponse<Todo>> { return this.updateTodo({ todoId, completed: true, }) } /** * Mark todo as incomplete */ async uncompleteTodo(todoId: string): Promise<ApiResponse<Todo>> { return this.updateTodo({ todoId, completed: false, }) } /** * Update todo text */ async updateTodoText(todoId: string, newText: string): Promise<ApiResponse<Todo>> { return this.updateTodo({ todoId, text: newText, }) } /** * Move todo to different line in note */ async moveTodo(todoId: string, newLineNumber: number): Promise<ApiResponse<Todo>> { return this.updateTodo({ todoId, lineNumber: newLineNumber, }) } /** * Get all todos in a workspace */ async getAllTodosInWorkspace( workspaceId: string, includeDeleted: boolean = false, includeCompleted: boolean = true, ): Promise<Todo[]> { const allTodos: Todo[] = [] let page = 1 const limit = 100 let hasMore = true while (hasMore) { const params: ListTodosParams = { workspaceId, isDeleted: includeDeleted, page, limit, sort: 'createdAt:desc', } // If we don't want completed todos, filter them out if (!includeCompleted) { params.completed = false } const response = await this.listTodos(params) if (!this.client.isSuccessResponse(response)) { throw new Error(this.client.getErrorMessage(response)) } allTodos.push(...response.data) // Check if there are more pages if (response.meta?.pagination) { hasMore = page < response.meta.pagination.totalPages page++ } else { hasMore = response.data.length === limit page++ } } return allTodos } /** * Get todo statistics for a workspace */ async getTodoStats(workspaceId?: string): Promise<TodoStats> { const response = await this.listTodos({ workspaceId, limit: 1000, // Get a large number to calculate stats }) if (!this.client.isSuccessResponse(response)) { throw new Error(this.client.getErrorMessage(response)) } const todos = response.data const completed = todos.filter((t) => t.completed).length const pending = todos.filter((t) => !t.completed).length const deleted = todos.filter((t) => t.isDeleted).length return { total: todos.length, completed, pending, deleted, completionRate: todos.length > 0 ? (completed / (completed + pending)) * 100 : 0, } } /** * Create multiple todos for a note (bulk operation) */ async createTodosForNote( noteId: string, todoTexts: string[], workspaceId?: string, startingLineNumber: number = 1, ): Promise<ApiResponse<Todo>[]> { const results: ApiResponse<Todo>[] = [] for (let i = 0; i < todoTexts.length; i++) { const result = await this.createTodo({ text: todoTexts[i], noteId, lineNumber: startingLineNumber + i, workspaceId, completed: false, }) results.push(result) } return results } /** * Get deleted todos */ async getDeletedTodos(workspaceId?: string): Promise<ApiResponse<Todo[]>> { return this.listTodos({ workspaceId, isDeleted: true, sort: 'updatedAt:desc', }) } /** * Get overdue todos (this would need additional date logic based on your needs) */ async getTodosByNote(noteId: string, workspaceId?: string): Promise<ApiResponse<Todo[]>> { return this.getTodosForNote(noteId, workspaceId) } } export interface TodoStats { total: number completed: number pending: number deleted: number completionRate: number // Percentage }

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/martinhjartmyr/sidvy-mcp'

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