botnote 0.1.24 → 0.1.26
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 +38 -0
- package/dist/bin.js +119 -4
- package/dist/bin.js.map +1 -1
- package/dist/db/migrations/0017_recurrence_rules.sql +55 -0
- package/dist/db/schema.d.ts +411 -0
- package/dist/db/schema.js +43 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/mcp/http-client.d.ts +54 -0
- package/dist/mcp/http-client.js +12 -0
- package/dist/mcp/http-client.js.map +1 -1
- package/dist/mcp/server.js +110 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/rest/routes.js +76 -9
- package/dist/rest/routes.js.map +1 -1
- package/dist/service/dates.d.ts +8 -0
- package/dist/service/dates.js +21 -0
- package/dist/service/dates.js.map +1 -0
- package/dist/service/entities.d.ts +1 -0
- package/dist/service/entities.js +46 -25
- package/dist/service/entities.js.map +1 -1
- package/dist/service/recurrence.d.ts +20 -0
- package/dist/service/recurrence.js +381 -0
- package/dist/service/recurrence.js.map +1 -0
- package/dist/service/types.d.ts +170 -0
- package/dist/service/types.js +37 -1
- package/dist/service/types.js.map +1 -1
- package/package.json +2 -1
- package/web/dist/assets/{index-DBDF6wZm.css → index-BLQefDfj.css} +1 -1
- package/web/dist/assets/{index-Ce0oSDsL.js → index-DWg0i6pr.js} +120 -120
- package/web/dist/index.html +2 -2
package/dist/service/entities.js
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { and, desc, eq, gte, inArray, isNull, sql } from "drizzle-orm";
|
|
2
2
|
import { edges, entities, projects } from "../db/schema.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* intended day across UTC-12..UTC+11. Anything with a non-zero time
|
|
8
|
-
* component is left alone — that's a real datetime, not a calendar date.
|
|
9
|
-
*/
|
|
10
|
-
function normalizeDueAt(value) {
|
|
11
|
-
if (value == null)
|
|
12
|
-
return null;
|
|
13
|
-
if (value.getUTCHours() === 0 &&
|
|
14
|
-
value.getUTCMinutes() === 0 &&
|
|
15
|
-
value.getUTCSeconds() === 0 &&
|
|
16
|
-
value.getUTCMilliseconds() === 0) {
|
|
17
|
-
const noon = new Date(value);
|
|
18
|
-
noon.setUTCHours(12);
|
|
19
|
-
return noon;
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
3
|
+
import { normalizeDueAt } from "./dates.js";
|
|
4
|
+
import { advanceRecurrenceOnCompletion } from "./recurrence.js";
|
|
5
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6
|
+
const UUID_PREFIX_RE = /^[0-9a-f-]{8,36}$/i;
|
|
23
7
|
function normalizeStatus(value) {
|
|
24
8
|
return value === "delayed" || value === "archived" ? "done" : value;
|
|
25
9
|
}
|
|
10
|
+
export async function resolveEntityId(db, idOrPrefix) {
|
|
11
|
+
if (UUID_RE.test(idOrPrefix))
|
|
12
|
+
return idOrPrefix;
|
|
13
|
+
if (!UUID_PREFIX_RE.test(idOrPrefix))
|
|
14
|
+
return null;
|
|
15
|
+
const rows = (await db.execute(sql `
|
|
16
|
+
SELECT id::text AS id
|
|
17
|
+
FROM entities
|
|
18
|
+
WHERE id::text LIKE ${`${idOrPrefix.toLowerCase()}%`}
|
|
19
|
+
LIMIT 2
|
|
20
|
+
`)).rows;
|
|
21
|
+
if (rows.length === 1)
|
|
22
|
+
return rows[0].id;
|
|
23
|
+
if (rows.length > 1)
|
|
24
|
+
throw new Error(`entity id prefix ${idOrPrefix} is ambiguous`);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
26
27
|
export async function write(db, input) {
|
|
27
28
|
if (input.idempotencyKey) {
|
|
28
29
|
const existing = await db
|
|
@@ -66,6 +67,9 @@ export async function write(db, input) {
|
|
|
66
67
|
return row;
|
|
67
68
|
}
|
|
68
69
|
export async function update(db, id, fields) {
|
|
70
|
+
const entityId = await resolveEntityId(db, id);
|
|
71
|
+
if (!entityId)
|
|
72
|
+
throw new Error(`entity ${id} not found`);
|
|
69
73
|
const normalizedFields = { ...fields };
|
|
70
74
|
if (fields.status !== undefined) {
|
|
71
75
|
normalizedFields.status = normalizeStatus(fields.status);
|
|
@@ -78,22 +82,24 @@ export async function update(db, id, fields) {
|
|
|
78
82
|
// prior status to know whether this is an entry into or exit from 'done',
|
|
79
83
|
// so do a tiny read first — cheaper than a CASE expression on UPDATE and
|
|
80
84
|
// keeps the SQL the same shape as other writes.
|
|
85
|
+
let enteredDone = false;
|
|
81
86
|
if (normalizedFields.status !== undefined) {
|
|
82
87
|
const prior = await db
|
|
83
88
|
.select({ status: entities.status })
|
|
84
89
|
.from(entities)
|
|
85
|
-
.where(eq(entities.id,
|
|
90
|
+
.where(eq(entities.id, entityId))
|
|
86
91
|
.limit(1);
|
|
87
92
|
if (!prior[0])
|
|
88
93
|
throw new Error(`entity ${id} not found`);
|
|
89
94
|
const wasDone = prior[0].status === "done";
|
|
90
95
|
const isDone = normalizedFields.status === "done";
|
|
96
|
+
enteredDone = isDone && !wasDone;
|
|
91
97
|
if (isDone && !wasDone)
|
|
92
98
|
set.completedAt = new Date();
|
|
93
99
|
else if (!isDone && wasDone)
|
|
94
100
|
set.completedAt = null;
|
|
95
101
|
}
|
|
96
|
-
const [row] = await db.update(entities).set(set).where(eq(entities.id,
|
|
102
|
+
const [row] = await db.update(entities).set(set).where(eq(entities.id, entityId)).returning();
|
|
97
103
|
if (!row)
|
|
98
104
|
throw new Error(`entity ${id} not found`);
|
|
99
105
|
if (fields.parentId !== undefined && fields.parentId !== null) {
|
|
@@ -102,17 +108,26 @@ export async function update(db, id, fields) {
|
|
|
102
108
|
.values({ fromId: fields.parentId, toId: row.id, kind: "parent_of" })
|
|
103
109
|
.onConflictDoNothing();
|
|
104
110
|
}
|
|
111
|
+
if (enteredDone && row.kind === "task") {
|
|
112
|
+
await advanceRecurrenceOnCompletion(db, row);
|
|
113
|
+
}
|
|
105
114
|
return row;
|
|
106
115
|
}
|
|
107
116
|
export async function listRelated(db, parentId) {
|
|
117
|
+
const entityId = await resolveEntityId(db, parentId);
|
|
118
|
+
if (!entityId)
|
|
119
|
+
return [];
|
|
108
120
|
return db
|
|
109
121
|
.select()
|
|
110
122
|
.from(entities)
|
|
111
|
-
.where(eq(entities.parentId,
|
|
123
|
+
.where(eq(entities.parentId, entityId))
|
|
112
124
|
.orderBy(desc(entities.createdAt));
|
|
113
125
|
}
|
|
114
126
|
export async function get(db, id) {
|
|
115
|
-
const
|
|
127
|
+
const entityId = await resolveEntityId(db, id);
|
|
128
|
+
if (!entityId)
|
|
129
|
+
return null;
|
|
130
|
+
const rows = await db.select().from(entities).where(eq(entities.id, entityId)).limit(1);
|
|
116
131
|
return rows[0] ?? null;
|
|
117
132
|
}
|
|
118
133
|
/**
|
|
@@ -129,7 +144,13 @@ export async function getByKey(db, projectKey, sequenceId) {
|
|
|
129
144
|
return rows[0]?.e ?? null;
|
|
130
145
|
}
|
|
131
146
|
export async function remove(db, id) {
|
|
132
|
-
const
|
|
147
|
+
const entityId = await resolveEntityId(db, id);
|
|
148
|
+
if (!entityId)
|
|
149
|
+
return false;
|
|
150
|
+
const res = await db
|
|
151
|
+
.delete(entities)
|
|
152
|
+
.where(eq(entities.id, entityId))
|
|
153
|
+
.returning({ id: entities.id });
|
|
133
154
|
return res.length > 0;
|
|
134
155
|
}
|
|
135
156
|
export async function recent(db, input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../../src/service/entities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAe,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../../src/service/entities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Database } from "../db/client.js";
|
|
2
|
+
import { type Entity, type RecurrenceRule } from "../db/schema.js";
|
|
3
|
+
import type { RecurrenceInput, StopRecurrenceInput, UpdateRecurrenceInput } from "./types.js";
|
|
4
|
+
export interface RecurrenceDetails {
|
|
5
|
+
rule: RecurrenceRule;
|
|
6
|
+
currentOccurrence: Entity | null;
|
|
7
|
+
}
|
|
8
|
+
export declare function getRecurrenceForTask(db: Database["db"], taskId: string): Promise<RecurrenceDetails | null>;
|
|
9
|
+
export declare function createRecurrenceRule(db: Database["db"], taskId: string, input: RecurrenceInput): Promise<RecurrenceRule>;
|
|
10
|
+
export declare function updateRecurrenceRule(db: Database["db"], ruleId: string, input: UpdateRecurrenceInput): Promise<RecurrenceRule>;
|
|
11
|
+
export declare function advanceRecurrenceOnCompletion(db: Database["db"], occurrence: Entity, completedAt?: Date): Promise<Entity | null>;
|
|
12
|
+
export declare function skipOccurrence(db: Database["db"], taskId: string, input?: {
|
|
13
|
+
reason?: string;
|
|
14
|
+
actorKind?: string;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
skipped: Entity;
|
|
17
|
+
next: Entity | null;
|
|
18
|
+
rule: RecurrenceRule;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function stopRecurrence(db: Database["db"], ruleId: string, _input?: StopRecurrenceInput): Promise<RecurrenceRule>;
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { and, eq, or } from "drizzle-orm";
|
|
2
|
+
import rrulePkg from "rrule";
|
|
3
|
+
import { entities, recurrenceExceptions, recurrenceRules } from "../db/schema.js";
|
|
4
|
+
import { normalizeDueAt } from "./dates.js";
|
|
5
|
+
const { RRule } = rrulePkg;
|
|
6
|
+
const WEEKDAYS = {
|
|
7
|
+
MO: RRule.MO,
|
|
8
|
+
TU: RRule.TU,
|
|
9
|
+
WE: RRule.WE,
|
|
10
|
+
TH: RRule.TH,
|
|
11
|
+
FR: RRule.FR,
|
|
12
|
+
SA: RRule.SA,
|
|
13
|
+
SU: RRule.SU
|
|
14
|
+
};
|
|
15
|
+
const FREQUENCIES = {
|
|
16
|
+
hourly: RRule.HOURLY,
|
|
17
|
+
daily: RRule.DAILY,
|
|
18
|
+
weekly: RRule.WEEKLY,
|
|
19
|
+
monthly: RRule.MONTHLY,
|
|
20
|
+
yearly: RRule.YEARLY
|
|
21
|
+
};
|
|
22
|
+
function metadataObject(value) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
24
|
+
return {};
|
|
25
|
+
return { ...value };
|
|
26
|
+
}
|
|
27
|
+
function recurrenceMarker(e) {
|
|
28
|
+
const metadata = metadataObject(e.metadata);
|
|
29
|
+
if (!metadata.recurrence || typeof metadata.recurrence !== "object")
|
|
30
|
+
return null;
|
|
31
|
+
return metadata.recurrence;
|
|
32
|
+
}
|
|
33
|
+
function withRecurrenceMetadata(e, marker) {
|
|
34
|
+
return {
|
|
35
|
+
...metadataObject(e.metadata),
|
|
36
|
+
recurrence: marker
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function normalizeRRuleText(raw) {
|
|
40
|
+
const lines = raw
|
|
41
|
+
.split(/\r?\n/)
|
|
42
|
+
.map((line) => line.trim())
|
|
43
|
+
.filter(Boolean);
|
|
44
|
+
const rruleLine = lines.find((line) => line.toUpperCase().startsWith("RRULE:")) ?? lines[0];
|
|
45
|
+
if (!rruleLine)
|
|
46
|
+
throw new Error("recurrence rule is empty");
|
|
47
|
+
return rruleLine.replace(/^RRULE:/i, "");
|
|
48
|
+
}
|
|
49
|
+
function rruleLine(rule) {
|
|
50
|
+
const line = rule
|
|
51
|
+
.toString()
|
|
52
|
+
.split(/\r?\n/)
|
|
53
|
+
.find((part) => part.startsWith("RRULE:"));
|
|
54
|
+
if (!line)
|
|
55
|
+
throw new Error("rrule did not produce an RRULE line");
|
|
56
|
+
return line.slice("RRULE:".length);
|
|
57
|
+
}
|
|
58
|
+
function buildRRuleFromInput(input, dtstart) {
|
|
59
|
+
if (input.rrule)
|
|
60
|
+
return normalizeRRuleText(input.rrule);
|
|
61
|
+
if (!input.preset)
|
|
62
|
+
throw new Error("recurrence preset is required");
|
|
63
|
+
const options = {
|
|
64
|
+
freq: FREQUENCIES[input.preset],
|
|
65
|
+
interval: input.interval,
|
|
66
|
+
dtstart
|
|
67
|
+
};
|
|
68
|
+
if (input.byWeekday?.length) {
|
|
69
|
+
options.byweekday = input.byWeekday.map((day) => WEEKDAYS[day]);
|
|
70
|
+
}
|
|
71
|
+
if (input.byMonthDay?.length)
|
|
72
|
+
options.bymonthday = input.byMonthDay;
|
|
73
|
+
if (input.bySetPos != null)
|
|
74
|
+
options.bysetpos = input.bySetPos;
|
|
75
|
+
if (input.byMonth?.length)
|
|
76
|
+
options.bymonth = input.byMonth;
|
|
77
|
+
if (input.until)
|
|
78
|
+
options.until = input.until;
|
|
79
|
+
if (input.count)
|
|
80
|
+
options.count = input.count;
|
|
81
|
+
return rruleLine(new RRule(options));
|
|
82
|
+
}
|
|
83
|
+
function buildRRule(rule, dtstart = rule.dtstart) {
|
|
84
|
+
const parsed = RRule.parseString(rule.rrule);
|
|
85
|
+
return new RRule({ ...parsed, dtstart });
|
|
86
|
+
}
|
|
87
|
+
function maxDate(a, b) {
|
|
88
|
+
return a.getTime() >= b.getTime() ? a : b;
|
|
89
|
+
}
|
|
90
|
+
function countLimit(rule) {
|
|
91
|
+
return buildRRule(rule).options.count ?? null;
|
|
92
|
+
}
|
|
93
|
+
function computeNextOccurrenceAt(rule, occurrence, completedAt) {
|
|
94
|
+
const count = countLimit(rule);
|
|
95
|
+
if (count != null && rule.generatedCount >= count)
|
|
96
|
+
return null;
|
|
97
|
+
const anchor = rule.anchor === "completion" ? "completion" : "scheduled";
|
|
98
|
+
const dtstart = anchor === "completion" ? completedAt : rule.dtstart;
|
|
99
|
+
const rrule = buildRRule(rule, dtstart);
|
|
100
|
+
const scheduledBase = occurrence.dueAt ?? rule.dtstart;
|
|
101
|
+
const cursor = anchor === "completion" ? completedAt : maxDate(scheduledBase, completedAt);
|
|
102
|
+
const next = rrule.after(cursor, false);
|
|
103
|
+
return next ? normalizeDueAt(next) : null;
|
|
104
|
+
}
|
|
105
|
+
async function fetchEntity(db, id) {
|
|
106
|
+
const rows = await db.select().from(entities).where(eq(entities.id, id)).limit(1);
|
|
107
|
+
const row = rows[0];
|
|
108
|
+
if (!row)
|
|
109
|
+
throw new Error(`entity ${id} not found`);
|
|
110
|
+
return row;
|
|
111
|
+
}
|
|
112
|
+
async function findRuleForTask(db, task, includeDisabled = true) {
|
|
113
|
+
const marker = recurrenceMarker(task);
|
|
114
|
+
const cond = marker?.ruleId
|
|
115
|
+
? eq(recurrenceRules.id, marker.ruleId)
|
|
116
|
+
: or(eq(recurrenceRules.currentOccurrenceId, task.id), eq(recurrenceRules.seriesId, task.id));
|
|
117
|
+
const where = includeDisabled ? cond : and(cond, eq(recurrenceRules.enabled, true));
|
|
118
|
+
const rows = await db.select().from(recurrenceRules).where(where).limit(1);
|
|
119
|
+
return rows[0] ?? null;
|
|
120
|
+
}
|
|
121
|
+
export async function getRecurrenceForTask(db, taskId) {
|
|
122
|
+
const task = await fetchEntity(db, taskId);
|
|
123
|
+
const rule = await findRuleForTask(db, task);
|
|
124
|
+
if (!rule)
|
|
125
|
+
return null;
|
|
126
|
+
const currentOccurrence = rule.currentOccurrenceId
|
|
127
|
+
? await fetchEntity(db, rule.currentOccurrenceId).catch(() => null)
|
|
128
|
+
: null;
|
|
129
|
+
return { rule, currentOccurrence };
|
|
130
|
+
}
|
|
131
|
+
export async function createRecurrenceRule(db, taskId, input) {
|
|
132
|
+
const task = await fetchEntity(db, taskId);
|
|
133
|
+
if (task.kind !== "task")
|
|
134
|
+
throw new Error("recurrence can only be attached to tasks");
|
|
135
|
+
if (!task.dueAt)
|
|
136
|
+
throw new Error("recurring tasks require a first due date");
|
|
137
|
+
if (task.status === "done" || task.status === "rejected") {
|
|
138
|
+
throw new Error("recurrence cannot be attached to a terminal task");
|
|
139
|
+
}
|
|
140
|
+
const existingRule = await findRuleForTask(db, task);
|
|
141
|
+
const seriesId = existingRule?.seriesId ?? recurrenceMarker(task)?.seriesId ?? task.id;
|
|
142
|
+
const dtstart = input.dtstart ? normalizeDueAt(input.dtstart) : task.dueAt;
|
|
143
|
+
const rrule = buildRRuleFromInput(input, dtstart);
|
|
144
|
+
const nextOccurrenceAt = buildRRule({ rrule, dtstart }).after(dtstart, false);
|
|
145
|
+
let rule;
|
|
146
|
+
if (existingRule) {
|
|
147
|
+
const [updated] = await db
|
|
148
|
+
.update(recurrenceRules)
|
|
149
|
+
.set({
|
|
150
|
+
currentOccurrenceId: task.id,
|
|
151
|
+
enabled: true,
|
|
152
|
+
rrule,
|
|
153
|
+
dtstart,
|
|
154
|
+
timezone: input.timezone,
|
|
155
|
+
allDay: input.allDay,
|
|
156
|
+
anchor: input.anchor,
|
|
157
|
+
maxInstancesAhead: 1,
|
|
158
|
+
nextOccurrenceAt: nextOccurrenceAt ? normalizeDueAt(nextOccurrenceAt) : null,
|
|
159
|
+
endedAt: null
|
|
160
|
+
})
|
|
161
|
+
.where(eq(recurrenceRules.id, existingRule.id))
|
|
162
|
+
.returning();
|
|
163
|
+
if (!updated)
|
|
164
|
+
throw new Error(`recurrence rule ${existingRule.id} not found`);
|
|
165
|
+
rule = updated;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const [inserted] = await db
|
|
169
|
+
.insert(recurrenceRules)
|
|
170
|
+
.values({
|
|
171
|
+
seriesId,
|
|
172
|
+
currentOccurrenceId: task.id,
|
|
173
|
+
enabled: true,
|
|
174
|
+
rrule,
|
|
175
|
+
dtstart,
|
|
176
|
+
timezone: input.timezone,
|
|
177
|
+
allDay: input.allDay,
|
|
178
|
+
anchor: input.anchor,
|
|
179
|
+
maxInstancesAhead: 1,
|
|
180
|
+
generatedCount: 1,
|
|
181
|
+
lastOccurrenceAt: null,
|
|
182
|
+
nextOccurrenceAt: nextOccurrenceAt ? normalizeDueAt(nextOccurrenceAt) : null,
|
|
183
|
+
endedAt: null
|
|
184
|
+
})
|
|
185
|
+
.returning();
|
|
186
|
+
if (!inserted)
|
|
187
|
+
throw new Error("recurrence rule insert returned no row");
|
|
188
|
+
rule = inserted;
|
|
189
|
+
}
|
|
190
|
+
await db
|
|
191
|
+
.update(entities)
|
|
192
|
+
.set({
|
|
193
|
+
metadata: withRecurrenceMetadata(task, {
|
|
194
|
+
ruleId: rule.id,
|
|
195
|
+
seriesId: rule.seriesId,
|
|
196
|
+
role: "occurrence",
|
|
197
|
+
occurrenceAt: (task.dueAt ?? rule.dtstart).toISOString(),
|
|
198
|
+
occurrenceIndex: 1
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
.where(eq(entities.id, task.id));
|
|
202
|
+
return rule;
|
|
203
|
+
}
|
|
204
|
+
export async function updateRecurrenceRule(db, ruleId, input) {
|
|
205
|
+
const rows = await db.select().from(recurrenceRules).where(eq(recurrenceRules.id, ruleId)).limit(1);
|
|
206
|
+
const current = rows[0];
|
|
207
|
+
if (!current)
|
|
208
|
+
throw new Error(`recurrence rule ${ruleId} not found`);
|
|
209
|
+
const currentOccurrence = current.currentOccurrenceId
|
|
210
|
+
? await fetchEntity(db, current.currentOccurrenceId)
|
|
211
|
+
: null;
|
|
212
|
+
const dtstart = input.dtstart
|
|
213
|
+
? normalizeDueAt(input.dtstart)
|
|
214
|
+
: currentOccurrence?.dueAt ?? current.dtstart;
|
|
215
|
+
const nextRRuleInput = {
|
|
216
|
+
rrule: input.rrule ?? current.rrule,
|
|
217
|
+
preset: input.preset,
|
|
218
|
+
interval: input.interval ?? 1,
|
|
219
|
+
byWeekday: input.byWeekday,
|
|
220
|
+
byMonthDay: input.byMonthDay,
|
|
221
|
+
bySetPos: input.bySetPos,
|
|
222
|
+
byMonth: input.byMonth,
|
|
223
|
+
until: input.until,
|
|
224
|
+
count: input.count,
|
|
225
|
+
dtstart,
|
|
226
|
+
timezone: input.timezone ?? current.timezone,
|
|
227
|
+
allDay: input.allDay ?? current.allDay,
|
|
228
|
+
anchor: input.anchor ?? (current.anchor === "completion" ? "completion" : "scheduled")
|
|
229
|
+
};
|
|
230
|
+
const rrule = input.rrule || input.preset ? buildRRuleFromInput(nextRRuleInput, dtstart) : current.rrule;
|
|
231
|
+
const nextOccurrenceAt = buildRRule({ rrule, dtstart }).after(dtstart, false);
|
|
232
|
+
const [updated] = await db
|
|
233
|
+
.update(recurrenceRules)
|
|
234
|
+
.set({
|
|
235
|
+
enabled: input.enabled ?? current.enabled,
|
|
236
|
+
rrule,
|
|
237
|
+
dtstart,
|
|
238
|
+
timezone: input.timezone ?? current.timezone,
|
|
239
|
+
allDay: input.allDay ?? current.allDay,
|
|
240
|
+
anchor: input.anchor ?? current.anchor,
|
|
241
|
+
nextOccurrenceAt: nextOccurrenceAt ? normalizeDueAt(nextOccurrenceAt) : null,
|
|
242
|
+
endedAt: input.enabled === true ? null : current.endedAt
|
|
243
|
+
})
|
|
244
|
+
.where(eq(recurrenceRules.id, ruleId))
|
|
245
|
+
.returning();
|
|
246
|
+
if (!updated)
|
|
247
|
+
throw new Error(`recurrence rule ${ruleId} not found`);
|
|
248
|
+
return updated;
|
|
249
|
+
}
|
|
250
|
+
async function insertNextOccurrence(db, rule, occurrence, nextDueAt) {
|
|
251
|
+
const occurrenceIndex = rule.generatedCount + 1;
|
|
252
|
+
const idempotencyKey = `recurrence:${rule.id}:${nextDueAt.toISOString()}`;
|
|
253
|
+
const metadata = {
|
|
254
|
+
...metadataObject(occurrence.metadata),
|
|
255
|
+
recurrence: {
|
|
256
|
+
ruleId: rule.id,
|
|
257
|
+
seriesId: rule.seriesId,
|
|
258
|
+
role: "occurrence",
|
|
259
|
+
occurrenceAt: nextDueAt.toISOString(),
|
|
260
|
+
occurrenceIndex
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const values = {
|
|
264
|
+
kind: "task",
|
|
265
|
+
projectId: occurrence.projectId,
|
|
266
|
+
title: occurrence.title,
|
|
267
|
+
body: occurrence.body,
|
|
268
|
+
tags: occurrence.tags,
|
|
269
|
+
status: "open",
|
|
270
|
+
parentId: occurrence.parentId,
|
|
271
|
+
actorKind: "system",
|
|
272
|
+
metadata,
|
|
273
|
+
dueAt: nextDueAt,
|
|
274
|
+
priority: occurrence.priority,
|
|
275
|
+
pinned: false,
|
|
276
|
+
completedAt: null,
|
|
277
|
+
idempotencyKey
|
|
278
|
+
};
|
|
279
|
+
const inserted = await db
|
|
280
|
+
.insert(entities)
|
|
281
|
+
.values(values)
|
|
282
|
+
.onConflictDoNothing()
|
|
283
|
+
.returning();
|
|
284
|
+
if (inserted[0])
|
|
285
|
+
return inserted[0];
|
|
286
|
+
const rows = await db.select().from(entities).where(eq(entities.idempotencyKey, idempotencyKey));
|
|
287
|
+
const existing = rows[0];
|
|
288
|
+
if (!existing)
|
|
289
|
+
throw new Error("recurrence idempotent insert returned no row");
|
|
290
|
+
return existing;
|
|
291
|
+
}
|
|
292
|
+
async function advanceRuleFromOccurrence(db, rule, occurrence, completedAt) {
|
|
293
|
+
if (!rule.enabled)
|
|
294
|
+
return null;
|
|
295
|
+
const nextDueAt = computeNextOccurrenceAt(rule, occurrence, completedAt);
|
|
296
|
+
if (!nextDueAt) {
|
|
297
|
+
await db
|
|
298
|
+
.update(recurrenceRules)
|
|
299
|
+
.set({
|
|
300
|
+
enabled: false,
|
|
301
|
+
currentOccurrenceId: null,
|
|
302
|
+
lastOccurrenceAt: occurrence.dueAt ?? rule.dtstart,
|
|
303
|
+
nextOccurrenceAt: null,
|
|
304
|
+
endedAt: completedAt
|
|
305
|
+
})
|
|
306
|
+
.where(eq(recurrenceRules.id, rule.id));
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const next = await insertNextOccurrence(db, rule, occurrence, nextDueAt);
|
|
310
|
+
await db
|
|
311
|
+
.update(recurrenceRules)
|
|
312
|
+
.set({
|
|
313
|
+
currentOccurrenceId: next.id,
|
|
314
|
+
generatedCount: Math.max(rule.generatedCount + 1, rule.generatedCount),
|
|
315
|
+
lastOccurrenceAt: occurrence.dueAt ?? rule.dtstart,
|
|
316
|
+
nextOccurrenceAt: nextDueAt
|
|
317
|
+
})
|
|
318
|
+
.where(eq(recurrenceRules.id, rule.id));
|
|
319
|
+
return next;
|
|
320
|
+
}
|
|
321
|
+
export async function advanceRecurrenceOnCompletion(db, occurrence, completedAt = occurrence.completedAt ?? new Date()) {
|
|
322
|
+
if (occurrence.kind !== "task")
|
|
323
|
+
return null;
|
|
324
|
+
const rule = await findRuleForTask(db, occurrence, false);
|
|
325
|
+
if (!rule)
|
|
326
|
+
return null;
|
|
327
|
+
if (rule.currentOccurrenceId && rule.currentOccurrenceId !== occurrence.id)
|
|
328
|
+
return null;
|
|
329
|
+
return advanceRuleFromOccurrence(db, rule, occurrence, completedAt);
|
|
330
|
+
}
|
|
331
|
+
export async function skipOccurrence(db, taskId, input = {}) {
|
|
332
|
+
const task = await fetchEntity(db, taskId);
|
|
333
|
+
if (task.kind !== "task")
|
|
334
|
+
throw new Error("only tasks can be skipped");
|
|
335
|
+
const rule = await findRuleForTask(db, task, false);
|
|
336
|
+
if (!rule)
|
|
337
|
+
throw new Error("task is not an active recurring occurrence");
|
|
338
|
+
if (rule.currentOccurrenceId && rule.currentOccurrenceId !== task.id) {
|
|
339
|
+
throw new Error("only the current recurring occurrence can be skipped");
|
|
340
|
+
}
|
|
341
|
+
await db.insert(recurrenceExceptions).values({
|
|
342
|
+
ruleId: rule.id,
|
|
343
|
+
occurrenceAt: task.dueAt ?? rule.dtstart,
|
|
344
|
+
action: "skipped",
|
|
345
|
+
entityId: task.id,
|
|
346
|
+
metadata: { reason: input.reason ?? null, actorKind: input.actorKind ?? "human" }
|
|
347
|
+
});
|
|
348
|
+
const [skipped] = await db
|
|
349
|
+
.update(entities)
|
|
350
|
+
.set({
|
|
351
|
+
status: "rejected",
|
|
352
|
+
updatedAt: new Date(),
|
|
353
|
+
metadata: {
|
|
354
|
+
...metadataObject(task.metadata),
|
|
355
|
+
recurrence: recurrenceMarker(task),
|
|
356
|
+
skippedAt: new Date().toISOString(),
|
|
357
|
+
skipReason: input.reason ?? null
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
.where(eq(entities.id, task.id))
|
|
361
|
+
.returning();
|
|
362
|
+
if (!skipped)
|
|
363
|
+
throw new Error(`entity ${task.id} not found`);
|
|
364
|
+
const next = await advanceRuleFromOccurrence(db, rule, skipped, new Date());
|
|
365
|
+
return { skipped, next, rule };
|
|
366
|
+
}
|
|
367
|
+
export async function stopRecurrence(db, ruleId, _input = {}) {
|
|
368
|
+
const [updated] = await db
|
|
369
|
+
.update(recurrenceRules)
|
|
370
|
+
.set({
|
|
371
|
+
enabled: false,
|
|
372
|
+
nextOccurrenceAt: null,
|
|
373
|
+
endedAt: new Date()
|
|
374
|
+
})
|
|
375
|
+
.where(eq(recurrenceRules.id, ruleId))
|
|
376
|
+
.returning();
|
|
377
|
+
if (!updated)
|
|
378
|
+
throw new Error(`recurrence rule ${ruleId} not found`);
|
|
379
|
+
return updated;
|
|
380
|
+
}
|
|
381
|
+
//# sourceMappingURL=recurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.js","sourceRoot":"","sources":["../../src/service/recurrence.ts"],"names":[],"mappings":"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"}
|