import { TodoistApi } from "@doist/todoist-api-typescript"; import type { Task, Label, Section, Comment, PersonalProject, WorkspaceProject, } from "@doist/todoist-api-typescript"; import type { AddTaskArgs, UpdateTaskArgs, AddProjectArgs, UpdateProjectArgs, AddSectionArgs, UpdateSectionArgs, AddCommentArgs, UpdateCommentArgs, AddLabelArgs, UpdateLabelArgs, } from "@doist/todoist-api-typescript"; /** * DryRunWrapper class that wraps TodoistApi to provide dry-run functionality. * When process.env.DRYRUN === 'true', mutation operations are intercepted and simulated, * while read operations pass through to the real API unchanged. */ export class DryRunWrapper { private client: TodoistApi; private isDryRun: boolean; private taskIdCounter: number = 100000; private projectIdCounter: number = 200000; private sectionIdCounter: number = 300000; private commentIdCounter: number = 400000; private labelIdCounter: number = 500000; constructor(client: TodoistApi) { this.client = client; this.isDryRun = process.env.DRYRUN === "true"; } /** * Logs dry-run actions with consistent formatting */ private logDryRunAction( action: string, entity: string, details: string ): void { console.error(`[DRY-RUN] Would ${action} ${entity}: ${details}`); } /** * Generates a unique ID for mocked entities */ private generateId( type: "task" | "project" | "section" | "comment" | "label" ): string { switch (type) { case "task": return (++this.taskIdCounter).toString(); case "project": return (++this.projectIdCounter).toString(); case "section": return (++this.sectionIdCounter).toString(); case "comment": return (++this.commentIdCounter).toString(); case "label": return (++this.labelIdCounter).toString(); default: return Math.random().toString(36).substr(2, 9); } } /** * Validates that a project exists (used in dry-run validation) */ private async validateProjectExists(projectId?: string): Promise { if (projectId) { try { await this.client.getProject(projectId); } catch { throw new Error(`Project with ID ${projectId} does not exist`); } } } /** * Validates that a task exists (used in dry-run validation) */ private async validateTaskExists(taskId: string): Promise { try { return await this.client.getTask(taskId); } catch { throw new Error(`Task with ID ${taskId} does not exist`); } } /** * Validates that a section exists (used in dry-run validation) */ private async validateSectionExists(sectionId?: string): Promise { if (sectionId) { try { await this.client.getSection(sectionId); } catch { throw new Error(`Section with ID ${sectionId} does not exist`); } } } /** * Validates that a label exists (used in dry-run validation) */ private async validateLabelExists(labelId: string): Promise