@doist/todoist-api-typescript 6.1.10 → 6.1.12

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.
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.fetchWithRetry = fetchWithRetry;
15
+ const undici_1 = require("undici");
15
16
  const http_1 = require("../types/http");
16
17
  /**
17
18
  * Default retry configuration matching the original axios-retry behavior
@@ -25,6 +26,14 @@ const DEFAULT_RETRY_CONFIG = {
25
26
  return retryNumber === 1 ? 0 : 500;
26
27
  },
27
28
  };
29
+ /**
30
+ * HTTP agent with keepAlive disabled to prevent hanging connections
31
+ * This ensures the process exits immediately after requests complete
32
+ */
33
+ const httpAgent = new undici_1.Agent({
34
+ keepAliveTimeout: 1, // Close connections after 1ms of idle time
35
+ keepAliveMaxTimeout: 1, // Maximum time to keep connections alive
36
+ });
28
37
  /**
29
38
  * Converts Headers object to a plain object
30
39
  */
@@ -36,7 +45,8 @@ function headersToObject(headers) {
36
45
  return result;
37
46
  }
38
47
  /**
39
- * Creates an AbortSignal that times out after the specified duration
48
+ * Creates an AbortSignal that aborts after timeoutMs. Returns the signal and a
49
+ * clear function to cancel the timeout early.
40
50
  */
