@doist/todoist-cli 1.1.2
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 +76 -0
- package/dist/commands/activity.d.ts +3 -0
- package/dist/commands/activity.d.ts.map +1 -0
- package/dist/commands/activity.js +193 -0
- package/dist/commands/activity.js.map +1 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +28 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +62 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/comment.d.ts +3 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +251 -0
- package/dist/commands/comment.js.map +1 -0
- package/dist/commands/completed.d.ts +3 -0
- package/dist/commands/completed.d.ts.map +1 -0
- package/dist/commands/completed.js +74 -0
- package/dist/commands/completed.js.map +1 -0
- package/dist/commands/filter.d.ts +3 -0
- package/dist/commands/filter.d.ts.map +1 -0
- package/dist/commands/filter.js +249 -0
- package/dist/commands/filter.js.map +1 -0
- package/dist/commands/inbox.d.ts +3 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +23 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/label.d.ts +3 -0
- package/dist/commands/label.d.ts.map +1 -0
- package/dist/commands/label.js +196 -0
- package/dist/commands/label.js.map +1 -0
- package/dist/commands/notification.d.ts +3 -0
- package/dist/commands/notification.d.ts.map +1 -0
- package/dist/commands/notification.js +274 -0
- package/dist/commands/notification.js.map +1 -0
- package/dist/commands/project.d.ts +3 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +364 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/reminder.d.ts +3 -0
- package/dist/commands/reminder.d.ts.map +1 -0
- package/dist/commands/reminder.js +225 -0
- package/dist/commands/reminder.js.map +1 -0
- package/dist/commands/section.d.ts +3 -0
- package/dist/commands/section.d.ts.map +1 -0
- package/dist/commands/section.js +138 -0
- package/dist/commands/section.js.map +1 -0
- package/dist/commands/settings.d.ts +3 -0
- package/dist/commands/settings.d.ts.map +1 -0
- package/dist/commands/settings.js +250 -0
- package/dist/commands/settings.js.map +1 -0
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +151 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/task.d.ts +3 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +363 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/today.d.ts +3 -0
- package/dist/commands/today.d.ts.map +1 -0
- package/dist/commands/today.js +97 -0
- package/dist/commands/today.js.map +1 -0
- package/dist/commands/upcoming.d.ts +3 -0
- package/dist/commands/upcoming.d.ts.map +1 -0
- package/dist/commands/upcoming.js +121 -0
- package/dist/commands/upcoming.js.map +1 -0
- package/dist/commands/workspace.d.ts +3 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +289 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api/core.d.ts +40 -0
- package/dist/lib/api/core.d.ts.map +1 -0
- package/dist/lib/api/core.js +142 -0
- package/dist/lib/api/core.js.map +1 -0
- package/dist/lib/api/filters.d.ts +26 -0
- package/dist/lib/api/filters.d.ts.map +1 -0
- package/dist/lib/api/filters.js +86 -0
- package/dist/lib/api/filters.js.map +1 -0
- package/dist/lib/api/notifications.d.ts +33 -0
- package/dist/lib/api/notifications.d.ts.map +1 -0
- package/dist/lib/api/notifications.js +112 -0
- package/dist/lib/api/notifications.js.map +1 -0
- package/dist/lib/api/reminders.d.ts +30 -0
- package/dist/lib/api/reminders.d.ts.map +1 -0
- package/dist/lib/api/reminders.js +79 -0
- package/dist/lib/api/reminders.js.map +1 -0
- package/dist/lib/api/stats.d.ts +41 -0
- package/dist/lib/api/stats.d.ts.map +1 -0
- package/dist/lib/api/stats.js +79 -0
- package/dist/lib/api/stats.js.map +1 -0
- package/dist/lib/api/uploads.d.ts +10 -0
- package/dist/lib/api/uploads.d.ts.map +1 -0
- package/dist/lib/api/uploads.js +31 -0
- package/dist/lib/api/uploads.js.map +1 -0
- package/dist/lib/api/user-settings.d.ts +33 -0
- package/dist/lib/api/user-settings.d.ts.map +1 -0
- package/dist/lib/api/user-settings.js +90 -0
- package/dist/lib/api/user-settings.js.map +1 -0
- package/dist/lib/api/workspaces.d.ts +23 -0
- package/dist/lib/api/workspaces.d.ts.map +1 -0
- package/dist/lib/api/workspaces.js +67 -0
- package/dist/lib/api/workspaces.js.map +1 -0
- package/dist/lib/auth.d.ts +4 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +66 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/browser.d.ts +2 -0
- package/dist/lib/browser.d.ts.map +1 -0
- package/dist/lib/browser.js +6 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/collaborators.d.ts +29 -0
- package/dist/lib/collaborators.d.ts.map +1 -0
- package/dist/lib/collaborators.js +184 -0
- package/dist/lib/collaborators.js.map +1 -0
- package/dist/lib/dates.d.ts +3 -0
- package/dist/lib/dates.d.ts.map +1 -0
- package/dist/lib/dates.js +20 -0
- package/dist/lib/dates.js.map +1 -0
- package/dist/lib/duration.d.ts +14 -0
- package/dist/lib/duration.d.ts.map +1 -0
- package/dist/lib/duration.js +58 -0
- package/dist/lib/duration.js.map +1 -0
- package/dist/lib/markdown.d.ts +2 -0
- package/dist/lib/markdown.d.ts.map +1 -0
- package/dist/lib/markdown.js +14 -0
- package/dist/lib/markdown.js.map +1 -0
- package/dist/lib/oauth-server.d.ts +6 -0
- package/dist/lib/oauth-server.d.ts.map +1 -0
- package/dist/lib/oauth-server.js +141 -0
- package/dist/lib/oauth-server.js.map +1 -0
- package/dist/lib/oauth.d.ts +3 -0
- package/dist/lib/oauth.d.ts.map +1 -0
- package/dist/lib/oauth.js +38 -0
- package/dist/lib/oauth.js.map +1 -0
- package/dist/lib/output.d.ts +36 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +293 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pagination.d.ts +23 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +26 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/pkce.d.ts +4 -0
- package/dist/lib/pkce.d.ts.map +1 -0
- package/dist/lib/pkce.js +19 -0
- package/dist/lib/pkce.js.map +1 -0
- package/dist/lib/refs.d.ts +13 -0
- package/dist/lib/refs.d.ts.map +1 -0
- package/dist/lib/refs.js +117 -0
- package/dist/lib/refs.js.map +1 -0
- package/dist/lib/spinner.d.ts +20 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +70 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/task-list.d.ts +28 -0
- package/dist/lib/task-list.d.ts.map +1 -0
- package/dist/lib/task-list.js +234 -0
- package/dist/lib/task-list.js.map +1 -0
- package/dist/lib/urls.d.ts +8 -0
- package/dist/lib/urls.d.ts.map +1 -0
- package/dist/lib/urls.js +26 -0
- package/dist/lib/urls.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { getApiToken } from '../auth.js';
|
|
2
|
+
import { executeSyncCommand, generateUuid } from './core.js';
|
|
3
|
+
export async function fetchUserSettings() {
|
|
4
|
+
const token = await getApiToken();
|
|
5
|
+
const response = await fetch('https://api.todoist.com/api/v1/sync', {
|
|
6
|
+
method: 'POST',
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${token}`,
|
|
9
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
10
|
+
},
|
|
11
|
+
body: new URLSearchParams({
|
|
12
|
+
sync_token: '*',
|
|
13
|
+
resource_types: '["user","user_settings"]',
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
throw new Error(`Failed to fetch user settings: ${response.status}`);
|
|
18
|
+
}
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
if (data.error) {
|
|
21
|
+
throw new Error(`User settings API error: ${data.error}`);
|
|
22
|
+
}
|
|
23
|
+
const user = data.user ?? {};
|
|
24
|
+
const settings = data.user_settings ?? {};
|
|
25
|
+
return {
|
|
26
|
+
timezone: String(user.timezone ?? 'UTC'),
|
|
27
|
+
timeFormat: Number(user.time_format ?? 0),
|
|
28
|
+
dateFormat: Number(user.date_format ?? 0),
|
|
29
|
+
startDay: Number(user.start_day ?? 1),
|
|
30
|
+
theme: Number(user.theme_id ?? user.theme ?? 0),
|
|
31
|
+
autoReminder: Number(user.auto_reminder ?? 0),
|
|
32
|
+
nextWeek: Number(user.next_week ?? 1),
|
|
33
|
+
startPage: String(user.start_page ?? 'today'),
|
|
34
|
+
reminderPush: Boolean(settings.reminder_push ?? true),
|
|
35
|
+
reminderDesktop: Boolean(settings.reminder_desktop ?? true),
|
|
36
|
+
reminderEmail: Boolean(settings.reminder_email ?? false),
|
|
37
|
+
completedSoundDesktop: Boolean(settings.completed_sound_desktop ?? true),
|
|
38
|
+
completedSoundMobile: Boolean(settings.completed_sound_mobile ?? true),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export async function updateUserSettings(args) {
|
|
42
|
+
const commands = [];
|
|
43
|
+
const userArgs = {};
|
|
44
|
+
if (args.timezone !== undefined)
|
|
45
|
+
userArgs.timezone = args.timezone;
|
|
46
|
+
if (args.timeFormat !== undefined)
|
|
47
|
+
userArgs.time_format = args.timeFormat;
|
|
48
|
+
if (args.dateFormat !== undefined)
|
|
49
|
+
userArgs.date_format = args.dateFormat;
|
|
50
|
+
if (args.startDay !== undefined)
|
|
51
|
+
userArgs.start_day = args.startDay;
|
|
52
|
+
if (args.theme !== undefined)
|
|
53
|
+
userArgs.theme_id = String(args.theme);
|
|
54
|
+
if (args.autoReminder !== undefined)
|
|
55
|
+
userArgs.auto_reminder = args.autoReminder;
|
|
56
|
+
if (args.nextWeek !== undefined)
|
|
57
|
+
userArgs.next_week = args.nextWeek;
|
|
58
|
+
if (args.startPage !== undefined)
|
|
59
|
+
userArgs.start_page = args.startPage;
|
|
60
|
+
if (Object.keys(userArgs).length > 0) {
|
|
61
|
+
commands.push({
|
|
62
|
+
type: 'user_update',
|
|
63
|
+
uuid: generateUuid(),
|
|
64
|
+
args: userArgs,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const settingsArgs = {};
|
|
68
|
+
if (args.reminderPush !== undefined)
|
|
69
|
+
settingsArgs.reminder_push = args.reminderPush;
|
|
70
|
+
if (args.reminderDesktop !== undefined)
|
|
71
|
+
settingsArgs.reminder_desktop = args.reminderDesktop;
|
|
72
|
+
if (args.reminderEmail !== undefined)
|
|
73
|
+
settingsArgs.reminder_email = args.reminderEmail;
|
|
74
|
+
if (args.completedSoundDesktop !== undefined)
|
|
75
|
+
settingsArgs.completed_sound_desktop = args.completedSoundDesktop;
|
|
76
|
+
if (args.completedSoundMobile !== undefined)
|
|
77
|
+
settingsArgs.completed_sound_mobile = args.completedSoundMobile;
|
|
78
|
+
if (Object.keys(settingsArgs).length > 0) {
|
|
79
|
+
commands.push({
|
|
80
|
+
type: 'user_settings_update',
|
|
81
|
+
uuid: generateUuid(),
|
|
82
|
+
args: settingsArgs,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (commands.length === 0) {
|
|
86
|
+
throw new Error('No settings to update');
|
|
87
|
+
}
|
|
88
|
+
await executeSyncCommand(commands);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=user-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-settings.js","sourceRoot":"","sources":["../../../src/lib/api/user-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Workspace {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
role: 'ADMIN' | 'MEMBER' | 'GUEST';
|
|
5
|
+
plan: string;
|
|
6
|
+
domainName: string | null;
|
|
7
|
+
currentMemberCount: number;
|
|
8
|
+
currentActiveProjects: number;
|
|
9
|
+
memberCountByType: {
|
|
10
|
+
adminCount: number;
|
|
11
|
+
memberCount: number;
|
|
12
|
+
guestCount: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface WorkspaceFolder {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
workspaceId: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function fetchWorkspaces(): Promise<Workspace[]>;
|
|
21
|
+
export declare function fetchWorkspaceFolders(): Promise<WorkspaceFolder[]>;
|
|
22
|
+
export declare function clearWorkspaceCache(): void;
|
|
23
|
+
//# sourceMappingURL=workspaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/lib/api/workspaces.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAA;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE;QACf,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;KACrB,CAAA;CACJ;AAED,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACtB;AA6DD,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAG5D;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAOxE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getApiToken } from '../auth.js';
|
|
2
|
+
let workspaceCache = null;
|
|
3
|
+
let folderCache = null;
|
|
4
|
+
async function fetchWorkspaceData() {
|
|
5
|
+
if (workspaceCache !== null && folderCache !== null) {
|
|
6
|
+
return { workspaces: workspaceCache, folders: folderCache };
|
|
7
|
+
}
|
|
8
|
+
const token = await getApiToken();
|
|
9
|
+
const response = await fetch('https://api.todoist.com/sync/v9/sync', {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${token}`,
|
|
13
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
14
|
+
},
|
|
15
|
+
body: new URLSearchParams({
|
|
16
|
+
sync_token: '*',
|
|
17
|
+
resource_types: '["workspaces","folders"]',
|
|
18
|
+
}),
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`Failed to fetch workspace data: ${response.status}`);
|
|
22
|
+
}
|
|
23
|
+
const data = await response.json();
|
|
24
|
+
if (data.error) {
|
|
25
|
+
throw new Error(`Workspace API error: ${data.error}`);
|
|
26
|
+
}
|
|
27
|
+
const workspaces = (data.workspaces ?? []).map((w) => ({
|
|
28
|
+
id: String(w.id),
|
|
29
|
+
name: w.name,
|
|
30
|
+
role: w.role,
|
|
31
|
+
plan: w.plan,
|
|
32
|
+
domainName: w.domain_name ?? null,
|
|
33
|
+
currentMemberCount: w.current_member_count ?? 0,
|
|
34
|
+
currentActiveProjects: w.current_active_projects ?? 0,
|
|
35
|
+
memberCountByType: {
|
|
36
|
+
adminCount: w.member_count_by_type?.admin_count ?? 0,
|
|
37
|
+
memberCount: w.member_count_by_type?.member_count ?? 0,
|
|
38
|
+
guestCount: w.member_count_by_type?.guest_count ?? 0,
|
|
39
|
+
},
|
|
40
|
+
}));
|
|
41
|
+
const folders = (data.folders ?? []).map((f) => ({
|
|
42
|
+
id: String(f.id),
|
|
43
|
+
name: String(f.name),
|
|
44
|
+
workspaceId: String(f.workspace_id),
|
|
45
|
+
}));
|
|
46
|
+
workspaceCache = workspaces;
|
|
47
|
+
folderCache = folders;
|
|
48
|
+
return { workspaces, folders };
|
|
49
|
+
}
|
|
50
|
+
export async function fetchWorkspaces() {
|
|
51
|
+
const { workspaces } = await fetchWorkspaceData();
|
|
52
|
+
return workspaces;
|
|
53
|
+
}
|
|
54
|
+
export async function fetchWorkspaceFolders() {
|
|
55
|
+
try {
|
|
56
|
+
const { folders } = await fetchWorkspaceData();
|
|
57
|
+
return folders;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function clearWorkspaceCache() {
|
|
64
|
+
workspaceCache = null;
|
|
65
|
+
folderCache = null;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=workspaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/lib/api/workspaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAUA,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBnD;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B/D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBnD"}
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
const CONFIG_PATH = join(homedir(), '.config', 'todoist-cli', 'config.json');
|
|
5
|
+
export async function getApiToken() {
|
|
6
|
+
// Priority 1: Environment variable
|
|
7
|
+
const envToken = process.env.TODOIST_API_TOKEN;
|
|
8
|
+
if (envToken) {
|
|
9
|
+
return envToken;
|
|
10
|
+
}
|
|
11
|
+
// Priority 2: Config file
|
|
12
|
+
try {
|
|
13
|
+
const content = await readFile(CONFIG_PATH, 'utf-8');
|
|
14
|
+
const config = JSON.parse(content);
|
|
15
|
+
if (config.api_token) {
|
|
16
|
+
return config.api_token;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Config file doesn't exist or is invalid
|
|
21
|
+
}
|
|
22
|
+
throw new Error('No API token found. Set TODOIST_API_TOKEN environment variable or create ~/.config/todoist-cli/config.json with {"api_token": "your-token"}');
|
|
23
|
+
}
|
|
24
|
+
export async function saveApiToken(token) {
|
|
25
|
+
// Validate token (non-empty, reasonable length)
|
|
26
|
+
if (!token || token.trim().length < 10) {
|
|
27
|
+
throw new Error('Invalid token: Token must be at least 10 characters');
|
|
28
|
+
}
|
|
29
|
+
// Ensure config directory exists
|
|
30
|
+
const configDir = dirname(CONFIG_PATH);
|
|
31
|
+
await mkdir(configDir, { recursive: true });
|
|
32
|
+
// Read existing config to preserve other settings
|
|
33
|
+
let existingConfig = {};
|
|
34
|
+
try {
|
|
35
|
+
const content = await readFile(CONFIG_PATH, 'utf-8');
|
|
36
|
+
existingConfig = JSON.parse(content);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Config doesn't exist - start fresh
|
|
40
|
+
}
|
|
41
|
+
// Update config with new token
|
|
42
|
+
const newConfig = {
|
|
43
|
+
...existingConfig,
|
|
44
|
+
api_token: token.trim(),
|
|
45
|
+
};
|
|
46
|
+
// Write config file with proper formatting
|
|
47
|
+
await writeFile(CONFIG_PATH, `${JSON.stringify(newConfig, null, 2)}\n`);
|
|
48
|
+
}
|
|
49
|
+
export async function clearApiToken() {
|
|
50
|
+
let config = {};
|
|
51
|
+
try {
|
|
52
|
+
const content = await readFile(CONFIG_PATH, 'utf-8');
|
|
53
|
+
config = JSON.parse(content);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return; // Config doesn't exist, nothing to clear
|
|
57
|
+
}
|
|
58
|
+
delete config.api_token;
|
|
59
|
+
if (Object.keys(config).length === 0) {
|
|
60
|
+
await unlink(CONFIG_PATH);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, 2)}\n`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,CAAA;AAM5E,MAAM,CAAC,KAAK,UAAU,WAAW;IAC7B,mCAAmC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACX,OAAO,QAAQ,CAAA;IACnB,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACpD,MAAM,MAAM,GAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC1C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC,SAAS,CAAA;QAC3B,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,0CAA0C;IAC9C,CAAC;IAED,MAAM,IAAI,KAAK,CACX,6IAA6I,CAChJ,CAAA;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa;IAC5C,gDAAgD;IAChD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAA;IAC1E,CAAC;IAED,iCAAiC;IACjC,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACtC,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,kDAAkD;IAClD,IAAI,cAAc,GAAW,EAAE,CAAA;IAC/B,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACpD,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACL,qCAAqC;IACzC,CAAC;IAED,+BAA+B;IAC/B,MAAM,SAAS,GAAW;QACtB,GAAG,cAAc;QACjB,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;KAC1B,CAAA;IAED,2CAA2C;IAC3C,MAAM,SAAS,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,IAAI,MAAM,GAAW,EAAE,CAAA;IACvB,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACpD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACL,OAAM,CAAC,yCAAyC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC,SAAS,CAAA;IAEvB,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;IAC7B,CAAC;SAAM,CAAC;QACJ,MAAM,SAAS,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;IACxE,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AAEA,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC3C,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAA;IAC7B,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TodoistApi } from '@doist/todoist-api-typescript';
|
|
2
|
+
import { type Project, type Task } from './api/core.js';
|
|
3
|
+
export interface CollaboratorInfo {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
email: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class CollaboratorCache {
|
|
9
|
+
private workspaceUsers;
|
|
10
|
+
private projectCollaborators;
|
|
11
|
+
preload(api: TodoistApi, tasks: Task[], projects: Map<string, Project>): Promise<void>;
|
|
12
|
+
private fetchWorkspaceUsers;
|
|
13
|
+
private fetchProjectCollaborators;
|
|
14
|
+
getUserName({ userId, projectId, projects, }: {
|
|
15
|
+
userId: string;
|
|
16
|
+
projectId: string;
|
|
17
|
+
projects: Map<string, Project>;
|
|
18
|
+
}): string | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function formatUserShortName(fullName: string): string;
|
|
21
|
+
export interface FormatAssigneeOptions {
|
|
22
|
+
userId: string | null;
|
|
23
|
+
projectId: string;
|
|
24
|
+
projects: Map<string, Project>;
|
|
25
|
+
cache: CollaboratorCache;
|
|
26
|
+
}
|
|
27
|
+
export declare function formatAssignee({ userId, projectId, projects, cache, }: FormatAssigneeOptions): string | null;
|
|
28
|
+
export declare function resolveAssigneeId(api: TodoistApi, ref: string, project: Project): Promise<string>;
|
|
29
|
+
//# sourceMappingURL=collaborators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collaborators.d.ts","sourceRoot":"","sources":["../../src/lib/collaborators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAwC,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,eAAe,CAAA;AAI7F,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,cAAc,CAAmD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAEzE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAyC9E,mBAAmB;YA2BnB,yBAAyB;IAsBvC,WAAW,CAAC,EACR,MAAM,EACN,SAAS,EACT,QAAQ,GACX,EAAE;QACC,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACjC,GAAG,MAAM,GAAG,IAAI;CAcpB;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,EAAE,iBAAiB,CAAA;CAC3B;AAED,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,QAAQ,EACR,KAAK,GACR,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAQvC;AA0DD,wBAAsB,iBAAiB,CACnC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,GACjB,OAAO,CAAC,MAAM,CAAC,CA+BjB"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { getCurrentUserId, isWorkspaceProject } from './api/core.js';
|
|
2
|
+
import { formatError } from './output.js';
|
|
3
|
+
import { extractId, isIdRef } from './refs.js';
|
|
4
|
+
export class CollaboratorCache {
|
|
5
|
+
workspaceUsers = new Map();
|
|
6
|
+
projectCollaborators = new Map();
|
|
7
|
+
async preload(api, tasks, projects) {
|
|
8
|
+
const projectsWithAssignees = new Set();
|
|
9
|
+
for (const task of tasks) {
|
|
10
|
+
if (task.responsibleUid) {
|
|
11
|
+
projectsWithAssignees.add(task.projectId);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (projectsWithAssignees.size === 0)
|
|
15
|
+
return;
|
|
16
|
+
const workspaceIds = new Set();
|
|
17
|
+
const sharedPersonalProjectIds = [];
|
|
18
|
+
for (const projectId of projectsWithAssignees) {
|
|
19
|
+
const project = projects.get(projectId);
|
|
20
|
+
if (!project)
|
|
21
|
+
continue;
|
|
22
|
+
if (isWorkspaceProject(project)) {
|
|
23
|
+
workspaceIds.add(project.workspaceId);
|
|
24
|
+
}
|
|
25
|
+
else if (project.isShared) {
|
|
26
|
+
sharedPersonalProjectIds.push(projectId);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const fetches = [];
|
|
30
|
+
for (const workspaceId of workspaceIds) {
|
|
31
|
+
if (!this.workspaceUsers.has(workspaceId)) {
|
|
32
|
+
fetches.push(this.fetchWorkspaceUsers(api, workspaceId));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const projectId of sharedPersonalProjectIds) {
|
|
36
|
+
if (!this.projectCollaborators.has(projectId)) {
|
|
37
|
+
fetches.push(this.fetchProjectCollaborators(api, projectId));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
await Promise.all(fetches);
|
|
41
|
+
}
|
|
42
|
+
async fetchWorkspaceUsers(api, workspaceId) {
|
|
43
|
+
const userMap = new Map();
|
|
44
|
+
let cursor;
|
|
45
|
+
const workspaceIdNum = parseInt(workspaceId, 10);
|
|
46
|
+
while (true) {
|
|
47
|
+
const response = await api.getWorkspaceUsers({
|
|
48
|
+
workspaceId: workspaceIdNum,
|
|
49
|
+
cursor,
|
|
50
|
+
limit: 200,
|
|
51
|
+
});
|
|
52
|
+
for (const user of response.workspaceUsers) {
|
|
53
|
+
userMap.set(user.userId, {
|
|
54
|
+
id: user.userId,
|
|
55
|
+
name: user.fullName,
|
|
56
|
+
email: user.userEmail,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!response.hasMore || !response.nextCursor)
|
|
60
|
+
break;
|
|
61
|
+
cursor = response.nextCursor;
|
|
62
|
+
}
|
|
63
|
+
this.workspaceUsers.set(workspaceId, userMap);
|
|
64
|
+
}
|
|
65
|
+
async fetchProjectCollaborators(api, projectId) {
|
|
66
|
+
const userMap = new Map();
|
|
67
|
+
let cursor;
|
|
68
|
+
while (true) {
|
|
69
|
+
const response = await api.getProjectCollaborators(projectId, { cursor });
|
|
70
|
+
for (const user of response.results) {
|
|
71
|
+
userMap.set(user.id, {
|
|
72
|
+
id: user.id,
|
|
73
|
+
name: user.name,
|
|
74
|
+
email: user.email,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (!response.nextCursor)
|
|
78
|
+
break;
|
|
79
|
+
cursor = response.nextCursor;
|
|
80
|
+
}
|
|
81
|
+
this.projectCollaborators.set(projectId, userMap);
|
|
82
|
+
}
|
|
83
|
+
getUserName({ userId, projectId, projects, }) {
|
|
84
|
+
const project = projects.get(projectId);
|
|
85
|
+
if (!project)
|
|
86
|
+
return null;
|
|
87
|
+
if (isWorkspaceProject(project)) {
|
|
88
|
+
const workspaceMap = this.workspaceUsers.get(project.workspaceId);
|
|
89
|
+
const user = workspaceMap?.get(userId);
|
|
90
|
+
return user?.name ?? null;
|
|
91
|
+
}
|
|
92
|
+
const projectMap = this.projectCollaborators.get(projectId);
|
|
93
|
+
const user = projectMap?.get(userId);
|
|
94
|
+
return user?.name ?? null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function formatUserShortName(fullName) {
|
|
98
|
+
const parts = fullName.trim().split(/\s+/);
|
|
99
|
+
if (parts.length === 1) {
|
|
100
|
+
return parts[0];
|
|
101
|
+
}
|
|
102
|
+
const firstName = parts[0];
|
|
103
|
+
const lastInitial = parts[parts.length - 1][0];
|
|
104
|
+
return `${firstName} ${lastInitial}.`;
|
|
105
|
+
}
|
|
106
|
+
export function formatAssignee({ userId, projectId, projects, cache, }) {
|
|
107
|
+
if (!userId)
|
|
108
|
+
return null;
|
|
109
|
+
const name = cache.getUserName({ userId, projectId, projects });
|
|
110
|
+
if (name) {
|
|
111
|
+
return `+${formatUserShortName(name)}`;
|
|
112
|
+
}
|
|
113
|
+
return `+${userId}`;
|
|
114
|
+
}
|
|
115
|
+
async function fetchCollaboratorsForProject(api, project) {
|
|
116
|
+
if (isWorkspaceProject(project)) {
|
|
117
|
+
const users = [];
|
|
118
|
+
let cursor;
|
|
119
|
+
const workspaceIdNum = parseInt(project.workspaceId, 10);
|
|
120
|
+
while (true) {
|
|
121
|
+
const response = await api.getWorkspaceUsers({
|
|
122
|
+
workspaceId: workspaceIdNum,
|
|
123
|
+
cursor,
|
|
124
|
+
limit: 200,
|
|
125
|
+
});
|
|
126
|
+
for (const user of response.workspaceUsers) {
|
|
127
|
+
users.push({
|
|
128
|
+
id: user.userId,
|
|
129
|
+
name: user.fullName,
|
|
130
|
+
email: user.userEmail,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (!response.hasMore || !response.nextCursor)
|
|
134
|
+
break;
|
|
135
|
+
cursor = response.nextCursor;
|
|
136
|
+
}
|
|
137
|
+
return users;
|
|
138
|
+
}
|
|
139
|
+
if (project.isShared) {
|
|
140
|
+
const users = [];
|
|
141
|
+
let cursor;
|
|
142
|
+
while (true) {
|
|
143
|
+
const response = await api.getProjectCollaborators(project.id, {
|
|
144
|
+
cursor,
|
|
145
|
+
});
|
|
146
|
+
for (const user of response.results) {
|
|
147
|
+
users.push({
|
|
148
|
+
id: user.id,
|
|
149
|
+
name: user.name,
|
|
150
|
+
email: user.email,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (!response.nextCursor)
|
|
154
|
+
break;
|
|
155
|
+
cursor = response.nextCursor;
|
|
156
|
+
}
|
|
157
|
+
return users;
|
|
158
|
+
}
|
|
159
|
+
throw new Error(formatError('NOT_SHARED', 'Cannot assign tasks in non-shared projects.'));
|
|
160
|
+
}
|
|
161
|
+
export async function resolveAssigneeId(api, ref, project) {
|
|
162
|
+
if (ref.toLowerCase() === 'me') {
|
|
163
|
+
return getCurrentUserId();
|
|
164
|
+
}
|
|
165
|
+
if (isIdRef(ref)) {
|
|
166
|
+
return extractId(ref);
|
|
167
|
+
}
|
|
168
|
+
const collaborators = await fetchCollaboratorsForProject(api, project);
|
|
169
|
+
const lower = ref.toLowerCase();
|
|
170
|
+
const exactName = collaborators.find((c) => c.name.toLowerCase() === lower);
|
|
171
|
+
if (exactName)
|
|
172
|
+
return exactName.id;
|
|
173
|
+
const exactEmail = collaborators.find((c) => c.email.toLowerCase() === lower);
|
|
174
|
+
if (exactEmail)
|
|
175
|
+
return exactEmail.id;
|
|
176
|
+
const partialName = collaborators.filter((c) => c.name.toLowerCase().includes(lower));
|
|
177
|
+
if (partialName.length === 1)
|
|
178
|
+
return partialName[0].id;
|
|
179
|
+
if (partialName.length > 1) {
|
|
180
|
+
throw new Error(formatError('AMBIGUOUS_ASSIGNEE', `Multiple users match "${ref}":`, partialName.slice(0, 5).map((c) => `"${c.name}" (id:${c.id})`)));
|
|
181
|
+
}
|
|
182
|
+
throw new Error(formatError('ASSIGNEE_NOT_FOUND', `User "${ref}" not found.`));
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=collaborators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collaborators.js","sourceRoot":"","sources":["../../src/lib/collaborators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/lib/dates.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,UAAU,SAAI,GAAG,MAAM,CAInD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUvE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function getLocalDate(daysOffset = 0) {
|
|
2
|
+
const date = new Date();
|
|
3
|
+
date.setDate(date.getDate() + daysOffset);
|
|
4
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
5
|
+
}
|
|
6
|
+
export function formatDateHeader(dateStr, today) {
|
|
7
|
+
if (dateStr < today)
|
|
8
|
+
return 'Overdue';
|
|
9
|
+
if (dateStr === today)
|
|
10
|
+
return 'Today';
|
|
11
|
+
const tomorrow = getLocalDate(1);
|
|
12
|
+
if (dateStr === tomorrow)
|
|
13
|
+
return 'Tomorrow';
|
|
14
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
15
|
+
return new Date(year, month - 1, day).toLocaleDateString('en-US', {
|
|
16
|
+
month: 'short',
|
|
17
|
+
day: 'numeric',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/lib/dates.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,UAAU,GAAG,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA;IACvB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IACzC,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AAC7H,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,KAAa;IAC3D,IAAI,OAAO,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACrC,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,OAAO,CAAA;IACrC,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,CAAA;IAChC,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAA;IAC3C,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACzD,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC9D,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;KACjB,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a duration string into minutes.
|
|
3
|
+
* Supports formats like: "1h", "30m", "2h15m", "1 hour 30 minutes"
|
|
4
|
+
* @returns minutes or null if invalid
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseDuration(input: string): number | null;
|
|
7
|
+
/**
|
|
8
|
+
* Format a duration for display.
|
|
9
|
+
* @param amount - the duration amount
|
|
10
|
+
* @param unit - 'minute' or 'day'
|
|
11
|
+
* @returns formatted string like "1h30m" or "2d"
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatDuration(amount: number, unit?: 'minute' | 'day'): string;
|
|
14
|
+
//# sourceMappingURL=duration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../src/lib/duration.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiC1D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,QAAQ,GAAG,KAAgB,GAAG,MAAM,CAaxF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a duration string into minutes.
|
|
3
|
+
* Supports formats like: "1h", "30m", "2h15m", "1 hour 30 minutes"
|
|
4
|
+
* @returns minutes or null if invalid
|
|
5
|
+
*/
|
|
6
|
+
export function parseDuration(input) {
|
|
7
|
+
const normalized = input.trim().toLowerCase();
|
|
8
|
+
if (!normalized)
|
|
9
|
+
return null;
|
|
10
|
+
// Match all occurrences of number + unit
|
|
11
|
+
// Units: h, hr, hrs, hour, hours, m, min, mins, minute, minutes
|
|
12
|
+
const pattern = /(\d+)\s*(hours?|hrs?|h|minutes?|mins?|m)(?=\s|$|\d)/gi;
|
|
13
|
+
const matches = [...normalized.matchAll(pattern)];
|
|
14
|
+
if (matches.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
// Verify the entire input is consumed by valid duration parts
|
|
17
|
+
// Remove all matched parts and whitespace, should be empty
|
|
18
|
+
let remaining = normalized;
|
|
19
|
+
for (const match of matches) {
|
|
20
|
+
remaining = remaining.replace(match[0], '');
|
|
21
|
+
}
|
|
22
|
+
remaining = remaining.replace(/\s+/g, '');
|
|
23
|
+
if (remaining !== '')
|
|
24
|
+
return null;
|
|
25
|
+
let totalMinutes = 0;
|
|
26
|
+
for (const match of matches) {
|
|
27
|
+
const value = parseInt(match[1], 10);
|
|
28
|
+
const unit = match[2].toLowerCase();
|
|
29
|
+
if (unit.startsWith('h')) {
|
|
30
|
+
totalMinutes += value * 60;
|
|
31
|
+
}
|
|
32
|
+
else if (unit.startsWith('m')) {
|
|
33
|
+
totalMinutes += value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return totalMinutes;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Format a duration for display.
|
|
40
|
+
* @param amount - the duration amount
|
|
41
|
+
* @param unit - 'minute' or 'day'
|
|
42
|
+
* @returns formatted string like "1h30m" or "2d"
|
|
43
|
+
*/
|
|
44
|
+
export function formatDuration(amount, unit = 'minute') {
|
|
45
|
+
const totalMinutes = unit === 'day' ? amount * 1440 : amount;
|
|
46
|
+
const days = Math.floor(totalMinutes / 1440);
|
|
47
|
+
const hours = Math.floor((totalMinutes % 1440) / 60);
|
|
48
|
+
const minutes = totalMinutes % 60;
|
|
49
|
+
const parts = [];
|
|
50
|
+
if (days > 0)
|
|
51
|
+
parts.push(`${days}d`);
|
|
52
|
+
if (hours > 0)
|
|
53
|
+
parts.push(`${hours}h`);
|
|
54
|
+
if (minutes > 0)
|
|
55
|
+
parts.push(`${minutes}m`);
|
|
56
|
+
return parts.length > 0 ? parts.join('') : '0m';
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=duration.js.map
|