@doist/todoist-api-typescript 5.9.0 → 6.0.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.
Files changed (85) hide show
  1. package/dist/cjs/authentication.js +158 -0
  2. package/dist/{consts → cjs/consts}/endpoints.js +10 -12
  3. package/dist/cjs/package.json +1 -0
  4. package/dist/cjs/rest-client.js +124 -0
  5. package/dist/{test-utils → cjs/test-utils}/asserts.js +1 -1
  6. package/dist/{test-utils → cjs/test-utils}/mocks.js +8 -4
  7. package/dist/cjs/test-utils/msw-setup.js +27 -0
  8. package/dist/{test-utils → cjs/test-utils}/test-defaults.js +41 -52
  9. package/dist/cjs/todoist-api.js +1235 -0
  10. package/dist/{types → cjs/types}/entities.js +19 -30
  11. package/dist/cjs/types/errors.js +22 -0
  12. package/dist/cjs/types/http.js +22 -0
  13. package/dist/cjs/utils/case-conversion.js +69 -0
  14. package/dist/{utils → cjs/utils}/colors.js +3 -3
  15. package/dist/cjs/utils/fetch-with-retry.js +150 -0
  16. package/dist/cjs/utils/multipart-upload.js +126 -0
  17. package/dist/{utils → cjs/utils}/processing-helpers.js +3 -3
  18. package/dist/{utils → cjs/utils}/sanitization.js +17 -28
  19. package/dist/{utils → cjs/utils}/url-helpers.js +15 -15
  20. package/dist/{utils → cjs/utils}/validators.js +2 -2
  21. package/dist/esm/authentication.js +151 -0
  22. package/dist/esm/consts/endpoints.js +65 -0
  23. package/dist/esm/index.js +4 -0
  24. package/dist/esm/rest-client.js +119 -0
  25. package/dist/esm/test-utils/asserts.js +8 -0
  26. package/dist/esm/test-utils/mocks.js +10 -0
  27. package/dist/esm/test-utils/msw-setup.js +22 -0
  28. package/dist/esm/test-utils/test-defaults.js +198 -0
  29. package/dist/esm/todoist-api.js +1231 -0
  30. package/dist/esm/types/entities.js +366 -0
  31. package/dist/esm/types/errors.js +18 -0
  32. package/dist/esm/types/http.js +18 -0
  33. package/dist/esm/types/index.js +3 -0
  34. package/dist/esm/types/requests.js +1 -0
  35. package/dist/esm/types/sync.js +1 -0
  36. package/dist/esm/utils/activity-helpers.js +36 -0
  37. package/dist/esm/utils/case-conversion.js +61 -0
  38. package/dist/esm/utils/colors.js +215 -0
  39. package/dist/esm/utils/fetch-with-retry.js +147 -0
  40. package/dist/esm/utils/index.js +3 -0
  41. package/dist/esm/utils/multipart-upload.js +120 -0
  42. package/dist/esm/utils/processing-helpers.js +12 -0
  43. package/dist/esm/utils/sanitization.js +112 -0
  44. package/dist/esm/utils/url-helpers.js +68 -0
  45. package/dist/esm/utils/validators.js +97 -0
  46. package/dist/{authentication.d.ts → types/authentication.d.ts} +6 -1
  47. package/dist/types/index.d.ts +4 -3
  48. package/dist/{rest-client.d.ts → types/rest-client.d.ts} +3 -4
  49. package/dist/types/test-utils/msw-setup.d.ts +3 -0
  50. package/dist/types/types/http.d.ts +68 -0
  51. package/dist/types/types/index.d.ts +3 -0
  52. package/dist/types/utils/case-conversion.d.ts +12 -0
  53. package/dist/types/utils/fetch-with-retry.d.ts +11 -0
  54. package/package.json +24 -8
  55. package/dist/authentication.js +0 -220
  56. package/dist/index.d.ts +0 -4
  57. package/dist/rest-client.js +0 -178
  58. package/dist/todoist-api.js +0 -1845
  59. package/dist/types/errors.js +0 -39
  60. package/dist/types/http.d.ts +0 -1
  61. package/dist/types/http.js +0 -2
  62. package/dist/utils/multipart-upload.js +0 -171
  63. /package/dist/{index.js → cjs/index.js} +0 -0
  64. /package/dist/{types → cjs/types}/index.js +0 -0
  65. /package/dist/{types → cjs/types}/requests.js +0 -0
  66. /package/dist/{types → cjs/types}/sync.js +0 -0
  67. /package/dist/{utils → cjs/utils}/activity-helpers.js +0 -0
  68. /package/dist/{utils → cjs/utils}/index.js +0 -0
  69. /package/dist/{consts → types/consts}/endpoints.d.ts +0 -0
  70. /package/dist/{test-utils → types/test-utils}/asserts.d.ts +0 -0
  71. /package/dist/{test-utils → types/test-utils}/mocks.d.ts +0 -0
  72. /package/dist/{test-utils → types/test-utils}/test-defaults.d.ts +0 -0
  73. /package/dist/{todoist-api.d.ts → types/todoist-api.d.ts} +0 -0
  74. /package/dist/types/{entities.d.ts → types/entities.d.ts} +0 -0
  75. /package/dist/types/{errors.d.ts → types/errors.d.ts} +0 -0
  76. /package/dist/types/{requests.d.ts → types/requests.d.ts} +0 -0
  77. /package/dist/types/{sync.d.ts → types/sync.d.ts} +0 -0
  78. /package/dist/{utils → types/utils}/activity-helpers.d.ts +0 -0
  79. /package/dist/{utils → types/utils}/colors.d.ts +0 -0
  80. /package/dist/{utils → types/utils}/index.d.ts +0 -0
  81. /package/dist/{utils → types/utils}/multipart-upload.d.ts +0 -0
  82. /package/dist/{utils → types/utils}/processing-helpers.d.ts +0 -0
  83. /package/dist/{utils → types/utils}/sanitization.d.ts +0 -0
  84. /package/dist/{utils → types/utils}/url-helpers.d.ts +0 -0
  85. /package/dist/{utils → types/utils}/validators.d.ts +0 -0