41
51
  function createTimeoutSignal(timeoutMs, existingSignal) {
42
52
  const controller = new AbortController();
@@ -44,6 +54,9 @@ function createTimeoutSignal(timeoutMs, existingSignal) {
44
54
  const timeoutId = setTimeout(() => {
45
55
  controller.abort(new Error(`Request timeout after ${timeoutMs}ms`));
46
56
  }, timeoutMs);
57
+ function clear() {
58
+ clearTimeout(timeoutId);
59
+ }
47
60
  // If there's an existing signal, forward its abort
48
61
  if (existingSignal) {
49
62
  if (existingSignal.aborted) {
@@ -61,7 +74,7 @@ function createTimeoutSignal(timeoutMs, existingSignal) {
61
74
  controller.signal.addEventListener('abort', () => {
62
75
  clearTimeout(timeoutId);
63
76
  });
64
- return controller.signal;
77
+ return { signal: controller.signal, clear };
65
78
  }
66
79
  /**
67
80
  * Converts native fetch Response to CustomFetchResponse for consistency
@@ -87,11 +100,15 @@ async function fetchWithRetry(args) {
87
100
  const { timeout, signal: userSignal } = options, fetchOptions = __rest(options, ["timeout", "signal"]);
88
101
  let lastError;
89
102
  for (let attempt = 0; attempt <= config.retries; attempt++) {
103
+ // Timeout clear function for this attempt (hoisted for catch scope)
104
+ let clearTimeoutFn;
90
105
  try {
91
106
  // Set up timeout and signal handling
92
107
  let requestSignal = userSignal || undefined;
93
108
  if (timeout && timeout > 0) {
94
- requestSignal = createTimeoutSignal(timeout, requestSignal);
109
+ const timeoutResult = createTimeoutSignal(timeout, requestSignal);
110
+ requestSignal = timeoutResult.signal;
111
+ clearTimeoutFn = timeoutResult.clear;
95
112
  }
96
113
  // Use custom fetch or native fetch
97
114
  let fetchResponse;
@@ -99,7 +116,9 @@ async function fetchWithRetry(args) {
99
116
  fetchResponse = await customFetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal, timeout }));
100
117
  }
101
118
  else {
102
- const nativeResponse = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal }));
119
+ const nativeResponse = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal,
120
+ // @ts-expect-error - dispatcher is a valid option for Node.js fetch but not in the TS types
121
+ dispatcher: httpAgent }));
103
122
  fetchResponse = convertResponseToCustomFetch(nativeResponse);
104
123
  }
105
124
  // Check if the response is successful
@@ -142,6 +161,10 @@ async function fetchWithRetry(args) {
142
161
  // If JSON parsing fails, return the raw text
143
162
  data = responseText;
144
163
  }
164
+ // Success – clear pending timeout (if any) so Node can exit promptly
165
+ if (clearTimeoutFn) {
166
+ clearTimeoutFn();
167
+ }
145
168
  return {
146
169
  data,
147
170
  status: fetchResponse.status,
@@ -159,6 +182,9 @@ async function fetchWithRetry(args) {
159
182
  const networkError = lastError;
160
183
  networkError.isNetworkError = true;
161
184
  }
185
+ if (clearTimeoutFn) {
186
+ clearTimeoutFn();
187
+ }
162
188
  throw lastError;
163
189
  }
164
190
  // Wait before retrying
@@ -166,6 +192,10 @@ async function fetchWithRetry(args) {
166
192
  if (delay > 0) {
167
193
  await new Promise((resolve) => setTimeout(resolve, delay));
168
194
  }
195
+ // Retry path – ensure this attempt's timeout is cleared before looping
196
+ if (clearTimeoutFn) {
197
+ clearTimeoutFn();
198
+ }
169
199
  }
170
200
  }
171
201
  // This should never be reached, but just in case
@@ -9,6 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
+ import { Agent } from 'undici';
12
13
  import { isNetworkError } from '../types/http.js';
13
14
  /**
14
15
  * Default retry configuration matching the original axios-retry behavior
@@ -22,6 +23,14 @@ const DEFAULT_RETRY_CONFIG = {
22
23
  return retryNumber === 1 ? 0 : 500;
23
24
  },
24
25
  };
26
+ /**
27
+ * HTTP agent with keepAlive disabled to prevent hanging connections
28
+ * This ensures the process exits immediately after requests complete
29
+ */
30
+ const httpAgent = new Agent({
31
+ keepAliveTimeout: 1, // Close connections after 1ms of idle time
32
+ keepAliveMaxTimeout: 1, // Maximum time to keep connections alive
33
+ });
25
34
  /**
26
35
  * Converts Headers object to a plain object
27
36
  */
@@ -33,7 +42,8 @@ function headersToObject(headers) {
33
42
  return result;
34
43
  }
35
44
  /**
36
- * Creates an AbortSignal that times out after the specified duration
45
+ * Creates an AbortSignal that aborts after timeoutMs. Returns the signal and a
46
+ * clear function to cancel the timeout early.
37
47
  */
38
48
  function createTimeoutSignal(timeoutMs, existingSignal) {
39
49
  const controller = new AbortController();
@@ -41,6 +51,9 @@ function createTimeoutSignal(timeoutMs, existingSignal) {
41
51
  const timeoutId = setTimeout(() => {
42
52
  controller.abort(new Error(`Request timeout after ${timeoutMs}ms`));
43
53
  }, timeoutMs);
54
+ function clear() {
55
+ clearTimeout(timeoutId);
56
+ }
44
57
  // If there's an existing signal, forward its abort
45
58
  if (existingSignal) {
46
59
  if (existingSignal.aborted) {
@@ -58,7 +71,7 @@ function createTimeoutSignal(timeoutMs, existingSignal) {
58
71
  controller.signal.addEventListener('abort', () => {
59
72
  clearTimeout(timeoutId);
60
73
  });
61
- return controller.signal;
74
+ return { signal: controller.signal, clear };
62
75
  }
63
76
  /**
64
77
  * Converts native fetch Response to CustomFetchResponse for consistency
@@ -84,11 +97,15 @@ export async function fetchWithRetry(args) {
84
97
  const { timeout, signal: userSignal } = options, fetchOptions = __rest(options, ["timeout", "signal"]);
85
98
  let lastError;
86
99
  for (let attempt = 0; attempt <= config.retries; attempt++) {
100
+ // Timeout clear function for this attempt (hoisted for catch scope)
101
+ let clearTimeoutFn;
87
102
  try {
88
103
  // Set up timeout and signal handling
89
104
  let requestSignal = userSignal || undefined;
90
105
  if (timeout && timeout > 0) {
91
- requestSignal = createTimeoutSignal(timeout, requestSignal);
106
+ const timeoutResult = createTimeoutSignal(timeout, requestSignal);
107
+ requestSignal = timeoutResult.signal;
108
+ clearTimeoutFn = timeoutResult.clear;
92
109
  }
93
110
  // Use custom fetch or native fetch
94
111
  let fetchResponse;
@@ -96,7 +113,9 @@ export async function fetchWithRetry(args) {
96
113
  fetchResponse = await customFetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal, timeout }));
97
114
  }
98
115
  else {
99
- const nativeResponse = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal }));
116
+ const nativeResponse = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal,
117
+ // @ts-expect-error - dispatcher is a valid option for Node.js fetch but not in the TS types
118
+ dispatcher: httpAgent }));
100
119
  fetchResponse = convertResponseToCustomFetch(nativeResponse);
101
120
  }
102
121
  // Check if the response is successful
@@ -139,6 +158,10 @@ export async function fetchWithRetry(args) {
139
158
  // If JSON parsing fails, return the raw text
140
159
  data = responseText;
141
160
  }
161
+ // Success – clear pending timeout (if any) so Node can exit promptly
162
+ if (clearTimeoutFn) {
163
+ clearTimeoutFn();
164
+ }
142
165
  return {
143
166
  data,
144
167
  status: fetchResponse.status,
@@ -156,6 +179,9 @@ export async function fetchWithRetry(args) {
156
179
  const networkError = lastError;
157
180
  networkError.isNetworkError = true;
158
181
  }
182
+ if (clearTimeoutFn) {
183
+ clearTimeoutFn();
184
+ }
159
185
  throw lastError;
160
186
  }
161
187
  // Wait before retrying
@@ -163,6 +189,10 @@ export async function fetchWithRetry(args) {
163
189
  if (delay > 0) {
164
190
  await new Promise((resolve) => setTimeout(resolve, delay));
165
191
  }
192
+ // Retry path – ensure this attempt's timeout is cleared before looping
193
+ if (clearTimeoutFn) {
194
+ clearTimeoutFn();
195
+ }
166
196
  }
167
197
  }
168
198
  // This should never be reached, but just in case
@@ -1,4 +1,4 @@
1
- import { CustomFetch } from './types/http';
1
+ import { CustomFetch } from './types/http.js';
2
2
  /**
3
3
  * Options for authentication functions
4
4
  */
@@ -1,4 +1,4 @@
1
- export * from './todoist-api';
2
- export * from './authentication';
3
- export * from './types';
4
- export * from './utils';
1
+ export * from './todoist-api.js';
2
+ export * from './authentication.js';
3
+ export * from './types/index.js';
4
+ export * from './utils/index.js';
@@ -1,4 +1,4 @@
1
- import { HttpMethod, HttpResponse, CustomFetch } from './types/http';
1
+ import { HttpMethod, HttpResponse, CustomFetch } from './types/http.js';
2
2
  type RequestArgs = {
3
3
  httpMethod: HttpMethod;
4
4
  baseUri: string;
@@ -1,5 +1,5 @@
1
1
  import type { RequestUrlParam, RequestUrlResponse } from 'obsidian';
2
- import type { CustomFetch } from '../types/http';
2
+ import type { CustomFetch } from '../types/http.js';
3
3
  /**
4
4
  * Creates a CustomFetch adapter for Obsidian's requestUrl API.
5
5
  *
@@ -16,7 +16,7 @@ import type { CustomFetch } from '../types/http';
16
16
  * @example
17
17
  * ```typescript
18
18
  * import { requestUrl } from 'obsidian';
19
- * import { createObsidianFetchAdapter } from './obsidian-fetch-adapter';
19
+ * import { createObsidianFetchAdapter } from './obsidian-fetch-adapter.js';
20
20
  *
21
21
  * const api = new TodoistApi('your-token', {
22
22
  * customFetch: createObsidianFetchAdapter(requestUrl)
@@ -1,4 +1,4 @@
1
- import { Label, Section, Task, User, Attachment, Duration, Deadline, RawComment, PersonalProject } from '../types';
1
+ import { Label, Section, Task, User, Attachment, Duration, Deadline, RawComment, PersonalProject } from '../types/index.js';
2
2
  export declare const DEFAULT_TASK_ID = "1234";
3
3
  export declare const DEFAULT_TASK_CONTENT = "This is a task";
4
4
  export declare const DEFAULT_TASK_DESCRIPTION = "A description";
@@ -1,6 +1,6 @@
1
- import { Attachment, PersonalProject, WorkspaceProject, Label, Section, Comment, Task, CurrentUser, ProductivityStats, WorkspaceInvitation, WorkspacePlanDetails, JoinWorkspaceResult } from './types/entities';
2
- import { AddCommentArgs, AddLabelArgs, AddProjectArgs, AddSectionArgs, AddTaskArgs, GetProjectCommentsArgs, GetTaskCommentsArgs, GetTasksArgs, GetTasksByFilterArgs, UpdateCommentArgs, UpdateLabelArgs, UpdateProjectArgs, UpdateSectionArgs, UpdateTaskArgs, QuickAddTaskArgs, GetSharedLabelsArgs, RenameSharedLabelArgs, RemoveSharedLabelArgs, GetProjectsArgs, GetProjectCollaboratorsArgs, GetLabelsArgs, GetLabelsResponse, GetTasksResponse, GetProjectsResponse, GetProjectCollaboratorsResponse, GetSectionsArgs, 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 } from './types/requests';
3
- import { CustomFetch } from './types/http';
1
+ import { Attachment, PersonalProject, WorkspaceProject, Label, Section, Comment, Task, CurrentUser, ProductivityStats, WorkspaceInvitation, WorkspacePlanDetails, JoinWorkspaceResult } from './types/entities.js';
2
+ import { AddCommentArgs, AddLabelArgs, AddProjectArgs, AddSectionArgs, AddTaskArgs, GetProjectCommentsArgs, GetTaskCommentsArgs, GetTasksArgs, GetTasksByFilterArgs, UpdateCommentArgs, UpdateLabelArgs, UpdateProjectArgs, UpdateSectionArgs, UpdateTaskArgs, QuickAddTaskArgs, GetSharedLabelsArgs, RenameSharedLabelArgs, RemoveSharedLabelArgs, GetProjectsArgs, GetProjectCollaboratorsArgs, GetLabelsArgs, GetLabelsResponse, GetTasksResponse, GetProjectsResponse, GetProjectCollaboratorsResponse, GetSectionsArgs, 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 } from './types/requests.js';
3
+ import { CustomFetch } from './types/http.js';
4
4
  /**
5
5
  * A client for interacting with the Todoist API v1.
6
6
  * This class provides methods to manage tasks, projects, sections, labels, and comments in Todoist.
@@ -1,4 +1,4 @@
1
- export * from './entities';
2
- export * from './errors';
3
- export * from './requests';
4
- export * from './http';
1
+ export * from './entities.js';
2
+ export * from './errors.js';
3
+ export * from './requests.js';
4
+ export * from './http.js';
@@ -1,5 +1,5 @@
1
1
  import type { RequireAllOrNone, RequireOneOrNone, RequireExactlyOne } from 'type-fest';
2
- import type { ActivityEvent, ActivityEventType, ActivityObjectType, Comment, Duration, Label, PersonalProject, ProjectViewStyle, Section, Task, User, WorkspaceProject } from './entities';
2
+ import type { ActivityEvent, ActivityEventType, ActivityObjectType, Comment, Duration, Label, PersonalProject, ProjectViewStyle, Section, Task, User, WorkspaceProject } from './entities.js';
3
3
  /**
4
4
  * Arguments for creating a new task.
5
5
  * @see https://todoist.com/api/v1/docs#tag/Tasks/operation/create_task_api_v1_tasks_post
@@ -633,7 +633,7 @@ export type GetWorkspaceUsersResponse = {
633
633
  /**
634
634
  * Array of workspace users.
635
635
  */
636
- workspaceUsers: import('./entities').WorkspaceUser[];
636
+ workspaceUsers: import('./entities.js').WorkspaceUser[];
637
637
  };
638
638
  /**
639
639
  * Response type for workspace invitations endpoint (simple email list).
@@ -642,7 +642,7 @@ export type WorkspaceInvitationsResponse = string[];
642
642
  /**
643
643
  * Response type for all workspace invitations endpoint (detailed objects).
644
644
  */
645
- export type AllWorkspaceInvitationsResponse = import('./entities').WorkspaceInvitation[];
645
+ export type AllWorkspaceInvitationsResponse = import('./entities.js').WorkspaceInvitation[];
646
646
  /**
647
647
  * Response type for workspace logo upload.
648
648
  */
@@ -1,4 +1,4 @@
1
- import { Task } from './entities';
1
+ import { Task } from './entities.js';
2
2
  export type Command = {
3
3
  type: string;
4
4
  uuid: string;
@@ -1,4 +1,4 @@
1
- import { Color } from '../types';
1
+ import { Color } from '../types/index.js';
2
2
  export declare const berryRed: Color;
3
3
  export declare const red: Color;
4
4
  export declare const orange: Color;
@@ -1,4 +1,4 @@
1
- import type { HttpResponse, RetryConfig, CustomFetch } from '../types/http';
1
+ import type { HttpResponse, RetryConfig, CustomFetch } from '../types/http.js';
2
2
  /**
3
3
  * Performs a fetch request with retry logic and timeout support
4
4
  */
@@ -1,3 +1,3 @@
1
- export * from './colors';
2
- export * from './sanitization';
3
- export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers';
1
+ export * from './colors.js';
2
+ export * from './sanitization.js';
3
+ export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers.js';
@@ -1,4 +1,4 @@
1
- import type { CustomFetch } from '../types/http';
1
+ import type { CustomFetch } from '../types/http.js';
2
2
  type UploadMultipartFileArgs = {
3
3
  baseUrl: string;
4
4
  authToken: string;
@@ -1,4 +1,4 @@
1
- import { Task } from '../types';
1
+ import { Task } from '../types/index.js';
2
2
  export type TaskWithSanitizedContent = Task & {
3
3
  sanitizedContent: string;
4
4
  };
@@ -1,4 +1,4 @@
1
- import { type Attachment, type Task, type Section, type Label, type Comment, type User, type CurrentUser, type ProductivityStats, type WorkspaceProject, type PersonalProject, type ActivityEvent, type WorkspaceUser, type WorkspaceInvitation, type WorkspacePlanDetails, type JoinWorkspaceResult } from '../types/entities';
1
+ import { type Attachment, type Task, type Section, type Label, type Comment, type User, type CurrentUser, type ProductivityStats, type WorkspaceProject, type PersonalProject, type ActivityEvent, type WorkspaceUser, type WorkspaceInvitation, type WorkspacePlanDetails, type JoinWorkspaceResult } from '../types/entities.js';
2
2
  export declare function validateTask(input: unknown): Task;
3
3
  export declare function validateTaskArray(input: unknown[]): Task[];
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/todoist-api-typescript",
3
- "version": "6.1.10",
3
+ "version": "6.1.12",
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",
@@ -33,9 +33,11 @@
33
33
  "build:cjs": "npx tsc -p tsconfig.cjs.json",
34
34
  "build:esm": "npx tsc -p tsconfig.esm.json",
35
35
  "build:fix-esm": "node scripts/fix-esm-imports.cjs",
36
+ "build:fix-dts": "node scripts/fix-dts-imports.cjs",
36
37
  "build:post": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
37
- "build": "npm-run-all clean build:cjs build:esm build:fix-esm build:post",
38
- "integrity-checks": "npm-run-all clean format-check lint-check test build",
38
+ "build": "npm-run-all clean build:cjs build:esm build:fix-esm build:fix-dts build:post",
39
+ "attw": "npx @arethetypeswrong/cli --pack --ignore-rules fallback-condition false-esm",
40
+ "integrity-checks": "npm-run-all clean format-check lint-check test build attw",
39
41
  "prepublishOnly": "npm run integrity-checks",
40
42
  "prepare": "npm run build"
41
43
  },
@@ -44,6 +46,7 @@
44
46
  "emoji-regex": "10.6.0",
45
47
  "form-data": "4.0.4",
46
48
  "ts-custom-error": "^3.2.0",
49
+ "undici": "^7.16.0",
47
50
  "uuid": "11.1.0",
48
51
  "zod": "4.1.12"
49
52
  },