@todu/engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/change-observer.d.ts +15 -0
- package/dist/change-observer.d.ts.map +1 -0
- package/dist/change-observer.js +64 -0
- package/dist/change-observer.js.map +1 -0
- package/dist/habits.d.ts +6 -0
- package/dist/habits.d.ts.map +1 -0
- package/dist/habits.js +397 -0
- package/dist/habits.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/labels.d.ts +5 -0
- package/dist/labels.d.ts.map +1 -0
- package/dist/labels.js +113 -0
- package/dist/labels.js.map +1 -0
- package/dist/notes.d.ts +5 -0
- package/dist/notes.d.ts.map +1 -0
- package/dist/notes.js +163 -0
- package/dist/notes.js.map +1 -0
- package/dist/projects.d.ts +5 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +117 -0
- package/dist/projects.js.map +1 -0
- package/dist/recurring.d.ts +23 -0
- package/dist/recurring.d.ts.map +1 -0
- package/dist/recurring.js +372 -0
- package/dist/recurring.js.map +1 -0
- package/dist/schedule.d.ts +38 -0
- package/dist/schedule.d.ts.map +1 -0
- package/dist/schedule.js +330 -0
- package/dist/schedule.js.map +1 -0
- package/dist/scheduling.d.ts +62 -0
- package/dist/scheduling.d.ts.map +1 -0
- package/dist/scheduling.js +58 -0
- package/dist/scheduling.js.map +1 -0
- package/dist/storage.d.ts +34 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +204 -0
- package/dist/storage.js.map +1 -0
- package/dist/sync-client.d.ts +16 -0
- package/dist/sync-client.d.ts.map +1 -0
- package/dist/sync-client.js +54 -0
- package/dist/sync-client.js.map +1 -0
- package/dist/sync-server.d.ts +12 -0
- package/dist/sync-server.d.ts.map +1 -0
- package/dist/sync-server.js +21 -0
- package/dist/sync-server.js.map +1 -0
- package/dist/tasks.d.ts +18 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +396 -0
- package/dist/tasks.js.map +1 -0
- package/dist/todu.d.ts +115 -0
- package/dist/todu.d.ts.map +1 -0
- package/dist/todu.js +76 -0
- package/dist/todu.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Repo } from "@automerge/automerge-repo";
|
|
2
|
+
/**
|
|
3
|
+
* Observe changes across all documents in a Repo.
|
|
4
|
+
*
|
|
5
|
+
* Subscribes to "change" events on every existing document handle and
|
|
6
|
+
* automatically subscribes to new documents as they are created or
|
|
7
|
+
* discovered (via the Repo "document" event).
|
|
8
|
+
*
|
|
9
|
+
* Changes are coalesced: multiple document changes within the same
|
|
10
|
+
* microtask batch fire the callback only once.
|
|
11
|
+
*
|
|
12
|
+
* @returns A cleanup function that removes all listeners.
|
|
13
|
+
*/
|
|
14
|
+
export declare function observeAllChanges(repo: Repo, callback: () => void): () => void;
|
|
15
|
+
//# sourceMappingURL=change-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-observer.d.ts","sourceRoot":"","sources":["../src/change-observer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAwD9E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observe changes across all documents in a Repo.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to "change" events on every existing document handle and
|
|
5
|
+
* automatically subscribes to new documents as they are created or
|
|
6
|
+
* discovered (via the Repo "document" event).
|
|
7
|
+
*
|
|
8
|
+
* Changes are coalesced: multiple document changes within the same
|
|
9
|
+
* microtask batch fire the callback only once.
|
|
10
|
+
*
|
|
11
|
+
* @returns A cleanup function that removes all listeners.
|
|
12
|
+
*/
|
|
13
|
+
export function observeAllChanges(repo, callback) {
|
|
14
|
+
const observed = new Set();
|
|
15
|
+
let pending = false;
|
|
16
|
+
let pollTimer = null;
|
|
17
|
+
function coalesced() {
|
|
18
|
+
if (!pending) {
|
|
19
|
+
pending = true;
|
|
20
|
+
queueMicrotask(() => {
|
|
21
|
+
pending = false;
|
|
22
|
+
callback();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function observe(handle) {
|
|
27
|
+
if (observed.has(handle.documentId))
|
|
28
|
+
return;
|
|
29
|
+
observed.add(handle.documentId);
|
|
30
|
+
handle.on("change", coalesced);
|
|
31
|
+
}
|
|
32
|
+
/** Scan repo.handles for any new unobserved handles. */
|
|
33
|
+
function scanForNewHandles() {
|
|
34
|
+
for (const handle of Object.values(repo.handles)) {
|
|
35
|
+
observe(handle);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Subscribe to all existing document handles
|
|
39
|
+
scanForNewHandles();
|
|
40
|
+
// The Repo "document" event may not fire in all versions of automerge-repo,
|
|
41
|
+
// so we also poll for new handles periodically. The poll is cheap — just
|
|
42
|
+
// iterating a map and checking a Set.
|
|
43
|
+
function onDocument({ handle }) {
|
|
44
|
+
observe(handle);
|
|
45
|
+
}
|
|
46
|
+
repo.on("document", onDocument);
|
|
47
|
+
// Poll every 2 seconds for new document handles that weren't caught by the event
|
|
48
|
+
pollTimer = setInterval(scanForNewHandles, 2000);
|
|
49
|
+
// Cleanup: remove all listeners
|
|
50
|
+
return () => {
|
|
51
|
+
repo.off("document", onDocument);
|
|
52
|
+
if (pollTimer !== null) {
|
|
53
|
+
clearInterval(pollTimer);
|
|
54
|
+
pollTimer = null;
|
|
55
|
+
}
|
|
56
|
+
for (const handle of Object.values(repo.handles)) {
|
|
57
|
+
if (observed.has(handle.documentId)) {
|
|
58
|
+
handle.off("change", coalesced);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
observed.clear();
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=change-observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-observer.js","sourceRoot":"","sources":["../src/change-observer.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU,EAAE,QAAoB,EAAc;IAC9E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAc,CAAC;IACvC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,SAAS,GAA0C,IAAI,CAAC;IAE5D,SAAS,SAAS,GAAS;QACzB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,IAAI,CAAC;YACf,cAAc,CAAC,GAAG,EAAE,CAAC;gBACnB,OAAO,GAAG,KAAK,CAAC;gBAChB,QAAQ,EAAE,CAAC;YAAA,CACZ,CAAC,CAAC;QACL,CAAC;IAAA,CACF;IAED,SAAS,OAAO,CAAC,MAA0B,EAAQ;QACjD,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;YAAE,OAAO;QAC5C,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAAA,CAChC;IAED,wDAAwD;IACxD,SAAS,iBAAiB,GAAS;QACjC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;IAAA,CACF;IAED,6CAA6C;IAC7C,iBAAiB,EAAE,CAAC;IAEpB,4EAA4E;IAC5E,2EAAyE;IACzE,sCAAsC;IACtC,SAAS,UAAU,CAAC,EAAE,MAAM,EAAkC,EAAQ;QACpE,OAAO,CAAC,MAAM,CAAC,CAAC;IAAA,CACjB;IACD,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAEhC,iFAAiF;IACjF,SAAS,GAAG,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IAEjD,gCAAgC;IAChC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACjC,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,KAAK,EAAE,CAAC;IAAA,CAClB,CAAC;AAAA,CACH"}
|
package/dist/habits.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DocHandle, Repo } from "@automerge/automerge-repo";
|
|
2
|
+
import { type CatalogDocument } from "@todu/core";
|
|
3
|
+
import type { HabitNamespace } from "./todu.js";
|
|
4
|
+
export declare function createHabitNamespace(catalog: DocHandle<CatalogDocument>, repo: Repo): HabitNamespace;
|
|
5
|
+
export declare function registerHabitProcessor(_catalog: DocHandle<CatalogDocument>, _repo: Repo): void;
|
|
6
|
+
//# sourceMappingURL=habits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"habits.d.ts","sourceRoot":"","sources":["../src/habits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EACL,KAAK,eAAe,EAmBrB,MAAM,YAAY,CAAC;AAGpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAqBhD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,CAAC,eAAe,CAAC,EACnC,IAAI,EAAE,IAAI,GACT,cAAc,CA0XhB;AAMD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,CA6B9F"}
|
package/dist/habits.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { createHabitId, createHabitLogDocument, err, notFound, ok, validateCreateHabitInput, validateUpdateHabitInput, validationError, } from "@todu/core";
|
|
2
|
+
import { isScheduledDate, nextOccurrence, todayInTimezone } from "./schedule.js";
|
|
3
|
+
import { registerProcessor } from "./scheduling.js";
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Helpers
|
|
6
|
+
// ============================================================================
|
|
7
|
+
function generateHabitId() {
|
|
8
|
+
const hex = [...crypto.getRandomValues(new Uint8Array(4))]
|
|
9
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
10
|
+
.join("");
|
|
11
|
+
return createHabitId(`hab-${hex}`);
|
|
12
|
+
}
|
|
13
|
+
function cloneHabit(h) {
|
|
14
|
+
return JSON.parse(JSON.stringify(h));
|
|
15
|
+
}
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Habit namespace factory
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export function createHabitNamespace(catalog, repo) {
|
|
20
|
+
async function getLogHandle(habitId) {
|
|
21
|
+
const doc = catalog.doc();
|
|
22
|
+
if (!doc)
|
|
23
|
+
return null;
|
|
24
|
+
const docId = doc.habitLogDocIds[habitId];
|
|
25
|
+
if (!docId)
|
|
26
|
+
return null;
|
|
27
|
+
return repo.find(docId);
|
|
28
|
+
}
|
|
29
|
+
async function getOrCreateLogHandle(habitId) {
|
|
30
|
+
const existing = await getLogHandle(habitId);
|
|
31
|
+
if (existing)
|
|
32
|
+
return existing;
|
|
33
|
+
const handle = repo.create();
|
|
34
|
+
const empty = createHabitLogDocument(habitId);
|
|
35
|
+
handle.change((doc) => {
|
|
36
|
+
doc.habitId = empty.habitId;
|
|
37
|
+
doc.entries = empty.entries;
|
|
38
|
+
});
|
|
39
|
+
catalog.change((doc) => {
|
|
40
|
+
doc.habitLogDocIds[habitId] = handle.documentId;
|
|
41
|
+
});
|
|
42
|
+
return handle;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
async create(input) {
|
|
46
|
+
const validationErr = validateCreateHabitInput(input);
|
|
47
|
+
if (validationErr)
|
|
48
|
+
return err(validationErr);
|
|
49
|
+
const id = generateHabitId();
|
|
50
|
+
const now = new Date().toISOString();
|
|
51
|
+
const nextDue = nextOccurrence(input.schedule, input.startDate, input.timezone, input.startDate, input.endDate);
|
|
52
|
+
if (!nextDue) {
|
|
53
|
+
return err(validationError("schedule", "Schedule produces no occurrences from start date"));
|
|
54
|
+
}
|
|
55
|
+
const habit = {
|
|
56
|
+
id,
|
|
57
|
+
title: input.title.trim(),
|
|
58
|
+
description: input.description,
|
|
59
|
+
schedule: input.schedule,
|
|
60
|
+
timezone: input.timezone,
|
|
61
|
+
startDate: input.startDate,
|
|
62
|
+
endDate: input.endDate,
|
|
63
|
+
nextDue,
|
|
64
|
+
paused: false,
|
|
65
|
+
createdAt: now,
|
|
66
|
+
updatedAt: now,
|
|
67
|
+
};
|
|
68
|
+
// Create the HabitLogDocument
|
|
69
|
+
await getOrCreateLogHandle(id);
|
|
70
|
+
catalog.change((doc) => {
|
|
71
|
+
// Strip undefined for Automerge
|
|
72
|
+
const entry = { ...habit };
|
|
73
|
+
for (const key of Object.keys(entry)) {
|
|
74
|
+
if (entry[key] === undefined)
|
|
75
|
+
delete entry[key];
|
|
76
|
+
}
|
|
77
|
+
doc.habits.push(entry);
|
|
78
|
+
});
|
|
79
|
+
return ok(cloneHabit(habit));
|
|
80
|
+
},
|
|
81
|
+
async list(filter) {
|
|
82
|
+
const doc = catalog.doc();
|
|
83
|
+
if (!doc)
|
|
84
|
+
return ok([]);
|
|
85
|
+
let habits = [...doc.habits];
|
|
86
|
+
if (filter?.paused !== undefined) {
|
|
87
|
+
habits = habits.filter((h) => h.paused === filter.paused);
|
|
88
|
+
}
|
|
89
|
+
if (filter?.search) {
|
|
90
|
+
const lowerQuery = filter.search.toLowerCase();
|
|
91
|
+
habits = habits.filter((h) => h.title.toLowerCase().includes(lowerQuery));
|
|
92
|
+
}
|
|
93
|
+
if (filter?.checkedToday !== undefined) {
|
|
94
|
+
const checked = [];
|
|
95
|
+
for (const h of habits) {
|
|
96
|
+
const logHandle = await getLogHandle(h.id);
|
|
97
|
+
const logDoc = logHandle?.doc();
|
|
98
|
+
const today = todayInTimezone(h.timezone);
|
|
99
|
+
const completedToday = logDoc?.entries[today]?.completed === true;
|
|
100
|
+
if (completedToday === filter.checkedToday) {
|
|
101
|
+
checked.push(h);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
habits = checked;
|
|
105
|
+
}
|
|
106
|
+
return ok(habits.map(cloneHabit));
|
|
107
|
+
},
|
|
108
|
+
async get(id) {
|
|
109
|
+
const doc = catalog.doc();
|
|
110
|
+
if (!doc)
|
|
111
|
+
return err(notFound("habit", id));
|
|
112
|
+
const habit = doc.habits.find((h) => h.id === id);
|
|
113
|
+
if (!habit)
|
|
114
|
+
return err(notFound("habit", id));
|
|
115
|
+
return ok(cloneHabit(habit));
|
|
116
|
+
},
|
|
117
|
+
async update(id, input) {
|
|
118
|
+
const validationErr = validateUpdateHabitInput(input);
|
|
119
|
+
if (validationErr)
|
|
120
|
+
return err(validationErr);
|
|
121
|
+
const doc = catalog.doc();
|
|
122
|
+
if (!doc)
|
|
123
|
+
return err(notFound("habit", id));
|
|
124
|
+
const index = doc.habits.findIndex((h) => h.id === id);
|
|
125
|
+
if (index === -1)
|
|
126
|
+
return err(notFound("habit", id));
|
|
127
|
+
const scheduleChanged = input.schedule !== undefined || input.timezone !== undefined;
|
|
128
|
+
catalog.change((doc) => {
|
|
129
|
+
const h = doc.habits[index];
|
|
130
|
+
if (input.title !== undefined)
|
|
131
|
+
h.title = input.title.trim();
|
|
132
|
+
if (input.description !== undefined)
|
|
133
|
+
h.description = input.description;
|
|
134
|
+
if (input.schedule !== undefined)
|
|
135
|
+
h.schedule = input.schedule;
|
|
136
|
+
if (input.timezone !== undefined)
|
|
137
|
+
h.timezone = input.timezone;
|
|
138
|
+
if (input.endDate !== undefined)
|
|
139
|
+
h.endDate = input.endDate;
|
|
140
|
+
h.updatedAt = new Date().toISOString();
|
|
141
|
+
if (scheduleChanged) {
|
|
142
|
+
const next = nextOccurrence(h.schedule, h.startDate, h.timezone, h.nextDue, h.endDate);
|
|
143
|
+
if (next)
|
|
144
|
+
h.nextDue = next;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const updated = catalog.doc().habits[index];
|
|
148
|
+
return ok(cloneHabit(updated));
|
|
149
|
+
},
|
|
150
|
+
async delete(id) {
|
|
151
|
+
const doc = catalog.doc();
|
|
152
|
+
if (!doc)
|
|
153
|
+
return err(notFound("habit", id));
|
|
154
|
+
const index = doc.habits.findIndex((h) => h.id === id);
|
|
155
|
+
if (index === -1)
|
|
156
|
+
return err(notFound("habit", id));
|
|
157
|
+
catalog.change((doc) => {
|
|
158
|
+
doc.habits.splice(index, 1);
|
|
159
|
+
delete doc.habitLogDocIds[id];
|
|
160
|
+
});
|
|
161
|
+
return ok(undefined);
|
|
162
|
+
},
|
|
163
|
+
async pause(id) {
|
|
164
|
+
const doc = catalog.doc();
|
|
165
|
+
if (!doc)
|
|
166
|
+
return err(notFound("habit", id));
|
|
167
|
+
const index = doc.habits.findIndex((h) => h.id === id);
|
|
168
|
+
if (index === -1)
|
|
169
|
+
return err(notFound("habit", id));
|
|
170
|
+
catalog.change((doc) => {
|
|
171
|
+
doc.habits[index].paused = true;
|
|
172
|
+
doc.habits[index].updatedAt = new Date().toISOString();
|
|
173
|
+
});
|
|
174
|
+
return ok(cloneHabit(catalog.doc().habits[index]));
|
|
175
|
+
},
|
|
176
|
+
async resume(id) {
|
|
177
|
+
const doc = catalog.doc();
|
|
178
|
+
if (!doc)
|
|
179
|
+
return err(notFound("habit", id));
|
|
180
|
+
const index = doc.habits.findIndex((h) => h.id === id);
|
|
181
|
+
if (index === -1)
|
|
182
|
+
return err(notFound("habit", id));
|
|
183
|
+
catalog.change((doc) => {
|
|
184
|
+
const h = doc.habits[index];
|
|
185
|
+
h.paused = false;
|
|
186
|
+
h.updatedAt = new Date().toISOString();
|
|
187
|
+
// Recalculate nextDue from today
|
|
188
|
+
const today = todayInTimezone(h.timezone);
|
|
189
|
+
const next = nextOccurrence(h.schedule, h.startDate, h.timezone, today, h.endDate);
|
|
190
|
+
if (next)
|
|
191
|
+
h.nextDue = next;
|
|
192
|
+
});
|
|
193
|
+
return ok(cloneHabit(catalog.doc().habits[index]));
|
|
194
|
+
},
|
|
195
|
+
async check(id) {
|
|
196
|
+
const doc = catalog.doc();
|
|
197
|
+
if (!doc)
|
|
198
|
+
return err(notFound("habit", id));
|
|
199
|
+
const habit = doc.habits.find((h) => h.id === id);
|
|
200
|
+
if (!habit)
|
|
201
|
+
return err(notFound("habit", id));
|
|
202
|
+
const today = todayInTimezone(habit.timezone);
|
|
203
|
+
const logHandle = await getLogHandle(id);
|
|
204
|
+
if (!logHandle)
|
|
205
|
+
return err(notFound("habit log", id));
|
|
206
|
+
const logDoc = logHandle.doc();
|
|
207
|
+
// If already checked today, return the existing entry (idempotent)
|
|
208
|
+
if (logDoc?.entries[today]?.completed) {
|
|
209
|
+
const entry = logDoc.entries[today];
|
|
210
|
+
return ok({ date: entry.date, completed: entry.completed, checkedAt: entry.checkedAt });
|
|
211
|
+
}
|
|
212
|
+
const entry = {
|
|
213
|
+
date: today,
|
|
214
|
+
completed: true,
|
|
215
|
+
checkedAt: new Date().toISOString(),
|
|
216
|
+
};
|
|
217
|
+
logHandle.change((doc) => {
|
|
218
|
+
doc.entries[today] = entry;
|
|
219
|
+
});
|
|
220
|
+
return ok(entry);
|
|
221
|
+
},
|
|
222
|
+
async uncheck(id) {
|
|
223
|
+
const doc = catalog.doc();
|
|
224
|
+
if (!doc)
|
|
225
|
+
return err(notFound("habit", id));
|
|
226
|
+
const habit = doc.habits.find((h) => h.id === id);
|
|
227
|
+
if (!habit)
|
|
228
|
+
return err(notFound("habit", id));
|
|
229
|
+
const today = todayInTimezone(habit.timezone);
|
|
230
|
+
const logHandle = await getLogHandle(id);
|
|
231
|
+
if (!logHandle)
|
|
232
|
+
return err(notFound("habit log", id));
|
|
233
|
+
const logDoc = logHandle.doc();
|
|
234
|
+
// If not checked today, return success (idempotent)
|
|
235
|
+
if (!logDoc?.entries[today])
|
|
236
|
+
return ok(undefined);
|
|
237
|
+
logHandle.change((doc) => {
|
|
238
|
+
delete doc.entries[today];
|
|
239
|
+
});
|
|
240
|
+
return ok(undefined);
|
|
241
|
+
},
|
|
242
|
+
async streak(id) {
|
|
243
|
+
const doc = catalog.doc();
|
|
244
|
+
if (!doc)
|
|
245
|
+
return err(notFound("habit", id));
|
|
246
|
+
const habit = doc.habits.find((h) => h.id === id);
|
|
247
|
+
if (!habit)
|
|
248
|
+
return err(notFound("habit", id));
|
|
249
|
+
const logHandle = await getLogHandle(id);
|
|
250
|
+
if (!logHandle)
|
|
251
|
+
return err(notFound("habit log", id));
|
|
252
|
+
const logDoc = logHandle.doc();
|
|
253
|
+
const entries = logDoc?.entries ?? {};
|
|
254
|
+
const today = todayInTimezone(habit.timezone);
|
|
255
|
+
const completedToday = entries[today]?.completed === true;
|
|
256
|
+
// Count total check-ins
|
|
257
|
+
let totalCheckins = 0;
|
|
258
|
+
for (const entry of Object.values(entries)) {
|
|
259
|
+
if (entry.completed)
|
|
260
|
+
totalCheckins++;
|
|
261
|
+
}
|
|
262
|
+
// Compute current streak: count backwards from today through scheduled dates
|
|
263
|
+
let current = 0;
|
|
264
|
+
let checkDate = today;
|
|
265
|
+
while (true) {
|
|
266
|
+
const isScheduled = isScheduledDate(habit.schedule, habit.startDate, habit.timezone, checkDate, habit.endDate);
|
|
267
|
+
if (isScheduled) {
|
|
268
|
+
if (entries[checkDate]?.completed) {
|
|
269
|
+
current++;
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
checkDate = shiftDate(checkDate, -1);
|
|
276
|
+
// Don't go before start date
|
|
277
|
+
if (checkDate < habit.startDate)
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
// Compute longest streak: scan all entries sorted by date
|
|
281
|
+
const sortedDates = Object.keys(entries)
|
|
282
|
+
.filter((d) => entries[d].completed)
|
|
283
|
+
.sort();
|
|
284
|
+
let longest = 0;
|
|
285
|
+
let streak = 0;
|
|
286
|
+
let prevScheduledDate = null;
|
|
287
|
+
for (const date of sortedDates) {
|
|
288
|
+
if (!isScheduledDate(habit.schedule, habit.startDate, habit.timezone, date, habit.endDate)) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (prevScheduledDate === null) {
|
|
292
|
+
streak = 1;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// Check if there's an unscheduled gap
|
|
296
|
+
const hasGap = hasUncompletedScheduledDateBetween(habit.schedule, habit.startDate, habit.timezone, prevScheduledDate, date, entries, habit.endDate);
|
|
297
|
+
if (hasGap) {
|
|
298
|
+
streak = 1;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
streak++;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (streak > longest)
|
|
305
|
+
longest = streak;
|
|
306
|
+
prevScheduledDate = date;
|
|
307
|
+
}
|
|
308
|
+
return ok({ current, longest, completedToday, totalCheckins });
|
|
309
|
+
},
|
|
310
|
+
async history(id, days = 30) {
|
|
311
|
+
const doc = catalog.doc();
|
|
312
|
+
if (!doc)
|
|
313
|
+
return err(notFound("habit", id));
|
|
314
|
+
const habit = doc.habits.find((h) => h.id === id);
|
|
315
|
+
if (!habit)
|
|
316
|
+
return err(notFound("habit", id));
|
|
317
|
+
const logHandle = await getLogHandle(id);
|
|
318
|
+
if (!logHandle)
|
|
319
|
+
return err(notFound("habit log", id));
|
|
320
|
+
const logDoc = logHandle.doc();
|
|
321
|
+
const entries = logDoc?.entries ?? {};
|
|
322
|
+
const today = todayInTimezone(habit.timezone);
|
|
323
|
+
const result = [];
|
|
324
|
+
for (let i = 0; i < days; i++) {
|
|
325
|
+
const date = shiftDate(today, -i);
|
|
326
|
+
if (date < habit.startDate)
|
|
327
|
+
break;
|
|
328
|
+
const scheduled = isScheduledDate(habit.schedule, habit.startDate, habit.timezone, date, habit.endDate);
|
|
329
|
+
if (scheduled) {
|
|
330
|
+
result.push({
|
|
331
|
+
date,
|
|
332
|
+
scheduled: true,
|
|
333
|
+
completed: entries[date]?.completed === true,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return ok(result);
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
// ============================================================================
|
|
342
|
+
// Habit processor for processTemplates()
|
|
343
|
+
// ============================================================================
|
|
344
|
+
export function registerHabitProcessor(_catalog, _repo) {
|
|
345
|
+
registerProcessor("habit", async (context) => {
|
|
346
|
+
const doc = context.catalog.doc();
|
|
347
|
+
if (!doc?.habits)
|
|
348
|
+
return 0;
|
|
349
|
+
let processed = 0;
|
|
350
|
+
for (let i = 0; i < doc.habits.length; i++) {
|
|
351
|
+
const habit = doc.habits[i];
|
|
352
|
+
if (habit.paused)
|
|
353
|
+
continue;
|
|
354
|
+
const today = todayInTimezone(habit.timezone);
|
|
355
|
+
if (habit.nextDue > today)
|
|
356
|
+
continue;
|
|
357
|
+
// Advance nextDue to today or next scheduled date
|
|
358
|
+
context.catalog.change((d) => {
|
|
359
|
+
const h = d.habits[i];
|
|
360
|
+
const next = nextOccurrence(h.schedule, h.startDate, h.timezone, today, h.endDate);
|
|
361
|
+
if (next) {
|
|
362
|
+
h.nextDue = next;
|
|
363
|
+
}
|
|
364
|
+
h.updatedAt = new Date().toISOString();
|
|
365
|
+
});
|
|
366
|
+
processed++;
|
|
367
|
+
}
|
|
368
|
+
return processed;
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
// ============================================================================
|
|
372
|
+
// Date helpers
|
|
373
|
+
// ============================================================================
|
|
374
|
+
function shiftDate(dateStr, days) {
|
|
375
|
+
const [y, m, d] = dateStr.split("-").map(Number);
|
|
376
|
+
const date = new Date(Date.UTC(y, m - 1, d));
|
|
377
|
+
date.setUTCDate(date.getUTCDate() + days);
|
|
378
|
+
const yy = date.getUTCFullYear();
|
|
379
|
+
const mm = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
380
|
+
const dd = String(date.getUTCDate()).padStart(2, "0");
|
|
381
|
+
return `${yy}-${mm}-${dd}`;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Check if there's any scheduled date between two dates that lacks a completed entry.
|
|
385
|
+
*/
|
|
386
|
+
function hasUncompletedScheduledDateBetween(schedule, startDate, timezone, from, to, entries, endDate) {
|
|
387
|
+
let date = shiftDate(from, 1);
|
|
388
|
+
while (date < to) {
|
|
389
|
+
if (isScheduledDate(schedule, startDate, timezone, date, endDate)) {
|
|
390
|
+
if (!entries[date]?.completed)
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
date = shiftDate(date, 1);
|
|
394
|
+
}
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=habits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"habits.js","sourceRoot":"","sources":["../src/habits.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Todu, type ToduConfig } from "./todu.js";
|
|
2
|
+
export type { UpcomingOccurrence } from "./recurring.js";
|
|
3
|
+
export { describeSchedule, isScheduledDate, nextOccurrence, nextOccurrences, todayInTimezone, } from "./schedule.js";
|
|
4
|
+
export type { ProcessingContext, SchedulableItem, TemplateProcessor } from "./scheduling.js";
|
|
5
|
+
export { clearProcessors, getRegisteredProcessors, registerProcessor } from "./scheduling.js";
|
|
6
|
+
export type { Storage } from "./storage.js";
|
|
7
|
+
export { isSyncServerAvailable } from "./sync-client.js";
|
|
8
|
+
export { DEFAULT_SYNC_PORT } from "./sync-server.js";
|
|
9
|
+
export type { HabitNamespace, LabelNamespace, LocalSyncMode, NoteNamespace, ProjectNamespace, RecurringNamespace, RemoteSyncState, SyncStatus, TaskNamespace, Todu, ToduConfig, } from "./todu.js";
|
|
10
|
+
/**
|
|
11
|
+
* Create a Todu SDK instance.
|
|
12
|
+
*
|
|
13
|
+
* Initializes Automerge storage, loads or creates the catalog document,
|
|
14
|
+
* processes any due recurring templates/habits, and returns the SDK
|
|
15
|
+
* with all operation namespaces.
|
|
16
|
+
*
|
|
17
|
+
* Sync modes:
|
|
18
|
+
* - `syncServer: true` — Start a WebSocket sync server. Other instances
|
|
19
|
+
* (CLI, other devices) can connect and sync. Used by Electron.
|
|
20
|
+
* - `syncClient: true` — Connect to a running sync server. Changes
|
|
21
|
+
* propagate bidirectionally via Automerge sync protocol. Used by CLI.
|
|
22
|
+
* - Neither — Standalone, no sync. Used by tests.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createTodu(config: Pick<ToduConfig, "storagePath"> & Partial<Omit<ToduConfig, "storagePath">>): Promise<Todu>;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAEnB,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,aAAa,EACb,IAAI,EACJ,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC,CA+Ef"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { observeAllChanges } from "./change-observer.js";
|
|
2
|
+
import { createHabitNamespace, registerHabitProcessor } from "./habits.js";
|
|
3
|
+
import { createLabelNamespace } from "./labels.js";
|
|
4
|
+
import { createNoteNamespace } from "./notes.js";
|
|
5
|
+
import { createProjectNamespace } from "./projects.js";
|
|
6
|
+
import { createRecurringNamespace, registerRecurringProcessor } from "./recurring.js";
|
|
7
|
+
import { processTemplates } from "./scheduling.js";
|
|
8
|
+
import { initEphemeralStorage, initStorage } from "./storage.js";
|
|
9
|
+
import { connectSyncClient } from "./sync-client.js";
|
|
10
|
+
import { startSyncServer } from "./sync-server.js";
|
|
11
|
+
import { createTaskNamespace } from "./tasks.js";
|
|
12
|
+
import { createStubNamespaces, } from "./todu.js";
|
|
13
|
+
// Re-export schedule utilities for consumers
|
|
14
|
+
export { describeSchedule, isScheduledDate, nextOccurrence, nextOccurrences, todayInTimezone, } from "./schedule.js";
|
|
15
|
+
export { clearProcessors, getRegisteredProcessors, registerProcessor } from "./scheduling.js";
|
|
16
|
+
export { isSyncServerAvailable } from "./sync-client.js";
|
|
17
|
+
export { DEFAULT_SYNC_PORT } from "./sync-server.js";
|
|
18
|
+
/**
|
|
19
|
+
* Create a Todu SDK instance.
|
|
20
|
+
*
|
|
21
|
+
* Initializes Automerge storage, loads or creates the catalog document,
|
|
22
|
+
* processes any due recurring templates/habits, and returns the SDK
|
|
23
|
+
* with all operation namespaces.
|
|
24
|
+
*
|
|
25
|
+
* Sync modes:
|
|
26
|
+
* - `syncServer: true` — Start a WebSocket sync server. Other instances
|
|
27
|
+
* (CLI, other devices) can connect and sync. Used by Electron.
|
|
28
|
+
* - `syncClient: true` — Connect to a running sync server. Changes
|
|
29
|
+
* propagate bidirectionally via Automerge sync protocol. Used by CLI.
|
|
30
|
+
* - Neither — Standalone, no sync. Used by tests.
|
|
31
|
+
*/
|
|
32
|
+
export async function createTodu(config) {
|
|
33
|
+
const resolvedConfig = {
|
|
34
|
+
storagePath: config.storagePath,
|
|
35
|
+
};
|
|
36
|
+
// Sync client mode: ephemeral in-memory repo that syncs with server
|
|
37
|
+
// Sync server mode: persistent repo that serves sync clients
|
|
38
|
+
// Standalone: persistent repo, no sync
|
|
39
|
+
let syncServer = null;
|
|
40
|
+
let storage;
|
|
41
|
+
if (config?.syncClient) {
|
|
42
|
+
// Mode 2: CLI as ephemeral sync client
|
|
43
|
+
// 1. Create ephemeral repo (no storage)
|
|
44
|
+
// 2. Connect sync adapter so the repo has a peer
|
|
45
|
+
// 3. Find catalog document — sync peer provides the data
|
|
46
|
+
const ephemeral = await initEphemeralStorage(resolvedConfig.storagePath);
|
|
47
|
+
const port = config.syncPort ?? 24377;
|
|
48
|
+
await connectSyncClient(ephemeral.repo, `ws://127.0.0.1:${port}`);
|
|
49
|
+
storage = await ephemeral.findCatalog();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Mode 1 (standalone) or Electron (sync server)
|
|
53
|
+
storage = await initStorage(resolvedConfig.storagePath);
|
|
54
|
+
if (config?.syncServer) {
|
|
55
|
+
syncServer = startSyncServer(storage.repo, config.syncPort);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Register processors before processing
|
|
59
|
+
registerRecurringProcessor(storage.catalog, storage.repo);
|
|
60
|
+
registerHabitProcessor(storage.catalog, storage.repo);
|
|
61
|
+
// Process due templates/habits before returning the SDK.
|
|
62
|
+
// This is the "generate on access" pattern — every CLI invocation
|
|
63
|
+
// and Electron launch triggers template processing.
|
|
64
|
+
await processTemplates(storage.catalog);
|
|
65
|
+
// Determine local sync mode
|
|
66
|
+
const localMode = config?.syncClient
|
|
67
|
+
? "ephemeral-client"
|
|
68
|
+
: config?.syncServer
|
|
69
|
+
? "sync-server"
|
|
70
|
+
: "standalone";
|
|
71
|
+
const syncStatus = {
|
|
72
|
+
local: { mode: localMode },
|
|
73
|
+
// Remote multi-device sync is not yet implemented (phase 3)
|
|
74
|
+
remote: { state: "disconnected" },
|
|
75
|
+
};
|
|
76
|
+
const stubs = createStubNamespaces(resolvedConfig);
|
|
77
|
+
return {
|
|
78
|
+
...stubs,
|
|
79
|
+
project: createProjectNamespace(storage.catalog),
|
|
80
|
+
task: createTaskNamespace(storage.catalog, storage.repo),
|
|
81
|
+
label: createLabelNamespace(storage.catalog, storage.repo),
|
|
82
|
+
note: createNoteNamespace(storage.catalog, storage.repo),
|
|
83
|
+
recurring: createRecurringNamespace(storage.catalog, storage.repo),
|
|
84
|
+
habit: createHabitNamespace(storage.catalog, storage.repo),
|
|
85
|
+
sync: {
|
|
86
|
+
status: () => syncStatus,
|
|
87
|
+
start: () => Promise.resolve(),
|
|
88
|
+
stop: () => Promise.resolve(),
|
|
89
|
+
},
|
|
90
|
+
onChange(callback) {
|
|
91
|
+
return observeAllChanges(storage.repo, callback);
|
|
92
|
+
},
|
|
93
|
+
async close() {
|
|
94
|
+
// repo.shutdown() handles disconnecting network adapters.
|
|
95
|
+
// We just need to close the WS server (if any) after shutdown.
|
|
96
|
+
await storage.close();
|
|
97
|
+
if (syncServer) {
|
|
98
|
+
await syncServer.close();
|
|
99
|
+
syncServer = null;
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=index.js.map
|