@@ -0,0 +1,1235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TodoistApi = void 0;
4
+ const rest_client_1 = require("./rest-client");
5
+ const endpoints_1 = require("./consts/endpoints");
6
+ const validators_1 = require("./utils/validators");
7
+ const url_helpers_1 = require("./utils/url-helpers");
8
+ const multipart_upload_1 = require("./utils/multipart-upload");
9
+ const activity_helpers_1 = require("./utils/activity-helpers");
10
+ const zod_1 = require("zod");
11
+ const uuid_1 = require("uuid");
12
+ const types_1 = require("./types");
13
+ const MAX_COMMAND_COUNT = 100;
14
+ /**
15
+ * Joins path segments using `/` separator.
16
+ * @param segments A list of **valid** path segments.
17
+ * @returns A joined path.
18
+ */
19
+ function generatePath(...segments) {
20
+ return segments.join('/');
21
+ }
22
+ /**
23
+ * A client for interacting with the Todoist API v1.
24
+ * This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const api = new TodoistApi('your-api-token');
29
+ *
30
+ * // Get all tasks
31
+ * const tasks = await api.getTasks();
32
+ *
33
+ * // Create a new task
34
+ * const newTask = await api.addTask({
35
+ * content: 'My new task',
36
+ * projectId: '12345'
37
+ * });
38
+ * ```
39
+ *
40
+ * For more information about the Todoist API v1, see the [official documentation](https://todoist.com/api/v1).
41
+ * If you're migrating from v9, please refer to the [migration guide](https://todoist.com/api/v1/docs#tag/Migrating-from-v9).
42
+ */
43
+ class TodoistApi {
44
+ constructor(
45
+ /**
46
+ * Your Todoist API token.
47
+ */
48
+ authToken,
49
+ /**
50
+ * Optional custom API base URL. If not provided, defaults to Todoist's standard API endpoint
51
+ */
52
+ baseUrl) {
53
+ this.authToken = authToken;
54
+ this.syncApiBase = (0, endpoints_1.getSyncBaseUri)(baseUrl);
55
+ }
56
+ /**
57
+ * Retrieves information about the authenticated user.
58
+ *
59
+ * @returns A promise that resolves to the current user's information.
60
+ */
61
+ async getUser() {
62
+ const response = await (0, rest_client_1.request)({
63
+ httpMethod: 'GET',
64
+ baseUri: this.syncApiBase,
65
+ relativePath: endpoints_1.ENDPOINT_REST_USER,
66
+ apiToken: this.authToken,
67
+ });
68
+ return (0, validators_1.validateCurrentUser)(response.data);
69
+ }
70
+ /**
71
+ * Retrieves a single active (non-completed) task by its ID.
72
+ *
73
+ * @param id - The unique identifier of the task.
74
+ * @returns A promise that resolves to the requested task.
75
+ */
76
+ async getTask(id) {
77
+ zod_1.z.string().parse(id);
78
+ const response = await (0, rest_client_1.request)({
79
+ httpMethod: 'GET',
80
+ baseUri: this.syncApiBase,
81
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
82
+ apiToken: this.authToken,
83
+ });
84
+ return (0, validators_1.validateTask)(response.data);
85
+ }
86
+ /**
87
+ * Retrieves a list of active tasks filtered by specific parameters.
88
+ *
89
+ * @param args - Filter parameters such as project ID, label ID, or due date.
90
+ * @returns A promise that resolves to an array of tasks.
91
+ */
92
+ async getTasks(args = {}) {
93
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
94
+ httpMethod: 'GET',
95
+ baseUri: this.syncApiBase,
96
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS,
97
+ apiToken: this.authToken,
98
+ payload: args,
99
+ });
100
+ return {
101
+ results: (0, validators_1.validateTaskArray)(results),
102
+ nextCursor,
103
+ };
104
+ }
105
+ /**
106
+ * Retrieves tasks filtered by a filter string.
107
+ *
108
+ * @param args - Parameters for filtering tasks, including the query string and optional language.
109
+ * @returns A promise that resolves to a paginated response of tasks.
110
+ */
111
+ async getTasksByFilter(args) {
112
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
113
+ httpMethod: 'GET',
114
+ baseUri: this.syncApiBase,
115
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS_FILTER,
116
+ apiToken: this.authToken,
117
+ payload: args,
118
+ });
119
+ return {
120
+ results: (0, validators_1.validateTaskArray)(results),
121
+ nextCursor,
122
+ };
123
+ }
124
+ /**
125
+ * Retrieves completed tasks by completion date.
126
+ *
127
+ * @param args - Parameters for filtering, including required since, until.
128
+ * @returns A promise that resolves to a paginated response of completed tasks.
129
+ */
130
+ async getCompletedTasksByCompletionDate(args) {
131
+ const { data: { items, nextCursor }, } = await (0, rest_client_1.request)({
132
+ httpMethod: 'GET',
133
+ baseUri: this.syncApiBase,
134
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_BY_COMPLETION_DATE,
135
+ apiToken: this.authToken,
136
+ payload: args,
137
+ });
138
+ return {
139
+ items: (0, validators_1.validateTaskArray)(items),
140
+ nextCursor,
141
+ };
142
+ }
143
+ /**
144
+ * Retrieves completed tasks by due date.
145
+ *
146
+ * @param args - Parameters for filtering, including required since, until.
147
+ * @returns A promise that resolves to a paginated response of completed tasks.
148
+ */
149
+ async getCompletedTasksByDueDate(args) {
150
+ const { data: { items, nextCursor }, } = await (0, rest_client_1.request)({
151
+ httpMethod: 'GET',
152
+ baseUri: this.syncApiBase,
153
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_BY_DUE_DATE,
154
+ apiToken: this.authToken,
155
+ payload: args,
156
+ });
157
+ return {
158
+ items: (0, validators_1.validateTaskArray)(items),
159
+ nextCursor,
160
+ };
161
+ }
162
+ /**
163
+ * Searches completed tasks by query string.
164
+ *
165
+ * @param args - Parameters for searching, including the query string.
166
+ * @returns A promise that resolves to a paginated response of completed tasks.
167
+ */
168
+ async searchCompletedTasks(args) {
169
+ const { data: { items, nextCursor }, } = await (0, rest_client_1.request)({
170
+ httpMethod: 'GET',
171
+ baseUri: this.syncApiBase,
172
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_SEARCH,
173
+ apiToken: this.authToken,
174
+ payload: args,
175
+ });
176
+ return {
177
+ items: (0, validators_1.validateTaskArray)(items),
178
+ nextCursor,
179
+ };
180
+ }
181
+ /**
182
+ * Creates a new task with the provided parameters.
183
+ *
184
+ * @param args - Task creation parameters such as content, due date, or priority.
185
+ * @param requestId - Optional custom identifier for the request.
186
+ * @returns A promise that resolves to the created task.
187
+ */
188
+ async addTask(args, requestId) {
189
+ const response = await (0, rest_client_1.request)({
190
+ httpMethod: 'POST',
191
+ baseUri: this.syncApiBase,
192
+ relativePath: endpoints_1.ENDPOINT_REST_TASKS,
193
+ apiToken: this.authToken,
194
+ payload: args,
195
+ requestId: requestId,
196
+ });
197
+ return (0, validators_1.validateTask)(response.data);
198
+ }
199
+ /**
200
+ * Quickly adds a task using natural language processing for due dates.
201
+ *
202
+ * @param args - Quick add task parameters, including content and due date.
203
+ * @returns A promise that resolves to the created task.
204
+ */
205
+ async quickAddTask(args) {
206
+ const response = await (0, rest_client_1.request)({
207
+ httpMethod: 'POST',
208
+ baseUri: this.syncApiBase,
209
+ relativePath: endpoints_1.ENDPOINT_SYNC_QUICK_ADD,
210
+ apiToken: this.authToken,
211
+ payload: args,
212
+ });
213
+ return (0, validators_1.validateTask)(response.data);
214
+ }
215
+ /**
216
+ * Updates an existing task by its ID with the provided parameters.
217
+ *
218
+ * @param id - The unique identifier of the task to update.
219
+ * @param args - Update parameters such as content, priority, or due date.
220
+ * @param requestId - Optional custom identifier for the request.
221
+ * @returns A promise that resolves to the updated task.
222
+ */
223
+ async updateTask(id, args, requestId) {
224
+ zod_1.z.string().parse(id);
225
+ const response = await (0, rest_client_1.request)({
226
+ httpMethod: 'POST',
227
+ baseUri: this.syncApiBase,
228
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
229
+ apiToken: this.authToken,
230
+ payload: args,
231
+ requestId: requestId,
232
+ });
233
+ return (0, validators_1.validateTask)(response.data);
234
+ }
235
+ /**
236
+ * Moves existing tasks by their ID to either a different parent/section/project.
237
+ *
238
+ * @param ids - The unique identifier of the tasks to be moved.
239
+ * @param args - The paramets that should contain only one of projectId, sectionId, or parentId
240
+ * @param requestId - Optional custom identifier for the request.
241
+ * @returns - A promise that resolves to an array of the updated tasks.
242
+ * @deprecated Use `moveTask` for single task operations. This method uses the Sync API and may be removed in a future version.
243
+ */
244
+ async moveTasks(ids, args, requestId) {
245
+ var _a;
246
+ if (ids.length > MAX_COMMAND_COUNT) {
247
+ throw new types_1.TodoistRequestError(`Maximum number of items is ${MAX_COMMAND_COUNT}`, 400);
248
+ }
249
+ const commands = ids.map((id) => ({
250
+ type: 'item_move',
251
+ uuid: (0, uuid_1.v4)(),
252
+ args: Object.assign(Object.assign(Object.assign({ id }, (args.projectId && { project_id: args.projectId })), (args.sectionId && { section_id: args.sectionId })), (args.parentId && { parent_id: args.parentId })),
253
+ }));
254
+ const syncRequest = {
255
+ commands,
256
+ resource_types: ['items'],
257
+ };
258
+ const response = await (0, rest_client_1.request)({
259
+ httpMethod: 'POST',
260
+ baseUri: this.syncApiBase,
261
+ relativePath: endpoints_1.ENDPOINT_SYNC,
262
+ apiToken: this.authToken,
263
+ payload: syncRequest,
264
+ requestId: requestId,
265
+ hasSyncCommands: true,
266
+ });
267
+ if (response.data.sync_status) {
268
+ Object.entries(response.data.sync_status).forEach(([_, value]) => {
269
+ if (value === 'ok')
270
+ return;
271
+ throw new types_1.TodoistRequestError(value.error, value.http_code, value.error_extra);
272
+ });
273
+ }
274
+ if (!((_a = response.data.items) === null || _a === void 0 ? void 0 : _a.length)) {
275
+ throw new types_1.TodoistRequestError('Tasks not found', 404);
276
+ }
277
+ const syncTasks = response.data.items.filter((task) => ids.includes(task.id));
278
+ if (!syncTasks.length) {
279
+ throw new types_1.TodoistRequestError('Tasks not found', 404);
280
+ }
281
+ return (0, validators_1.validateTaskArray)(syncTasks);
282
+ }
283
+ /**
284
+ * Moves a task by its ID to either a different parent/section/project.
285
+ *
286
+ * @param id - The unique identifier of the task to be moved.
287
+ * @param args - The parameters that should contain exactly one of projectId, sectionId, or parentId
288
+ * @param requestId - Optional custom identifier for the request.
289
+ * @returns A promise that resolves to the updated task.
290
+ */
291
+ async moveTask(id, args, requestId) {
292
+ zod_1.z.string().parse(id);
293
+ const response = await (0, rest_client_1.request)({
294
+ httpMethod: 'POST',
295
+ baseUri: this.syncApiBase,
296
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_MOVE),
297
+ apiToken: this.authToken,
298
+ payload: Object.assign(Object.assign(Object.assign({}, (args.projectId && { project_id: args.projectId })), (args.sectionId && { section_id: args.sectionId })), (args.parentId && { parent_id: args.parentId })),
299
+ requestId: requestId,
300
+ });
301
+ return (0, validators_1.validateTask)(response.data);
302
+ }
303
+ /**
304
+ * Closes (completes) a task by its ID.
305
+ *
306
+ * @param id - The unique identifier of the task to close.
307
+ * @param requestId - Optional custom identifier for the request.
308
+ * @returns A promise that resolves to `true` if successful.
309
+ */
310
+ async closeTask(id, requestId) {
311
+ zod_1.z.string().parse(id);
312
+ const response = await (0, rest_client_1.request)({
313
+ httpMethod: 'POST',
314
+ baseUri: this.syncApiBase,
315
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_CLOSE),
316
+ apiToken: this.authToken,
317
+ requestId: requestId,
318
+ });
319
+ return (0, rest_client_1.isSuccess)(response);
320
+ }
321
+ /**
322
+ * Reopens a previously closed (completed) task by its ID.
323
+ *
324
+ * @param id - The unique identifier of the task to reopen.
325
+ * @param requestId - Optional custom identifier for the request.
326
+ * @returns A promise that resolves to `true` if successful.
327
+ */
328
+ async reopenTask(id, requestId) {
329
+ zod_1.z.string().parse(id);
330
+ const response = await (0, rest_client_1.request)({
331
+ httpMethod: 'POST',
332
+ baseUri: this.syncApiBase,
333
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_REOPEN),
334
+ apiToken: this.authToken,
335
+ requestId: requestId,
336
+ });
337
+ return (0, rest_client_1.isSuccess)(response);
338
+ }
339
+ /**
340
+ * Deletes a task by its ID.
341
+ *
342
+ * @param id - The unique identifier of the task to delete.
343
+ * @param requestId - Optional custom identifier for the request.
344
+ * @returns A promise that resolves to `true` if successful.
345
+ */
346
+ async deleteTask(id, requestId) {
347
+ zod_1.z.string().parse(id);
348
+ const response = await (0, rest_client_1.request)({
349
+ httpMethod: 'DELETE',
350
+ baseUri: this.syncApiBase,
351
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
352
+ apiToken: this.authToken,
353
+ requestId: requestId,
354
+ });
355
+ return (0, rest_client_1.isSuccess)(response);
356
+ }
357
+ /**
358
+ * Retrieves a project by its ID.
359
+ *
360
+ * @param id - The unique identifier of the project.
361
+ * @returns A promise that resolves to the requested project.
362
+ */
363
+ async getProject(id) {
364
+ zod_1.z.string().parse(id);
365
+ const response = await (0, rest_client_1.request)({
366
+ httpMethod: 'GET',
367
+ baseUri: this.syncApiBase,
368
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
369
+ apiToken: this.authToken,
370
+ });
371
+ return (0, validators_1.validateProject)(response.data);
372
+ }
373
+ /**
374
+ * Retrieves all projects with optional filters.
375
+ *
376
+ * @param args - Optional filters for retrieving projects.
377
+ * @returns A promise that resolves to an array of projects.
378
+ */
379
+ async getProjects(args = {}) {
380
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
381
+ httpMethod: 'GET',
382
+ baseUri: this.syncApiBase,
383
+ relativePath: endpoints_1.ENDPOINT_REST_PROJECTS,
384
+ apiToken: this.authToken,
385
+ payload: args,
386
+ });
387
+ return {
388
+ results: (0, validators_1.validateProjectArray)(results),
389
+ nextCursor,
390
+ };
391
+ }
392
+ /**
393
+ * Retrieves all archived projects with optional filters.
394
+ *
395
+ * @param args - Optional filters for retrieving archived projects.
396
+ * @returns A promise that resolves to an array of archived projects.
397
+ */
398
+ async getArchivedProjects(args = {}) {
399
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
400
+ httpMethod: 'GET',
401
+ baseUri: this.syncApiBase,
402
+ relativePath: endpoints_1.ENDPOINT_REST_PROJECTS_ARCHIVED,
403
+ apiToken: this.authToken,
404
+ payload: args,
405
+ });
406
+ return {
407
+ results: (0, validators_1.validateProjectArray)(results),
408
+ nextCursor,
409
+ };
410
+ }
411
+ /**
412
+ * Creates a new project with the provided parameters.
413
+ *
414
+ * @param args - Project creation parameters such as name or color.
415
+ * @param requestId - Optional custom identifier for the request.
416
+ * @returns A promise that resolves to the created project.
417
+ */
418
+ async addProject(args, requestId) {
419
+ const response = await (0, rest_client_1.request)({
420
+ httpMethod: 'POST',
421
+ baseUri: this.syncApiBase,
422
+ relativePath: endpoints_1.ENDPOINT_REST_PROJECTS,
423
+ apiToken: this.authToken,
424
+ payload: args,
425
+ requestId: requestId,
426
+ });
427
+ return (0, validators_1.validateProject)(response.data);
428
+ }
429
+ /**
430
+ * Updates an existing project by its ID with the provided parameters.
431
+ *
432
+ * @param id - The unique identifier of the project to update.
433
+ * @param args - Update parameters such as name or color.
434
+ * @param requestId - Optional custom identifier for the request.
435
+ * @returns A promise that resolves to the updated project.
436
+ */
437
+ async updateProject(id, args, requestId) {
438
+ zod_1.z.string().parse(id);
439
+ const response = await (0, rest_client_1.request)({
440
+ httpMethod: 'POST',
441
+ baseUri: this.syncApiBase,
442
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
443
+ apiToken: this.authToken,
444
+ payload: args,
445
+ requestId: requestId,
446
+ });
447
+ return (0, validators_1.validateProject)(response.data);
448
+ }
449
+ /**
450
+ * Deletes a project by its ID.
451
+ *
452
+ * @param id - The unique identifier of the project to delete.
453
+ * @param requestId - Optional custom identifier for the request.
454
+ * @returns A promise that resolves to `true` if successful.
455
+ */
456
+ async deleteProject(id, requestId) {
457
+ zod_1.z.string().parse(id);
458
+ const response = await (0, rest_client_1.request)({
459
+ httpMethod: 'DELETE',
460
+ baseUri: this.syncApiBase,
461
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
462
+ apiToken: this.authToken,
463
+ requestId: requestId,
464
+ });
465
+ return (0, rest_client_1.isSuccess)(response);
466
+ }
467
+ /**
468
+ * Archives a project by its ID.
469
+ *
470
+ * @param id - The unique identifier of the project to archive.
471
+ * @param requestId - Optional custom identifier for the request.
472
+ * @returns A promise that resolves to the updated project.
473
+ */
474
+ async archiveProject(id, requestId) {
475
+ zod_1.z.string().parse(id);
476
+ const response = await (0, rest_client_1.request)({
477
+ httpMethod: 'POST',
478
+ baseUri: this.syncApiBase,
479
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id, endpoints_1.PROJECT_ARCHIVE),
480
+ apiToken: this.authToken,
481
+ requestId: requestId,
482
+ });
483
+ return (0, validators_1.validateProject)(response.data);
484
+ }
485
+ /**
486
+ * Unarchives a project by its ID.
487
+ *
488
+ * @param id - The unique identifier of the project to unarchive.
489
+ * @param requestId - Optional custom identifier for the request.
490
+ * @returns A promise that resolves to the updated project.
491
+ */
492
+ async unarchiveProject(id, requestId) {
493
+ zod_1.z.string().parse(id);
494
+ const response = await (0, rest_client_1.request)({
495
+ httpMethod: 'POST',
496
+ baseUri: this.syncApiBase,
497
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id, endpoints_1.PROJECT_UNARCHIVE),
498
+ apiToken: this.authToken,
499
+ requestId: requestId,
500
+ });
501
+ return (0, validators_1.validateProject)(response.data);
502
+ }
503
+ /**
504
+ * Retrieves a list of collaborators for a specific project.
505
+ *
506
+ * @param projectId - The unique identifier of the project.
507
+ * @param args - Optional parameters to filter collaborators.
508
+ * @returns A promise that resolves to an array of collaborators for the project.
509
+ */
510
+ async getProjectCollaborators(projectId, args = {}) {
511
+ zod_1.z.string().parse(projectId);
512
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
513
+ httpMethod: 'GET',
514
+ baseUri: this.syncApiBase,
515
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, projectId, endpoints_1.ENDPOINT_REST_PROJECT_COLLABORATORS),
516
+ apiToken: this.authToken,
517
+ payload: args,
518
+ });
519
+ return {
520
+ results: (0, validators_1.validateUserArray)(results),
521
+ nextCursor,
522
+ };
523
+ }
524
+ /**
525
+ * Retrieves all sections within a specific project or matching criteria.
526
+ *
527
+ * @param args - Filter parameters such as project ID.
528
+ * @returns A promise that resolves to an array of sections.
529
+ */
530
+ async getSections(args) {
531
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
532
+ httpMethod: 'GET',
533
+ baseUri: this.syncApiBase,
534
+ relativePath: endpoints_1.ENDPOINT_REST_SECTIONS,
535
+ apiToken: this.authToken,
536
+ payload: args,
537
+ });
538
+ return {
539
+ results: (0, validators_1.validateSectionArray)(results),
540
+ nextCursor,
541
+ };
542
+ }
543
+ /**
544
+ * Retrieves a single section by its ID.
545
+ *
546
+ * @param id - The unique identifier of the section.
547
+ * @returns A promise that resolves to the requested section.
548
+ */
549
+ async getSection(id) {
550
+ zod_1.z.string().parse(id);
551
+ const response = await (0, rest_client_1.request)({
552
+ httpMethod: 'GET',
553
+ baseUri: this.syncApiBase,
554
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
555
+ apiToken: this.authToken,
556
+ });
557
+ return (0, validators_1.validateSection)(response.data);
558
+ }
559
+ /**
560
+ * Creates a new section within a project.
561
+ *
562
+ * @param args - Section creation parameters such as name or project ID.
563
+ * @param requestId - Optional custom identifier for the request.
564
+ * @returns A promise that resolves to the created section.
565
+ */
566
+ async addSection(args, requestId) {
567
+ const response = await (0, rest_client_1.request)({
568
+ httpMethod: 'POST',
569
+ baseUri: this.syncApiBase,
570
+ relativePath: endpoints_1.ENDPOINT_REST_SECTIONS,
571
+ apiToken: this.authToken,
572
+ payload: args,
573
+ requestId: requestId,
574
+ });
575
+ return (0, validators_1.validateSection)(response.data);
576
+ }
577
+ /**
578
+ * Updates a section by its ID with the provided parameters.
579
+ *
580
+ * @param id - The unique identifier of the section to update.
581
+ * @param args - Update parameters such as name or project ID.
582
+ * @param requestId - Optional custom identifier for the request.
583
+ * @returns A promise that resolves to the updated section.
584
+ */
585
+ async updateSection(id, args, requestId) {
586
+ zod_1.z.string().parse(id);
587
+ const response = await (0, rest_client_1.request)({
588
+ httpMethod: 'POST',
589
+ baseUri: this.syncApiBase,
590
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
591
+ apiToken: this.authToken,
592
+ payload: args,
593
+ requestId: requestId,
594
+ });
595
+ return (0, validators_1.validateSection)(response.data);
596
+ }
597
+ /**
598
+ * Deletes a section by its ID.
599
+ *
600
+ * @param id - The unique identifier of the section to delete.
601
+ * @param requestId - Optional custom identifier for the request.
602
+ * @returns A promise that resolves to `true` if successful.
603
+ */
604
+ async deleteSection(id, requestId) {
605
+ zod_1.z.string().parse(id);
606
+ const response = await (0, rest_client_1.request)({
607
+ httpMethod: 'DELETE',
608
+ baseUri: this.syncApiBase,
609
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
610
+ apiToken: this.authToken,
611
+ requestId: requestId,
612
+ });
613
+ return (0, rest_client_1.isSuccess)(response);
614
+ }
615
+ /**
616
+ * Retrieves a label by its ID.
617
+ *
618
+ * @param id - The unique identifier of the label.
619
+ * @returns A promise that resolves to the requested label.
620
+ */
621
+ async getLabel(id) {
622
+ zod_1.z.string().parse(id);
623
+ const response = await (0, rest_client_1.request)({
624
+ httpMethod: 'GET',
625
+ baseUri: this.syncApiBase,
626
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
627
+ apiToken: this.authToken,
628
+ });
629
+ return (0, validators_1.validateLabel)(response.data);
630
+ }
631
+ /**
632
+ * Retrieves all labels.
633
+ *
634
+ * @param args - Optional filter parameters.
635
+ * @returns A promise that resolves to an array of labels.
636
+ */
637
+ async getLabels(args = {}) {
638
+ const { data: { results, nextCursor: nextCursor }, } = await (0, rest_client_1.request)({
639
+ httpMethod: 'GET',
640
+ baseUri: this.syncApiBase,
641
+ relativePath: endpoints_1.ENDPOINT_REST_LABELS,
642
+ apiToken: this.authToken,
643
+ payload: args,
644
+ });
645
+ return {
646
+ results: (0, validators_1.validateLabelArray)(results),
647
+ nextCursor,
648
+ };
649
+ }
650
+ /**
651
+ * Adds a new label.
652
+ *
653
+ * @param args - Label creation parameters such as name.
654
+ * @param requestId - Optional custom identifier for the request.
655
+ * @returns A promise that resolves to the created label.
656
+ */
657
+ async addLabel(args, requestId) {
658
+ const response = await (0, rest_client_1.request)({
659
+ httpMethod: 'POST',
660
+ baseUri: this.syncApiBase,
661
+ relativePath: endpoints_1.ENDPOINT_REST_LABELS,
662
+ apiToken: this.authToken,
663
+ payload: args,
664
+ requestId: requestId,
665
+ });
666
+ return (0, validators_1.validateLabel)(response.data);
667
+ }
668
+ /**
669
+ * Updates an existing label by its ID.
670
+ *
671
+ * @param id - The unique identifier of the label to update.
672
+ * @param args - Update parameters such as name or color.
673
+ * @param requestId - Optional custom identifier for the request.
674
+ * @returns A promise that resolves to the updated label.
675
+ */
676
+ async updateLabel(id, args, requestId) {
677
+ zod_1.z.string().parse(id);
678
+ const response = await (0, rest_client_1.request)({
679
+ httpMethod: 'POST',
680
+ baseUri: this.syncApiBase,
681
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
682
+ apiToken: this.authToken,
683
+ payload: args,
684
+ requestId: requestId,
685
+ });
686
+ return (0, validators_1.validateLabel)(response.data);
687
+ }
688
+ /**
689
+ * Deletes a label by its ID.
690
+ *
691
+ * @param id - The unique identifier of the label to delete.
692
+ * @param requestId - Optional custom identifier for the request.
693
+ * @returns A promise that resolves to `true` if successful.
694
+ */
695
+ async deleteLabel(id, requestId) {
696
+ zod_1.z.string().parse(id);
697
+ const response = await (0, rest_client_1.request)({
698
+ httpMethod: 'DELETE',
699
+ baseUri: this.syncApiBase,
700
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
701
+ apiToken: this.authToken,
702
+ requestId: requestId,
703
+ });
704
+ return (0, rest_client_1.isSuccess)(response);
705
+ }
706
+ /**
707
+ * Retrieves a list of shared labels.
708
+ *
709
+ * @param args - Optional parameters to filter shared labels.
710
+ * @returns A promise that resolves to an array of shared labels.
711
+ */
712
+ async getSharedLabels(args) {
713
+ const { data: { results, nextCursor: nextCursor }, } = await (0, rest_client_1.request)({
714
+ httpMethod: 'GET',
715
+ baseUri: this.syncApiBase,
716
+ relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED,
717
+ apiToken: this.authToken,
718
+ payload: args,
719
+ });
720
+ return { results, nextCursor };
721
+ }
722
+ /**
723
+ * Renames an existing shared label.
724
+ *
725
+ * @param args - Parameters for renaming the shared label, including the current and new name.
726
+ * @returns A promise that resolves to `true` if successful.
727
+ */
728
+ async renameSharedLabel(args) {
729
+ const response = await (0, rest_client_1.request)({
730
+ httpMethod: 'POST',
731
+ baseUri: this.syncApiBase,
732
+ relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED_RENAME,
733
+ apiToken: this.authToken,
734
+ payload: args,
735
+ });
736
+ return (0, rest_client_1.isSuccess)(response);
737
+ }
738
+ /**
739
+ * Removes a shared label.
740
+ *
741
+ * @param args - Parameters for removing the shared label.
742
+ * @returns A promise that resolves to `true` if successful.
743
+ */
744
+ async removeSharedLabel(args) {
745
+ const response = await (0, rest_client_1.request)({
746
+ httpMethod: 'POST',
747
+ baseUri: this.syncApiBase,
748
+ relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED_REMOVE,
749
+ apiToken: this.authToken,
750
+ payload: args,
751
+ });
752
+ return (0, rest_client_1.isSuccess)(response);
753
+ }
754
+ /**
755
+ * Retrieves all comments associated with a task or project.
756
+ *
757
+ * @param args - Parameters for retrieving comments, such as task ID or project ID.
758
+ * @returns A promise that resolves to an array of comments.
759
+ */
760
+ async getComments(args) {
761
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
762
+ httpMethod: 'GET',
763
+ baseUri: this.syncApiBase,
764
+ relativePath: endpoints_1.ENDPOINT_REST_COMMENTS,
765
+ apiToken: this.authToken,
766
+ payload: args,
767
+ });
768
+ return {
769
+ results: (0, validators_1.validateCommentArray)(results),
770
+ nextCursor,
771
+ };
772
+ }
773
+ /**
774
+ * Retrieves a specific comment by its ID.
775
+ *
776
+ * @param id - The unique identifier of the comment to retrieve.
777
+ * @returns A promise that resolves to the requested comment.
778
+ */
779
+ async getComment(id) {
780
+ zod_1.z.string().parse(id);
781
+ const response = await (0, rest_client_1.request)({
782
+ httpMethod: 'GET',
783
+ baseUri: this.syncApiBase,
784
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
785
+ apiToken: this.authToken,
786
+ });
787
+ return (0, validators_1.validateComment)(response.data);
788
+ }
789
+ /**
790
+ * Adds a comment to a task or project.
791
+ *
792
+ * @param args - Parameters for creating the comment, such as content and the target task or project ID.
793
+ * @param requestId - Optional custom identifier for the request.
794
+ * @returns A promise that resolves to the created comment.
795
+ */
796
+ async addComment(args, requestId) {
797
+ const response = await (0, rest_client_1.request)({
798
+ httpMethod: 'POST',
799
+ baseUri: this.syncApiBase,
800
+ relativePath: endpoints_1.ENDPOINT_REST_COMMENTS,
801
+ apiToken: this.authToken,
802
+ payload: args,
803
+ requestId: requestId,
804
+ });
805
+ return (0, validators_1.validateComment)(response.data);
806
+ }
807
+ /**
808
+ * Updates an existing comment by its ID.
809
+ *
810
+ * @param id - The unique identifier of the comment to update.
811
+ * @param args - Update parameters such as new content.
812
+ * @param requestId - Optional custom identifier for the request.
813
+ * @returns A promise that resolves to the updated comment.
814
+ */
815
+ async updateComment(id, args, requestId) {
816
+ zod_1.z.string().parse(id);
817
+ const response = await (0, rest_client_1.request)({
818
+ httpMethod: 'POST',
819
+ baseUri: this.syncApiBase,
820
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
821
+ apiToken: this.authToken,
822
+ payload: args,
823
+ requestId: requestId,
824
+ });
825
+ return (0, validators_1.validateComment)(response.data);
826
+ }
827
+ /**
828
+ * Deletes a comment by its ID.
829
+ *
830
+ * @param id - The unique identifier of the comment to delete.
831
+ * @param requestId - Optional custom identifier for the request.
832
+ * @returns A promise that resolves to `true` if successful.
833
+ */
834
+ async deleteComment(id, requestId) {
835
+ zod_1.z.string().parse(id);
836
+ const response = await (0, rest_client_1.request)({
837
+ httpMethod: 'DELETE',
838
+ baseUri: this.syncApiBase,
839
+ relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
840
+ apiToken: this.authToken,
841
+ requestId: requestId,
842
+ });
843
+ return (0, rest_client_1.isSuccess)(response);
844
+ }
845
+ /**
846
+ * Retrieves productivity stats for the authenticated user.
847
+ *
848
+ * @returns A promise that resolves to the productivity stats.
849
+ */
850
+ async getProductivityStats() {
851
+ const response = await (0, rest_client_1.request)({
852
+ httpMethod: 'GET',
853
+ baseUri: this.syncApiBase,
854
+ relativePath: endpoints_1.ENDPOINT_REST_PRODUCTIVITY,
855
+ apiToken: this.authToken,
856
+ });
857
+ return (0, validators_1.validateProductivityStats)(response.data);
858
+ }
859
+ /**
860
+ * Retrieves activity logs with optional filters.
861
+ *
862
+ * @param args - Optional filter parameters for activity logs.
863
+ * @returns A promise that resolves to a paginated response of activity events.
864
+ */
865
+ async getActivityLogs(args = {}) {
866
+ // Convert Date objects to YYYY-MM-DD strings and modern object types to legacy API types
867
+ const processedArgs = Object.assign(Object.assign(Object.assign(Object.assign({}, args), (args.since instanceof Date && { since: (0, url_helpers_1.formatDateToYYYYMMDD)(args.since) })), (args.until instanceof Date && { until: (0, url_helpers_1.formatDateToYYYYMMDD)(args.until) })), (args.objectType && { objectType: (0, activity_helpers_1.normalizeObjectTypeForApi)(args.objectType) }));
868
+ const { data: { results, nextCursor }, } = await (0, rest_client_1.request)({
869
+ httpMethod: 'GET',
870
+ baseUri: this.syncApiBase,
871
+ relativePath: endpoints_1.ENDPOINT_REST_ACTIVITIES,
872
+ apiToken: this.authToken,
873
+ payload: processedArgs,
874
+ });
875
+ // Convert legacy API object types back to modern SDK types
876
+ const normalizedResults = results.map((event) => {
877
+ const normalizedType = (0, activity_helpers_1.denormalizeObjectTypeFromApi)(event.objectType);
878
+ return Object.assign(Object.assign({}, event), { objectType: normalizedType || event.objectType });
879
+ });
880
+ return {
881
+ results: (0, validators_1.validateActivityEventArray)(normalizedResults),
882
+ nextCursor,
883
+ };
884
+ }
885
+ /**
886
+ * Uploads a file and returns attachment metadata.
887
+ * This creates an upload record that can be referenced in tasks or comments.
888
+ *
889
+ * @param args - Upload parameters including file content, filename, and optional project ID.
890
+ * @param requestId - Optional custom identifier for the request.
891
+ * @returns A promise that resolves to the uploaded file's attachment metadata.
892
+ *
893
+ * @example
894
+ * ```typescript
895
+ * // Upload from a file path
896
+ * const upload = await api.uploadFile({
897
+ * file: '/path/to/document.pdf',
898
+ * projectId: '12345'
899
+ * })
900
+ *
901
+ * // Upload from a Buffer
902
+ * const buffer = fs.readFileSync('/path/to/document.pdf')
903
+ * const upload = await api.uploadFile({
904
+ * file: buffer,
905
+ * fileName: 'document.pdf', // Required for Buffer/Stream
906
+ * projectId: '12345'
907
+ * })
908
+ *
909
+ * // Use the returned fileUrl in a comment
910
+ * await api.addComment({
911
+ * content: 'See attached document',
912
+ * taskId: '67890',
913
+ * attachment: {
914
+ * fileUrl: upload.fileUrl,
915
+ * fileName: upload.fileName,
916
+ * fileType: upload.fileType,
917
+ * resourceType: upload.resourceType
918
+ * }
919
+ * })
920
+ * ```
921
+ */
922
+ async uploadFile(args, requestId) {
923
+ const additionalFields = {};
924
+ if (args.projectId) {
925
+ additionalFields.project_id = args.projectId;
926
+ }
927
+ const data = await (0, multipart_upload_1.uploadMultipartFile)({
928
+ baseUrl: this.syncApiBase,
929
+ authToken: this.authToken,
930
+ endpoint: endpoints_1.ENDPOINT_REST_UPLOADS,
931
+ file: args.file,
932
+ fileName: args.fileName,
933
+ additionalFields: additionalFields,
934
+ requestId: requestId,
935
+ });
936
+ return (0, validators_1.validateAttachment)(data);
937
+ }
938
+ /**
939
+ * Deletes an uploaded file by its URL.
940
+ *
941
+ * @param args - The file URL to delete.
942
+ * @param requestId - Optional custom identifier for the request.
943
+ * @returns A promise that resolves to `true` if deletion was successful.
944
+ *
945
+ * @example
946
+ * ```typescript
947
+ * await api.deleteUpload({
948
+ * fileUrl: 'https://cdn.todoist.com/...'
949
+ * })
950
+ * ```
951
+ */
952
+ async deleteUpload(args, requestId) {
953
+ const response = await (0, rest_client_1.request)({
954
+ httpMethod: 'DELETE',
955
+ baseUri: this.syncApiBase,
956
+ relativePath: endpoints_1.ENDPOINT_REST_UPLOADS,
957
+ apiToken: this.authToken,
958
+ payload: args,
959
+ requestId: requestId,
960
+ });
961
+ return (0, rest_client_1.isSuccess)(response);
962
+ }
963
+ /* Workspace methods */
964
+ /**
965
+ * Gets pending invitations for a workspace.
966
+ *
967
+ * @param args - Arguments including workspace ID.
968
+ * @param requestId - Optional request ID for idempotency.
969
+ * @returns Array of email addresses with pending invitations.
970
+ */
971
+ async getWorkspaceInvitations(args, requestId) {
972
+ const response = await (0, rest_client_1.request)({
973
+ httpMethod: 'GET',
974
+ baseUri: this.syncApiBase,
975
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS,
976
+ apiToken: this.authToken,
977
+ payload: { workspace_id: args.workspaceId },
978
+ requestId: requestId,
979
+ });
980
+ return response.data;
981
+ }
982
+ /**
983
+ * Gets all workspace invitations (admin only).
984
+ *
985
+ * @param requestId - Optional request ID for idempotency.
986
+ * @returns Array of email addresses with pending invitations.
987
+ */
988
+ async getAllWorkspaceInvitations(args = {}, requestId) {
989
+ const queryParams = {};
990
+ if (args.workspaceId) {
991
+ queryParams.workspace_id = args.workspaceId;
992
+ }
993
+ const response = await (0, rest_client_1.request)({
994
+ httpMethod: 'GET',
995
+ baseUri: this.syncApiBase,
996
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS_ALL,
997
+ apiToken: this.authToken,
998
+ payload: queryParams,
999
+ requestId: requestId,
1000
+ });
1001
+ return (0, validators_1.validateWorkspaceInvitationArray)(response.data);
1002
+ }
1003
+ /**
1004
+ * Deletes a workspace invitation (admin only).
1005
+ *
1006
+ * @param args - Arguments including workspace ID and user email.
1007
+ * @param requestId - Optional request ID for idempotency.
1008
+ * @returns The deleted invitation.
1009
+ */
1010
+ async deleteWorkspaceInvitation(args, requestId) {
1011
+ const response = await (0, rest_client_1.request)({
1012
+ httpMethod: 'POST',
1013
+ baseUri: this.syncApiBase,
1014
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS_DELETE,
1015
+ apiToken: this.authToken,
1016
+ payload: {
1017
+ workspace_id: args.workspaceId,
1018
+ user_email: args.userEmail,
1019
+ },
1020
+ requestId: requestId,
1021
+ });
1022
+ return (0, validators_1.validateWorkspaceInvitation)(response.data);
1023
+ }
1024
+ /**
1025
+ * Accepts a workspace invitation.
1026
+ *
1027
+ * @param args - Arguments including invite code.
1028
+ * @param requestId - Optional request ID for idempotency.
1029
+ * @returns The accepted invitation.
1030
+ */
1031
+ async acceptWorkspaceInvitation(args, requestId) {
1032
+ const response = await (0, rest_client_1.request)({
1033
+ httpMethod: 'PUT',
1034
+ baseUri: this.syncApiBase,
1035
+ relativePath: (0, endpoints_1.getWorkspaceInvitationAcceptEndpoint)(args.inviteCode),
1036
+ apiToken: this.authToken,
1037
+ requestId: requestId,
1038
+ });
1039
+ return (0, validators_1.validateWorkspaceInvitation)(response.data);
1040
+ }
1041
+ /**
1042
+ * Rejects a workspace invitation.
1043
+ *
1044
+ * @param args - Arguments including invite code.
1045
+ * @param requestId - Optional request ID for idempotency.
1046
+ * @returns The rejected invitation.
1047
+ */
1048
+ async rejectWorkspaceInvitation(args, requestId) {
1049
+ const response = await (0, rest_client_1.request)({
1050
+ httpMethod: 'PUT',
1051
+ baseUri: this.syncApiBase,
1052
+ relativePath: (0, endpoints_1.getWorkspaceInvitationRejectEndpoint)(args.inviteCode),
1053
+ apiToken: this.authToken,
1054
+ requestId: requestId,
1055
+ });
1056
+ return (0, validators_1.validateWorkspaceInvitation)(response.data);
1057
+ }
1058
+ /**
1059
+ * Joins a workspace via invitation link or domain auto-join.
1060
+ *
1061
+ * @param args - Arguments including invite code or workspace ID.
1062
+ * @param requestId - Optional request ID for idempotency.
1063
+ * @returns Workspace user information.
1064
+ */
1065
+ async joinWorkspace(args, requestId) {
1066
+ const response = await (0, rest_client_1.request)({
1067
+ httpMethod: 'POST',
1068
+ baseUri: this.syncApiBase,
1069
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_JOIN,
1070
+ apiToken: this.authToken,
1071
+ payload: {
1072
+ invite_code: args.inviteCode,
1073
+ workspace_id: args.workspaceId,
1074
+ },
1075
+ requestId: requestId,
1076
+ });
1077
+ return (0, validators_1.validateJoinWorkspaceResult)(response.data);
1078
+ }
1079
+ /**
1080
+ * Uploads or updates a workspace logo.
1081
+ *
1082
+ * @param args - Arguments including workspace ID, file, and options.
1083
+ * @param requestId - Optional request ID for idempotency.
1084
+ * @returns Logo information or null if deleted.
1085
+ */
1086
+ async uploadWorkspaceLogo(args, requestId) {
1087
+ if (args.delete) {
1088
+ // Delete logo
1089
+ const data = await (0, multipart_upload_1.uploadMultipartFile)({
1090
+ baseUrl: this.syncApiBase,
1091
+ authToken: this.authToken,
1092
+ endpoint: endpoints_1.ENDPOINT_WORKSPACE_LOGO,
1093
+ file: Buffer.alloc(0), // Empty buffer for delete
1094
+ fileName: 'delete',
1095
+ additionalFields: {
1096
+ workspace_id: args.workspaceId,
1097
+ delete: true,
1098
+ },
1099
+ requestId: requestId,
1100
+ });
1101
+ return data;
1102
+ }
1103
+ if (!args.file) {
1104
+ throw new Error('file is required when not deleting logo');
1105
+ }
1106
+ // Validate buffer is not empty if it's a Buffer
1107
+ if (Buffer.isBuffer(args.file) && args.file.length === 0) {
1108
+ throw new Error('Cannot upload empty image file');
1109
+ }
1110
+ const additionalFields = {
1111
+ workspace_id: args.workspaceId,
1112
+ };
1113
+ const data = await (0, multipart_upload_1.uploadMultipartFile)({
1114
+ baseUrl: this.syncApiBase,
1115
+ authToken: this.authToken,
1116
+ endpoint: endpoints_1.ENDPOINT_WORKSPACE_LOGO,
1117
+ file: args.file,
1118
+ fileName: args.fileName,
1119
+ additionalFields: additionalFields,
1120
+ requestId: requestId,
1121
+ });
1122
+ return data;
1123
+ }
1124
+ /**
1125
+ * Gets workspace plan and billing details.
1126
+ *
1127
+ * @param args - Arguments including workspace ID.
1128
+ * @param requestId - Optional request ID for idempotency.
1129
+ * @returns Workspace plan details.
1130
+ */
1131
+ async getWorkspacePlanDetails(args, requestId) {
1132
+ const response = await (0, rest_client_1.request)({
1133
+ httpMethod: 'GET',
1134
+ baseUri: this.syncApiBase,
1135
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_PLAN_DETAILS,
1136
+ apiToken: this.authToken,
1137
+ payload: { workspace_id: args.workspaceId },
1138
+ requestId: requestId,
1139
+ });
1140
+ return (0, validators_1.validateWorkspacePlanDetails)(response.data);
1141
+ }
1142
+ /**
1143
+ * Gets workspace users with pagination.
1144
+ *
1145
+ * @param args - Arguments including optional workspace ID, cursor, and limit.
1146
+ * @param requestId - Optional request ID for idempotency.
1147
+ * @returns Paginated list of workspace users.
1148
+ */
1149
+ async getWorkspaceUsers(args = {}, requestId) {
1150
+ const queryParams = {};
1151
+ if (args.workspaceId !== undefined && args.workspaceId !== null) {
1152
+ queryParams.workspace_id = args.workspaceId;
1153
+ }
1154
+ if (args.cursor) {
1155
+ queryParams.cursor = args.cursor;
1156
+ }
1157
+ if (args.limit) {
1158
+ queryParams.limit = args.limit;
1159
+ }
1160
+ const response = await (0, rest_client_1.request)({
1161
+ httpMethod: 'GET',
1162
+ baseUri: this.syncApiBase,
1163
+ relativePath: endpoints_1.ENDPOINT_WORKSPACE_USERS,
1164
+ apiToken: this.authToken,
1165
+ payload: queryParams,
1166
+ requestId: requestId,
1167
+ });
1168
+ return {
1169
+ hasMore: response.data.has_more || false,
1170
+ nextCursor: response.data.next_cursor,
1171
+ workspaceUsers: (0, validators_1.validateWorkspaceUserArray)(response.data.workspace_users || []),
1172
+ };
1173
+ }
1174
+ /**
1175
+ * Gets active projects in a workspace with pagination.
1176
+ *
1177
+ * @param args - Arguments including workspace ID, cursor, and limit.
1178
+ * @param requestId - Optional request ID for idempotency.
1179
+ * @returns Paginated list of active workspace projects.
1180
+ */
1181
+ async getWorkspaceActiveProjects(args, requestId) {
1182
+ var _a;
1183
+ const queryParams = {};
1184
+ if (args.cursor) {
1185
+ queryParams.cursor = args.cursor;
1186
+ }
1187
+ if (args.limit) {
1188
+ queryParams.limit = args.limit;
1189
+ }
1190
+ const response = await (0, rest_client_1.request)({
1191
+ httpMethod: 'GET',
1192
+ baseUri: this.syncApiBase,
1193
+ relativePath: (0, endpoints_1.getWorkspaceActiveProjectsEndpoint)(args.workspaceId),
1194
+ apiToken: this.authToken,
1195
+ payload: queryParams,
1196
+ requestId: requestId,
1197
+ });
1198
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1199
+ const validatedProjects = (_a = response.data.results) === null || _a === void 0 ? void 0 : _a.map((project) => (0, validators_1.validateProject)(project));
1200
+ return Object.assign(Object.assign({}, response.data), {
1201
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1202
+ results: validatedProjects || [] });
1203
+ }
1204
+ /**
1205
+ * Gets archived projects in a workspace with pagination.
1206
+ *
1207
+ * @param args - Arguments including workspace ID, cursor, and limit.
1208
+ * @param requestId - Optional request ID for idempotency.
1209
+ * @returns Paginated list of archived workspace projects.
1210
+ */
1211
+ async getWorkspaceArchivedProjects(args, requestId) {
1212
+ var _a;
1213
+ const queryParams = {};
1214
+ if (args.cursor) {
1215
+ queryParams.cursor = args.cursor;
1216
+ }
1217
+ if (args.limit) {
1218
+ queryParams.limit = args.limit;
1219
+ }
1220
+ const response = await (0, rest_client_1.request)({
1221
+ httpMethod: 'GET',
1222
+ baseUri: this.syncApiBase,
1223
+ relativePath: (0, endpoints_1.getWorkspaceArchivedProjectsEndpoint)(args.workspaceId),
1224
+ apiToken: this.authToken,
1225
+ payload: queryParams,
1226
+ requestId: requestId,
1227
+ });
1228
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1229
+ const validatedProjects = (_a = response.data.results) === null || _a === void 0 ? void 0 : _a.map((project) => (0, validators_1.validateProject)(project));
1230
+ return Object.assign(Object.assign({}, response.data), {
1231
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1232
+ results: validatedProjects || [] });
1233
+ }
1234
+ }
1235
+ exports.TodoistApi = TodoistApi;