@doist/todoist-sdk 10.1.2 → 10.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.
@@ -16,7 +16,6 @@ const zod_1 = require("zod");
16
16
  const endpoints_1 = require("../consts/endpoints");
17
17
  const http_client_1 = require("../transport/http-client");
18
18
  const apps_1 = require("../types/apps");
19
- const case_conversion_1 = require("../utils/case-conversion");
20
19
  const multipart_upload_1 = require("../utils/multipart-upload");
21
20
  const validators_1 = require("../utils/validators");
22
21
  const base_client_1 = require("./base-client");
@@ -145,7 +144,7 @@ class AppClient extends base_client_1.BaseClient {
145
144
  requestId: requestId,
146
145
  customFetch: this.customFetch,
147
146
  });
148
- return (0, validators_1.validateAppWithUserCount)((0, case_conversion_1.camelCaseKeys)(data));
147
+ return (0, validators_1.validateAppWithUserCount)(data);
149
148
  }
150
149
  async getAppTestToken(appId, requestId) {
151
150
  validators_1.IdSchema.parse(appId);
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TemplateClient = void 0;
4
4
  const endpoints_1 = require("../consts/endpoints");
5
5
  const http_client_1 = require("../transport/http-client");
6
- const case_conversion_1 = require("../utils/case-conversion");
7
6
  const multipart_upload_1 = require("../utils/multipart-upload");
8
7
  const validators_1 = require("../utils/validators");
9
8
  const base_client_1 = require("./base-client");
@@ -53,7 +52,7 @@ class TemplateClient extends base_client_1.BaseClient {
53
52
  customFetch: this.customFetch,
54
53
  requestId,
55
54
  });
56
- return this.validateTemplateResponse((0, case_conversion_1.camelCaseKeys)(data));
55
+ return this.validateTemplateResponse(data);
57
56
  }
58
57
  async importTemplateIntoProject(args, requestId) {
59
58
  const { file, fileName, projectId } = args;
@@ -67,7 +66,7 @@ class TemplateClient extends base_client_1.BaseClient {
67
66
  customFetch: this.customFetch,
68
67
  requestId,
69
68
  });
70
- return this.validateTemplateResponse((0, case_conversion_1.camelCaseKeys)(data));
69
+ return this.validateTemplateResponse(data);
71
70
  }
72
71
  async importTemplateFromId(args, requestId) {
73
72
  const { data } = await (0, http_client_1.request)({
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UiExtensionClient = void 0;
4
4
  const endpoints_1 = require("../consts/endpoints");
5
5
  const http_client_1 = require("../transport/http-client");
6
- const case_conversion_1 = require("../utils/case-conversion");
7
6
  const multipart_upload_1 = require("../utils/multipart-upload");
8
7
  const validators_1 = require("../utils/validators");
9
8
  const base_client_1 = require("./base-client");
@@ -102,7 +101,7 @@ class UiExtensionClient extends base_client_1.BaseClient {
102
101
  requestId: requestId,
103
102
  customFetch: this.customFetch,
104
103
  });
105
- return (0, validators_1.validateUiExtension)((0, case_conversion_1.camelCaseKeys)(data));
104
+ return (0, validators_1.validateUiExtension)(data);
106
105
  }
107
106
  }
108
107
  exports.UiExtensionClient = UiExtensionClient;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getDefaultDispatcher = getDefaultDispatcher;
37
37
  exports.resetDefaultDispatcherForTests = resetDefaultDispatcherForTests;
38
+ exports.suppressExperimentalWarningsSync = suppressExperimentalWarningsSync;
38
39
  // Use effectively-disabled keep-alive so short-lived CLI processes do not stay
39
40
  // open waiting on idle sockets. Undici requires positive values, so we use 1ms.
