@j0hanz/todokit-mcp 1.0.5 → 1.0.7
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 +48 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/db.d.ts +8 -0
- package/dist/lib/db.d.ts.map +1 -0
- package/dist/lib/db.js +177 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/errors.js +17 -12
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/resolve.js +1 -1
- package/dist/lib/resolve.js.map +1 -1
- package/dist/lib/storage.d.ts +7 -6
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +148 -71
- package/dist/lib/storage.js.map +1 -1
- package/dist/lib/storage_filters.d.ts +6 -6
- package/dist/lib/storage_filters.d.ts.map +1 -1
- package/dist/lib/storage_filters.js +26 -45
- package/dist/lib/storage_filters.js.map +1 -1
- package/dist/lib/storage_mutations.d.ts +8 -3
- package/dist/lib/storage_mutations.d.ts.map +1 -1
- package/dist/lib/storage_mutations.js +0 -58
- package/dist/lib/storage_mutations.js.map +1 -1
- package/dist/lib/storage_state.d.ts.map +1 -1
- package/dist/lib/storage_state.js +36 -2
- package/dist/lib/storage_state.js.map +1 -1
- package/dist/schemas/inputs.d.ts +74 -40
- package/dist/schemas/inputs.d.ts.map +1 -1
- package/dist/schemas/inputs.js +54 -66
- package/dist/schemas/inputs.js.map +1 -1
- package/dist/tools/complete_todo.d.ts.map +1 -1
- package/dist/tools/complete_todo.js +2 -1
- package/dist/tools/complete_todo.js.map +1 -1
- package/dist/tools/delete_todo.d.ts.map +1 -1
- package/dist/tools/delete_todo.js +4 -2
- package/dist/tools/delete_todo.js.map +1 -1
- package/dist/tools/delete_todos.d.ts +3 -0
- package/dist/tools/delete_todos.d.ts.map +1 -0
- package/dist/tools/delete_todos.js +134 -0
- package/dist/tools/delete_todos.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list_todos.d.ts.map +1 -1
- package/dist/tools/list_todos.js +68 -45
- package/dist/tools/list_todos.js.map +1 -1
- package/dist/tools/update_todo.d.ts.map +1 -1
- package/dist/tools/update_todo.js +55 -50
- package/dist/tools/update_todo.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/storage.js
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readTodos, withTodos } from './db.js';
|
|
2
3
|
import { resolveTodoTargetFromTodos, unwrapResolution, } from './resolve.js';
|
|
3
4
|
import { filterTodos, normalizeTags, } from './storage_filters.js';
|
|
4
|
-
import {
|
|
5
|
-
import { persistTodos, queueWrite, readTodosFromDisk, waitForWrites, } from './storage_state.js';
|
|
5
|
+
import { createNotFoundOutcome, } from './storage_mutations.js';
|
|
6
6
|
import {} from './types.js';
|
|
7
7
|
export { normalizeTags };
|
|
8
|
+
function normalizeUpdates(updates) {
|
|
9
|
+
if (!updates.tags)
|
|
10
|
+
return updates;
|
|
11
|
+
return { ...updates, tags: normalizeTags(updates.tags) };
|
|
12
|
+
}
|
|
13
|
+
function areStringArraysEqual(left, right) {
|
|
14
|
+
if (left.length !== right.length)
|
|
15
|
+
return false;
|
|
16
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
17
|
+
if (left[i] !== right[i])
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
function isStringArray(value) {
|
|
23
|
+
return (Array.isArray(value) && value.every((item) => typeof item === 'string'));
|
|
24
|
+
}
|
|
25
|
+
function valuesEqual(current, update) {
|
|
26
|
+
if (isStringArray(update) && isStringArray(current)) {
|
|
27
|
+
return areStringArraysEqual(update, current);
|
|
28
|
+
}
|
|
29
|
+
return Object.is(current, update);
|
|
30
|
+
}
|
|
31
|
+
function hasChanges(current, updates) {
|
|
32
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
33
|
+
const currentValue = current[key];
|
|
34
|
+
if (!valuesEqual(currentValue, value)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
8
40
|
export async function getTodos(filters) {
|
|
9
|
-
await
|
|
10
|
-
const todos = await readTodosFromDisk();
|
|
41
|
+
const todos = await readTodos();
|
|
11
42
|
return filters ? filterTodos(todos, filters) : todos;
|
|
12
43
|
}
|
|
13
44
|
export async function addTodo(title, description, priority = 'normal', dueDate, tags = []) {
|
|
@@ -19,97 +50,143 @@ export async function addTodo(title, description, priority = 'normal', dueDate,
|
|
|
19
50
|
}
|
|
20
51
|
return todo;
|
|
21
52
|
}
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
updatedAt: timestamp,
|
|
36
|
-
completedAt: undefined,
|
|
37
|
-
}));
|
|
38
|
-
const nextTodos = [...todos, ...newTodos];
|
|
39
|
-
await persistTodos(nextTodos);
|
|
40
|
-
return newTodos;
|
|
41
|
-
});
|
|
53
|
+
function createNewTodo(item, timestamp) {
|
|
54
|
+
return {
|
|
55
|
+
id: randomUUID(),
|
|
56
|
+
title: item.title,
|
|
57
|
+
description: item.description,
|
|
58
|
+
completed: false,
|
|
59
|
+
priority: item.priority ?? 'normal',
|
|
60
|
+
dueDate: item.dueDate,
|
|
61
|
+
tags: normalizeTags(item.tags ?? []),
|
|
62
|
+
createdAt: timestamp,
|
|
63
|
+
updatedAt: timestamp,
|
|
64
|
+
completedAt: undefined,
|
|
65
|
+
};
|
|
42
66
|
}
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
await persistTodos(todos);
|
|
50
|
-
return updatedTodo;
|
|
67
|
+
export function addTodos(items) {
|
|
68
|
+
const timestamp = new Date().toISOString();
|
|
69
|
+
return withTodos((todos) => {
|
|
70
|
+
const newTodos = items.map((item) => createNewTodo(item, timestamp));
|
|
71
|
+
return { todos: [...todos, ...newTodos], result: newTodos };
|
|
51
72
|
});
|
|
52
73
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
function calculateUpdatedTodo(current, updates) {
|
|
75
|
+
const updatedTodo = {
|
|
76
|
+
...current,
|
|
77
|
+
...updates,
|
|
78
|
+
updatedAt: new Date().toISOString(),
|
|
79
|
+
};
|
|
80
|
+
if (updates.completed !== undefined &&
|
|
81
|
+
updates.completed !== current.completed) {
|
|
82
|
+
updatedTodo.completedAt = updates.completed
|
|
83
|
+
? new Date().toISOString()
|
|
84
|
+
: undefined;
|
|
85
|
+
}
|
|
86
|
+
return updatedTodo;
|
|
87
|
+
}
|
|
88
|
+
function applyUpdateToTodos(todos, id, updates) {
|
|
89
|
+
const index = todos.findIndex((todo) => todo.id === id);
|
|
90
|
+
if (index < 0) {
|
|
91
|
+
return { todos, result: null };
|
|
92
|
+
}
|
|
93
|
+
const current = todos[index];
|
|
94
|
+
if (!current) {
|
|
95
|
+
return { todos, result: null };
|
|
96
|
+
}
|
|
97
|
+
const normalizedUpdates = normalizeUpdates(updates);
|
|
98
|
+
if (!hasChanges(current, normalizedUpdates)) {
|
|
99
|
+
return { todos, result: current };
|
|
100
|
+
}
|
|
101
|
+
const updatedTodo = calculateUpdatedTodo(current, normalizedUpdates);
|
|
102
|
+
const nextTodos = [...todos];
|
|
103
|
+
nextTodos[index] = updatedTodo;
|
|
104
|
+
return { todos: nextTodos, result: updatedTodo };
|
|
105
|
+
}
|
|
106
|
+
export function updateTodo(id, updates) {
|
|
107
|
+
return withTodos((todos) => applyUpdateToTodos(todos, id, updates));
|
|
108
|
+
}
|
|
109
|
+
export function deleteTodo(id) {
|
|
110
|
+
return withTodos((todos) => {
|
|
111
|
+
const remaining = todos.filter((todo) => todo.id !== id);
|
|
112
|
+
return { todos: remaining, result: remaining.length !== todos.length };
|
|
62
113
|
});
|
|
63
114
|
}
|
|
64
115
|
export async function updateTodoBySelector(input, buildUpdates) {
|
|
65
|
-
return
|
|
66
|
-
const todos = await readTodosFromDisk();
|
|
116
|
+
return withTodos((todos) => {
|
|
67
117
|
const outcome = unwrapResolution(resolveTodoTargetFromTodos(todos, input));
|
|
68
118
|
if (outcome.kind !== 'match') {
|
|
69
|
-
return outcome;
|
|
119
|
+
return { todos, result: outcome };
|
|
70
120
|
}
|
|
71
121
|
const updates = buildUpdates(outcome.todo);
|
|
72
122
|
if (!updates || Object.keys(updates).length === 0) {
|
|
73
|
-
return { kind: 'no_updates' };
|
|
123
|
+
return { todos, result: { kind: 'no_updates' } };
|
|
74
124
|
}
|
|
75
|
-
const
|
|
76
|
-
if (!
|
|
77
|
-
return
|
|
125
|
+
const updated = applyUpdateToTodos(todos, outcome.todo.id, updates);
|
|
126
|
+
if (!updated.result) {
|
|
127
|
+
return {
|
|
128
|
+
todos,
|
|
129
|
+
result: createNotFoundOutcome(outcome.todo.id),
|
|
130
|
+
};
|
|
78
131
|
}
|
|
79
|
-
|
|
80
|
-
|
|
132
|
+
return {
|
|
133
|
+
todos: updated.todos,
|
|
134
|
+
result: { kind: 'match', todo: updated.result },
|
|
135
|
+
};
|
|
81
136
|
});
|
|
82
137
|
}
|
|
83
138
|
export async function deleteTodoBySelector(input) {
|
|
84
|
-
return
|
|
85
|
-
const todos = await readTodosFromDisk();
|
|
139
|
+
return withTodos((todos) => {
|
|
86
140
|
const outcome = unwrapResolution(resolveTodoTargetFromTodos(todos, input));
|
|
87
|
-
if (outcome.kind !== 'match')
|
|
88
|
-
return outcome;
|
|
89
|
-
const index = todos.findIndex((todo) => todo.id === outcome.todo.id);
|
|
90
|
-
if (index === -1) {
|
|
91
|
-
return createNotFoundOutcome(outcome.todo.id);
|
|
141
|
+
if (outcome.kind !== 'match') {
|
|
142
|
+
return { todos, result: outcome };
|
|
92
143
|
}
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
return
|
|
144
|
+
const remaining = todos.filter((todo) => todo.id !== outcome.todo.id);
|
|
145
|
+
if (remaining.length === todos.length) {
|
|
146
|
+
return {
|
|
147
|
+
todos,
|
|
148
|
+
result: createNotFoundOutcome(outcome.todo.id),
|
|
149
|
+
};
|
|
96
150
|
}
|
|
97
|
-
todos
|
|
98
|
-
await persistTodos(todos);
|
|
99
|
-
return { kind: 'match', todo: removed };
|
|
151
|
+
return { todos: remaining, result: { kind: 'match', todo: outcome.todo } };
|
|
100
152
|
});
|
|
101
153
|
}
|
|
102
154
|
export async function completeTodoBySelector(input, completed) {
|
|
103
|
-
return
|
|
104
|
-
const todos = await readTodosFromDisk();
|
|
155
|
+
return withTodos((todos) => {
|
|
105
156
|
const outcome = unwrapResolution(resolveTodoTargetFromTodos(todos, input));
|
|
106
|
-
if (outcome.kind !== 'match')
|
|
107
|
-
return outcome;
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
157
|
+
if (outcome.kind !== 'match') {
|
|
158
|
+
return { todos, result: outcome };
|
|
159
|
+
}
|
|
160
|
+
if (outcome.todo.completed === completed) {
|
|
161
|
+
return { todos, result: { kind: 'already', todo: outcome.todo } };
|
|
162
|
+
}
|
|
163
|
+
const updated = applyUpdateToTodos(todos, outcome.todo.id, { completed });
|
|
164
|
+
if (!updated.result) {
|
|
165
|
+
return {
|
|
166
|
+
todos,
|
|
167
|
+
result: createNotFoundOutcome(outcome.todo.id),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
todos: updated.todos,
|
|
172
|
+
result: { kind: 'match', todo: updated.result },
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
export function deleteTodosByIds(ids) {
|
|
177
|
+
const idsToDelete = new Set(ids);
|
|
178
|
+
return withTodos((todos) => {
|
|
179
|
+
const deletedIds = [];
|
|
180
|
+
const remaining = [];
|
|
181
|
+
for (const todo of todos) {
|
|
182
|
+
if (idsToDelete.has(todo.id)) {
|
|
183
|
+
deletedIds.push(todo.id);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
remaining.push(todo);
|
|
187
|
+
}
|
|
111
188
|
}
|
|
112
|
-
return result;
|
|
189
|
+
return { todos: remaining, result: deletedIds };
|
|
113
190
|
});
|
|
114
191
|
}
|
|
115
192
|
//# sourceMappingURL=storage.js.map
|
package/dist/lib/storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAGL,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,aAAa,GAEd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Todo } from './types.js';
|
|
2
2
|
export interface TodoFilters {
|
|
3
|
-
completed?: boolean;
|
|
4
|
-
priority?: 'low' | 'normal' | 'high';
|
|
5
|
-
tag?: string;
|
|
6
|
-
dueBefore?: string;
|
|
7
|
-
dueAfter?: string;
|
|
8
|
-
query?: string;
|
|
3
|
+
completed?: boolean | undefined;
|
|
4
|
+
priority?: 'low' | 'normal' | 'high' | undefined;
|
|
5
|
+
tag?: string | undefined;
|
|
6
|
+
dueBefore?: string | undefined;
|
|
7
|
+
dueAfter?: string | undefined;
|
|
8
|
+
query?: string | undefined;
|
|
9
9
|
}
|
|
10
10
|
export declare function normalizeTags(tags: string[]): string[];
|
|
11
11
|
export declare function filterTodos(todos: Todo[], filters: TodoFilters): Todo[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_filters.d.ts","sourceRoot":"","sources":["../../src/lib/storage_filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"storage_filters.d.ts","sourceRoot":"","sources":["../../src/lib/storage_filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACjD,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKtD;AA6CD,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,CAUvE"}
|
|
@@ -7,60 +7,41 @@ export function normalizeTags(tags) {
|
|
|
7
7
|
.filter((tag) => tag.length > 0);
|
|
8
8
|
return Array.from(new Set(normalized));
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
return haystack.includes(query);
|
|
13
|
-
}
|
|
14
|
-
function normalizeQuery(query) {
|
|
15
|
-
const trimmed = query?.trim().toLowerCase();
|
|
16
|
-
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
17
|
-
}
|
|
18
|
-
function normalizeFilters(filters) {
|
|
19
|
-
return {
|
|
20
|
-
completed: filters.completed,
|
|
21
|
-
priority: filters.priority,
|
|
22
|
-
tag: filters.tag ? normalizeTag(filters.tag) : undefined,
|
|
23
|
-
dueBefore: filters.dueBefore,
|
|
24
|
-
dueAfter: filters.dueAfter,
|
|
25
|
-
query: normalizeQuery(filters.query),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function matchesCompletion(todo, completed) {
|
|
29
|
-
return completed === undefined ? true : todo.completed === completed;
|
|
10
|
+
function matchesCompleted(todo, completed) {
|
|
11
|
+
return completed === undefined || todo.completed === completed;
|
|
30
12
|
}
|
|
31
13
|
function matchesPriority(todo, priority) {
|
|
32
|
-
return priority
|
|
14
|
+
return !priority || todo.priority === priority;
|
|
33
15
|
}
|
|
34
16
|
function matchesTag(todo, tag) {
|
|
35
|
-
return tag
|
|
17
|
+
return !tag || todo.tags.includes(tag);
|
|
18
|
+
}
|
|
19
|
+
function matchesBasic(todo, filters, tag) {
|
|
20
|
+
return (matchesCompleted(todo, filters.completed) &&
|
|
21
|
+
matchesPriority(todo, filters.priority) &&
|
|
22
|
+
matchesTag(todo, tag));
|
|
36
23
|
}
|
|
37
|
-
function
|
|
38
|
-
return
|
|
24
|
+
function matchesDueBefore(todo, date) {
|
|
25
|
+
return !date || (!!todo.dueDate && todo.dueDate < date);
|
|
39
26
|
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
27
|
+
function matchesDueAfter(todo, date) {
|
|
28
|
+
return !date || (!!todo.dueDate && todo.dueDate > date);
|
|
42
29
|
}
|
|
43
|
-
function
|
|
44
|
-
return
|
|
30
|
+
function matchesDate(todo, filters) {
|
|
31
|
+
return (matchesDueBefore(todo, filters.dueBefore) &&
|
|
32
|
+
matchesDueAfter(todo, filters.dueAfter));
|
|
45
33
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(todo, filters) => matchesDueBefore(todo, filters.dueBefore),
|
|
52
|
-
(todo, filters) => matchesDueAfter(todo, filters.dueAfter),
|
|
53
|
-
];
|
|
54
|
-
function todoMatches(todo, filters) {
|
|
55
|
-
for (const check of MATCHERS) {
|
|
56
|
-
if (!check(todo, filters)) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return true;
|
|
34
|
+
function matchesQuery(todo, query) {
|
|
35
|
+
if (!query)
|
|
36
|
+
return true;
|
|
37
|
+
const haystack = `${todo.title} ${todo.description ?? ''} ${todo.tags.join(' ')}`.toLowerCase();
|
|
38
|
+
return haystack.includes(query);
|
|
61
39
|
}
|
|
62
40
|
export function filterTodos(todos, filters) {
|
|
63
|
-
const
|
|
64
|
-
|
|
41
|
+
const query = filters.query?.trim().toLowerCase();
|
|
42
|
+
const tag = filters.tag ? normalizeTag(filters.tag) : undefined;
|
|
43
|
+
return todos.filter((todo) => matchesBasic(todo, filters, tag) &&
|
|
44
|
+
matchesDate(todo, filters) &&
|
|
45
|
+
matchesQuery(todo, query));
|
|
65
46
|
}
|
|
66
47
|
//# sourceMappingURL=storage_filters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_filters.js","sourceRoot":"","sources":["../../src/lib/storage_filters.ts"],"names":[],"mappings":"AAWA,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,MAAM,UAAU,GAAG,IAAI;SACpB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;SAC/B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,
|
|
1
|
+
{"version":3,"file":"storage_filters.js","sourceRoot":"","sources":["../../src/lib/storage_filters.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { MatchOutcome } from './resolve.js';
|
|
2
2
|
import type { Todo } from './types.js';
|
|
3
|
-
export
|
|
4
|
-
|
|
3
|
+
export interface TodoUpdate {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string | undefined;
|
|
6
|
+
completed?: boolean;
|
|
7
|
+
priority?: Todo['priority'];
|
|
8
|
+
dueDate?: string | undefined;
|
|
9
|
+
tags?: string[];
|
|
10
|
+
}
|
|
5
11
|
export declare function createNotFoundOutcome(id: string): MatchOutcome;
|
|
6
12
|
export type CompleteTodoOutcome = MatchOutcome | {
|
|
7
13
|
kind: 'already';
|
|
8
14
|
todo: Todo;
|
|
9
15
|
};
|
|
10
|
-
export declare function completeTodoInList(todos: Todo[], id: string, completed: boolean): CompleteTodoOutcome;
|
|
11
16
|
//# sourceMappingURL=storage_mutations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_mutations.d.ts","sourceRoot":"","sources":["../../src/lib/storage_mutations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"storage_mutations.d.ts","sourceRoot":"","sources":["../../src/lib/storage_mutations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAQ9D;AAED,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC"}
|
|
@@ -1,66 +1,8 @@
|
|
|
1
1
|
import { createErrorResponse } from './errors.js';
|
|
2
|
-
import { normalizeTags } from './storage_filters.js';
|
|
3
|
-
function normalizeUpdateTags(updates) {
|
|
4
|
-
const normalizedUpdates = { ...updates };
|
|
5
|
-
if (normalizedUpdates.tags) {
|
|
6
|
-
normalizedUpdates.tags = normalizeTags(normalizedUpdates.tags);
|
|
7
|
-
}
|
|
8
|
-
return normalizedUpdates;
|
|
9
|
-
}
|
|
10
|
-
function resolveCompletionUpdate(currentTodo, updates, now) {
|
|
11
|
-
const completed = updates.completed ?? currentTodo.completed;
|
|
12
|
-
const completedAt = updates.completedAt ??
|
|
13
|
-
(updates.completed !== undefined
|
|
14
|
-
? completed
|
|
15
|
-
? now
|
|
16
|
-
: undefined
|
|
17
|
-
: currentTodo.completedAt);
|
|
18
|
-
return { completed, completedAt };
|
|
19
|
-
}
|
|
20
|
-
function buildUpdatedTodo(currentTodo, updates) {
|
|
21
|
-
const now = new Date().toISOString();
|
|
22
|
-
const { completed, completedAt } = resolveCompletionUpdate(currentTodo, updates, now);
|
|
23
|
-
return {
|
|
24
|
-
...currentTodo,
|
|
25
|
-
...updates,
|
|
26
|
-
completed,
|
|
27
|
-
completedAt,
|
|
28
|
-
updatedAt: now,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
export function updateTodoInList(todos, id, updates) {
|
|
32
|
-
const index = todos.findIndex((todo) => todo.id === id);
|
|
33
|
-
if (index === -1)
|
|
34
|
-
return null;
|
|
35
|
-
const currentTodo = todos[index];
|
|
36
|
-
if (!currentTodo)
|
|
37
|
-
return null;
|
|
38
|
-
const normalizedUpdates = normalizeUpdateTags(updates);
|
|
39
|
-
const updatedTodo = buildUpdatedTodo(currentTodo, normalizedUpdates);
|
|
40
|
-
todos[index] = updatedTodo;
|
|
41
|
-
return updatedTodo;
|
|
42
|
-
}
|
|
43
2
|
export function createNotFoundOutcome(id) {
|
|
44
3
|
return {
|
|
45
4
|
kind: 'error',
|
|
46
5
|
response: createErrorResponse('E_NOT_FOUND', `Todo with ID ${id} not found`),
|
|
47
6
|
};
|
|
48
7
|
}
|
|
49
|
-
export function completeTodoInList(todos, id, completed) {
|
|
50
|
-
const currentTodo = todos.find((todo) => todo.id === id);
|
|
51
|
-
if (!currentTodo) {
|
|
52
|
-
return createNotFoundOutcome(id);
|
|
53
|
-
}
|
|
54
|
-
if (currentTodo.completed === completed) {
|
|
55
|
-
return { kind: 'already', todo: currentTodo };
|
|
56
|
-
}
|
|
57
|
-
const updatedTodo = updateTodoInList(todos, id, {
|
|
58
|
-
completed,
|
|
59
|
-
completedAt: completed ? new Date().toISOString() : undefined,
|
|
60
|
-
});
|
|
61
|
-
if (!updatedTodo) {
|
|
62
|
-
return createNotFoundOutcome(id);
|
|
63
|
-
}
|
|
64
|
-
return { kind: 'match', todo: updatedTodo };
|
|
65
|
-
}
|
|
66
8
|
//# sourceMappingURL=storage_mutations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_mutations.js","sourceRoot":"","sources":["../../src/lib/storage_mutations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"storage_mutations.js","sourceRoot":"","sources":["../../src/lib/storage_mutations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAalD,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,mBAAmB,CAC3B,aAAa,EACb,gBAAgB,EAAE,YAAY,CAC/B;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_state.d.ts","sourceRoot":"","sources":["../../src/lib/storage_state.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,IAAI,EAAe,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"storage_state.d.ts","sourceRoot":"","sources":["../../src/lib/storage_state.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,IAAI,EAAe,MAAM,YAAY,CAAC;AA4HpD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAoBzD;AA+ED,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOhE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/D"}
|
|
@@ -8,6 +8,7 @@ const FILE_TIMEOUT_MS = 5000;
|
|
|
8
8
|
const FILE_ENCODING = 'utf-8';
|
|
9
9
|
const TEMP_DIR_PREFIX = '.tmp-';
|
|
10
10
|
let writeChain = Promise.resolve();
|
|
11
|
+
let todosCache = null;
|
|
11
12
|
function withTimeout(promise, timeoutMs, label) {
|
|
12
13
|
let timer;
|
|
13
14
|
const timeout = new Promise((_, reject) => {
|
|
@@ -59,6 +60,25 @@ function parseTodos(rawJson) {
|
|
|
59
60
|
}
|
|
60
61
|
return parsed.data;
|
|
61
62
|
}
|
|
63
|
+
function getCachedTodos(path, stats) {
|
|
64
|
+
if (!todosCache)
|
|
65
|
+
return null;
|
|
66
|
+
if (todosCache.path !== path)
|
|
67
|
+
return null;
|
|
68
|
+
if (todosCache.mtimeMs !== stats.mtimeMs)
|
|
69
|
+
return null;
|
|
70
|
+
if (todosCache.size !== stats.size)
|
|
71
|
+
return null;
|
|
72
|
+
return todosCache.todos;
|
|
73
|
+
}
|
|
74
|
+
function setTodosCache(path, stats, todos) {
|
|
75
|
+
todosCache = {
|
|
76
|
+
path,
|
|
77
|
+
mtimeMs: stats.mtimeMs,
|
|
78
|
+
size: stats.size,
|
|
79
|
+
todos,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
62
82
|
async function statTodoFile(path) {
|
|
63
83
|
try {
|
|
64
84
|
const stats = await withTimeout(stat(path), FILE_TIMEOUT_MS, 'stat todo file');
|
|
@@ -86,12 +106,19 @@ export async function readTodosFromDisk() {
|
|
|
86
106
|
try {
|
|
87
107
|
const stats = await statTodoFile(path);
|
|
88
108
|
if (!stats) {
|
|
109
|
+
todosCache = null;
|
|
89
110
|
return [];
|
|
90
111
|
}
|
|
91
|
-
|
|
112
|
+
const cached = getCachedTodos(path, stats);
|
|
113
|
+
if (cached)
|
|
114
|
+
return cached;
|
|
115
|
+
const todos = await readTodosFile(path);
|
|
116
|
+
setTodosCache(path, stats, todos);
|
|
117
|
+
return todos;
|
|
92
118
|
}
|
|
93
119
|
catch (error) {
|
|
94
120
|
if (isFileNotFound(error)) {
|
|
121
|
+
todosCache = null;
|
|
95
122
|
return [];
|
|
96
123
|
}
|
|
97
124
|
throw error;
|
|
@@ -142,7 +169,7 @@ async function writeFileAtomically(path, data) {
|
|
|
142
169
|
await withTimeout(rm(tempDir, { recursive: true, force: true }), FILE_TIMEOUT_MS, 'cleanup temp dir');
|
|
143
170
|
}
|
|
144
171
|
catch {
|
|
145
|
-
|
|
172
|
+
// Cleanup failure is non-critical
|
|
146
173
|
}
|
|
147
174
|
}
|
|
148
175
|
}
|
|
@@ -157,5 +184,12 @@ export async function waitForWrites() {
|
|
|
157
184
|
export async function persistTodos(todos) {
|
|
158
185
|
const path = getTodoFilePath();
|
|
159
186
|
await writeFileAtomically(path, JSON.stringify(todos, null, 2));
|
|
187
|
+
const stats = await statTodoFile(path);
|
|
188
|
+
if (stats) {
|
|
189
|
+
setTodosCache(path, stats, todos);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
todosCache = null;
|
|
193
|
+
}
|
|
160
194
|
}
|
|
161
195
|
//# sourceMappingURL=storage_state.js.map
|