@doist/todoist-sdk 9.1.0-next.2 → 9.1.1
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/dist/cjs/authentication.js +1 -0
- package/dist/cjs/clients/app-client.js +347 -0
- package/dist/cjs/clients/base-client.js +1 -0
- package/dist/cjs/clients/ui-extension-client.js +109 -0
- package/dist/cjs/consts/endpoints.js +70 -6
- package/dist/cjs/test-utils/test-defaults.js +75 -23
- package/dist/cjs/todoist-api.js +269 -33
- package/dist/cjs/transport/http-client.js +1 -0
- package/dist/cjs/types/apps/types.js +253 -0
- package/dist/cjs/types/index.js +2 -1
- package/dist/cjs/types/sync/commands/index.js +0 -1
- package/dist/cjs/types/sync/resource-types.js +0 -1
- package/dist/cjs/types/sync/response.js +10 -12
- package/dist/cjs/types/ui-extensions/index.js +18 -0
- package/dist/cjs/types/ui-extensions/types.js +77 -0
- package/dist/cjs/utils/validators.js +45 -33
- package/dist/esm/authentication.js +1 -0
- package/dist/esm/clients/app-client.js +343 -0
- package/dist/esm/clients/base-client.js +1 -0
- package/dist/esm/clients/ui-extension-client.js +105 -0
- package/dist/esm/consts/endpoints.js +54 -5
- package/dist/esm/test-utils/test-defaults.js +73 -22
- package/dist/esm/todoist-api.js +269 -33
- package/dist/esm/transport/http-client.js +1 -0
- package/dist/esm/types/apps/types.js +248 -0
- package/dist/esm/types/index.js +2 -1
- package/dist/esm/types/sync/commands/index.js +0 -1
- package/dist/esm/types/sync/resource-types.js +0 -1
- package/dist/esm/types/sync/response.js +0 -2
- package/dist/esm/types/ui-extensions/types.js +74 -0
- package/dist/esm/utils/validators.js +14 -2
- package/dist/types/authentication.d.ts +1 -1
- package/dist/types/clients/app-client.d.ts +37 -0
- package/dist/types/clients/base-client.d.ts +1 -0
- package/dist/types/clients/ui-extension-client.d.ts +18 -0
- package/dist/types/consts/endpoints.d.ts +25 -5
- package/dist/types/test-utils/test-defaults.d.ts +16 -4
- package/dist/types/todoist-api.d.ts +202 -12
- package/dist/types/types/apps/index.d.ts +2 -0
- package/dist/types/types/apps/requests.d.ts +89 -0
- package/dist/types/types/apps/types.d.ts +414 -0
- package/dist/types/types/http.d.ts +1 -1
- package/dist/types/types/index.d.ts +2 -1
- package/dist/types/types/sync/commands/index.d.ts +0 -9
- package/dist/types/types/sync/resource-types.d.ts +1 -1
- package/dist/types/types/sync/resources/user.d.ts +2 -2
- package/dist/types/types/sync/resources/view-options.d.ts +6 -6
- package/dist/types/types/sync/response.d.ts +6 -31
- package/dist/types/types/sync/user-preferences.d.ts +1 -1
- package/dist/types/types/tasks/requests.d.ts +0 -1
- package/dist/types/types/ui-extensions/index.d.ts +2 -0
- package/dist/types/types/ui-extensions/requests.d.ts +108 -0
- package/dist/types/types/ui-extensions/types.d.ts +185 -0
- package/dist/types/utils/validators.d.ts +231 -55
- package/package.json +1 -1
- package/dist/cjs/clients/goals-client.js +0 -145
- package/dist/cjs/types/goals/types.js +0 -56
- package/dist/esm/clients/goals-client.js +0 -141
- package/dist/esm/types/goals/types.js +0 -53
- package/dist/types/clients/goals-client.d.ts +0 -20
- package/dist/types/types/goals/requests.d.ts +0 -33
- package/dist/types/types/goals/types.d.ts +0 -51
- package/dist/types/types/sync/commands/goals.d.ts +0 -33
- /package/dist/cjs/types/{goals → apps}/index.js +0 -0
- /package/dist/cjs/types/{goals → apps}/requests.js +0 -0
- /package/dist/cjs/types/{sync/commands/goals.js → ui-extensions/requests.js} +0 -0
- /package/dist/esm/types/{goals → apps}/index.js +0 -0
- /package/dist/esm/types/{goals → apps}/requests.js +0 -0
- /package/dist/{types/types/goals/index.d.ts → esm/types/ui-extensions/index.js} +0 -0
- /package/dist/esm/types/{sync/commands/goals.js → ui-extensions/requests.js} +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { z } from 'zod';
|
|
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
|
+
import { isSuccess, request } from '../transport/http-client.js';
|
|
15
|
+
import { webhookEventToWireName } from '../types/apps/index.js';
|
|
16
|
+
import { camelCaseKeys } from '../utils/case-conversion.js';
|
|
17
|
+
import { uploadMultipartFile } from '../utils/multipart-upload.js';
|
|
18
|
+
import { validateApp, validateAppArray, validateAppByDistributionToken, validateAppDistributionToken, validateAppInstallation, validateAppInstallationArray, validateAppSecrets, validateAppTestToken, validateAppVerificationToken, validateAppWebhook, validateAppWithUserCount, validateUserAuthorizationArray, } from '../utils/validators.js';
|
|
19
|
+
import { BaseClient } from './base-client.js';
|
|
20
|
+
/**
|
|
21
|
+
* Internal sub-client handling all developer-app management endpoints
|
|
22
|
+
* (apps, secrets, tokens, webhooks, installations, user authorizations).
|
|
23
|
+
* All endpoints require the `dev:app_console` OAuth scope.
|
|
24
|
+
*
|
|
25
|
+
* Instantiated by `TodoistApi`; every public app-management method on
|
|
26
|
+
* `TodoistApi` delegates here. See `todoist-api.ts` for user-facing JSDoc.
|
|
27
|
+
*/
|
|
28
|
+
export class AppClient extends BaseClient {
|
|
29
|
+
async getApps(requestId) {
|
|
30
|
+
const response = await request({
|
|
31
|
+
httpMethod: 'GET',
|
|
32
|
+
baseUri: this.apiRootBase,
|
|
33
|
+
relativePath: ENDPOINT_REST_APPS,
|
|
34
|
+
apiToken: this.authToken,
|
|
35
|
+
customFetch: this.customFetch,
|
|
36
|
+
requestId: requestId,
|
|
37
|
+
});
|
|
38
|
+
return validateAppArray(response.data);
|
|
39
|
+
}
|
|
40
|
+
async getApp(appId, requestId) {
|
|
41
|
+
z.string().parse(appId);
|
|
42
|
+
const response = await request({
|
|
43
|
+
httpMethod: 'GET',
|
|
44
|
+
baseUri: this.apiRootBase,
|
|
45
|
+
relativePath: getAppEndpoint(appId),
|
|
46
|
+
apiToken: this.authToken,
|
|
47
|
+
customFetch: this.customFetch,
|
|
48
|
+
requestId: requestId,
|
|
49
|
+
});
|
|
50
|
+
return validateAppWithUserCount(response.data);
|
|
51
|
+
}
|
|
52
|
+
async addApp(args, requestId) {
|
|
53
|
+
const response = await request({
|
|
54
|
+
httpMethod: 'POST',
|
|
55
|
+
baseUri: this.apiRootBase,
|
|
56
|
+
relativePath: ENDPOINT_REST_APPS,
|
|
57
|
+
apiToken: this.authToken,
|
|
58
|
+
customFetch: this.customFetch,
|
|
59
|
+
payload: args,
|
|
60
|
+
requestId: requestId,
|
|
61
|
+
});
|
|
62
|
+
return validateApp(response.data);
|
|
63
|
+
}
|
|
64
|
+
async updateApp(appId, args, requestId) {
|
|
65
|
+
z.string().parse(appId);
|
|
66
|
+
const { appTokenScopes } = args, rest = __rest(args, ["appTokenScopes"]);
|
|
67
|
+
const payload = Object.assign({}, rest);
|
|
68
|
+
if (appTokenScopes !== undefined) {
|
|
69
|
+
payload.appTokenScopes = appTokenScopes === null ? null : appTokenScopes.join(',');
|
|
70
|
+
}
|
|
71
|
+
const response = await request({
|
|
72
|
+
httpMethod: 'POST',
|
|
73
|
+
baseUri: this.apiRootBase,
|
|
74
|
+
relativePath: getAppEndpoint(appId),
|
|
75
|
+
apiToken: this.authToken,
|
|
76
|
+
customFetch: this.customFetch,
|
|
77
|
+
payload: payload,
|
|
78
|
+
requestId: requestId,
|
|
79
|
+
});
|
|
80
|
+
return validateAppWithUserCount(response.data);
|
|
81
|
+
}
|
|
82
|
+
async deleteApp(appId, requestId) {
|
|
83
|
+
z.string().parse(appId);
|
|
84
|
+
const response = await request({
|
|
85
|
+
httpMethod: 'DELETE',
|
|
86
|
+
baseUri: this.apiRootBase,
|
|
87
|
+
relativePath: getAppEndpoint(appId),
|
|
88
|
+
apiToken: this.authToken,
|
|
89
|
+
customFetch: this.customFetch,
|
|
90
|
+
requestId: requestId,
|
|
91
|
+
});
|
|
92
|
+
return isSuccess(response);
|
|
93
|
+
}
|
|
94
|
+
async getAppSecrets(appId, requestId) {
|
|
95
|
+
z.string().parse(appId);
|
|
96
|
+
const response = await request({
|
|
97
|
+
httpMethod: 'GET',
|
|
98
|
+
baseUri: this.apiRootBase,
|
|
99
|
+
relativePath: getAppSecretsEndpoint(appId),
|
|
100
|
+
apiToken: this.authToken,
|
|
101
|
+
customFetch: this.customFetch,
|
|
102
|
+
requestId: requestId,
|
|
103
|
+
});
|
|
104
|
+
return validateAppSecrets(response.data);
|
|
105
|
+
}
|
|
106
|
+
async resetAppClientSecret(appId, requestId) {
|
|
107
|
+
z.string().parse(appId);
|
|
108
|
+
const response = await request({
|
|
109
|
+
httpMethod: 'DELETE',
|
|
110
|
+
baseUri: this.apiRootBase,
|
|
111
|
+
relativePath: getAppClientSecretEndpoint(appId),
|
|
112
|
+
apiToken: this.authToken,
|
|
113
|
+
customFetch: this.customFetch,
|
|
114
|
+
requestId: requestId,
|
|
115
|
+
});
|
|
116
|
+
return validateAppWithUserCount(response.data);
|
|
117
|
+
}
|
|
118
|
+
async revokeAppTokens(appId, requestId) {
|
|
119
|
+
z.string().parse(appId);
|
|
120
|
+
const response = await request({
|
|
121
|
+
httpMethod: 'DELETE',
|
|
122
|
+
baseUri: this.apiRootBase,
|
|
123
|
+
relativePath: getAppTokensEndpoint(appId),
|
|
124
|
+
apiToken: this.authToken,
|
|
125
|
+
customFetch: this.customFetch,
|
|
126
|
+
requestId: requestId,
|
|
127
|
+
});
|
|
128
|
+
return validateAppWithUserCount(response.data);
|
|
129
|
+
}
|
|
130
|
+
async uploadAppIcon(args, requestId) {
|
|
131
|
+
var _a, _b;
|
|
132
|
+
if (Buffer.isBuffer(args.file) && args.file.length === 0) {
|
|
133
|
+
throw new Error('Cannot upload empty image file');
|
|
134
|
+
}
|
|
135
|
+
const size = (_a = args.size) !== null && _a !== void 0 ? _a : 'medium';
|
|
136
|
+
const data = await uploadMultipartFile({
|
|
137
|
+
baseUrl: this.apiRootBase,
|
|
138
|
+
authToken: this.authToken,
|
|
139
|
+
endpoint: getAppIconEndpoint(args.appId, size),
|
|
140
|
+
file: args.file,
|
|
141
|
+
fileName: args.fileName,
|
|
142
|
+
additionalFields: { file_name: (_b = args.fileName) !== null && _b !== void 0 ? _b : '' },
|
|
143
|
+
requestId: requestId,
|
|
144
|
+
customFetch: this.customFetch,
|
|
145
|
+
});
|
|
146
|
+
return validateAppWithUserCount(camelCaseKeys(data));
|
|
147
|
+
}
|
|
148
|
+
async getAppTestToken(appId, requestId) {
|
|
149
|
+
z.string().parse(appId);
|
|
150
|
+
const response = await request({
|
|
151
|
+
httpMethod: 'GET',
|
|
152
|
+
baseUri: this.apiRootBase,
|
|
153
|
+
relativePath: getAppTestTokenEndpoint(appId),
|
|
154
|
+
apiToken: this.authToken,
|
|
155
|
+
customFetch: this.customFetch,
|
|
156
|
+
requestId: requestId,
|
|
157
|
+
});
|
|
158
|
+
return validateAppTestToken(response.data);
|
|
159
|
+
}
|
|
160
|
+
async createAppTestToken(appId, requestId) {
|
|
161
|
+
z.string().parse(appId);
|
|
162
|
+
const response = await request({
|
|
163
|
+
httpMethod: 'PUT',
|
|
164
|
+
baseUri: this.apiRootBase,
|
|
165
|
+
relativePath: getAppTestTokenEndpoint(appId),
|
|
166
|
+
apiToken: this.authToken,
|
|
167
|
+
customFetch: this.customFetch,
|
|
168
|
+
requestId: requestId,
|
|
169
|
+
});
|
|
170
|
+
return validateAppTestToken(response.data);
|
|
171
|
+
}
|
|
172
|
+
async getAppDistributionToken(appId, requestId) {
|
|
173
|
+
z.string().parse(appId);
|
|
174
|
+
const response = await request({
|
|
175
|
+
httpMethod: 'GET',
|
|
176
|
+
baseUri: this.apiRootBase,
|
|
177
|
+
relativePath: getAppDistributionTokenEndpoint(appId),
|
|
178
|
+
apiToken: this.authToken,
|
|
179
|
+
customFetch: this.customFetch,
|
|
180
|
+
requestId: requestId,
|
|
181
|
+
});
|
|
182
|
+
return validateAppDistributionToken(response.data);
|
|
183
|
+
}
|
|
184
|
+
async getAppVerificationToken(appId, requestId) {
|
|
185
|
+
z.string().parse(appId);
|
|
186
|
+
const response = await request({
|
|
187
|
+
httpMethod: 'GET',
|
|
188
|
+
baseUri: this.apiRootBase,
|
|
189
|
+
relativePath: getAppVerificationTokenEndpoint(appId),
|
|
190
|
+
apiToken: this.authToken,
|
|
191
|
+
customFetch: this.customFetch,
|
|
192
|
+
requestId: requestId,
|
|
193
|
+
});
|
|
194
|
+
return validateAppVerificationToken(response.data);
|
|
195
|
+
}
|
|
196
|
+
async resetAppVerificationToken(appId, requestId) {
|
|
197
|
+
z.string().parse(appId);
|
|
198
|
+
const response = await request({
|
|
199
|
+
httpMethod: 'DELETE',
|
|
200
|
+
baseUri: this.apiRootBase,
|
|
201
|
+
relativePath: getAppVerificationTokenEndpoint(appId),
|
|
202
|
+
apiToken: this.authToken,
|
|
203
|
+
customFetch: this.customFetch,
|
|
204
|
+
requestId: requestId,
|
|
205
|
+
});
|
|
206
|
+
return validateAppVerificationToken(response.data);
|
|
207
|
+
}
|
|
208
|
+
async getAppByDistributionToken(distributionToken, requestId) {
|
|
209
|
+
z.string().parse(distributionToken);
|
|
210
|
+
const response = await request({
|
|
211
|
+
httpMethod: 'GET',
|
|
212
|
+
baseUri: this.apiRootBase,
|
|
213
|
+
relativePath: getAppByDistributionTokenEndpoint(distributionToken),
|
|
214
|
+
apiToken: this.authToken,
|
|
215
|
+
customFetch: this.customFetch,
|
|
216
|
+
requestId: requestId,
|
|
217
|
+
});
|
|
218
|
+
return validateAppByDistributionToken(response.data);
|
|
219
|
+
}
|
|
220
|
+
// --- App webhooks ---
|
|
221
|
+
async getAppWebhook(appId, requestId) {
|
|
222
|
+
z.string().parse(appId);
|
|
223
|
+
const response = await request({
|
|
224
|
+
httpMethod: 'GET',
|
|
225
|
+
baseUri: this.apiRootBase,
|
|
226
|
+
relativePath: getAppWebhookEndpoint(appId),
|
|
227
|
+
apiToken: this.authToken,
|
|
228
|
+
customFetch: this.customFetch,
|
|
229
|
+
requestId: requestId,
|
|
230
|
+
});
|
|
231
|
+
return response.data ? validateAppWebhook(response.data) : null;
|
|
232
|
+
}
|
|
233
|
+
async updateAppWebhook(args, requestId) {
|
|
234
|
+
const { appId, events } = args, rest = __rest(args, ["appId", "events"]);
|
|
235
|
+
const response = await request({
|
|
236
|
+
httpMethod: 'POST',
|
|
237
|
+
baseUri: this.apiRootBase,
|
|
238
|
+
relativePath: getAppWebhookEndpoint(appId),
|
|
239
|
+
apiToken: this.authToken,
|
|
240
|
+
customFetch: this.customFetch,
|
|
241
|
+
payload: Object.assign(Object.assign({}, rest), { events: events.map(webhookEventToWireName) }),
|
|
242
|
+
requestId: requestId,
|
|
243
|
+
});
|
|
244
|
+
return validateAppWebhook(response.data);
|
|
245
|
+
}
|
|
246
|
+
async deleteAppWebhook(appId, requestId) {
|
|
247
|
+
z.string().parse(appId);
|
|
248
|
+
const response = await request({
|
|
249
|
+
httpMethod: 'DELETE',
|
|
250
|
+
baseUri: this.apiRootBase,
|
|
251
|
+
relativePath: getAppWebhookEndpoint(appId),
|
|
252
|
+
apiToken: this.authToken,
|
|
253
|
+
customFetch: this.customFetch,
|
|
254
|
+
requestId: requestId,
|
|
255
|
+
});
|
|
256
|
+
return isSuccess(response);
|
|
257
|
+
}
|
|
258
|
+
// --- App installations ---
|
|
259
|
+
async getAppInstallations(requestId) {
|
|
260
|
+
const response = await request({
|
|
261
|
+
httpMethod: 'GET',
|
|
262
|
+
baseUri: this.apiRootBase,
|
|
263
|
+
relativePath: ENDPOINT_REST_APPS_INSTALLATIONS,
|
|
264
|
+
apiToken: this.authToken,
|
|
265
|
+
customFetch: this.customFetch,
|
|
266
|
+
requestId: requestId,
|
|
267
|
+
});
|
|
268
|
+
return validateAppInstallationArray(response.data);
|
|
269
|
+
}
|
|
270
|
+
async installApp(args, requestId) {
|
|
271
|
+
const response = await request({
|
|
272
|
+
httpMethod: 'POST',
|
|
273
|
+
baseUri: this.apiRootBase,
|
|
274
|
+
relativePath: ENDPOINT_REST_APPS_INSTALLATIONS,
|
|
275
|
+
apiToken: this.authToken,
|
|
276
|
+
customFetch: this.customFetch,
|
|
277
|
+
payload: args,
|
|
278
|
+
requestId: requestId,
|
|
279
|
+
});
|
|
280
|
+
return validateAppInstallation(response.data);
|
|
281
|
+
}
|
|
282
|
+
async getAppInstallation(installationId, requestId) {
|
|
283
|
+
z.string().parse(installationId);
|
|
284
|
+
const response = await request({
|
|
285
|
+
httpMethod: 'GET',
|
|
286
|
+
baseUri: this.apiRootBase,
|
|
287
|
+
relativePath: getAppInstallationEndpoint(installationId),
|
|
288
|
+
apiToken: this.authToken,
|
|
289
|
+
customFetch: this.customFetch,
|
|
290
|
+
requestId: requestId,
|
|
291
|
+
});
|
|
292
|
+
return validateAppInstallation(response.data);
|
|
293
|
+
}
|
|
294
|
+
async updateAppInstallation(installationId, args, requestId) {
|
|
295
|
+
z.string().parse(installationId);
|
|
296
|
+
const response = await request({
|
|
297
|
+
httpMethod: 'POST',
|
|
298
|
+
baseUri: this.apiRootBase,
|
|
299
|
+
relativePath: getAppInstallationEndpoint(installationId),
|
|
300
|
+
apiToken: this.authToken,
|
|
301
|
+
customFetch: this.customFetch,
|
|
302
|
+
payload: args,
|
|
303
|
+
requestId: requestId,
|
|
304
|
+
});
|
|
305
|
+
return validateAppInstallation(response.data);
|
|
306
|
+
}
|
|
307
|
+
async uninstallApp(installationId, requestId) {
|
|
308
|
+
z.string().parse(installationId);
|
|
309
|
+
const response = await request({
|
|
310
|
+
httpMethod: 'DELETE',
|
|
311
|
+
baseUri: this.apiRootBase,
|
|
312
|
+
relativePath: getAppInstallationEndpoint(installationId),
|
|
313
|
+
apiToken: this.authToken,
|
|
314
|
+
customFetch: this.customFetch,
|
|
315
|
+
requestId: requestId,
|
|
316
|
+
});
|
|
317
|
+
return isSuccess(response);
|
|
318
|
+
}
|
|
319
|
+
// --- User authorizations ---
|
|
320
|
+
async getUserAuthorizations(requestId) {
|
|
321
|
+
const response = await request({
|
|
322
|
+
httpMethod: 'GET',
|
|
323
|
+
baseUri: this.apiRootBase,
|
|
324
|
+
relativePath: ENDPOINT_REST_USER_AUTHORIZATIONS,
|
|
325
|
+
apiToken: this.authToken,
|
|
326
|
+
customFetch: this.customFetch,
|
|
327
|
+
requestId: requestId,
|
|
328
|
+
});
|
|
329
|
+
return validateUserAuthorizationArray(response.data);
|
|
330
|
+
}
|
|
331
|
+
async revokeUserAuthorization(args, requestId) {
|
|
332
|
+
const response = await request({
|
|
333
|
+
httpMethod: 'POST',
|
|
334
|
+
baseUri: this.apiRootBase,
|
|
335
|
+
relativePath: ENDPOINT_REST_USER_AUTHORIZATIONS_DELETE,
|
|
336
|
+
apiToken: this.authToken,
|
|
337
|
+
customFetch: this.customFetch,
|
|
338
|
+
payload: args,
|
|
339
|
+
requestId: requestId,
|
|
340
|
+
});
|
|
341
|
+
return isSuccess(response);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -14,6 +14,7 @@ export class BaseClient {
|
|
|
14
14
|
constructor(context) {
|
|
15
15
|
this.authToken = context.authToken;
|
|
16
16
|
this.syncApiBase = context.syncApiBase;
|
|
17
|
+
this.apiRootBase = new URL('/', context.syncApiBase).toString();
|
|
17
18
|
this.customFetch = context.customFetch;
|
|
18
19
|
}
|
|
19
20
|
get syncContext() {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ENDPOINT_REST_APPS_UI_EXTENSIONS, ENDPOINT_REST_APPS_UI_EXTENSIONS_INSTALLED, getUiExtensionEndpoint, getUiExtensionIconEndpoint, getUiExtensionsByIntegrationEndpoint, } from '../consts/endpoints.js';
|
|
3
|
+
import { isSuccess, request } from '../transport/http-client.js';
|
|
4
|
+
import { camelCaseKeys } from '../utils/case-conversion.js';
|
|
5
|
+
import { uploadMultipartFile } from '../utils/multipart-upload.js';
|
|
6
|
+
import { validateUiExtension, validateUiExtensionArray } from '../utils/validators.js';
|
|
7
|
+
import { BaseClient } from './base-client.js';
|
|
8
|
+
/**
|
|
9
|
+
* Internal sub-client handling all UI-extension endpoints for developer
|
|
10
|
+
* applications. All endpoints require the `dev:app_console` OAuth scope.
|
|
11
|
+
*
|
|
12
|
+
* Instantiated by `TodoistApi`; every public UI-extension method on
|
|
13
|
+
* `TodoistApi` delegates here. See `todoist-api.ts` for user-facing JSDoc.
|
|
14
|
+
*/
|
|
15
|
+
export class UiExtensionClient extends BaseClient {
|
|
16
|
+
async getUiExtension(uiExtensionId, requestId) {
|
|
17
|
+
z.string().parse(uiExtensionId);
|
|
18
|
+
const response = await request({
|
|
19
|
+
httpMethod: 'GET',
|
|
20
|
+
baseUri: this.apiRootBase,
|
|
21
|
+
relativePath: getUiExtensionEndpoint(uiExtensionId),
|
|
22
|
+
apiToken: this.authToken,
|
|
23
|
+
customFetch: this.customFetch,
|
|
24
|
+
requestId: requestId,
|
|
25
|
+
});
|
|
26
|
+
return validateUiExtension(response.data);
|
|
27
|
+
}
|
|
28
|
+
async getInstalledUiExtensions(requestId) {
|
|
29
|
+
const response = await request({
|
|
30
|
+
httpMethod: 'GET',
|
|
31
|
+
baseUri: this.apiRootBase,
|
|
32
|
+
relativePath: ENDPOINT_REST_APPS_UI_EXTENSIONS_INSTALLED,
|
|
33
|
+
apiToken: this.authToken,
|
|
34
|
+
customFetch: this.customFetch,
|
|
35
|
+
requestId: requestId,
|
|
36
|
+
});
|
|
37
|
+
return validateUiExtensionArray(response.data);
|
|
38
|
+
}
|
|
39
|
+
async getUiExtensionsForApp(appId, requestId) {
|
|
40
|
+
z.string().parse(appId);
|
|
41
|
+
const response = await request({
|
|
42
|
+
httpMethod: 'GET',
|
|
43
|
+
baseUri: this.apiRootBase,
|
|
44
|
+
relativePath: getUiExtensionsByIntegrationEndpoint(appId),
|
|
45
|
+
apiToken: this.authToken,
|
|
46
|
+
customFetch: this.customFetch,
|
|
47
|
+
requestId: requestId,
|
|
48
|
+
});
|
|
49
|
+
return validateUiExtensionArray(response.data);
|
|
50
|
+
}
|
|
51
|
+
async addUiExtension(args, requestId) {
|
|
52
|
+
const response = await request({
|
|
53
|
+
httpMethod: 'POST',
|
|
54
|
+
baseUri: this.apiRootBase,
|
|
55
|
+
relativePath: ENDPOINT_REST_APPS_UI_EXTENSIONS,
|
|
56
|
+
apiToken: this.authToken,
|
|
57
|
+
customFetch: this.customFetch,
|
|
58
|
+
payload: args,
|
|
59
|
+
requestId: requestId,
|
|
60
|
+
});
|
|
61
|
+
return validateUiExtension(response.data);
|
|
62
|
+
}
|
|
63
|
+
async updateUiExtension(uiExtensionId, args, requestId) {
|
|
64
|
+
z.string().parse(uiExtensionId);
|
|
65
|
+
const response = await request({
|
|
66
|
+
httpMethod: 'PATCH',
|
|
67
|
+
baseUri: this.apiRootBase,
|
|
68
|
+
relativePath: getUiExtensionEndpoint(uiExtensionId),
|
|
69
|
+
apiToken: this.authToken,
|
|
70
|
+
customFetch: this.customFetch,
|
|
71
|
+
payload: args,
|
|
72
|
+
requestId: requestId,
|
|
73
|
+
});
|
|
74
|
+
return validateUiExtension(response.data);
|
|
75
|
+
}
|
|
76
|
+
async deleteUiExtension(uiExtensionId, requestId) {
|
|
77
|
+
z.string().parse(uiExtensionId);
|
|
78
|
+
const response = await request({
|
|
79
|
+
httpMethod: 'DELETE',
|
|
80
|
+
baseUri: this.apiRootBase,
|
|
81
|
+
relativePath: getUiExtensionEndpoint(uiExtensionId),
|
|
82
|
+
apiToken: this.authToken,
|
|
83
|
+
customFetch: this.customFetch,
|
|
84
|
+
requestId: requestId,
|
|
85
|
+
});
|
|
86
|
+
return isSuccess(response);
|
|
87
|
+
}
|
|
88
|
+
async uploadUiExtensionIcon(args, requestId) {
|
|
89
|
+
var _a;
|
|
90
|
+
if (Buffer.isBuffer(args.file) && args.file.length === 0) {
|
|
91
|
+
throw new Error('Cannot upload empty image file');
|
|
92
|
+
}
|
|
93
|
+
const data = await uploadMultipartFile({
|
|
94
|
+
baseUrl: this.apiRootBase,
|
|
95
|
+
authToken: this.authToken,
|
|
96
|
+
endpoint: getUiExtensionIconEndpoint(args.uiExtensionId),
|
|
97
|
+
file: args.file,
|
|
98
|
+
fileName: args.fileName,
|
|
99
|
+
additionalFields: { file_name: (_a = args.fileName) !== null && _a !== void 0 ? _a : '' },
|
|
100
|
+
requestId: requestId,
|
|
101
|
+
customFetch: this.customFetch,
|
|
102
|
+
});
|
|
103
|
+
return validateUiExtension(camelCaseKeys(data));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -9,6 +9,9 @@ const API_AUTHORIZATION_BASE_URI = '/oauth/';
|
|
|
9
9
|
export function getSyncBaseUri(domainBase = BASE_URI) {
|
|
10
10
|
return new URL(API_BASE_URI, domainBase).toString();
|
|
11
11
|
}
|
|
12
|
+
export function getApiRootBaseUri(domainBase = BASE_URI) {
|
|
13
|
+
return new URL('/', domainBase).toString();
|
|
14
|
+
}
|
|
12
15
|
export function getAuthBaseUri(domainBase = TODOIST_URI) {
|
|
13
16
|
return new URL(API_AUTHORIZATION_BASE_URI, domainBase).toString();
|
|
14
17
|
}
|
|
@@ -67,11 +70,6 @@ export const ENDPOINT_GET_TOKEN = 'access_token';
|
|
|
67
70
|
export const ENDPOINT_REVOKE = 'revoke';
|
|
68
71
|
export const ENDPOINT_REGISTER = 'register';
|
|
69
72
|
export const ENDPOINT_REST_FOLDERS = 'folders';
|
|
70
|
-
export const ENDPOINT_REST_GOALS = 'goals';
|
|
71
|
-
export const ENDPOINT_REST_GOALS_SEARCH = ENDPOINT_REST_GOALS + '/search';
|
|
72
|
-
export const GOAL_COMPLETE = 'complete';
|
|
73
|
-
export const GOAL_UNCOMPLETE = 'uncomplete';
|
|
74
|
-
export const GOAL_TASKS = 'items';
|
|
75
73
|
// Workspace endpoints
|
|
76
74
|
export const ENDPOINT_REST_WORKSPACES = 'workspaces';
|
|
77
75
|
export const ENDPOINT_WORKSPACE_INVITATIONS = 'workspaces/invitations';
|
|
@@ -126,3 +124,54 @@ export function getWorkspaceActiveProjectsEndpoint(workspaceId) {
|
|
|
126
124
|
export function getWorkspaceArchivedProjectsEndpoint(workspaceId) {
|
|
127
125
|
return `workspaces/${workspaceId}/projects/archived`;
|
|
128
126
|
}
|
|
127
|
+
// App management endpoints (dev:app_console scope)
|
|
128
|
+
export const ENDPOINT_REST_APPS = 'apps';
|
|
129
|
+
export const ENDPOINT_REST_APPS_INSTALLATIONS = 'apps/installations';
|
|
130
|
+
export const ENDPOINT_REST_APPS_UI_EXTENSIONS = 'apps/ui_extensions';
|
|
131
|
+
export const ENDPOINT_REST_APPS_UI_EXTENSIONS_INSTALLED = 'apps/ui_extensions/installed';
|
|
132
|
+
export const ENDPOINT_REST_USER_AUTHORIZATIONS = 'user/authorizations';
|
|
133
|
+
export const ENDPOINT_REST_USER_AUTHORIZATIONS_DELETE = 'user/authorizations/delete';
|
|
134
|
+
/** Available app icon sizes (small 60x60, medium 300x300, large 600x600). */
|
|
135
|
+
export const APP_ICON_SIZES = ['small', 'medium', 'large'];
|
|
136
|
+
export function getAppEndpoint(appId) {
|
|
137
|
+
return `apps/${appId}`;
|
|
138
|
+
}
|
|
139
|
+
export function getAppSecretsEndpoint(appId) {
|
|
140
|
+
return `apps/${appId}/secrets`;
|
|
141
|
+
}
|
|
142
|
+
export function getAppClientSecretEndpoint(appId) {
|
|
143
|
+
return `apps/${appId}/client_secret`;
|
|
144
|
+
}
|
|
145
|
+
export function getAppTokensEndpoint(appId) {
|
|
146
|
+
return `apps/${appId}/tokens`;
|
|
147
|
+
}
|
|
148
|
+
export function getAppTestTokenEndpoint(appId) {
|
|
149
|
+
return `apps/${appId}/test_token`;
|
|
150
|
+
}
|
|
151
|
+
export function getAppDistributionTokenEndpoint(appId) {
|
|
152
|
+
return `apps/${appId}/distribution_token`;
|
|
153
|
+
}
|
|
154
|
+
export function getAppVerificationTokenEndpoint(appId) {
|
|
155
|
+
return `apps/${appId}/verification_token`;
|
|
156
|
+
}
|
|
157
|
+
export function getAppWebhookEndpoint(appId) {
|
|
158
|
+
return `apps/${appId}/webhook`;
|
|
159
|
+
}
|
|
160
|
+
export function getAppIconEndpoint(appId, size) {
|
|
161
|
+
return size === 'medium' ? `apps/${appId}/icon` : `apps/${appId}/icon/${size}`;
|
|
162
|
+
}
|
|
163
|
+
export function getAppInstallationEndpoint(installationId) {
|
|
164
|
+
return `apps/installations/${installationId}`;
|
|
165
|
+
}
|
|
166
|
+
export function getAppByDistributionTokenEndpoint(distributionToken) {
|
|
167
|
+
return `apps/by_distribution_token/${distributionToken}`;
|
|
168
|
+
}
|
|
169
|
+
export function getUiExtensionEndpoint(uiExtensionId) {
|
|
170
|
+
return `apps/ui_extensions/${uiExtensionId}`;
|
|
171
|
+
}
|
|
172
|
+
export function getUiExtensionIconEndpoint(uiExtensionId) {
|
|
173
|
+
return `apps/ui_extensions/${uiExtensionId}/icon`;
|
|
174
|
+
}
|
|
175
|
+
export function getUiExtensionsByIntegrationEndpoint(integrationId) {
|
|
176
|
+
return `apps/ui_extensions/integration/${integrationId}`;
|
|
177
|
+
}
|
|
@@ -277,30 +277,81 @@ export const DEFAULT_COLLABORATOR_STATE = {
|
|
|
277
277
|
state: 'active',
|
|
278
278
|
isDeleted: false,
|
|
279
279
|
};
|
|
280
|
-
export const
|
|
281
|
-
export const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
isCompleted: false,
|
|
291
|
-
completedAt: null,
|
|
292
|
-
responsibleUid: null,
|
|
293
|
-
isDeleted: false,
|
|
294
|
-
progress: {
|
|
295
|
-
totalTaskCount: 5,
|
|
296
|
-
completedTaskCount: 2,
|
|
297
|
-
percentage: 40,
|
|
298
|
-
},
|
|
299
|
-
creatorUid: DEFAULT_USER_ID,
|
|
280
|
+
export const DEFAULT_APP_ID = '42';
|
|
281
|
+
export const DEFAULT_INSTALLATION_ID = '1001';
|
|
282
|
+
export const DEFAULT_UI_EXTENSION_ID = '2002';
|
|
283
|
+
export const DEFAULT_DISTRIBUTION_TOKEN = 'dist-token-abc';
|
|
284
|
+
export const DEFAULT_ACCESS_TOKEN_ID = '3003';
|
|
285
|
+
export const DEFAULT_APP = {
|
|
286
|
+
id: DEFAULT_APP_ID,
|
|
287
|
+
status: 'public',
|
|
288
|
+
displayName: 'Sample App',
|
|
289
|
+
userId: DEFAULT_USER_ID,
|
|
300
290
|
createdAt: defaultDate(),
|
|
301
|
-
|
|
291
|
+
serviceUrl: 'https://example.com',
|
|
292
|
+
oauthRedirectUri: 'https://example.com/callback',
|
|
293
|
+
description: 'A sample app',
|
|
294
|
+
iconSm: 'https://example.com/icon-sm.png',
|
|
295
|
+
iconMd: 'https://example.com/icon-md.png',
|
|
296
|
+
iconLg: 'https://example.com/icon-lg.png',
|
|
297
|
+
appTokenScopes: ['data:read', 'task:add'],
|
|
298
|
+
};
|
|
299
|
+
export const DEFAULT_APP_WITH_USER_COUNT = Object.assign(Object.assign({}, DEFAULT_APP), { userCount: 12 });
|
|
300
|
+
export const DEFAULT_APP_SECRETS = {
|
|
301
|
+
clientId: 'client-id-xyz',
|
|
302
|
+
clientSecret: 'client-secret-xyz',
|
|
303
|
+
};
|
|
304
|
+
export const DEFAULT_APP_VERIFICATION_TOKEN = {
|
|
305
|
+
verificationToken: 'verif-token-abc',
|
|
306
|
+
};
|
|
307
|
+
export const DEFAULT_APP_TEST_TOKEN = {
|
|
308
|
+
accessToken: 'test-token-xyz',
|
|
309
|
+
};
|
|
310
|
+
export const DEFAULT_APP_DISTRIBUTION_TOKEN = {
|
|
311
|
+
distributionToken: DEFAULT_DISTRIBUTION_TOKEN,
|
|
312
|
+
};
|
|
313
|
+
export const DEFAULT_APP_WEBHOOK = {
|
|
314
|
+
status: 'active',
|
|
315
|
+
callbackUrl: 'https://example.com/webhook',
|
|
316
|
+
version: '1',
|
|
317
|
+
events: ['item:added', 'item:completed'],
|
|
318
|
+
};
|
|
319
|
+
export const DEFAULT_APP_INSTALLATION = {
|
|
320
|
+
id: DEFAULT_INSTALLATION_ID,
|
|
321
|
+
creator: DEFAULT_USER_ID,
|
|
322
|
+
createdTs: 1700000000,
|
|
323
|
+
installationType: 'user',
|
|
324
|
+
appTokenScopesValidated: true,
|
|
325
|
+
integration: DEFAULT_APP,
|
|
326
|
+
};
|
|
327
|
+
export const DEFAULT_USER_AUTHORIZATION = {
|
|
328
|
+
accessTokenId: DEFAULT_ACCESS_TOKEN_ID,
|
|
329
|
+
scope: ['data:read', 'task:add'],
|
|
330
|
+
scopeDescriptions: ['Read data', 'Add tasks'],
|
|
331
|
+
createdAt: new Date('2025-01-01T00:00:00Z'),
|
|
332
|
+
app: {
|
|
333
|
+
id: DEFAULT_APP_ID,
|
|
334
|
+
displayName: 'Sample App',
|
|
335
|
+
description: 'A sample app',
|
|
336
|
+
serviceUrl: 'https://example.com',
|
|
337
|
+
iconMd: 'https://example.com/icon-md.png',
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
export const DEFAULT_UI_EXTENSION = {
|
|
341
|
+
id: DEFAULT_UI_EXTENSION_ID,
|
|
342
|
+
integrationId: DEFAULT_APP_ID,
|
|
343
|
+
extensionId: 'ext-guid-1',
|
|
344
|
+
extensionType: 'context-menu',
|
|
345
|
+
contextType: 'task',
|
|
346
|
+
url: 'https://example.com/extension',
|
|
347
|
+
icon: 'https://example.com/icon.png',
|
|
348
|
+
name: 'My Extension',
|
|
349
|
+
description: 'Does things in the task context menu',
|
|
350
|
+
width: 400,
|
|
351
|
+
height: 600,
|
|
352
|
+
defVersion: 2,
|
|
353
|
+
minimumCardistVersion: '0.60',
|
|
302
354
|
};
|
|
303
|
-
export const DEFAULT_GOAL_NO_PROGRESS = Object.assign(Object.assign({}, DEFAULT_GOAL), { id: 'e5f6g7h8-e29b-41d4-a716-446655440001', progress: undefined });
|
|
304
355
|
export const DEFAULT_NOTE = {
|
|
305
356
|
id: DEFAULT_COMMENT_ID,
|
|
306
357
|
projectId: DEFAULT_PROJECT_ID,
|