40
41
  const KEEP_ALIVE_OPTIONS = {
@@ -63,8 +64,53 @@ async function resetDefaultDispatcherForTests() {
63
64
  await dispatcherPromise.then((dispatcher) => dispatcher.close(), () => undefined);
64
65
  }
65
66
  async function createDefaultDispatcher() {
66
- const { EnvHttpProxyAgent } = await Promise.resolve().then(() => __importStar(require('undici')));
67
- return new EnvHttpProxyAgent(KEEP_ALIVE_OPTIONS);
67
+ // Dynamic import so non-Node consumers (browser, edge runtimes) don't pull
68
+ // undici into their bundle. `getDefaultDispatcher` already short-circuits
69
+ // outside Node, so this branch only runs when undici is safe to load.
70
+ const { EnvHttpProxyAgent, interceptors } = await Promise.resolve().then(() => __importStar(require('undici')));
71
+ // Compose the response-decompression interceptor so gzip/deflate/br/zstd
72
+ // bodies are decoded before consumers parse them. Required on Node 24+:
73
+ // attaching any custom dispatcher to the global `fetch` strips the
74
+ // `content-encoding` header but does not actually decompress the body,
75
+ // so callers receive raw gzipped bytes and `JSON.parse` fails.
76
+ // See https://github.com/Doist/todoist-cli/issues/318.
77
+ const decompress = suppressExperimentalWarningsSync(() => interceptors.decompress());
78
+ return new EnvHttpProxyAgent(KEEP_ALIVE_OPTIONS).compose(decompress);
79
+ }
80
+ // undici emits an `ExperimentalWarning` the first time `interceptors.decompress()`
81
+ // runs. The interceptor is stable for our gzipped-JSON-over-HTTPS use case;
82
+ // silence the warning during dispatcher init only so it does not leak to every
83
+ // consumer's stderr on the first request.
84
+ //
85
+ // `fn` must be synchronous so the override covers a single critical section
86
+ // (microseconds) — no unrelated `ExperimentalWarning` from elsewhere can
87
+ // interleave and be lost. We suppress every `ExperimentalWarning` rather than
88
+ // pattern-matching the message text: the message wording is an undici
89
+ // implementation detail (not a stable API), and the suppression window is
90
+ // narrow enough that a coarse type filter is safe.
91
+ //
92
+ // Exported for direct unit testing — the integration path through
93
+ // `getDefaultDispatcher()` cannot reliably exercise the helper because both
94
+ // the dispatcher singleton and undici's internal `warningEmitted` flag are
95
+ // once-per-process.
96
+ function suppressExperimentalWarningsSync(fn) {
97
+ const originalEmit = process.emitWarning;
98
+ process.emitWarning = ((warning, typeOrOptions, ...rest) => {
99
+ const type = typeof typeOrOptions === 'string'
100
+ ? typeOrOptions
101
+ : typeof typeOrOptions === 'object' && typeOrOptions !== null
102
+ ? typeOrOptions.type
103
+ : undefined;
104
+ if (type === 'ExperimentalWarning')
105
+ return;
106
+ originalEmit.call(process, warning, typeOrOptions, ...rest);
107
+ });
108
+ try {
109
+ return fn();
110
+ }
111
+ finally {
112
+ process.emitWarning = originalEmit;
113
+ }
68
114
  }
69
115
  function isNodeEnvironment() {
70
116
  var _a;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.uploadMultipartFile = uploadMultipartFile;
37
37
  const fetch_with_retry_1 = require("../transport/fetch-with-retry");
38
+ const case_conversion_1 = require("./case-conversion");
38
39
  /**
39
40
  * Helper function to determine content-type from filename extension.
40
41
  * @param fileName - The filename to analyze
@@ -174,5 +175,5 @@ async function uploadMultipartFile(args) {
174
175
  },
175
176
  customFetch,
176
177
  });
177
- return response.data;
178
+ return (0, case_conversion_1.camelCaseKeys)(response.data);
178
179
  }
@@ -13,7 +13,6 @@ import { z } from 'zod';
13
13
  import { ENDPOINT_REST_APPS, ENDPOINT_REST_APPS_INSTALLATIONS, ENDPOINT_REST_USER_AUTHORIZATIONS, ENDPOINT_REST_USER_AUTHORIZATIONS_DELETE, getAppByDistributionTokenEndpoint, getAppClientSecretEndpoint, getAppDistributionTokenEndpoint, getAppEndpoint, getAppIconEndpoint, getAppInstallationEndpoint, getAppSecretsEndpoint, getAppTestTokenEndpoint, getAppTokensEndpoint, getAppVerificationTokenEndpoint, getAppWebhookEndpoint, } from '../consts/endpoints.js';
14
14
  import { isSuccess, request } from '../transport/http-client.js';
15
15
  import { webhookEventToWireName } from '../types/apps/index.js';
16
- import { camelCaseKeys } from '../utils/case-conversion.js';
17
16
  import { uploadMultipartFile } from '../utils/multipart-upload.js';
18
17
  import { IdSchema, validateApp, validateAppArray, validateAppByDistributionToken, validateAppDistributionToken, validateAppInstallation, validateAppInstallationArray, validateAppSecrets, validateAppTestToken, validateAppVerificationToken, validateAppWebhook, validateAppWithUserCount, validateUserAuthorizationArray, } from '../utils/validators.js';
19
18
  import { BaseClient } from './base-client.js';
@@ -142,7 +141,7 @@ export class AppClient extends BaseClient {
142
141
  requestId: requestId,
143
142
  customFetch: this.customFetch,
144
143
  });
145
- return validateAppWithUserCount(camelCaseKeys(data));
144
+ return validateAppWithUserCount(data);
146
145
  }
147
146
  async getAppTestToken(appId, requestId) {
148
147
  IdSchema.parse(appId);
@@ -1,6 +1,5 @@
1
1
  import { ENDPOINT_REST_TEMPLATES_CREATE_FROM_FILE, ENDPOINT_REST_TEMPLATES_FILE, ENDPOINT_REST_TEMPLATES_IMPORT_FROM_FILE, ENDPOINT_REST_TEMPLATES_IMPORT_FROM_ID, ENDPOINT_REST_TEMPLATES_URL, } from '../consts/endpoints.js';
2
2
  import { request } from '../transport/http-client.js';
3
- import { camelCaseKeys } from '../utils/case-conversion.js';
4
3
  import { uploadMultipartFile } from '../utils/multipart-upload.js';
5
4
  import { validateCommentArray, validateProjectArray, validateSectionArray, validateTaskArray, } from '../utils/validators.js';
6
5
  import { BaseClient } from './base-client.js';
@@ -50,7 +49,7 @@ export class TemplateClient extends BaseClient {
50
49
  customFetch: this.customFetch,
51
50
  requestId,
52
51
  });
53
- return this.validateTemplateResponse(camelCaseKeys(data));
52
+ return this.validateTemplateResponse(data);
54
53
  }
55
54
  async importTemplateIntoProject(args, requestId) {
56
55
  const { file, fileName, projectId } = args;
@@ -64,7 +63,7 @@ export class TemplateClient extends BaseClient {
64
63
  customFetch: this.customFetch,
65
64
  requestId,
66
65
  });
67
- return this.validateTemplateResponse(camelCaseKeys(data));
66
+ return this.validateTemplateResponse(data);
68
67
  }
69
68
  async importTemplateFromId(args, requestId) {
70
69
  const { data } = await request({
@@ -1,6 +1,5 @@
1
1
  import { ENDPOINT_REST_APPS_UI_EXTENSIONS, ENDPOINT_REST_APPS_UI_EXTENSIONS_INSTALLED, getUiExtensionEndpoint, getUiExtensionIconEndpoint, getUiExtensionsByIntegrationEndpoint, } from '../consts/endpoints.js';
2
2
  import { isSuccess, request } from '../transport/http-client.js';
3
- import { camelCaseKeys } from '../utils/case-conversion.js';
4
3
  import { uploadMultipartFile } from '../utils/multipart-upload.js';
5
4
  import { IdSchema, validateUiExtension, validateUiExtensionArray } from '../utils/validators.js';
6
5
  import { BaseClient } from './base-client.js';
@@ -99,6 +98,6 @@ export class UiExtensionClient extends BaseClient {
99
98
  requestId: requestId,
100
99
  customFetch: this.customFetch,
101
100
  });
102
- return validateUiExtension(camelCaseKeys(data));
101
+ return validateUiExtension(data);
103
102
  }
104
103
  }
@@ -26,8 +26,53 @@ export async function resetDefaultDispatcherForTests() {
26
26
  await dispatcherPromise.then((dispatcher) => dispatcher.close(), () => undefined);
27
27
  }
28
28
  async function createDefaultDispatcher() {
29
- const { EnvHttpProxyAgent } = await import('undici');
30
- return new EnvHttpProxyAgent(KEEP_ALIVE_OPTIONS);
29
+ // Dynamic import so non-Node consumers (browser, edge runtimes) don't pull
30
+ // undici into their bundle. `getDefaultDispatcher` already short-circuits
31
+ // outside Node, so this branch only runs when undici is safe to load.
32
+ const { EnvHttpProxyAgent, interceptors } = await import('undici');
33
+ // Compose the response-decompression interceptor so gzip/deflate/br/zstd
34
+ // bodies are decoded before consumers parse them. Required on Node 24+:
35
+ // attaching any custom dispatcher to the global `fetch` strips the
36
+ // `content-encoding` header but does not actually decompress the body,
37
+ // so callers receive raw gzipped bytes and `JSON.parse` fails.
38
+ // See https://github.com/Doist/todoist-cli/issues/318.
39
+ const decompress = suppressExperimentalWarningsSync(() => interceptors.decompress());
40
+ return new EnvHttpProxyAgent(KEEP_ALIVE_OPTIONS).compose(decompress);
41
+ }
42
+ // undici emits an `ExperimentalWarning` the first time `interceptors.decompress()`
43
+ // runs. The interceptor is stable for our gzipped-JSON-over-HTTPS use case;
44
+ // silence the warning during dispatcher init only so it does not leak to every
45
+ // consumer's stderr on the first request.
46
+ //
47
+ // `fn` must be synchronous so the override covers a single critical section
48
+ // (microseconds) — no unrelated `ExperimentalWarning` from elsewhere can
49
+ // interleave and be lost. We suppress every `ExperimentalWarning` rather than
50
+ // pattern-matching the message text: the message wording is an undici
51
+ // implementation detail (not a stable API), and the suppression window is
52
+ // narrow enough that a coarse type filter is safe.
53
+ //
54
+ // Exported for direct unit testing — the integration path through
55
+ // `getDefaultDispatcher()` cannot reliably exercise the helper because both
56
+ // the dispatcher singleton and undici's internal `warningEmitted` flag are
57
+ // once-per-process.
58
+ export function suppressExperimentalWarningsSync(fn) {
59
+ const originalEmit = process.emitWarning;
60
+ process.emitWarning = ((warning, typeOrOptions, ...rest) => {
61
+ const type = typeof typeOrOptions === 'string'
62
+ ? typeOrOptions
63
+ : typeof typeOrOptions === 'object' && typeOrOptions !== null
64
+ ? typeOrOptions.type
65
+ : undefined;
66
+ if (type === 'ExperimentalWarning')
67
+ return;
68
+ originalEmit.call(process, warning, typeOrOptions, ...rest);
69
+ });
70
+ try {
71
+ return fn();
72
+ }
73
+ finally {
74
+ process.emitWarning = originalEmit;
75
+ }
31
76
  }
32
77
  function isNodeEnvironment() {
33
78
  var _a;
@@ -1,4 +1,5 @@
1
1
  import { fetchWithRetry } from '../transport/fetch-with-retry.js';
2
+ import { camelCaseKeys } from './case-conversion.js';
2
3
  /**
3
4
  * Helper function to determine content-type from filename extension.
4
5
  * @param fileName - The filename to analyze
@@ -138,5 +139,5 @@ export async function uploadMultipartFile(args) {
138
139
  },
139
140
  customFetch,
140
141
  });
141
- return response.data;
142
+ return camelCaseKeys(response.data);
142
143
  }
@@ -1,3 +1,4 @@
1
1
  import type { Dispatcher } from 'undici';
2
2
  export declare function getDefaultDispatcher(): Promise<Dispatcher | undefined>;
3
3
  export declare function resetDefaultDispatcherForTests(): Promise<void>;
4
+ export declare function suppressExperimentalWarningsSync<T>(fn: () => T): T;
@@ -50,5 +50,5 @@ type UploadMultipartFileArgs = {
50
50
  * )
51
51
  * ```
52
52
  */
53
- export declare function uploadMultipartFile<T>(args: UploadMultipartFileArgs): Promise<T>;
53
+ export declare function uploadMultipartFile(args: UploadMultipartFileArgs): Promise<unknown>;
54
54
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/todoist-sdk",
3
- "version": "10.1.2",
3
+ "version": "10.1.4",
4
4
  "description": "The official TypeScript SDK for the Todoist REST API.",
5
5
  "author": "Doist developers",
6
6
  "repository": "https://github.com/Doist/todoist-sdk-typescript",