@doist/todoist-sdk 14.1.0 → 15.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.
- package/README.md +46 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/transport/http-dispatcher.js +25 -0
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/multipart-upload.js +171 -57
- package/dist/esm/utils/url-helpers.js +151 -23
- package/dist/types/index.d.ts +2 -1
- package/dist/types/transport/http-dispatcher.d.ts +26 -1
- package/dist/types/utils/index.d.ts +2 -1
- package/dist/types/utils/url-helpers.d.ts +88 -0
- package/package.json +6 -12
- package/dist/cjs/authentication.js +0 -317
- package/dist/cjs/clients/activity-client.js +0 -63
- package/dist/cjs/clients/app-client.js +0 -345
- package/dist/cjs/clients/backup-client.js +0 -47
- package/dist/cjs/clients/base-client.js +0 -31
- package/dist/cjs/clients/billing-client.js +0 -152
- package/dist/cjs/clients/comment-client.js +0 -91
- package/dist/cjs/clients/email-client.js +0 -43
- package/dist/cjs/clients/folder-client.js +0 -79
- package/dist/cjs/clients/id-mapping-client.js +0 -39
- package/dist/cjs/clients/insights-client.js +0 -87
- package/dist/cjs/clients/label-client.js +0 -126
- package/dist/cjs/clients/productivity-client.js +0 -27
- package/dist/cjs/clients/project-client.js +0 -235
- package/dist/cjs/clients/reminder-client.js +0 -198
- package/dist/cjs/clients/section-client.js +0 -117
- package/dist/cjs/clients/task-client.js +0 -254
- package/dist/cjs/clients/template-client.js +0 -88
- package/dist/cjs/clients/ui-extension-client.js +0 -107
- package/dist/cjs/clients/upload-client.js +0 -155
- package/dist/cjs/clients/view-options-client.js +0 -25
- package/dist/cjs/clients/workspace-client.js +0 -366
- package/dist/cjs/consts/endpoints.js +0 -224
- package/dist/cjs/index.js +0 -23
- package/dist/cjs/package.json +0 -1
- package/dist/cjs/test-utils/asserts.js +0 -11
- package/dist/cjs/test-utils/msw-setup.js +0 -97
- package/dist/cjs/test-utils/obsidian-fetch-adapter.js +0 -54
- package/dist/cjs/test-utils/test-defaults.js +0 -371
- package/dist/cjs/test-utils/transport-seam.js +0 -17
- package/dist/cjs/test-utils/webhook-fixtures.js +0 -32
- package/dist/cjs/todoist-api.js +0 -1711
- package/dist/cjs/transport/fetch-with-retry.js +0 -219
- package/dist/cjs/transport/http-client.js +0 -134
- package/dist/cjs/transport/http-dispatcher.js +0 -173
- package/dist/cjs/transport/sync-request.js +0 -83
- package/dist/cjs/types/activity/index.js +0 -18
- package/dist/cjs/types/activity/requests.js +0 -2
- package/dist/cjs/types/activity/types.js +0 -28
- package/dist/cjs/types/apps/index.js +0 -18
- package/dist/cjs/types/apps/requests.js +0 -2
- package/dist/cjs/types/apps/types.js +0 -254
- package/dist/cjs/types/backups/index.js +0 -18
- package/dist/cjs/types/backups/requests.js +0 -2
- package/dist/cjs/types/backups/types.js +0 -8
- package/dist/cjs/types/billing/index.js +0 -18
- package/dist/cjs/types/billing/requests.js +0 -2
- package/dist/cjs/types/billing/types.js +0 -92
- package/dist/cjs/types/comments/index.js +0 -18
- package/dist/cjs/types/comments/requests.js +0 -2
- package/dist/cjs/types/comments/types.js +0 -60
- package/dist/cjs/types/common.js +0 -10
- package/dist/cjs/types/emails/index.js +0 -17
- package/dist/cjs/types/emails/requests.js +0 -5
- package/dist/cjs/types/errors.js +0 -29
- package/dist/cjs/types/folders/index.js +0 -17
- package/dist/cjs/types/folders/requests.js +0 -2
- package/dist/cjs/types/http.js +0 -24
- package/dist/cjs/types/id-mappings/index.js +0 -18
- package/dist/cjs/types/id-mappings/requests.js +0 -20
- package/dist/cjs/types/id-mappings/types.js +0 -12
- package/dist/cjs/types/index.js +0 -40
- package/dist/cjs/types/insights/index.js +0 -18
- package/dist/cjs/types/insights/requests.js +0 -2
- package/dist/cjs/types/insights/types.js +0 -80
- package/dist/cjs/types/labels/index.js +0 -18
- package/dist/cjs/types/labels/requests.js +0 -2
- package/dist/cjs/types/labels/types.js +0 -11
- package/dist/cjs/types/productivity/index.js +0 -17
- package/dist/cjs/types/productivity/types.js +0 -68
- package/dist/cjs/types/projects/index.js +0 -18
- package/dist/cjs/types/projects/requests.js +0 -2
- package/dist/cjs/types/projects/types.js +0 -66
- package/dist/cjs/types/reminders/index.js +0 -17
- package/dist/cjs/types/reminders/requests.js +0 -95
- package/dist/cjs/types/sections/index.js +0 -18
- package/dist/cjs/types/sections/requests.js +0 -2
- package/dist/cjs/types/sections/types.js +0 -25
- package/dist/cjs/types/sync/commands/calendars.js +0 -2
- package/dist/cjs/types/sync/commands/filters.js +0 -2
- package/dist/cjs/types/sync/commands/folders.js +0 -2
- package/dist/cjs/types/sync/commands/index.js +0 -34
- package/dist/cjs/types/sync/commands/labels.js +0 -5
- package/dist/cjs/types/sync/commands/notes.js +0 -2
- package/dist/cjs/types/sync/commands/notifications.js +0 -2
- package/dist/cjs/types/sync/commands/others.js +0 -2
- package/dist/cjs/types/sync/commands/project-view-options.js +0 -2
- package/dist/cjs/types/sync/commands/projects.js +0 -2
- package/dist/cjs/types/sync/commands/reminders.js +0 -2
- package/dist/cjs/types/sync/commands/sections.js +0 -2
- package/dist/cjs/types/sync/commands/shared.js +0 -20
- package/dist/cjs/types/sync/commands/sharing.js +0 -2
- package/dist/cjs/types/sync/commands/tasks.js +0 -2
- package/dist/cjs/types/sync/commands/view-options.js +0 -2
- package/dist/cjs/types/sync/commands/workspace-filters.js +0 -2
- package/dist/cjs/types/sync/commands/workspaces.js +0 -2
- package/dist/cjs/types/sync/index.js +0 -22
- package/dist/cjs/types/sync/request.js +0 -2
- package/dist/cjs/types/sync/resource-types.js +0 -39
- package/dist/cjs/types/sync/resources/calendars.js +0 -27
- package/dist/cjs/types/sync/resources/collaborators.js +0 -21
- package/dist/cjs/types/sync/resources/completed-info.js +0 -24
- package/dist/cjs/types/sync/resources/filters.js +0 -14
- package/dist/cjs/types/sync/resources/folders.js +0 -12
- package/dist/cjs/types/sync/resources/index.js +0 -32
- package/dist/cjs/types/sync/resources/live-notifications.js +0 -38
- package/dist/cjs/types/sync/resources/notes.js +0 -21
- package/dist/cjs/types/sync/resources/reminders.js +0 -50
- package/dist/cjs/types/sync/resources/suggestions.js +0 -36
- package/dist/cjs/types/sync/resources/tooltips.js +0 -8
- package/dist/cjs/types/sync/resources/user-plan-limits.js +0 -20
- package/dist/cjs/types/sync/resources/user-settings.js +0 -40
- package/dist/cjs/types/sync/resources/user.js +0 -110
- package/dist/cjs/types/sync/resources/view-options.js +0 -86
- package/dist/cjs/types/sync/resources/workspace-filters.js +0 -19
- package/dist/cjs/types/sync/resources/workspaces.js +0 -72
- package/dist/cjs/types/sync/response.js +0 -54
- package/dist/cjs/types/sync/user-preferences.js +0 -71
- package/dist/cjs/types/tasks/index.js +0 -18
- package/dist/cjs/types/tasks/requests.js +0 -2
- package/dist/cjs/types/tasks/types.js +0 -59
- package/dist/cjs/types/templates/index.js +0 -17
- package/dist/cjs/types/templates/requests.js +0 -2
- package/dist/cjs/types/ui-extensions/index.js +0 -18
- package/dist/cjs/types/ui-extensions/requests.js +0 -2
- package/dist/cjs/types/ui-extensions/types.js +0 -77
- package/dist/cjs/types/uploads/index.js +0 -17
- package/dist/cjs/types/uploads/requests.js +0 -2
- package/dist/cjs/types/users/index.js +0 -17
- package/dist/cjs/types/users/types.js +0 -51
- package/dist/cjs/types/webhooks/comments.js +0 -96
- package/dist/cjs/types/webhooks/envelope.js +0 -26
- package/dist/cjs/types/webhooks/filters.js +0 -30
- package/dist/cjs/types/webhooks/index.js +0 -25
- package/dist/cjs/types/webhooks/labels.js +0 -54
- package/dist/cjs/types/webhooks/projects.js +0 -36
- package/dist/cjs/types/webhooks/reminders.js +0 -35
- package/dist/cjs/types/webhooks/sections.js +0 -53
- package/dist/cjs/types/webhooks/tasks.js +0 -68
- package/dist/cjs/types/webhooks/types.js +0 -55
- package/dist/cjs/types/workspaces/index.js +0 -18
- package/dist/cjs/types/workspaces/requests.js +0 -2
- package/dist/cjs/types/workspaces/types.js +0 -154
- package/dist/cjs/utils/activity-helpers.js +0 -58
- package/dist/cjs/utils/case-conversion.js +0 -69
- package/dist/cjs/utils/colors.js +0 -143
- package/dist/cjs/utils/file-response.js +0 -32
- package/dist/cjs/utils/headers.js +0 -16
- package/dist/cjs/utils/index.js +0 -31
- package/dist/cjs/utils/multipart-upload.js +0 -179
- package/dist/cjs/utils/processing-helpers.js +0 -18
- package/dist/cjs/utils/project-helpers.js +0 -20
- package/dist/cjs/utils/request-helpers.js +0 -21
- package/dist/cjs/utils/sanitization.js +0 -116
- package/dist/cjs/utils/sync-helpers.js +0 -22
- package/dist/cjs/utils/task-sorting.js +0 -281
- package/dist/cjs/utils/uncompletable-helpers.js +0 -60
- package/dist/cjs/utils/url-helpers.js +0 -74
- package/dist/cjs/utils/validators.js +0 -108
- package/dist/cjs/utils/view-options.js +0 -19
- package/dist/cjs/utils/webhook-parser.js +0 -60
package/README.md
CHANGED
|
@@ -125,12 +125,57 @@ const refreshed = await refreshAuthToken({
|
|
|
125
125
|
> refresh. For public clients (`tokenEndpointAuthMethod: 'none'`), omit
|
|
126
126
|
> `clientSecret` when calling `refreshAuthToken`.
|
|
127
127
|
|
|
128
|
+
### Keeping Proxy Support and Response Decompression
|
|
129
|
+
|
|
130
|
+
On Node, the SDK's default transport reads the proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) and decodes compressed response bodies. Supplying a `customFetch` replaces that transport, so a custom implementation that still wants both can borrow it with `getDefaultTransport`:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { type CustomFetch, getDefaultTransport, TodoistApi } from '@doist/todoist-sdk'
|
|
134
|
+
|
|
135
|
+
const customFetch: CustomFetch = async (url, options) => {
|
|
136
|
+
const transport = await getDefaultTransport()
|
|
137
|
+
// undici's `fetch` and the global one are the same call at runtime but
|
|
138
|
+
// carry different types, so settle on one signature.
|
|
139
|
+
const fetchImpl = (transport?.fetch ?? fetch) as typeof fetch
|
|
140
|
+
|
|
141
|
+
const response = await fetchImpl(url, {
|
|
142
|
+
...options,
|
|
143
|
+
headers: {
|
|
144
|
+
...(options?.headers as Record<string, string> | undefined),
|
|
145
|
+
'x-my-header': 'value',
|
|
146
|
+
},
|
|
147
|
+
// `dispatcher` is a Node fetch option that the DOM types don't declare.
|
|
148
|
+
dispatcher: transport?.dispatcher,
|
|
149
|
+
} as RequestInit)
|
|
150
|
+
|
|
151
|
+
// `CustomFetchResponse` wants plain-object headers, not a `Headers`.
|
|
152
|
+
const headers: Record<string, string> = {}
|
|
153
|
+
response.headers.forEach((value, key) => {
|
|
154
|
+
headers[key] = value
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
ok: response.ok,
|
|
159
|
+
status: response.status,
|
|
160
|
+
statusText: response.statusText,
|
|
161
|
+
headers,
|
|
162
|
+
text: () => response.text(),
|
|
163
|
+
json: () => response.json(),
|
|
164
|
+
arrayBuffer: () => response.arrayBuffer(),
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const api = new TodoistApi('YOURTOKEN', { customFetch })
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`getDefaultTransport` returns the dispatcher and the `fetch` it must be used with as a single value, and both halves have to be used together. The dispatcher decompresses the response body itself, so pairing it with a `fetch` from a different undici build — including the runtime's global `fetch` on Node 26 — decodes the body twice and the request fails mid-stream with `terminated`. A `fetch` of `undefined` means the global `fetch` is the correct partner; the whole value is `undefined` outside Node, where no dispatcher applies.
|
|
172
|
+
|
|
128
173
|
### Important Notes
|
|
129
174
|
|
|
130
175
|
- All existing transforms (snake_case ↔ camelCase) work automatically with custom fetch
|
|
131
176
|
- Retry logic and error handling are preserved
|
|
132
177
|
- File uploads work with custom fetch implementations
|
|
133
|
-
-
|
|
178
|
+
- File upload bodies are a `Blob`, or a `ReadableStream` when uploading from a stream — a custom fetch must pass them through unchanged
|
|
134
179
|
- Timeout parameter is optional and up to your custom implementation
|
|
135
180
|
|
|
136
181
|
## Development and Testing
|
package/dist/esm/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export * from './todoist-api.js';
|
|
|
2
2
|
export * from './authentication.js';
|
|
3
3
|
export * from './types/index.js';
|
|
4
4
|
export * from './utils/index.js';
|
|
5
|
-
export { getDefaultDispatcher } from './transport/http-dispatcher.js';
|
|
5
|
+
export { getDefaultDispatcher, getDefaultTransport } from './transport/http-dispatcher.js';
|
|
@@ -10,6 +10,23 @@ let defaultTransportPromise;
|
|
|
10
10
|
* The default dispatcher and its paired `fetch`, as a single value so the two
|
|
11
11
|
* are always read consistently. Resolves to `undefined` outside Node (browser/
|
|
12
12
|
* edge), where callers use the global `fetch` with no dispatcher.
|
|
13
|
+
*
|
|
14
|
+
* Use this when supplying a `customFetch` that should still honour the proxy
|
|
15
|
+
* environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) and decode
|
|
16
|
+
* compressed responses the way the SDK does by default.
|
|
17
|
+
*
|
|
18
|
+
* Both halves must be used together. `dispatcher` decompresses the response
|
|
19
|
+
* body itself, so a `fetch` from a different undici build will try to decode
|
|
20
|
+
* it a second time and the request fails mid-stream with `terminated`. A
|
|
21
|
+
* `fetch` of `undefined` means the runtime's global `fetch` is the correct
|
|
22
|
+
* partner for this dispatcher.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const transport = await getDefaultTransport()
|
|
27
|
+
* const fetchImpl = transport?.fetch ?? fetch
|
|
28
|
+
* const response = await fetchImpl(url, { ...options, dispatcher: transport?.dispatcher })
|
|
29
|
+
* ```
|
|
13
30
|
*/
|
|
14
31
|
export function getDefaultTransport() {
|
|
15
32
|
if (!isNodeEnvironment()) {
|
|
@@ -29,6 +46,14 @@ export function getDefaultTransport() {
|
|
|
29
46
|
}
|
|
30
47
|
return defaultTransportPromise;
|
|
31
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* The default dispatcher on its own.
|
|
51
|
+
*
|
|
52
|
+
* @deprecated Use {@link getDefaultTransport} instead, which returns this
|
|
53
|
+
* dispatcher together with the `fetch` it must be used with. Attaching this
|
|
54
|
+
* dispatcher to the runtime's global `fetch` decodes compressed responses
|
|
55
|
+
* twice on Node 26 and the request fails with `terminated`.
|
|
56
|
+
*/
|
|
32
57
|
export async function getDefaultDispatcher() {
|
|
33
58
|
var _a;
|
|
34
59
|
return (_a = (await getDefaultTransport())) === null || _a === void 0 ? void 0 : _a.dispatcher;
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './colors.js';
|
|
2
2
|
export * from './sanitization.js';
|
|
3
|
-
export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers.js';
|
|
3
|
+
export { getTaskUrl, getProjectUrl, getSectionUrl, getLabelUrl, getFilterUrl, getWorkspaceFilterUrl, getWorkspaceUrl, getTaskCommentsUrl, getProjectCommentsUrl, getTaskCommentUrl, getProjectCommentUrl, parseTodoistUrl, TODOIST_LINK_TYPES, } from './url-helpers.js';
|
|
4
4
|
export { createCommand } from './sync-helpers.js';
|
|
5
5
|
export * from './project-helpers.js';
|
|
6
6
|
export * from './task-sorting.js';
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
2
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
3
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
+
var m = o[Symbol.asyncIterator], i;
|
|
5
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
6
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
7
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
|
+
};
|
|
9
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
10
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
11
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
12
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
13
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
14
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
15
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
16
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
17
|
+
function fulfill(value) { resume("next", value); }
|
|
18
|
+
function reject(value) { resume("throw", value); }
|
|
19
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
20
|
+
};
|
|
21
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
1
22
|
import { fetchWithRetry } from '../transport/fetch-with-retry.js';
|
|
2
23
|
import { camelCaseKeys } from './case-conversion.js';
|
|
3
24
|
/**
|
|
@@ -23,6 +44,116 @@ function getContentTypeFromFileName(fileName) {
|
|
|
23
44
|
return 'application/octet-stream';
|
|
24
45
|
}
|
|
25
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Escapes a value for use inside a quoted `Content-Disposition` parameter,
|
|
49
|
+
* where a raw quote would end the value early and a raw CR or LF would end the
|
|
50
|
+
* header. Note that a lone CR needs escaping too, not just CRLF pairs.
|
|
51
|
+
*
|
|
52
|
+
* This is the same escaping the platform's own `FormData` encoder applies, so
|
|
53
|
+
* servers see exactly what they would from any browser or from undici.
|
|
54
|
+
*/
|
|
55
|
+
function escapeDispositionValue(value) {
|
|
56
|
+
return value.replace(/"/g, '%22').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Lays out a `multipart/form-data` payload around a single file part, as the
|
|
60
|
+
* text that goes before and after the file content. Keeping the file content
|
|
61
|
+
* out of it lets the same layout serve both a `Blob` body and a streamed one.
|
|
62
|
+
*/
|
|
63
|
+
function layOutMultipart(args) {
|
|
64
|
+
const { fileName, fileContentType, additionalFields } = args;
|
|
65
|
+
const boundary = `----todoist-sdk-${uuidv4()}`;
|
|
66
|
+
const head = `--${boundary}\r\n` +
|
|
67
|
+
`Content-Disposition: form-data; name="file"; filename="${escapeDispositionValue(fileName)}"\r\n` +
|
|
68
|
+
`Content-Type: ${fileContentType}\r\n\r\n`;
|
|
69
|
+
let tail = '\r\n';
|
|
70
|
+
for (const [key, value] of Object.entries(additionalFields)) {
|
|
71
|
+
if (value !== undefined && value !== null) {
|
|
72
|
+
tail +=
|
|
73
|
+
`--${boundary}\r\n` +
|
|
74
|
+
`Content-Disposition: form-data; name="${escapeDispositionValue(key)}"\r\n\r\n` +
|
|
75
|
+
`${value.toString()}\r\n`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
tail += `--${boundary}--\r\n`;
|
|
79
|
+
return { boundary, head, tail };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Wraps a Node readable stream as a `multipart/form-data` request body.
|
|
83
|
+
*
|
|
84
|
+
* The result is a web `ReadableStream`, which both the runtime's `fetch` and
|
|
85
|
+
* undici's own accept — unlike a Node stream or a `FormData`, either of which
|
|
86
|
+
* only works with one particular client. The file is never buffered, so the
|
|
87
|
+
* request is sent with `Transfer-Encoding: chunked`.
|
|
88
|
+
*/
|
|
89
|
+
function streamMultipartBody(file, parts) {
|
|
90
|
+
const encoder = new TextEncoder();
|
|
91
|
+
function chunks() {
|
|
92
|
+
return __asyncGenerator(this, arguments, function* chunks_1() {
|
|
93
|
+
var _a, e_1, _b, _c;
|
|
94
|
+
yield yield __await(encoder.encode(parts.head));
|
|
95
|
+
try {
|
|
96
|
+
for (var _d = true, file_1 = __asyncValues(file), file_1_1; file_1_1 = yield __await(file_1.next()), _a = file_1_1.done, !_a; _d = true) {
|
|
97
|
+
_c = file_1_1.value;
|
|
98
|
+
_d = false;
|
|
99
|
+
const chunk = _c;
|
|
100
|
+
yield yield __await(typeof chunk === 'string' ? encoder.encode(chunk) : new Uint8Array(chunk));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
104
|
+
finally {
|
|
105
|
+
try {
|
|
106
|
+
if (!_d && !_a && (_b = file_1.return)) yield __await(_b.call(file_1));
|
|
107
|
+
}
|
|
108
|
+
finally { if (e_1) throw e_1.error; }
|
|
109
|
+
}
|
|
110
|
+
yield yield __await(encoder.encode(parts.tail));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const iterator = chunks();
|
|
114
|
+
// Driven by hand rather than with `ReadableStream.from`, which is absent
|
|
115
|
+
// from this project's DOM lib types and is still missing in some browsers,
|
|
116
|
+
// or `Readable.toWeb`, which would drag a Node-only import into a module
|
|
117
|
+
// that browsers also load.
|
|
118
|
+
return new ReadableStream({
|
|
119
|
+
async pull(controller) {
|
|
120
|
+
const { value, done } = await iterator.next();
|
|
121
|
+
if (done) {
|
|
122
|
+
controller.close();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
controller.enqueue(value);
|
|
126
|
+
},
|
|
127
|
+
async cancel(reason) {
|
|
128
|
+
var _a;
|
|
129
|
+
await ((_a = iterator.return) === null || _a === void 0 ? void 0 : _a.call(iterator, reason));
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Builds the request body for a multipart upload.
|
|
135
|
+
*
|
|
136
|
+
* Deliberately avoids `FormData`. A `FormData` body is only encoded by the
|
|
137
|
+
* `fetch` that owns that `FormData` class — undici brands its own — so a body
|
|
138
|
+
* built from the global `FormData` and sent through undici's `fetch`, or the
|
|
139
|
+
* reverse, is stringified to the literal `"[object FormData]"` and the upload
|
|
140
|
+
* silently carries no file. The `form-data` package fares worse: neither
|
|
141
|
+
* `fetch` accepts it as a body at all. `Blob` and `ReadableStream` carry no
|
|
142
|
+
* such brand and work with whichever `fetch` dispatches the request,
|
|
143
|
+
* including a caller-supplied `customFetch`.
|
|
144
|
+
*/
|
|
145
|
+
function buildMultipartBody(args) {
|
|
146
|
+
const { file, fileName, fileContentType, additionalFields } = args;
|
|
147
|
+
const parts = layOutMultipart({ fileName, fileContentType, additionalFields });
|
|
148
|
+
const contentType = `multipart/form-data; boundary=${parts.boundary}`;
|
|
149
|
+
if (file instanceof Blob) {
|
|
150
|
+
// A Blob keeps its length, so the request gets a Content-Length and
|
|
151
|
+
// stays replayable if it has to be retried. File-backed Blobs (from
|
|
152
|
+
// `fs.openAsBlob`) stay lazy here, so nothing is read into memory.
|
|
153
|
+
return { body: new Blob([parts.head, file, parts.tail]), contentType, isStreamed: false };
|
|
154
|
+
}
|
|
155
|
+
return { body: streamMultipartBody(file, parts), contentType, isStreamed: true };
|
|
156
|
+
}
|
|
26
157
|
/**
|
|
27
158
|
* Uploads a file using multipart/form-data.
|
|
28
159
|
*
|
|
@@ -75,69 +206,52 @@ export async function uploadMultipartFile(args) {
|
|
|
75
206
|
if (requestId) {
|
|
76
207
|
headers['X-Request-Id'] = requestId;
|
|
77
208
|
}
|
|
209
|
+
// Resolve the file to something every `fetch` accepts as a body part: a
|
|
210
|
+
// Blob where the size is known up front, or a Node stream that gets piped
|
|
211
|
+
// through untouched.
|
|
212
|
+
let filePart;
|
|
213
|
+
let resolvedFileName;
|
|
78
214
|
if (file instanceof Blob) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
215
|
+
filePart = file;
|
|
216
|
+
resolvedFileName = fileName || (file instanceof File ? file.name : undefined) || 'upload';
|
|
217
|
+
}
|
|
218
|
+
else if (typeof file === 'string') {
|
|
219
|
+
// File path: Node-only, so import lazily to keep browser bundles clean.
|
|
220
|
+
const [fsModule, pathModule] = await Promise.all([import('fs'), import('path')]);
|
|
221
|
+
resolvedFileName = fileName || pathModule.basename(file);
|
|
222
|
+
// `openAsBlob` reads the file lazily, so a large upload is not pulled
|
|
223
|
+
// into memory, and the resulting body still has a known length.
|
|
224
|
+
filePart = await fsModule.openAsBlob(file);
|
|
225
|
+
}
|
|
226
|
+
else if (Buffer.isBuffer(file)) {
|
|
227
|
+
if (!fileName) {
|
|
228
|
+
throw new Error('fileName is required when uploading from a Buffer');
|
|
87
229
|
}
|
|
88
|
-
|
|
89
|
-
|
|
230
|
+
resolvedFileName = fileName;
|
|
231
|
+
filePart = new Blob([
|
|
232
|
+
new Uint8Array(file.buffer, file.byteOffset, file.byteLength),
|
|
233
|
+
]);
|
|
90
234
|
}
|
|
91
235
|
else {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
import('form-data'),
|
|
95
|
-
import('fs'),
|
|
96
|
-
import('path'),
|
|
97
|
-
]);
|
|
98
|
-
const FormData = FormDataModule.default;
|
|
99
|
-
const form = new FormData();
|
|
100
|
-
if (typeof file === 'string') {
|
|
101
|
-
// File path - create read stream
|
|
102
|
-
const resolvedFileName = fileName || pathModule.basename(file);
|
|
103
|
-
form.append('file', fsModule.createReadStream(file), resolvedFileName);
|
|
104
|
-
}
|
|
105
|
-
else if (Buffer.isBuffer(file)) {
|
|
106
|
-
// Buffer - require fileName
|
|
107
|
-
if (!fileName) {
|
|
108
|
-
throw new Error('fileName is required when uploading from a Buffer');
|
|
109
|
-
}
|
|
110
|
-
const contentType = getContentTypeFromFileName(fileName);
|
|
111
|
-
form.append('file', file, {
|
|
112
|
-
filename: fileName,
|
|
113
|
-
contentType: contentType,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// Stream - require fileName
|
|
118
|
-
if (!fileName) {
|
|
119
|
-
throw new Error('fileName is required when uploading from a stream');
|
|
120
|
-
}
|
|
121
|
-
form.append('file', file, fileName);
|
|
236
|
+
if (!fileName) {
|
|
237
|
+
throw new Error('fileName is required when uploading from a stream');
|
|
122
238
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
form.append(key, value.toString());
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
Object.assign(headers, form.getHeaders());
|
|
129
|
-
body = form;
|
|
239
|
+
resolvedFileName = fileName;
|
|
240
|
+
filePart = file;
|
|
130
241
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
headers,
|
|
138
|
-
timeout: 30000, // 30 second timeout for file uploads
|
|
139
|
-
},
|
|
140
|
-
customFetch,
|
|
242
|
+
const multipart = buildMultipartBody({
|
|
243
|
+
file: filePart,
|
|
244
|
+
fileName: resolvedFileName,
|
|
245
|
+
fileContentType: (filePart instanceof Blob ? filePart.type : undefined) ||
|
|
246
|
+
getContentTypeFromFileName(resolvedFileName),
|
|
247
|
+
additionalFields,
|
|
141
248
|
});
|
|
249
|
+
// The boundary is ours, so Content-Type has to be set explicitly — `fetch`
|
|
250
|
+
// only fills it in for a `FormData` body.
|
|
251
|
+
headers['Content-Type'] = multipart.contentType;
|
|
252
|
+
body = multipart.body;
|
|
253
|
+
// Make the request using fetch
|
|
254
|
+
const response = await fetchWithRetry(Object.assign(Object.assign({ url, options: Object.assign({ method: 'POST', body,
|
|
255
|
+
headers, timeout: 30000 }, (multipart.isStreamed ? { duplex: 'half' } : {})) }, (multipart.isStreamed ? { retryConfig: { retries: 0 } } : {})), { customFetch }));
|
|
142
256
|
return camelCaseKeys(response.data);
|
|
143
257
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LinkEnvironment } from '@doist/sdk-kmp/common';
|
|
2
|
+
import { parseTodoistLink, todoistFilterUrl, todoistLabelUrl, todoistProjectCommentsUrl, todoistProjectCommentUrl, todoistProjectUrl, todoistSectionUrl, todoistTaskCommentsUrl, todoistTaskCommentUrl, todoistTaskUrl, todoistWorkspaceFilterUrl, todoistWorkspaceUrl, } from '@doist/sdk-kmp/todoist';
|
|
1
3
|
import { TODOIST_WEB_URI } from '../consts/endpoints.js';
|
|
2
4
|
/**
|
|
3
5
|
* Formats a Date object to YYYY-MM-DD string format.
|
|
@@ -12,6 +14,23 @@ export function formatDateToYYYYMMDD(date) {
|
|
|
12
14
|
const day = String(date.getDate()).padStart(2, '0');
|
|
13
15
|
return `${year}-${month}-${day}`;
|
|
14
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Builds a URL, falling back to a bare-id URL when the link builder rejects the
|
|
19
|
+
* given id. These helpers are called while parsing API responses, so generating
|
|
20
|
+
* a URL must never fail the parse.
|
|
21
|
+
*
|
|
22
|
+
* @param build Builds the URL.
|
|
23
|
+
* @param fallbackPath The path to fall back to, relative to the Todoist web app.
|
|
24
|
+
* @returns The built URL, or a bare-id URL if the id was rejected.
|
|
25
|
+
*/
|
|
26
|
+
function buildUrl(build, fallbackPath) {
|
|
27
|
+
try {
|
|
28
|
+
return build();
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
return `${TODOIST_WEB_URI}/${fallbackPath}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
15
34
|
/**
|
|
16
35
|
* Generate the URL for a given task.
|
|
17
36
|
*
|
|
@@ -20,9 +39,7 @@ export function formatDateToYYYYMMDD(date) {
|
|
|
20
39
|
* @returns The URL string for the task view.
|
|
21
40
|
*/
|
|
22
41
|
export function getTaskUrl(taskId, content) {
|
|
23
|
-
|
|
24
|
-
const path = slug ? `${slug}-${taskId}` : taskId;
|
|
25
|
-
return `${TODOIST_WEB_URI}/task/${path}`;
|
|
42
|
+
return buildUrl(() => todoistTaskUrl(taskId, content !== null && content !== void 0 ? content : '', LinkEnvironment.Production), `task/${taskId}`);
|
|
26
43
|
}
|
|
27
44
|
/**
|
|
28
45
|
* Generate the URL for a given project.
|
|
@@ -32,9 +49,7 @@ export function getTaskUrl(taskId, content) {
|
|
|
32
49
|
* @returns The URL string for the project view.
|
|
33
50
|
*/
|
|
34
51
|
export function getProjectUrl(projectId, name) {
|
|
35
|
-
|
|
36
|
-
const path = slug ? `${slug}-${projectId}` : projectId;
|
|
37
|
-
return `${TODOIST_WEB_URI}/project/${path}`;
|
|
52
|
+
return buildUrl(() => todoistProjectUrl(projectId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `project/${projectId}`);
|
|
38
53
|
}
|
|
39
54
|
/**
|
|
40
55
|
* Generate the URL for a given section.
|
|
@@ -44,25 +59,138 @@ export function getProjectUrl(projectId, name) {
|
|
|
44
59
|
* @returns The URL string for the section view.
|
|
45
60
|
*/
|
|
46
61
|
export function getSectionUrl(sectionId, name) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
return buildUrl(() => todoistSectionUrl(sectionId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `section/${sectionId}`);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate the URL for a given label.
|
|
66
|
+
*
|
|
67
|
+
* @param labelId The ID of the label.
|
|
68
|
+
* @param name The name of the label.
|
|
69
|
+
* @returns The URL string for the label view.
|
|
70
|
+
*/
|
|
71
|
+
export function getLabelUrl(labelId, name) {
|
|
72
|
+
return buildUrl(() => todoistLabelUrl(labelId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `label/${labelId}`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate the URL for a given filter.
|
|
76
|
+
*
|
|
77
|
+
* @param filterId The ID of the filter.
|
|
78
|
+
* @param name The name of the filter.
|
|
79
|
+
* @returns The URL string for the filter view.
|
|
80
|
+
*/
|
|
81
|
+
export function getFilterUrl(filterId, name) {
|
|
82
|
+
return buildUrl(() => todoistFilterUrl(filterId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `filter/${filterId}`);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Generate the URL for a filter belonging to a workspace.
|
|
86
|
+
*
|
|
87
|
+
* @param workspaceId The ID of the workspace the filter belongs to.
|
|
88
|
+
* @param filterId The ID of the filter.
|
|
89
|
+
* @param name The name of the filter.
|
|
90
|
+
* @returns The URL string for the workspace filter view.
|
|
91
|
+
*/
|
|
92
|
+
export function getWorkspaceFilterUrl(workspaceId, filterId, name) {
|
|
93
|
+
return buildUrl(() => todoistWorkspaceFilterUrl(workspaceId, filterId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `${workspaceId}/filter/${filterId}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Generate the URL for a given workspace.
|
|
97
|
+
*
|
|
98
|
+
* @param workspaceId The ID of the workspace.
|
|
99
|
+
* @returns The URL string for the workspace view.
|
|
100
|
+
*/
|
|
101
|
+
export function getWorkspaceUrl(workspaceId) {
|
|
102
|
+
return buildUrl(() => todoistWorkspaceUrl(workspaceId, LinkEnvironment.Production), workspaceId);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Generate the URL for the comments on a given task.
|
|
106
|
+
*
|
|
107
|
+
* @param taskId The ID of the task.
|
|
108
|
+
* @param content The content of the task.
|
|
109
|
+
* @returns The URL string for the task's comments.
|
|
110
|
+
*/
|
|
111
|
+
export function getTaskCommentsUrl(taskId, content) {
|
|
112
|
+
return buildUrl(() => todoistTaskCommentsUrl(taskId, content !== null && content !== void 0 ? content : '', LinkEnvironment.Production), `task/${taskId}/comments`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generate the URL for the comments on a given project.
|
|
116
|
+
*
|
|
117
|
+
* @param projectId The ID of the project.
|
|
118
|
+
* @param name The name of the project.
|
|
119
|
+
* @returns The URL string for the project's comments.
|
|
120
|
+
*/
|
|
121
|
+
export function getProjectCommentsUrl(projectId, name) {
|
|
122
|
+
return buildUrl(() => todoistProjectCommentsUrl(projectId, name !== null && name !== void 0 ? name : '', LinkEnvironment.Production), `project/${projectId}/comments`);
|
|
50
123
|
}
|
|
51
124
|
/**
|
|
52
|
-
*
|
|
125
|
+
* Generate the URL for a single comment on a given task.
|
|
126
|
+
*
|
|
127
|
+
* @param taskId The ID of the task.
|
|
128
|
+
* @param commentId The ID of the comment.
|
|
129
|
+
* @param content The content of the task.
|
|
130
|
+
* @returns The URL string for the comment.
|
|
131
|
+
*/
|
|
132
|
+
export function getTaskCommentUrl(taskId, commentId, content) {
|
|
133
|
+
return buildUrl(() => todoistTaskCommentUrl(taskId, content !== null && content !== void 0 ? content : '', commentId, LinkEnvironment.Production), `task/${taskId}#comment-${commentId}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generate the URL for a single comment on a given project.
|
|
137
|
+
*
|
|
138
|
+
* @param projectId The ID of the project.
|
|
139
|
+
* @param commentId The ID of the comment.
|
|
140
|
+
* @param name The name of the project.
|
|
141
|
+
* @returns The URL string for the comment.
|
|
142
|
+
*/
|
|
143
|
+
export function getProjectCommentUrl(projectId, commentId, name) {
|
|
144
|
+
return buildUrl(() => todoistProjectCommentUrl(projectId, name !== null && name !== void 0 ? name : '', commentId, LinkEnvironment.Production), `project/${projectId}#comment-${commentId}`);
|
|
145
|
+
}
|
|
146
|
+
/** The kinds of Todoist entity a URL can point at. */
|
|
147
|
+
export const TODOIST_LINK_TYPES = [
|
|
148
|
+
'task',
|
|
149
|
+
'project',
|
|
150
|
+
'filter',
|
|
151
|
+
'label',
|
|
152
|
+
'section',
|
|
153
|
+
'workspace',
|
|
154
|
+
'template',
|
|
155
|
+
'comment',
|
|
156
|
+
'label_by_name',
|
|
157
|
+
];
|
|
158
|
+
/**
|
|
159
|
+
* Maps the link parser's type names onto the types this SDK exposes. A name
|
|
160
|
+
* that is missing here is one this SDK does not know about, and is treated as
|
|
161
|
+
* an unrecognised URL rather than surfaced as a value outside the union.
|
|
162
|
+
*/
|
|
163
|
+
const LINK_TYPE_BY_PARSED_NAME = {
|
|
164
|
+
Task: 'task',
|
|
165
|
+
Project: 'project',
|
|
166
|
+
Filter: 'filter',
|
|
167
|
+
Label: 'label',
|
|
168
|
+
Section: 'section',
|
|
169
|
+
Workspace: 'workspace',
|
|
170
|
+
Template: 'template',
|
|
171
|
+
Comment: 'comment',
|
|
172
|
+
LabelByName: 'label_by_name',
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Parse a Todoist URL into the entity it points at.
|
|
53
176
|
*
|
|
54
|
-
* @param
|
|
55
|
-
* @returns The
|
|
177
|
+
* @param url The URL to parse.
|
|
178
|
+
* @returns The entity the URL points at, or `null` if it is not a Todoist URL.
|
|
56
179
|
*/
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return
|
|
180
|
+
export function parseTodoistUrl(url) {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
const link = parseTodoistLink(url);
|
|
183
|
+
if (!link) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const type = LINK_TYPE_BY_PARSED_NAME[link.type.name];
|
|
187
|
+
if (!type) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
type,
|
|
192
|
+
id: link.id,
|
|
193
|
+
workspaceId: (_a = link.workspaceId) !== null && _a !== void 0 ? _a : null,
|
|
194
|
+
commentId: (_b = link.commentId) !== null && _b !== void 0 ? _b : null,
|
|
195
|
+
};
|
|
68
196
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ export * from './todoist-api.js';
|
|
|
2
2
|
export * from './authentication.js';
|
|
3
3
|
export * from './types/index.js';
|
|
4
4
|
export * from './utils/index.js';
|
|
5
|
-
export { getDefaultDispatcher } from './transport/http-dispatcher.js';
|
|
5
|
+
export { getDefaultDispatcher, getDefaultTransport } from './transport/http-dispatcher.js';
|
|
6
|
+
export type { DefaultTransport } from './transport/http-dispatcher.js';
|
|
@@ -7,7 +7,7 @@ type UndiciFetch = typeof import('undici').fetch;
|
|
|
7
7
|
* never observe a dispatcher paired with a mismatched `fetch` — see
|
|
8
8
|
* {@link getDefaultFetch} for why the pairing matters.
|
|
9
9
|
*/
|
|
10
|
-
type DefaultTransport = {
|
|
10
|
+
export type DefaultTransport = {
|
|
11
11
|
dispatcher: Dispatcher;
|
|
12
12
|
fetch: UndiciFetch | undefined;
|
|
13
13
|
};
|
|
@@ -15,8 +15,33 @@ type DefaultTransport = {
|
|
|
15
15
|
* The default dispatcher and its paired `fetch`, as a single value so the two
|
|
16
16
|
* are always read consistently. Resolves to `undefined` outside Node (browser/
|
|
17
17
|
* edge), where callers use the global `fetch` with no dispatcher.
|
|
18
|
+
*
|
|
19
|
+
* Use this when supplying a `customFetch` that should still honour the proxy
|
|
20
|
+
* environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) and decode
|
|
21
|
+
* compressed responses the way the SDK does by default.
|
|
22
|
+
*
|
|
23
|
+
* Both halves must be used together. `dispatcher` decompresses the response
|
|
24
|
+
* body itself, so a `fetch` from a different undici build will try to decode
|
|
25
|
+
* it a second time and the request fails mid-stream with `terminated`. A
|
|
26
|
+
* `fetch` of `undefined` means the runtime's global `fetch` is the correct
|
|
27
|
+
* partner for this dispatcher.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const transport = await getDefaultTransport()
|
|
32
|
+
* const fetchImpl = transport?.fetch ?? fetch
|
|
33
|
+
* const response = await fetchImpl(url, { ...options, dispatcher: transport?.dispatcher })
|
|
34
|
+
* ```
|
|
18
35
|
*/
|
|
19
36
|
export declare function getDefaultTransport(): Promise<DefaultTransport | undefined>;
|
|
37
|
+
/**
|
|
38
|
+
* The default dispatcher on its own.
|
|
39
|
+
*
|
|
40
|
+
* @deprecated Use {@link getDefaultTransport} instead, which returns this
|
|
41
|
+
* dispatcher together with the `fetch` it must be used with. Attaching this
|
|
42
|
+
* dispatcher to the runtime's global `fetch` decodes compressed responses
|
|
43
|
+
* twice on Node 26 and the request fails with `terminated`.
|
|
44
|
+
*/
|
|
20
45
|
export declare function getDefaultDispatcher(): Promise<Dispatcher | undefined>;
|
|
21
46
|
/**
|
|
22
47
|
* The `fetch` implementation that must be used with the default dispatcher.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './colors.js';
|
|
2
2
|
export * from './sanitization.js';
|
|
3
|
-
export { getTaskUrl, getProjectUrl, getSectionUrl } from './url-helpers.js';
|
|
3
|
+
export { getTaskUrl, getProjectUrl, getSectionUrl, getLabelUrl, getFilterUrl, getWorkspaceFilterUrl, getWorkspaceUrl, getTaskCommentsUrl, getProjectCommentsUrl, getTaskCommentUrl, getProjectCommentUrl, parseTodoistUrl, TODOIST_LINK_TYPES, } from './url-helpers.js';
|
|
4
|
+
export type { TodoistLinkType, TodoistUrlInfo } from './url-helpers.js';
|
|
4
5
|
export { createCommand } from './sync-helpers.js';
|
|
5
6
|
export * from './project-helpers.js';
|
|
6
7
|
export * from './task-sorting.js';
|