@doist/todoist-api-typescript 6.0.1 → 6.1.4

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 (34) hide show
  1. package/README.md +105 -5
  2. package/dist/cjs/authentication.js +59 -63
  3. package/dist/cjs/rest-client.js +12 -10
  4. package/dist/cjs/test-utils/mocks.js +2 -45
  5. package/dist/cjs/test-utils/msw-setup.js +74 -5
  6. package/dist/cjs/test-utils/obsidian-fetch-adapter.js +53 -0
  7. package/dist/cjs/todoist-api.js +80 -30
  8. package/dist/cjs/types/entities.js +4 -4
  9. package/dist/cjs/types/index.js +1 -0
  10. package/dist/cjs/utils/fetch-with-retry.js +37 -14
  11. package/dist/cjs/utils/multipart-upload.js +2 -1
  12. package/dist/esm/authentication.js +59 -63
  13. package/dist/esm/rest-client.js +12 -10
  14. package/dist/esm/test-utils/mocks.js +3 -10
  15. package/dist/esm/test-utils/msw-setup.js +67 -2
  16. package/dist/esm/test-utils/obsidian-fetch-adapter.js +50 -0
  17. package/dist/esm/todoist-api.js +80 -30
  18. package/dist/esm/types/entities.js +4 -4
  19. package/dist/esm/types/index.js +1 -0
  20. package/dist/esm/utils/fetch-with-retry.js +37 -14
  21. package/dist/esm/utils/multipart-upload.js +2 -1
  22. package/dist/types/authentication.d.ts +20 -0
  23. package/dist/types/rest-client.d.ts +2 -1
  24. package/dist/types/test-utils/mocks.d.ts +0 -1
  25. package/dist/types/test-utils/msw-setup.d.ts +31 -1
  26. package/dist/types/test-utils/obsidian-fetch-adapter.d.ts +29 -0
  27. package/dist/types/todoist-api.d.ts +18 -7
  28. package/dist/types/types/entities.d.ts +4 -4
  29. package/dist/types/types/http.d.ts +17 -0
  30. package/dist/types/types/index.d.ts +1 -0
  31. package/dist/types/types/sync.d.ts +5 -5
  32. package/dist/types/utils/fetch-with-retry.d.ts +2 -1
  33. package/dist/types/utils/multipart-upload.d.ts +2 -0
  34. package/package.json +4 -3
