@doist/todoist-api-typescript 7.1.0 → 7.2.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.
@@ -55,6 +55,34 @@ function preprocessSyncCommands(commands) {
55
55
  return cmd;
56
56
  });
57
57
  }
58
+ /**
59
+ * A client for interacting with the Todoist API v1.
60
+ * This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const api = new TodoistApi('your-api-token');
65
+ *
66
+ * // Get all tasks
67
+ * const tasks = await api.getTasks();
68
+ *
69
+ * // Create a new task
70
+ * const newTask = await api.addTask({
71
+ * content: 'My new task',
72
+ * projectId: '12345'
73
+ * });
74
+ * ```
75
+ *
76
+ * For more information about the Todoist API v1, see the [official documentation](https://todoist.com/api/v1).
77
+ * If you're migrating from v9, please refer to the [migration guide](https://todoist.com/api/v1/docs#tag/Migrating-from-v9).
78
+ */
79
+ function headersToRecord(headers) {
80
+ const result = {};
81
+ headers.forEach((value, key) => {
82
+ result[key] = value;
83
+ });
84
+ return result;
85
+ }
58
86
  class TodoistApi {
59
87
  constructor(
60
88
  /**
@@ -1194,6 +1222,83 @@ class TodoistApi {
1194
1222
  });
1195
1223
  return (0, rest_client_1.isSuccess)(response);
1196
1224
  }
1225
+ /**
1226
+ * Fetches the content of a file attachment from a Todoist comment.
1227
+ *
1228
+ * Accepts either a Comment object (extracts the file URL from its attachment)
1229
+ * or a direct file URL string. Returns the raw Response object so the caller
1230
+ * can read the body in the appropriate format (.arrayBuffer(), .text(), etc.).
1231
+ *
1232
+ * @param commentOrUrl - A Comment object with a file attachment, or a file URL string.
1233
+ * @returns The raw fetch Response for the file content.
1234
+ * @throws Error if a Comment is provided without a file attachment or file URL.
1235
+ *
1236
+ * @example
1237
+ * ```typescript
1238
+ * // From a comment object
1239
+ * const comments = await api.getComments({ taskId: '12345' })
1240
+ * const comment = comments.results[0]
1241
+ * const response = await api.viewAttachment(comment)
1242
+ * const imageData = await response.arrayBuffer()
1243
+ *
1244
+ * // From a URL string
1245
+ * const response = await api.viewAttachment('https://files.todoist.com/...')
1246
+ * const text = await response.text()
1247
+ * ```
1248
+ */
1249
+ async viewAttachment(commentOrUrl) {
1250
+ var _a;
1251
+ let fileUrl;
1252
+ if (typeof commentOrUrl === 'string') {
1253
+ fileUrl = commentOrUrl;
1254
+ }
1255
+ else {
1256
+ if (!((_a = commentOrUrl.fileAttachment) === null || _a === void 0 ? void 0 : _a.fileUrl)) {
1257
+ throw new Error('Comment does not have a file attachment');
1258
+ }
1259
+ fileUrl = commentOrUrl.fileAttachment.fileUrl;
1260
+ }
1261
+ // Validate the URL belongs to Todoist to prevent leaking the auth token
1262
+ const urlHostname = new URL(fileUrl).hostname;
1263
+ if (!urlHostname.endsWith('.todoist.com')) {
1264
+ throw new Error('Attachment URLs must be on a todoist.com domain');
1265
+ }
1266
+ const fetchOptions = {
1267
+ method: 'GET',
1268
+ headers: { Authorization: `Bearer ${this.authToken}` },
1269
+ };
1270
+ if (this.customFetch) {
1271
+ const response = await this.customFetch(fileUrl, fetchOptions);
1272
+ if (!response.ok) {
1273
+ throw new Error(`Failed to fetch attachment: ${response.status} ${response.statusText}`);
1274
+ }
1275
+ // Convert text to ArrayBuffer for custom fetch implementations that lack arrayBuffer()
1276
+ const text = await response.text();
1277
+ const buffer = new TextEncoder().encode(text).buffer;
1278
+ return {
1279
+ ok: response.ok,
1280
+ status: response.status,
1281
+ statusText: response.statusText,
1282
+ headers: response.headers,
1283
+ text: () => Promise.resolve(text),
1284
+ json: () => response.json(),
1285
+ arrayBuffer: () => Promise.resolve(buffer),
1286
+ };
1287
+ }
1288
+ const response = await fetch(fileUrl, fetchOptions);
1289
+ if (!response.ok) {
1290
+ throw new Error(`Failed to fetch attachment: ${response.status} ${response.statusText}`);
1291
+ }
1292
+ return {
1293
+ ok: response.ok,
1294
+ status: response.status,
1295
+ statusText: response.statusText,
1296
+ headers: headersToRecord(response.headers),
1297
+ text: () => response.text(),
1298
+ json: () => response.json(),
1299
+ arrayBuffer: () => response.arrayBuffer(),
1300
+ };
1301
+ }
1197
1302
  /* Workspace methods */
1198
1303
  /**
1199
1304
  * Gets pending invitations for a workspace.
@@ -52,6 +52,34 @@ function preprocessSyncCommands(commands) {
52
52
  return cmd;
53
53
  });
54
54
  }
55
+ /**
56
+ * A client for interacting with the Todoist API v1.
57
+ * This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const api = new TodoistApi('your-api-token');
62
+ *
63
+ * // Get all tasks
64
+ * const tasks = await api.getTasks();
65
+ *
66
+ * // Create a new task
67
+ * const newTask = await api.addTask({
68
+ * content: 'My new task',
69
+ * projectId: '12345'
70
+ * });
71
+ * ```
72
+ *
73
+ * For more information about the Todoist API v1, see the [official documentation](https://todoist.com/api/v1).
74
+ * If you're migrating from v9, please refer to the [migration guide](https://todoist.com/api/v1/docs#tag/Migrating-from-v9).
75
+ */
76
+ function headersToRecord(headers) {
77
+ const result = {};
78
+ headers.forEach((value, key) => {
79
+ result[key] = value;
80
+ });
81
+ return result;
82
+ }
55
83
  export class TodoistApi {
56
84
  constructor(
57
85
  /**
@@ -1191,6 +1219,83 @@ export class TodoistApi {
1191
1219
  });
1192
1220
  return isSuccess(response);
1193
1221
  }
1222
+ /**
1223
+ * Fetches the content of a file attachment from a Todoist comment.
1224
+ *
1225
+ * Accepts either a Comment object (extracts the file URL from its attachment)
1226
+ * or a direct file URL string. Returns the raw Response object so the caller
1227
+ * can read the body in the appropriate format (.arrayBuffer(), .text(), etc.).
1228
+ *
1229
+ * @param commentOrUrl - A Comment object with a file attachment, or a file URL string.
1230
+ * @returns The raw fetch Response for the file content.
1231
+ * @throws Error if a Comment is provided without a file attachment or file URL.
1232
+ *
1233
+ * @example
1234
+ * ```typescript
1235
+ * // From a comment object
1236
+ * const comments = await api.getComments({ taskId: '12345' })
1237
+ * const comment = comments.results[0]
1238
+ * const response = await api.viewAttachment(comment)
1239
+ * const imageData = await response.arrayBuffer()
1240
+ *
1241
+ * // From a URL string
1242
+ * const response = await api.viewAttachment('https://files.todoist.com/...')
1243
+ * const text = await response.text()
1244
+ * ```
1245
+ */
1246
+ async viewAttachment(commentOrUrl) {
1247
+ var _a;
1248
+ let fileUrl;
1249
+ if (typeof commentOrUrl === 'string') {
1250
+ fileUrl = commentOrUrl;
1251
+ }
1252
+ else {
1253
+ if (!((_a = commentOrUrl.fileAttachment) === null || _a === void 0 ? void 0 : _a.fileUrl)) {
1254
+ throw new Error('Comment does not have a file attachment');
1255
+ }
1256
+ fileUrl = commentOrUrl.fileAttachment.fileUrl;
1257
+ }
1258
+ // Validate the URL belongs to Todoist to prevent leaking the auth token
1259
+ const urlHostname = new URL(fileUrl).hostname;
1260
+ if (!urlHostname.endsWith('.todoist.com')) {
1261
+ throw new Error('Attachment URLs must be on a todoist.com domain');
1262
+ }
1263
+ const fetchOptions = {
1264
+ method: 'GET',
1265
+ headers: { Authorization: `Bearer ${this.authToken}` },
1266
+ };
1267
+ if (this.customFetch) {
1268
+ const response = await this.customFetch(fileUrl, fetchOptions);
1269
+ if (!response.ok) {
1270
+ throw new Error(`Failed to fetch attachment: ${response.status} ${response.statusText}`);
1271
+ }
1272
+ // Convert text to ArrayBuffer for custom fetch implementations that lack arrayBuffer()
1273
+ const text = await response.text();
1274
+ const buffer = new TextEncoder().encode(text).buffer;
1275
+ return {
1276
+ ok: response.ok,
1277
+ status: response.status,
1278
+ statusText: response.statusText,
1279
+ headers: response.headers,
1280
+ text: () => Promise.resolve(text),
1281
+ json: () => response.json(),
1282
+ arrayBuffer: () => Promise.resolve(buffer),
1283
+ };
1284
+ }
1285
+ const response = await fetch(fileUrl, fetchOptions);
1286
+ if (!response.ok) {
1287
+ throw new Error(`Failed to fetch attachment: ${response.status} ${response.statusText}`);
1288
+ }
1289
+ return {
1290
+ ok: response.ok,
1291
+ status: response.status,
1292
+ statusText: response.statusText,
1293
+ headers: headersToRecord(response.headers),
1294
+ text: () => response.text(),
1295
+ json: () => response.json(),
1296
+ arrayBuffer: () => response.arrayBuffer(),
1297
+ };
1298
+ }
1194
1299
  /* Workspace methods */
1195
1300
  /**
1196
1301
  * Gets pending invitations for a workspace.
@@ -1,28 +1,14 @@
1
1
  import { Attachment, PersonalProject, WorkspaceProject, Label, Section, Comment, Task, CurrentUser, ProductivityStats, WorkspaceInvitation, WorkspacePlanDetails, JoinWorkspaceResult, Workspace } from './types/entities.js';
2
2
  import { AddCommentArgs, AddLabelArgs, AddProjectArgs, AddSectionArgs, AddTaskArgs, GetProjectCommentsArgs, GetTaskCommentsArgs, GetTasksArgs, GetTasksByFilterArgs, UpdateCommentArgs, UpdateLabelArgs, UpdateProjectArgs, UpdateSectionArgs, UpdateTaskArgs, QuickAddTaskArgs, GetSharedLabelsArgs, RenameSharedLabelArgs, RemoveSharedLabelArgs, GetProjectsArgs, SearchProjectsArgs, GetProjectCollaboratorsArgs, GetLabelsArgs, SearchLabelsArgs, GetLabelsResponse, GetTasksResponse, GetProjectsResponse, GetProjectCollaboratorsResponse, GetSectionsArgs, SearchSectionsArgs, GetSectionsResponse, GetSharedLabelsResponse, GetCommentsResponse, type MoveTaskArgs, GetCompletedTasksByCompletionDateArgs, GetCompletedTasksByDueDateArgs, GetCompletedTasksResponse, GetArchivedProjectsArgs, GetArchivedProjectsResponse, SearchCompletedTasksArgs, GetActivityLogsArgs, GetActivityLogsResponse, UploadFileArgs, DeleteUploadArgs, GetWorkspaceInvitationsArgs, DeleteWorkspaceInvitationArgs, WorkspaceInvitationActionArgs, JoinWorkspaceArgs, WorkspaceLogoArgs, GetWorkspacePlanDetailsArgs, GetWorkspaceUsersArgs, GetWorkspaceUsersResponse, GetWorkspaceProjectsArgs, WorkspaceInvitationsResponse, AllWorkspaceInvitationsResponse, WorkspaceLogoResponse, MoveProjectToWorkspaceArgs, MoveProjectToPersonalArgs } from './types/requests.js';
3
- import { CustomFetch } from './types/http.js';
3
+ import { CustomFetch, CustomFetchResponse } from './types/http.js';
4
4
  import { type SyncResponse, type SyncRequest } from './types/sync/index.js';
5
5
  /**
6
- * A client for interacting with the Todoist API v1.
7
- * This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
8
- *
9
- * @example
10
- * ```typescript
11
- * const api = new TodoistApi('your-api-token');
12
- *
13
- * // Get all tasks
14
- * const tasks = await api.getTasks();
15
- *
16
- * // Create a new task
17
- * const newTask = await api.addTask({
18
- * content: 'My new task',
19
- * projectId: '12345'
20
- * });
21
- * ```
22
- *
23
- * For more information about the Todoist API v1, see the [official documentation](https://todoist.com/api/v1).
24
- * If you're migrating from v9, please refer to the [migration guide](https://todoist.com/api/v1/docs#tag/Migrating-from-v9).
6
+ * Response from viewAttachment, extending CustomFetchResponse with
7
+ * arrayBuffer() support for binary file content.
25
8
  */
9
+ export type ViewAttachmentResponse = CustomFetchResponse & {
10
+ arrayBuffer(): Promise<ArrayBuffer>;
11
+ };
26
12
  /**
27
13
  * Configuration options for the TodoistApi constructor
28
14
  */
@@ -511,6 +497,31 @@ export declare class TodoistApi {
511
497
  * ```
512
498
  */
513
499
  deleteUpload(args: DeleteUploadArgs, requestId?: string): Promise<boolean>;
500
+ /**
501
+ * Fetches the content of a file attachment from a Todoist comment.
502
+ *
503
+ * Accepts either a Comment object (extracts the file URL from its attachment)
504
+ * or a direct file URL string. Returns the raw Response object so the caller
505
+ * can read the body in the appropriate format (.arrayBuffer(), .text(), etc.).
506
+ *
507
+ * @param commentOrUrl - A Comment object with a file attachment, or a file URL string.
508
+ * @returns The raw fetch Response for the file content.
509
+ * @throws Error if a Comment is provided without a file attachment or file URL.
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * // From a comment object
514
+ * const comments = await api.getComments({ taskId: '12345' })
515
+ * const comment = comments.results[0]
516
+ * const response = await api.viewAttachment(comment)
517
+ * const imageData = await response.arrayBuffer()
518
+ *
519
+ * // From a URL string
520
+ * const response = await api.viewAttachment('https://files.todoist.com/...')
521
+ * const text = await response.text()
522
+ * ```
523
+ */
524
+ viewAttachment(commentOrUrl: Comment | string): Promise<ViewAttachmentResponse>;
514
525
  /**
515
526
  * Gets pending invitations for a workspace.
516
527
  *
@@ -217,6 +217,7 @@ export type AddProjectArgs = {
217
217
  color?: ColorKey;
218
218
  isFavorite?: boolean;
219
219
  viewStyle?: ProjectViewStyle;
220
+ workspaceId?: string;
220
221
  };
221
222
  /**
222
223
  * Arguments for updating a project.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/todoist-api-typescript",
3
- "version": "7.1.0",
3
+ "version": "7.2.0",
4
4
  "description": "A typescript wrapper for the Todoist REST API.",
5
5
  "author": "Doist developers",
6
6
  "repository": "https://github.com/Doist/todoist-api-typescript",