@bobfrankston/gcal 0.1.45 → 0.1.47
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 +150 -92
- package/gcal.js +145 -121
- package/gcal.js.map +1 -1
- package/gcal.ts +155 -137
- package/glib/goauth.d.ts +13 -0
- package/glib/goauth.d.ts.map +1 -0
- package/glib/goauth.js +70 -0
- package/glib/goauth.js.map +1 -0
- package/glib/goauth.ts +93 -0
- package/glib/tasksapi.d.ts +23 -0
- package/glib/tasksapi.d.ts.map +1 -0
- package/glib/tasksapi.js +113 -0
- package/glib/tasksapi.js.map +1 -0
- package/glib/tasksapi.ts +155 -0
- package/glib/tasktypes.d.ts +47 -0
- package/glib/tasktypes.d.ts.map +1 -0
- package/glib/tasktypes.js +6 -0
- package/glib/tasktypes.js.map +1 -0
- package/glib/tasktypes.ts +51 -0
- package/gtask.d.ts +7 -0
- package/gtask.d.ts.map +1 -0
- package/gtask.js +429 -0
- package/gtask.js.map +1 -0
- package/gtask.ts +459 -0
- package/package.json +8 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goauth.js","sourceRoot":"","sources":["goauth.ts"],"names":[],"mappings":"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"}
|
package/glib/goauth.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared OAuth + HTTP plumbing for gcal and gtask.
|
|
3
|
+
*
|
|
4
|
+
* Both CLIs request the same combined scope set (Calendar + Tasks) so a single
|
|
5
|
+
* consent and a single token file pair (read / write) covers both tools.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { authenticateOAuth } from '@bobfrankston/oauthsupport';
|
|
11
|
+
import { CREDENTIALS_FILE, getUserPaths, ensureUserDir, ts } from './gutils.js';
|
|
12
|
+
|
|
13
|
+
export const SCOPE_READ =
|
|
14
|
+
'https://www.googleapis.com/auth/calendar.readonly '
|
|
15
|
+
+ 'https://www.googleapis.com/auth/tasks.readonly';
|
|
16
|
+
|
|
17
|
+
export const SCOPE_WRITE =
|
|
18
|
+
'https://www.googleapis.com/auth/calendar '
|
|
19
|
+
+ 'https://www.googleapis.com/auth/tasks';
|
|
20
|
+
|
|
21
|
+
let abortController: AbortController | null = null;
|
|
22
|
+
|
|
23
|
+
export function setupAbortHandler(): AbortController {
|
|
24
|
+
abortController = new AbortController();
|
|
25
|
+
let ctrlCCount = 0;
|
|
26
|
+
process.on('SIGINT', () => {
|
|
27
|
+
ctrlCCount++;
|
|
28
|
+
abortController?.abort();
|
|
29
|
+
if (ctrlCCount >= 2) {
|
|
30
|
+
console.log('\n\nForce exit.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
console.log('\n\nCtrl+C pressed - aborting... (press again to force exit)');
|
|
34
|
+
});
|
|
35
|
+
return abortController;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getAbortController(): AbortController | null {
|
|
39
|
+
return abortController;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function getAccessToken(
|
|
43
|
+
user: string,
|
|
44
|
+
writeAccess = false,
|
|
45
|
+
forceRefresh = false
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
if (!fs.existsSync(CREDENTIALS_FILE)) {
|
|
48
|
+
console.error(`\nCredentials file not found: ${CREDENTIALS_FILE}\n`);
|
|
49
|
+
console.error(`gcal/gtask use the same credentials as gcards.`);
|
|
50
|
+
console.error(`Make sure gcards is set up with OAuth credentials first.`);
|
|
51
|
+
console.error(`See: https://github.com/BobFrankston/oauthsupport/blob/master/SETUP-GOOGLE-OAUTH.md`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const paths = getUserPaths(user);
|
|
56
|
+
ensureUserDir(user);
|
|
57
|
+
|
|
58
|
+
const scope = writeAccess ? SCOPE_WRITE : SCOPE_READ;
|
|
59
|
+
const tokenFileName = writeAccess ? 'token-write.json' : 'token.json';
|
|
60
|
+
const tokenFilePath = path.join(paths.userDir, tokenFileName);
|
|
61
|
+
|
|
62
|
+
if (forceRefresh && fs.existsSync(tokenFilePath)) {
|
|
63
|
+
fs.unlinkSync(tokenFilePath);
|
|
64
|
+
console.log(`${ts()} Token expired, refreshing...`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const token = await authenticateOAuth(CREDENTIALS_FILE, {
|
|
68
|
+
scope,
|
|
69
|
+
tokenDirectory: paths.userDir,
|
|
70
|
+
tokenFileName,
|
|
71
|
+
credentialsKey: 'installed',
|
|
72
|
+
signal: abortController?.signal
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!token) {
|
|
76
|
+
throw new Error('OAuth authentication failed');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return token.access_token;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function apiFetch(
|
|
83
|
+
url: string,
|
|
84
|
+
accessToken: string,
|
|
85
|
+
options: RequestInit = {}
|
|
86
|
+
): Promise<Response> {
|
|
87
|
+
const headers = {
|
|
88
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
...options.headers
|
|
91
|
+
};
|
|
92
|
+
return fetch(url, { ...options, headers });
|
|
93
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Tasks API wrapper. Mirrors the calendar API helpers in gcal.ts.
|
|
3
|
+
*/
|
|
4
|
+
import type { Task, TaskList } from './tasktypes.js';
|
|
5
|
+
export declare function listTaskLists(accessToken: string): Promise<TaskList[]>;
|
|
6
|
+
export interface ListTasksOptions {
|
|
7
|
+
showCompleted?: boolean;
|
|
8
|
+
showHidden?: boolean;
|
|
9
|
+
dueMin?: string; /** RFC3339 */
|
|
10
|
+
dueMax?: string;
|
|
11
|
+
completedMin?: string;
|
|
12
|
+
completedMax?: string;
|
|
13
|
+
maxResults?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function listTasks(accessToken: string, tasklistId?: string, opts?: ListTasksOptions): Promise<Task[]>;
|
|
16
|
+
export declare function createTask(accessToken: string, task: Task, tasklistId?: string): Promise<Task>;
|
|
17
|
+
export declare function patchTask(accessToken: string, taskId: string, patch: Partial<Task>, tasklistId?: string): Promise<Task>;
|
|
18
|
+
export declare function deleteTask(accessToken: string, taskId: string, tasklistId?: string): Promise<void>;
|
|
19
|
+
export declare function moveTask(accessToken: string, taskId: string, fromListId: string, toListId?: string, parent?: string, previous?: string): Promise<Task>;
|
|
20
|
+
export declare function clearCompleted(accessToken: string, tasklistId?: string): Promise<void>;
|
|
21
|
+
/** Resolve a tasklist by name, id, or '@default'. Case-insensitive title match. */
|
|
22
|
+
export declare function resolveTaskList(accessToken: string, nameOrId: string): Promise<TaskList>;
|
|
23
|
+
//# sourceMappingURL=tasksapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasksapi.d.ts","sourceRoot":"","sources":["tasksapi.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAoC,MAAM,gBAAgB,CAAC;AAIvF,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAQ5E;AAED,MAAM,WAAW,gBAAgB;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,CAAO,cAAc;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,SAAS,CAC3B,WAAW,EAAE,MAAM,EACnB,UAAU,SAAa,EACvB,IAAI,GAAE,gBAAqB,GAC5B,OAAO,CAAC,IAAI,EAAE,CAAC,CAkBjB;AAED,wBAAsB,UAAU,CAC5B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,IAAI,EACV,UAAU,SAAa,GACxB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,SAAS,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,EACpB,UAAU,SAAa,GACxB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,UAAU,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,UAAU,SAAa,GACxB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,QAAQ,CAC1B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,cAAc,CAChC,WAAW,EAAE,MAAM,EACnB,UAAU,SAAa,GACxB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,mFAAmF;AACnF,wBAAsB,eAAe,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,CAAC,CAcnB"}
|
package/glib/tasksapi.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Tasks API wrapper. Mirrors the calendar API helpers in gcal.ts.
|
|
3
|
+
*/
|
|
4
|
+
import { apiFetch } from './goauth.js';
|
|
5
|
+
const TASKS_API_BASE = 'https://tasks.googleapis.com/tasks/v1';
|
|
6
|
+
export async function listTaskLists(accessToken) {
|
|
7
|
+
const url = `${TASKS_API_BASE}/users/@me/lists?maxResults=100`;
|
|
8
|
+
const res = await apiFetch(url, accessToken);
|
|
9
|
+
if (!res.ok) {
|
|
10
|
+
throw new Error(`Failed to list tasklists: ${res.status} ${res.statusText}`);
|
|
11
|
+
}
|
|
12
|
+
const data = await res.json();
|
|
13
|
+
return data.items || [];
|
|
14
|
+
}
|
|
15
|
+
export async function listTasks(accessToken, tasklistId = '@default', opts = {}) {
|
|
16
|
+
const params = new URLSearchParams({
|
|
17
|
+
maxResults: String(opts.maxResults ?? 100),
|
|
18
|
+
showCompleted: String(opts.showCompleted ?? false),
|
|
19
|
+
showHidden: String(opts.showHidden ?? false)
|
|
20
|
+
});
|
|
21
|
+
if (opts.dueMin)
|
|
22
|
+
params.set('dueMin', opts.dueMin);
|
|
23
|
+
if (opts.dueMax)
|
|
24
|
+
params.set('dueMax', opts.dueMax);
|
|
25
|
+
if (opts.completedMin)
|
|
26
|
+
params.set('completedMin', opts.completedMin);
|
|
27
|
+
if (opts.completedMax)
|
|
28
|
+
params.set('completedMax', opts.completedMax);
|
|
29
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks?${params}`;
|
|
30
|
+
const res = await apiFetch(url, accessToken);
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw new Error(`Failed to list tasks: ${res.status} ${res.statusText}`);
|
|
33
|
+
}
|
|
34
|
+
const data = await res.json();
|
|
35
|
+
return data.items || [];
|
|
36
|
+
}
|
|
37
|
+
export async function createTask(accessToken, task, tasklistId = '@default') {
|
|
38
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks`;
|
|
39
|
+
const res = await apiFetch(url, accessToken, {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
body: JSON.stringify(task)
|
|
42
|
+
});
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
const errText = await res.text();
|
|
45
|
+
throw new Error(`Failed to create task: ${res.status} ${errText}`);
|
|
46
|
+
}
|
|
47
|
+
return await res.json();
|
|
48
|
+
}
|
|
49
|
+
export async function patchTask(accessToken, taskId, patch, tasklistId = '@default') {
|
|
50
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks/${encodeURIComponent(taskId)}`;
|
|
51
|
+
const res = await apiFetch(url, accessToken, {
|
|
52
|
+
method: 'PATCH',
|
|
53
|
+
body: JSON.stringify(patch)
|
|
54
|
+
});
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
const errText = await res.text();
|
|
57
|
+
throw new Error(`Failed to update task: ${res.status} ${errText}`);
|
|
58
|
+
}
|
|
59
|
+
return await res.json();
|
|
60
|
+
}
|
|
61
|
+
export async function deleteTask(accessToken, taskId, tasklistId = '@default') {
|
|
62
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks/${encodeURIComponent(taskId)}`;
|
|
63
|
+
const res = await apiFetch(url, accessToken, { method: 'DELETE' });
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const errText = await res.text();
|
|
66
|
+
throw new Error(`Failed to delete task: ${res.status} ${errText}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function moveTask(accessToken, taskId, fromListId, toListId, parent, previous) {
|
|
70
|
+
const params = new URLSearchParams();
|
|
71
|
+
if (toListId)
|
|
72
|
+
params.set('destinationTasklist', toListId);
|
|
73
|
+
if (parent)
|
|
74
|
+
params.set('parent', parent);
|
|
75
|
+
if (previous)
|
|
76
|
+
params.set('previous', previous);
|
|
77
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(fromListId)}/tasks/${encodeURIComponent(taskId)}/move`
|
|
78
|
+
+ (params.toString() ? `?${params}` : '');
|
|
79
|
+
const res = await apiFetch(url, accessToken, { method: 'POST' });
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
const errText = await res.text();
|
|
82
|
+
throw new Error(`Failed to move task: ${res.status} ${errText}`);
|
|
83
|
+
}
|
|
84
|
+
return await res.json();
|
|
85
|
+
}
|
|
86
|
+
export async function clearCompleted(accessToken, tasklistId = '@default') {
|
|
87
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/clear`;
|
|
88
|
+
const res = await apiFetch(url, accessToken, { method: 'POST' });
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
const errText = await res.text();
|
|
91
|
+
throw new Error(`Failed to clear completed: ${res.status} ${errText}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Resolve a tasklist by name, id, or '@default'. Case-insensitive title match. */
|
|
95
|
+
export async function resolveTaskList(accessToken, nameOrId) {
|
|
96
|
+
if (!nameOrId || nameOrId === '@default') {
|
|
97
|
+
const lists = await listTaskLists(accessToken);
|
|
98
|
+
const def = lists[0];
|
|
99
|
+
if (!def)
|
|
100
|
+
throw new Error('No tasklists found');
|
|
101
|
+
return def;
|
|
102
|
+
}
|
|
103
|
+
const lists = await listTaskLists(accessToken);
|
|
104
|
+
const lower = nameOrId.toLowerCase();
|
|
105
|
+
const byTitle = lists.find(l => (l.title || '').toLowerCase() === lower);
|
|
106
|
+
if (byTitle)
|
|
107
|
+
return byTitle;
|
|
108
|
+
const byId = lists.find(l => l.id === nameOrId);
|
|
109
|
+
if (byId)
|
|
110
|
+
return byId;
|
|
111
|
+
throw new Error(`Tasklist not found: ${nameOrId}`);
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=tasksapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasksapi.js","sourceRoot":"","sources":["tasksapi.ts"],"names":[],"mappings":"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"}
|
package/glib/tasksapi.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Tasks API wrapper. Mirrors the calendar API helpers in gcal.ts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { apiFetch } from './goauth.js';
|
|
6
|
+
import type { Task, TaskList, TasksResponse, TaskListsResponse } from './tasktypes.js';
|
|
7
|
+
|
|
8
|
+
const TASKS_API_BASE = 'https://tasks.googleapis.com/tasks/v1';
|
|
9
|
+
|
|
10
|
+
export async function listTaskLists(accessToken: string): Promise<TaskList[]> {
|
|
11
|
+
const url = `${TASKS_API_BASE}/users/@me/lists?maxResults=100`;
|
|
12
|
+
const res = await apiFetch(url, accessToken);
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
throw new Error(`Failed to list tasklists: ${res.status} ${res.statusText}`);
|
|
15
|
+
}
|
|
16
|
+
const data = await res.json() as TaskListsResponse;
|
|
17
|
+
return data.items || [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ListTasksOptions {
|
|
21
|
+
showCompleted?: boolean;
|
|
22
|
+
showHidden?: boolean;
|
|
23
|
+
dueMin?: string; /** RFC3339 */
|
|
24
|
+
dueMax?: string;
|
|
25
|
+
completedMin?: string;
|
|
26
|
+
completedMax?: string;
|
|
27
|
+
maxResults?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function listTasks(
|
|
31
|
+
accessToken: string,
|
|
32
|
+
tasklistId = '@default',
|
|
33
|
+
opts: ListTasksOptions = {}
|
|
34
|
+
): Promise<Task[]> {
|
|
35
|
+
const params = new URLSearchParams({
|
|
36
|
+
maxResults: String(opts.maxResults ?? 100),
|
|
37
|
+
showCompleted: String(opts.showCompleted ?? false),
|
|
38
|
+
showHidden: String(opts.showHidden ?? false)
|
|
39
|
+
});
|
|
40
|
+
if (opts.dueMin) params.set('dueMin', opts.dueMin);
|
|
41
|
+
if (opts.dueMax) params.set('dueMax', opts.dueMax);
|
|
42
|
+
if (opts.completedMin) params.set('completedMin', opts.completedMin);
|
|
43
|
+
if (opts.completedMax) params.set('completedMax', opts.completedMax);
|
|
44
|
+
|
|
45
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks?${params}`;
|
|
46
|
+
const res = await apiFetch(url, accessToken);
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
throw new Error(`Failed to list tasks: ${res.status} ${res.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
const data = await res.json() as TasksResponse;
|
|
51
|
+
return data.items || [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function createTask(
|
|
55
|
+
accessToken: string,
|
|
56
|
+
task: Task,
|
|
57
|
+
tasklistId = '@default'
|
|
58
|
+
): Promise<Task> {
|
|
59
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks`;
|
|
60
|
+
const res = await apiFetch(url, accessToken, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
body: JSON.stringify(task)
|
|
63
|
+
});
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const errText = await res.text();
|
|
66
|
+
throw new Error(`Failed to create task: ${res.status} ${errText}`);
|
|
67
|
+
}
|
|
68
|
+
return await res.json() as Task;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function patchTask(
|
|
72
|
+
accessToken: string,
|
|
73
|
+
taskId: string,
|
|
74
|
+
patch: Partial<Task>,
|
|
75
|
+
tasklistId = '@default'
|
|
76
|
+
): Promise<Task> {
|
|
77
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks/${encodeURIComponent(taskId)}`;
|
|
78
|
+
const res = await apiFetch(url, accessToken, {
|
|
79
|
+
method: 'PATCH',
|
|
80
|
+
body: JSON.stringify(patch)
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
const errText = await res.text();
|
|
84
|
+
throw new Error(`Failed to update task: ${res.status} ${errText}`);
|
|
85
|
+
}
|
|
86
|
+
return await res.json() as Task;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function deleteTask(
|
|
90
|
+
accessToken: string,
|
|
91
|
+
taskId: string,
|
|
92
|
+
tasklistId = '@default'
|
|
93
|
+
): Promise<void> {
|
|
94
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/tasks/${encodeURIComponent(taskId)}`;
|
|
95
|
+
const res = await apiFetch(url, accessToken, { method: 'DELETE' });
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const errText = await res.text();
|
|
98
|
+
throw new Error(`Failed to delete task: ${res.status} ${errText}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function moveTask(
|
|
103
|
+
accessToken: string,
|
|
104
|
+
taskId: string,
|
|
105
|
+
fromListId: string,
|
|
106
|
+
toListId?: string,
|
|
107
|
+
parent?: string,
|
|
108
|
+
previous?: string
|
|
109
|
+
): Promise<Task> {
|
|
110
|
+
const params = new URLSearchParams();
|
|
111
|
+
if (toListId) params.set('destinationTasklist', toListId);
|
|
112
|
+
if (parent) params.set('parent', parent);
|
|
113
|
+
if (previous) params.set('previous', previous);
|
|
114
|
+
|
|
115
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(fromListId)}/tasks/${encodeURIComponent(taskId)}/move`
|
|
116
|
+
+ (params.toString() ? `?${params}` : '');
|
|
117
|
+
const res = await apiFetch(url, accessToken, { method: 'POST' });
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
const errText = await res.text();
|
|
120
|
+
throw new Error(`Failed to move task: ${res.status} ${errText}`);
|
|
121
|
+
}
|
|
122
|
+
return await res.json() as Task;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export async function clearCompleted(
|
|
126
|
+
accessToken: string,
|
|
127
|
+
tasklistId = '@default'
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
const url = `${TASKS_API_BASE}/lists/${encodeURIComponent(tasklistId)}/clear`;
|
|
130
|
+
const res = await apiFetch(url, accessToken, { method: 'POST' });
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const errText = await res.text();
|
|
133
|
+
throw new Error(`Failed to clear completed: ${res.status} ${errText}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Resolve a tasklist by name, id, or '@default'. Case-insensitive title match. */
|
|
138
|
+
export async function resolveTaskList(
|
|
139
|
+
accessToken: string,
|
|
140
|
+
nameOrId: string
|
|
141
|
+
): Promise<TaskList> {
|
|
142
|
+
if (!nameOrId || nameOrId === '@default') {
|
|
143
|
+
const lists = await listTaskLists(accessToken);
|
|
144
|
+
const def = lists[0];
|
|
145
|
+
if (!def) throw new Error('No tasklists found');
|
|
146
|
+
return def;
|
|
147
|
+
}
|
|
148
|
+
const lists = await listTaskLists(accessToken);
|
|
149
|
+
const lower = nameOrId.toLowerCase();
|
|
150
|
+
const byTitle = lists.find(l => (l.title || '').toLowerCase() === lower);
|
|
151
|
+
if (byTitle) return byTitle;
|
|
152
|
+
const byId = lists.find(l => l.id === nameOrId);
|
|
153
|
+
if (byId) return byId;
|
|
154
|
+
throw new Error(`Tasklist not found: ${nameOrId}`);
|
|
155
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Tasks API types.
|
|
3
|
+
* https://developers.google.com/tasks/reference/rest
|
|
4
|
+
*/
|
|
5
|
+
export interface TaskList {
|
|
6
|
+
kind?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
etag?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
updated?: string;
|
|
11
|
+
selfLink?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface TaskListsResponse {
|
|
14
|
+
kind?: string;
|
|
15
|
+
etag?: string;
|
|
16
|
+
nextPageToken?: string;
|
|
17
|
+
items?: TaskList[];
|
|
18
|
+
}
|
|
19
|
+
export interface TaskLink {
|
|
20
|
+
type?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
link?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface Task {
|
|
25
|
+
kind?: string;
|
|
26
|
+
id?: string;
|
|
27
|
+
etag?: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
updated?: string;
|
|
30
|
+
selfLink?: string;
|
|
31
|
+
parent?: string;
|
|
32
|
+
position?: string;
|
|
33
|
+
notes?: string;
|
|
34
|
+
status?: 'needsAction' | 'completed';
|
|
35
|
+
due?: string; /** RFC3339 — date-only in practice; time component is ignored by the UI. */
|
|
36
|
+
completed?: string; /** RFC3339 timestamp, set when status='completed'. */
|
|
37
|
+
deleted?: boolean;
|
|
38
|
+
hidden?: boolean;
|
|
39
|
+
links?: TaskLink[];
|
|
40
|
+
}
|
|
41
|
+
export interface TasksResponse {
|
|
42
|
+
kind?: string;
|
|
43
|
+
etag?: string;
|
|
44
|
+
nextPageToken?: string;
|
|
45
|
+
items?: Task[];
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=tasktypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasktypes.d.ts","sourceRoot":"","sources":["tasktypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,QAAQ;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAQ,4EAA4E;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC,CAAE,sDAAsD;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasktypes.js","sourceRoot":"","sources":["tasktypes.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Tasks API types.
|
|
3
|
+
* https://developers.google.com/tasks/reference/rest
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface TaskList {
|
|
7
|
+
kind?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
etag?: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
updated?: string;
|
|
12
|
+
selfLink?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TaskListsResponse {
|
|
16
|
+
kind?: string;
|
|
17
|
+
etag?: string;
|
|
18
|
+
nextPageToken?: string;
|
|
19
|
+
items?: TaskList[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TaskLink {
|
|
23
|
+
type?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
link?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Task {
|
|
29
|
+
kind?: string;
|
|
30
|
+
id?: string;
|
|
31
|
+
etag?: string;
|
|
32
|
+
title?: string;
|
|
33
|
+
updated?: string;
|
|
34
|
+
selfLink?: string;
|
|
35
|
+
parent?: string;
|
|
36
|
+
position?: string;
|
|
37
|
+
notes?: string;
|
|
38
|
+
status?: 'needsAction' | 'completed';
|
|
39
|
+
due?: string; /** RFC3339 — date-only in practice; time component is ignored by the UI. */
|
|
40
|
+
completed?: string; /** RFC3339 timestamp, set when status='completed'. */
|
|
41
|
+
deleted?: boolean;
|
|
42
|
+
hidden?: boolean;
|
|
43
|
+
links?: TaskLink[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface TasksResponse {
|
|
47
|
+
kind?: string;
|
|
48
|
+
etag?: string;
|
|
49
|
+
nextPageToken?: string;
|
|
50
|
+
items?: Task[];
|
|
51
|
+
}
|
package/gtask.d.ts
ADDED
package/gtask.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtask.d.ts","sourceRoot":"","sources":["gtask.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|