@@ -19,27 +19,6 @@ const MAX_COMMAND_COUNT = 100;
19
19
  function generatePath(...segments) {
20
20
  return segments.join('/');
21
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
22
  class TodoistApi {
44
23
  constructor(
45
24
  /**
@@ -47,11 +26,24 @@ class TodoistApi {
47
26
  */
48
27
  authToken,
49
28
  /**
50
- * Optional custom API base URL. If not provided, defaults to Todoist's standard API endpoint
29
+ * Optional custom API base URL or options object
51
30
  */
52
- baseUrl) {
31
+ baseUrlOrOptions) {
53
32
  this.authToken = authToken;
54
- this.syncApiBase = (0, endpoints_1.getSyncBaseUri)(baseUrl);
33
+ // Handle backward compatibility
34
+ if (typeof baseUrlOrOptions === 'string') {
35
+ // Legacy constructor: (authToken, baseUrl)
36
+ // eslint-disable-next-line no-console
37
+ console.warn('TodoistApi constructor with baseUrl as second parameter is deprecated. Use options object instead: new TodoistApi(token, { baseUrl, customFetch })');
38
+ this.syncApiBase = (0, endpoints_1.getSyncBaseUri)(baseUrlOrOptions);
39
+ this.customFetch = undefined;
40
+ }
41
+ else {
42
+ // New constructor: (authToken, options)
43
+ const options = baseUrlOrOptions || {};
44
+ this.syncApiBase = (0, endpoints_1.getSyncBaseUri)(options.baseUrl);
45
+ this.customFetch = options.customFetch;
46
+ }
55
47
  }
56
48
  /**
57
49
  * Retrieves information about the authenticated user.
@@ -64,6 +56,7 @@ class TodoistApi {
64
56
  baseUri: this.syncApiBase,
65
57
  relativePath: endpoints_1.ENDPOINT_REST_USER,
66
58
  apiToken: this.authToken,
59
+ customFetch: this.customFetch,
67
60
  });
68
61
  return (0, validators_1.validateCurrentUser)(response.data);
69
62
  }
@@ -80,6 +73,7 @@ class TodoistApi {
80
73
  baseUri: this.syncApiBase,
81
74
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
82
75
  apiToken: this.authToken,
76
+ customFetch: this.customFetch,
83
77
  });
84
78
  return (0, validators_1.validateTask)(response.data);
85
79
  }
@@ -95,6 +89,7 @@ class TodoistApi {
95
89
  baseUri: this.syncApiBase,
96
90
  relativePath: endpoints_1.ENDPOINT_REST_TASKS,
97
91
  apiToken: this.authToken,
92
+ customFetch: this.customFetch,
98
93
  payload: args,
99
94
  });
100
95
  return {
@@ -114,6 +109,7 @@ class TodoistApi {
114
109
  baseUri: this.syncApiBase,
115
110
  relativePath: endpoints_1.ENDPOINT_REST_TASKS_FILTER,
116
111
  apiToken: this.authToken,
112
+ customFetch: this.customFetch,
117
113
  payload: args,
118
114
  });
119
115
  return {
@@ -133,6 +129,7 @@ class TodoistApi {
133
129
  baseUri: this.syncApiBase,
134
130
  relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_BY_COMPLETION_DATE,
135
131
  apiToken: this.authToken,
132
+ customFetch: this.customFetch,
136
133
  payload: args,
137
134
  });
138
135
  return {
@@ -152,6 +149,7 @@ class TodoistApi {
152
149
  baseUri: this.syncApiBase,
153
150
  relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_BY_DUE_DATE,
154
151
  apiToken: this.authToken,
152
+ customFetch: this.customFetch,
155
153
  payload: args,
156
154
  });
157
155
  return {
@@ -171,6 +169,7 @@ class TodoistApi {
171
169
  baseUri: this.syncApiBase,
172
170
  relativePath: endpoints_1.ENDPOINT_REST_TASKS_COMPLETED_SEARCH,
173
171
  apiToken: this.authToken,
172
+ customFetch: this.customFetch,
174
173
  payload: args,
175
174
  });
176
175
  return {
@@ -191,6 +190,7 @@ class TodoistApi {
191
190
  baseUri: this.syncApiBase,
192
191
  relativePath: endpoints_1.ENDPOINT_REST_TASKS,
193
192
  apiToken: this.authToken,
193
+ customFetch: this.customFetch,
194
194
  payload: args,
195
195
  requestId: requestId,
196
196
  });
@@ -208,6 +208,7 @@ class TodoistApi {
208
208
  baseUri: this.syncApiBase,
209
209
  relativePath: endpoints_1.ENDPOINT_SYNC_QUICK_ADD,
210
210
  apiToken: this.authToken,
211
+ customFetch: this.customFetch,
211
212
  payload: args,
212
213
  });
213
214
  return (0, validators_1.validateTask)(response.data);
@@ -227,6 +228,7 @@ class TodoistApi {
227
228
  baseUri: this.syncApiBase,
228
229
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
229
230
  apiToken: this.authToken,
231
+ customFetch: this.customFetch,
230
232
  payload: args,
231
233
  requestId: requestId,
232
234
  });
@@ -260,15 +262,16 @@ class TodoistApi {
260
262
  baseUri: this.syncApiBase,
261
263
  relativePath: endpoints_1.ENDPOINT_SYNC,
262
264
  apiToken: this.authToken,
265
+ customFetch: this.customFetch,
263
266
  payload: syncRequest,
264
267
  requestId: requestId,
265
268
  hasSyncCommands: true,
266
269
  });
267
- if (response.data.sync_status) {
268
- Object.entries(response.data.sync_status).forEach(([_, value]) => {
270
+ if (response.data.syncStatus) {
271
+ Object.entries(response.data.syncStatus).forEach(([_, value]) => {
269
272
  if (value === 'ok')
270
273
  return;
271
- throw new types_1.TodoistRequestError(value.error, value.http_code, value.error_extra);
274
+ throw new types_1.TodoistRequestError(value.error, value.httpCode, value.errorExtra);
272
275
  });
273
276
  }
274
277
  if (!((_a = response.data.items) === null || _a === void 0 ? void 0 : _a.length)) {
@@ -295,6 +298,7 @@ class TodoistApi {
295
298
  baseUri: this.syncApiBase,
296
299
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_MOVE),
297
300
  apiToken: this.authToken,
301
+ customFetch: this.customFetch,
298
302
  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
303
  requestId: requestId,
300
304
  });
@@ -314,6 +318,7 @@ class TodoistApi {
314
318
  baseUri: this.syncApiBase,
315
319
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_CLOSE),
316
320
  apiToken: this.authToken,
321
+ customFetch: this.customFetch,
317
322
  requestId: requestId,
318
323
  });
319
324
  return (0, rest_client_1.isSuccess)(response);
@@ -332,6 +337,7 @@ class TodoistApi {
332
337
  baseUri: this.syncApiBase,
333
338
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id, endpoints_1.ENDPOINT_REST_TASK_REOPEN),
334
339
  apiToken: this.authToken,
340
+ customFetch: this.customFetch,
335
341
  requestId: requestId,
336
342
  });
337
343
  return (0, rest_client_1.isSuccess)(response);
@@ -350,6 +356,7 @@ class TodoistApi {
350
356
  baseUri: this.syncApiBase,
351
357
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_TASKS, id),
352
358
  apiToken: this.authToken,
359
+ customFetch: this.customFetch,
353
360
  requestId: requestId,
354
361
  });
355
362
  return (0, rest_client_1.isSuccess)(response);
@@ -367,6 +374,7 @@ class TodoistApi {
367
374
  baseUri: this.syncApiBase,
368
375
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
369
376
  apiToken: this.authToken,
377
+ customFetch: this.customFetch,
370
378
  });
371
379
  return (0, validators_1.validateProject)(response.data);
372
380
  }
@@ -382,6 +390,7 @@ class TodoistApi {
382
390
  baseUri: this.syncApiBase,
383
391
  relativePath: endpoints_1.ENDPOINT_REST_PROJECTS,
384
392
  apiToken: this.authToken,
393
+ customFetch: this.customFetch,
385
394
  payload: args,
386
395
  });
387
396
  return {
@@ -401,6 +410,7 @@ class TodoistApi {
401
410
  baseUri: this.syncApiBase,
402
411
  relativePath: endpoints_1.ENDPOINT_REST_PROJECTS_ARCHIVED,
403
412
  apiToken: this.authToken,
413
+ customFetch: this.customFetch,
404
414
  payload: args,
405
415
  });
406
416
  return {
@@ -421,6 +431,7 @@ class TodoistApi {
421
431
  baseUri: this.syncApiBase,
422
432
  relativePath: endpoints_1.ENDPOINT_REST_PROJECTS,
423
433
  apiToken: this.authToken,
434
+ customFetch: this.customFetch,
424
435
  payload: args,
425
436
  requestId: requestId,
426
437
  });
@@ -441,6 +452,7 @@ class TodoistApi {
441
452
  baseUri: this.syncApiBase,
442
453
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
443
454
  apiToken: this.authToken,
455
+ customFetch: this.customFetch,
444
456
  payload: args,
445
457
  requestId: requestId,
446
458
  });
@@ -460,6 +472,7 @@ class TodoistApi {
460
472
  baseUri: this.syncApiBase,
461
473
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id),
462
474
  apiToken: this.authToken,
475
+ customFetch: this.customFetch,
463
476
  requestId: requestId,
464
477
  });
465
478
  return (0, rest_client_1.isSuccess)(response);
@@ -478,6 +491,7 @@ class TodoistApi {
478
491
  baseUri: this.syncApiBase,
479
492
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id, endpoints_1.PROJECT_ARCHIVE),
480
493
  apiToken: this.authToken,
494
+ customFetch: this.customFetch,
481
495
  requestId: requestId,
482
496
  });
483
497
  return (0, validators_1.validateProject)(response.data);
@@ -496,6 +510,7 @@ class TodoistApi {
496
510
  baseUri: this.syncApiBase,
497
511
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, id, endpoints_1.PROJECT_UNARCHIVE),
498
512
  apiToken: this.authToken,
513
+ customFetch: this.customFetch,
499
514
  requestId: requestId,
500
515
  });
501
516
  return (0, validators_1.validateProject)(response.data);
@@ -514,6 +529,7 @@ class TodoistApi {
514
529
  baseUri: this.syncApiBase,
515
530
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_PROJECTS, projectId, endpoints_1.ENDPOINT_REST_PROJECT_COLLABORATORS),
516
531
  apiToken: this.authToken,
532
+ customFetch: this.customFetch,
517
533
  payload: args,
518
534
  });
519
535
  return {
@@ -533,6 +549,7 @@ class TodoistApi {
533
549
  baseUri: this.syncApiBase,
534
550
  relativePath: endpoints_1.ENDPOINT_REST_SECTIONS,
535
551
  apiToken: this.authToken,
552
+ customFetch: this.customFetch,
536
553
  payload: args,
537
554
  });
538
555
  return {
@@ -553,6 +570,7 @@ class TodoistApi {
553
570
  baseUri: this.syncApiBase,
554
571
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
555
572
  apiToken: this.authToken,
573
+ customFetch: this.customFetch,
556
574
  });
557
575
  return (0, validators_1.validateSection)(response.data);
558
576
  }
@@ -569,6 +587,7 @@ class TodoistApi {
569
587
  baseUri: this.syncApiBase,
570
588
  relativePath: endpoints_1.ENDPOINT_REST_SECTIONS,
571
589
  apiToken: this.authToken,
590
+ customFetch: this.customFetch,
572
591
  payload: args,
573
592
  requestId: requestId,
574
593
  });
@@ -589,6 +608,7 @@ class TodoistApi {
589
608
  baseUri: this.syncApiBase,
590
609
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
591
610
  apiToken: this.authToken,
611
+ customFetch: this.customFetch,
592
612
  payload: args,
593
613
  requestId: requestId,
594
614
  });
@@ -608,6 +628,7 @@ class TodoistApi {
608
628
  baseUri: this.syncApiBase,
609
629
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_SECTIONS, id),
610
630
  apiToken: this.authToken,
631
+ customFetch: this.customFetch,
611
632
  requestId: requestId,
612
633
  });
613
634
  return (0, rest_client_1.isSuccess)(response);
@@ -625,6 +646,7 @@ class TodoistApi {
625
646
  baseUri: this.syncApiBase,
626
647
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
627
648
  apiToken: this.authToken,
649
+ customFetch: this.customFetch,
628
650
  });
629
651
  return (0, validators_1.validateLabel)(response.data);
630
652
  }
@@ -640,6 +662,7 @@ class TodoistApi {
640
662
  baseUri: this.syncApiBase,
641
663
  relativePath: endpoints_1.ENDPOINT_REST_LABELS,
642
664
  apiToken: this.authToken,
665
+ customFetch: this.customFetch,
643
666
  payload: args,
644
667
  });
645
668
  return {
@@ -660,6 +683,7 @@ class TodoistApi {
660
683
  baseUri: this.syncApiBase,
661
684
  relativePath: endpoints_1.ENDPOINT_REST_LABELS,
662
685
  apiToken: this.authToken,
686
+ customFetch: this.customFetch,
663
687
  payload: args,
664
688
  requestId: requestId,
665
689
  });
@@ -680,6 +704,7 @@ class TodoistApi {
680
704
  baseUri: this.syncApiBase,
681
705
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
682
706
  apiToken: this.authToken,
707
+ customFetch: this.customFetch,
683
708
  payload: args,
684
709
  requestId: requestId,
685
710
  });
@@ -699,6 +724,7 @@ class TodoistApi {
699
724
  baseUri: this.syncApiBase,
700
725
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_LABELS, id),
701
726
  apiToken: this.authToken,
727
+ customFetch: this.customFetch,
702
728
  requestId: requestId,
703
729
  });
704
730
  return (0, rest_client_1.isSuccess)(response);
@@ -715,6 +741,7 @@ class TodoistApi {
715
741
  baseUri: this.syncApiBase,
716
742
  relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED,
717
743
  apiToken: this.authToken,
744
+ customFetch: this.customFetch,
718
745
  payload: args,
719
746
  });
720
747
  return { results, nextCursor };
@@ -731,6 +758,7 @@ class TodoistApi {
731
758
  baseUri: this.syncApiBase,
732
759
  relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED_RENAME,
733
760
  apiToken: this.authToken,
761
+ customFetch: this.customFetch,
734
762
  payload: args,
735
763
  });
736
764
  return (0, rest_client_1.isSuccess)(response);
@@ -747,6 +775,7 @@ class TodoistApi {
747
775
  baseUri: this.syncApiBase,
748
776
  relativePath: endpoints_1.ENDPOINT_REST_LABELS_SHARED_REMOVE,
749
777
  apiToken: this.authToken,
778
+ customFetch: this.customFetch,
750
779
  payload: args,
751
780
  });
752
781
  return (0, rest_client_1.isSuccess)(response);
@@ -763,6 +792,7 @@ class TodoistApi {
763
792
  baseUri: this.syncApiBase,
764
793
  relativePath: endpoints_1.ENDPOINT_REST_COMMENTS,
765
794
  apiToken: this.authToken,
795
+ customFetch: this.customFetch,
766
796
  payload: args,
767
797
  });
768
798
  return {
@@ -783,6 +813,7 @@ class TodoistApi {
783
813
  baseUri: this.syncApiBase,
784
814
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
785
815
  apiToken: this.authToken,
816
+ customFetch: this.customFetch,
786
817
  });
787
818
  return (0, validators_1.validateComment)(response.data);
788
819
  }
@@ -799,6 +830,7 @@ class TodoistApi {
799
830
  baseUri: this.syncApiBase,
800
831
  relativePath: endpoints_1.ENDPOINT_REST_COMMENTS,
801
832
  apiToken: this.authToken,
833
+ customFetch: this.customFetch,
802
834
  payload: args,
803
835
  requestId: requestId,
804
836
  });
@@ -819,6 +851,7 @@ class TodoistApi {
819
851
  baseUri: this.syncApiBase,
820
852
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
821
853
  apiToken: this.authToken,
854
+ customFetch: this.customFetch,
822
855
  payload: args,
823
856
  requestId: requestId,
824
857
  });
@@ -838,6 +871,7 @@ class TodoistApi {
838
871
  baseUri: this.syncApiBase,
839
872
  relativePath: generatePath(endpoints_1.ENDPOINT_REST_COMMENTS, id),
840
873
  apiToken: this.authToken,
874
+ customFetch: this.customFetch,
841
875
  requestId: requestId,
842
876
  });
843
877
  return (0, rest_client_1.isSuccess)(response);
@@ -853,6 +887,7 @@ class TodoistApi {
853
887
  baseUri: this.syncApiBase,
854
888
  relativePath: endpoints_1.ENDPOINT_REST_PRODUCTIVITY,
855
889
  apiToken: this.authToken,
890
+ customFetch: this.customFetch,
856
891
  });
857
892
  return (0, validators_1.validateProductivityStats)(response.data);
858
893
  }
@@ -870,6 +905,7 @@ class TodoistApi {
870
905
  baseUri: this.syncApiBase,
871
906
  relativePath: endpoints_1.ENDPOINT_REST_ACTIVITIES,
872
907
  apiToken: this.authToken,
908
+ customFetch: this.customFetch,
873
909
  payload: processedArgs,
874
910
  });
875
911
  // Convert legacy API object types back to modern SDK types
@@ -932,6 +968,7 @@ class TodoistApi {
932
968
  fileName: args.fileName,
933
969
  additionalFields: additionalFields,
934
970
  requestId: requestId,
971
+ customFetch: this.customFetch,
935
972
  });
936
973
  return (0, validators_1.validateAttachment)(data);
937
974
  }
@@ -955,6 +992,7 @@ class TodoistApi {
955
992
  baseUri: this.syncApiBase,
956
993
  relativePath: endpoints_1.ENDPOINT_REST_UPLOADS,
957
994
  apiToken: this.authToken,
995
+ customFetch: this.customFetch,
958
996
  payload: args,
959
997
  requestId: requestId,
960
998
  });
@@ -974,6 +1012,7 @@ class TodoistApi {
974
1012
  baseUri: this.syncApiBase,
975
1013
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS,
976
1014
  apiToken: this.authToken,
1015
+ customFetch: this.customFetch,
977
1016
  payload: { workspace_id: args.workspaceId },
978
1017
  requestId: requestId,
979
1018
  });
@@ -995,6 +1034,7 @@ class TodoistApi {
995
1034
  baseUri: this.syncApiBase,
996
1035
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS_ALL,
997
1036
  apiToken: this.authToken,
1037
+ customFetch: this.customFetch,
998
1038
  payload: queryParams,
999
1039
  requestId: requestId,
1000
1040
  });
@@ -1013,6 +1053,7 @@ class TodoistApi {
1013
1053
  baseUri: this.syncApiBase,
1014
1054
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_INVITATIONS_DELETE,
1015
1055
  apiToken: this.authToken,
1056
+ customFetch: this.customFetch,
1016
1057
  payload: {
1017
1058
  workspace_id: args.workspaceId,
1018
1059
  user_email: args.userEmail,
@@ -1034,6 +1075,7 @@ class TodoistApi {
1034
1075
  baseUri: this.syncApiBase,
1035
1076
  relativePath: (0, endpoints_1.getWorkspaceInvitationAcceptEndpoint)(args.inviteCode),
1036
1077
  apiToken: this.authToken,
1078
+ customFetch: this.customFetch,
1037
1079
  requestId: requestId,
1038
1080
  });
1039
1081
  return (0, validators_1.validateWorkspaceInvitation)(response.data);
@@ -1051,6 +1093,7 @@ class TodoistApi {
1051
1093
  baseUri: this.syncApiBase,
1052
1094
  relativePath: (0, endpoints_1.getWorkspaceInvitationRejectEndpoint)(args.inviteCode),
1053
1095
  apiToken: this.authToken,
1096
+ customFetch: this.customFetch,
1054
1097
  requestId: requestId,
1055
1098
  });
1056
1099
  return (0, validators_1.validateWorkspaceInvitation)(response.data);
@@ -1068,6 +1111,7 @@ class TodoistApi {
1068
1111
  baseUri: this.syncApiBase,
1069
1112
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_JOIN,
1070
1113
  apiToken: this.authToken,
1114
+ customFetch: this.customFetch,
1071
1115
  payload: {
1072
1116
  invite_code: args.inviteCode,
1073
1117
  workspace_id: args.workspaceId,
@@ -1097,6 +1141,7 @@ class TodoistApi {
1097
1141
  delete: true,
1098
1142
  },
1099
1143
  requestId: requestId,
1144
+ customFetch: this.customFetch,
1100
1145
  });
1101
1146
  return data;
1102
1147
  }
@@ -1118,6 +1163,7 @@ class TodoistApi {
1118
1163
  fileName: args.fileName,
1119
1164
  additionalFields: additionalFields,
1120
1165
  requestId: requestId,
1166
+ customFetch: this.customFetch,
1121
1167
  });
1122
1168
  return data;
1123
1169
  }
@@ -1134,6 +1180,7 @@ class TodoistApi {
1134
1180
  baseUri: this.syncApiBase,
1135
1181
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_PLAN_DETAILS,
1136
1182
  apiToken: this.authToken,
1183
+ customFetch: this.customFetch,
1137
1184
  payload: { workspace_id: args.workspaceId },
1138
1185
  requestId: requestId,
1139
1186
  });
@@ -1162,13 +1209,14 @@ class TodoistApi {
1162
1209
  baseUri: this.syncApiBase,
1163
1210
  relativePath: endpoints_1.ENDPOINT_WORKSPACE_USERS,
1164
1211
  apiToken: this.authToken,
1212
+ customFetch: this.customFetch,
1165
1213
  payload: queryParams,
1166
1214
  requestId: requestId,
1167
1215
  });
1168
1216
  return {
1169
- hasMore: response.data.has_more || false,
1170
- nextCursor: response.data.next_cursor,
1171
- workspaceUsers: (0, validators_1.validateWorkspaceUserArray)(response.data.workspace_users || []),
1217
+ hasMore: response.data.hasMore || false,
1218
+ nextCursor: response.data.nextCursor,
1219
+ workspaceUsers: (0, validators_1.validateWorkspaceUserArray)(response.data.workspaceUsers || []),
1172
1220
  };
1173
1221
  }
1174
1222
  /**
@@ -1192,6 +1240,7 @@ class TodoistApi {
1192
1240
  baseUri: this.syncApiBase,
1193
1241
  relativePath: (0, endpoints_1.getWorkspaceActiveProjectsEndpoint)(args.workspaceId),
1194
1242
  apiToken: this.authToken,
1243
+ customFetch: this.customFetch,
1195
1244
  payload: queryParams,
1196
1245
  requestId: requestId,
1197
1246
  });
@@ -1222,6 +1271,7 @@ class TodoistApi {
1222
1271
  baseUri: this.syncApiBase,
1223
1272
  relativePath: (0, endpoints_1.getWorkspaceArchivedProjectsEndpoint)(args.workspaceId),
1224
1273
  apiToken: this.authToken,
1274
+ customFetch: this.customFetch,
1225
1275
  payload: queryParams,
1226
1276
  requestId: requestId,
1227
1277
  });
@@ -361,9 +361,9 @@ exports.WorkspacePlanDetailsSchema = zod_1.z.object({
361
361
  hasBillingPortalSwitchToAnnual: zod_1.z.boolean(),
362
362
  });
363
363
  exports.JoinWorkspaceResultSchema = zod_1.z.object({
364
- custom_sorting_applied: zod_1.z.boolean(),
365
- project_sort_preference: zod_1.z.string(),
364
+ customSortingApplied: zod_1.z.boolean(),
365
+ projectSortPreference: zod_1.z.string(),
366
366
  role: exports.WorkspaceRoleSchema,
367
- user_id: zod_1.z.string(),
368
- workspace_id: zod_1.z.string(),
367
+ userId: zod_1.z.string(),
368
+ workspaceId: zod_1.z.string(),
369
369
  });
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./entities"), exports);
18
18
  __exportStar(require("./errors"), exports);
19
19
  __exportStar(require("./requests"), exports);
20
+ __exportStar(require("./http"), exports);
@@ -63,11 +63,26 @@ function createTimeoutSignal(timeoutMs, existingSignal) {
63
63
  });
64
64
  return controller.signal;
65
65
  }
66
+ /**
67
+ * Converts native fetch Response to CustomFetchResponse for consistency
68
+ */
69
+ function convertResponseToCustomFetch(response) {
70
+ // Clone the response so we can read it multiple times (if clone method exists)
71
+ const clonedResponse = response.clone ? response.clone() : response;
72
+ return {
73
+ ok: response.ok,
74
+ status: response.status,
75
+ statusText: response.statusText,
76
+ headers: headersToObject(response.headers),
77
+ text: () => clonedResponse.text(),
78
+ json: () => response.json(),
79
+ };
80
+ }
66
81
  /**
67
82
  * Performs a fetch request with retry logic and timeout support
68
83
  */
69
84
  async function fetchWithRetry(args) {
70
- const { url, options = {}, retryConfig = {} } = args;
85
+ const { url, options = {}, retryConfig = {}, customFetch } = args;
71
86
  const config = Object.assign(Object.assign({}, DEFAULT_RETRY_CONFIG), retryConfig);
72
87
  const { timeout, signal: userSignal } = options, fetchOptions = __rest(options, ["timeout", "signal"]);
73
88
  let lastError;
@@ -78,22 +93,30 @@ async function fetchWithRetry(args) {
78
93
  if (timeout && timeout > 0) {
79
94
  requestSignal = createTimeoutSignal(timeout, requestSignal);
80
95
  }
81
- const response = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal }));
96
+ // Use custom fetch or native fetch
97
+ let fetchResponse;
98
+ if (customFetch) {
99
+ fetchResponse = await customFetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal, timeout }));
100
+ }
101
+ else {
102
+ const nativeResponse = await fetch(url, Object.assign(Object.assign({}, fetchOptions), { signal: requestSignal }));
103
+ fetchResponse = convertResponseToCustomFetch(nativeResponse);
104
+ }
82
105
  // Check if the response is successful
83
- if (!response.ok) {
84
- const errorMessage = `HTTP ${response.status}: ${response.statusText}`;
106
+ if (!fetchResponse.ok) {
107
+ const errorMessage = `HTTP ${fetchResponse.status}: ${fetchResponse.statusText}`;
85
108
  const error = new Error(errorMessage);
86
- error.status = response.status;
87
- error.statusText = response.statusText;
109
+ error.status = fetchResponse.status;
110
+ error.statusText = fetchResponse.statusText;
88
111
  error.response = {
89
112
  data: undefined, // Will be set below if we can parse the response
90
- status: response.status,
91
- statusText: response.statusText,
92
- headers: headersToObject(response.headers),
113
+ status: fetchResponse.status,
114
+ statusText: fetchResponse.statusText,
115
+ headers: fetchResponse.headers,
93
116
  };
94
117
  // Try to get response body for error details
95
118
  try {
96
- const responseText = await response.text();
119
+ const responseText = await fetchResponse.text();
97
120
  let responseData;
98
121
  try {
99
122
  responseData = responseText ? JSON.parse(responseText) : undefined;
@@ -110,7 +133,7 @@ async function fetchWithRetry(args) {
110
133
  throw error;
111
134
  }
112
135
  // Parse response
113
- const responseText = await response.text();
136
+ const responseText = await fetchResponse.text();
114
137
  let data;
115
138
  try {
116
139
  data = responseText ? JSON.parse(responseText) : undefined;
@@ -121,9 +144,9 @@ async function fetchWithRetry(args) {
121
144
  }
122
145
  return {
123
146
  data,
124
- status: response.status,
125
- statusText: response.statusText,
126
- headers: headersToObject(response.headers),
147
+ status: fetchResponse.status,
148
+ statusText: fetchResponse.statusText,
149
+ headers: fetchResponse.headers,
127
150
  };
128
151
  }
129
152
  catch (error) {
@@ -71,7 +71,7 @@ function getContentTypeFromFileName(fileName) {
71
71
  * ```
72
72
  */
73
73
  async function uploadMultipartFile(args) {
74
- const { baseUrl, authToken, endpoint, file, fileName, additionalFields, requestId } = args;
74
+ const { baseUrl, authToken, endpoint, file, fileName, additionalFields, requestId, customFetch, } = args;
75
75
  const form = new form_data_1.default();
76
76
  // Determine file type and add to form data
77
77
  if (typeof file === 'string') {
@@ -121,6 +121,7 @@ async function uploadMultipartFile(args) {
121
121
  headers,
122
122
  timeout: 30000, // 30 second timeout for file uploads
123
123
  },
124
+ customFetch,
124
125
  });
125
126
  return response.data;
126
127
  }