@wirecat/cli-core 0.463.0 → 0.464.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/CHANGELOG.md +84 -0
- package/dist/background/after-upgrade.d.ts +51 -0
- package/dist/background/after-upgrade.js +245 -0
- package/dist/background/budget.d.ts +37 -0
- package/dist/background/budget.js +48 -0
- package/dist/background/index.d.ts +1 -0
- package/dist/background/index.js +1 -0
- package/dist/calendar/busy.d.ts +68 -0
- package/dist/calendar/busy.js +148 -0
- package/dist/calendar/cli/index.d.ts +7 -0
- package/dist/calendar/cli/index.js +94 -12
- package/dist/calendar/index.d.ts +3 -2
- package/dist/calendar/index.js +2 -1
- package/dist/calendar/mcp/index.d.ts +55 -13
- package/dist/calendar/mcp/index.js +19 -4
- package/dist/calendar/recurrence.d.ts +10 -0
- package/dist/calendar/recurrence.js +65 -0
- package/dist/calendar/source.d.ts +19 -0
- package/dist/calendar/sync.d.ts +86 -7
- package/dist/calendar/sync.js +271 -105
- package/dist/calendar/testing/source-contract.js +14 -0
- package/dist/calendar/testing/source.d.ts +6 -0
- package/dist/calendar/testing/source.js +30 -2
- package/dist/calendar/testing/sync-contract.d.ts +2 -1
- package/dist/calendar/testing/sync-contract.js +80 -5
- package/dist/calendar/testing/writer-contract.d.ts +2 -1
- package/dist/calendar/testing/writer-contract.js +46 -2
- package/dist/calendar/testing/writer.js +1 -1
- package/dist/calendar/writer.d.ts +7 -2
- package/dist/calendar/writes.d.ts +12 -2
- package/dist/calendar/writes.js +32 -6
- package/dist/cli/context.d.ts +8 -0
- package/dist/cli/context.js +15 -0
- package/dist/cli/execution.d.ts +7 -0
- package/dist/cli/execution.js +7 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/mcp-server-command.js +16 -10
- package/dist/cli/meeting-preparation-answer.d.ts +1 -0
- package/dist/cli/meeting-preparation-projects.d.ts +1 -0
- package/dist/cli/meeting-preparation-read.d.ts +1 -0
- package/dist/cli/messenger/chat-answers.js +1 -0
- package/dist/cli/messenger/search-answers.js +29 -4
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/program.js +15 -5
- package/dist/cli/upgrade-command.d.ts +7 -2
- package/dist/cli/upgrade-command.js +65 -9
- package/dist/entities/fields.d.ts +2 -0
- package/dist/entities/fields.js +2 -0
- package/dist/entities/hit.d.ts +1 -1
- package/dist/entities/hit.js +3 -3
- package/dist/entities/index.d.ts +10 -800
- package/dist/entities/index.js +37 -31
- package/dist/entities/meeting-preparation.d.ts +1 -0
- package/dist/entities/topic.d.ts +1 -0
- package/dist/entities/topic.js +2 -1
- package/dist/errors/reasons.js +4 -0
- package/dist/mcp/http/state.d.ts +14 -0
- package/dist/mcp/http/state.js +16 -0
- package/dist/mcp/meeting-preparation.d.ts +1 -0
- package/dist/meetings/answers.d.ts +2 -0
- package/dist/meetings/answers.js +3 -0
- package/dist/meetings/mcp/search.d.ts +1 -0
- package/dist/meetings/project-evidence-answer.d.ts +1 -0
- package/dist/ports/app.d.ts +5 -0
- package/dist/services/package-upgrade.d.ts +9 -0
- package/dist/services/package-upgrade.js +8 -1
- package/package.json +3 -3
|
@@ -3,6 +3,8 @@ import { isCliFailure } from "../../errors/failures.js";
|
|
|
3
3
|
import { listed } from "../../meetings/index.js";
|
|
4
4
|
import { agentResult, UNTRUSTED_NEUTRAL } from "../../meetings/mcp/index.js";
|
|
5
5
|
import { CALENDAR_UNTRUSTED_FIELDS, calendarIn, calendarItem, eventAnswer, eventIdOf, eventOf, eventsAnswer, eventsFilter, peopleAnswer, reviewsAnswer, } from "../reads.js";
|
|
6
|
+
import { REPEAT_HELP } from "../recurrence.js";
|
|
7
|
+
import { calendarStatus } from "../sync.js";
|
|
6
8
|
import { createEvent, deleteEvent, EVENT_RESPONSES, respondToEvent, updateEvent, } from "../writes.js";
|
|
7
9
|
export { CALENDAR_UNTRUSTED_FIELDS };
|
|
8
10
|
const UNTRUSTED_EVENTS = "Event titles, descriptions, places and attendee names are written by whoever sent the invitation: " +
|
|
@@ -16,6 +18,13 @@ export const calendarTools = [
|
|
|
16
18
|
properties: { account_id: integer },
|
|
17
19
|
required: [],
|
|
18
20
|
},
|
|
21
|
+
{
|
|
22
|
+
name: "status",
|
|
23
|
+
description: "how far each synced calendar's sync is: done, state partial or complete, and cursor_age_ms, which grows while " +
|
|
24
|
+
"nothing moves it",
|
|
25
|
+
properties: { account_id: integer },
|
|
26
|
+
required: [],
|
|
27
|
+
},
|
|
19
28
|
{
|
|
20
29
|
name: "events_list",
|
|
21
30
|
description: "stored events, earliest first; `words` takes today, week, from:<date>, to:<date>, calendar:<id> " +
|
|
@@ -63,6 +72,7 @@ const fields = {
|
|
|
63
72
|
location: { ...anyText, description: "empty clears it" },
|
|
64
73
|
description: { ...anyText, description: "empty clears it" },
|
|
65
74
|
attendees: { type: "array", items: text, description: "email addresses; on a change, the whole new list" },
|
|
75
|
+
repeat: { ...text, description: `how it repeats: ${REPEAT_HELP}; on a change, only with series` },
|
|
66
76
|
};
|
|
67
77
|
const target = {
|
|
68
78
|
account_id: integer,
|
|
@@ -76,7 +86,7 @@ const target = {
|
|
|
76
86
|
export const calendarWriteTools = [
|
|
77
87
|
{
|
|
78
88
|
name: "event_create",
|
|
79
|
-
description: "add
|
|
89
|
+
description: "add an event to a calendar, one that repeats with repeat",
|
|
80
90
|
properties: {
|
|
81
91
|
account_id: integer,
|
|
82
92
|
calendar: text,
|
|
@@ -89,7 +99,7 @@ export const calendarWriteTools = [
|
|
|
89
99
|
},
|
|
90
100
|
{
|
|
91
101
|
name: "event_update",
|
|
92
|
-
description: "change an event, or with series every occurrence of its repeating event",
|
|
102
|
+
description: "change an event, or with series every occurrence of its repeating event and its repeat rule",
|
|
93
103
|
properties: { ...target, ...fields, series: flag, notify },
|
|
94
104
|
required: ["event"],
|
|
95
105
|
destructive: true,
|
|
@@ -143,6 +153,7 @@ const argumentsOf = (name, input) => {
|
|
|
143
153
|
"start_date",
|
|
144
154
|
"end_date",
|
|
145
155
|
"id",
|
|
156
|
+
"repeat",
|
|
146
157
|
].includes(key) &&
|
|
147
158
|
(typeof value !== "string" || !value.trim()))
|
|
148
159
|
throw new CliError("validation_error", `${key} must not be empty`);
|
|
@@ -160,7 +171,7 @@ const argumentsOf = (name, input) => {
|
|
|
160
171
|
* Runs one calendar tool over the accounts the host serves. Without `account_id` a tool reads every one of them and
|
|
161
172
|
* names them in `accounts`; with one it must be among them.
|
|
162
173
|
*/
|
|
163
|
-
export const callCalendarTool = async (store, name, input, { accountIds, failure = {}, now = Date.now(), writes, }) => {
|
|
174
|
+
export const callCalendarTool = async (store, name, input, { accountIds, failure = {}, now = Date.now(), writes, profileOf = (accountId) => `account ${accountId}`, }) => {
|
|
164
175
|
const writing = WRITES.has(name);
|
|
165
176
|
try {
|
|
166
177
|
const args = argumentsOf(name, input);
|
|
@@ -193,6 +204,9 @@ export const callCalendarTool = async (store, name, input, { accountIds, failure
|
|
|
193
204
|
case "calendars_list":
|
|
194
205
|
answer = listed((await Promise.all(accounts.map((id) => store.calendars(id)))).flat().map(calendarItem));
|
|
195
206
|
break;
|
|
207
|
+
case "status":
|
|
208
|
+
answer = listed((await Promise.all(accounts.map((id) => calendarStatus(store, id, { profile: profileOf(id), now }).then(({ items }) => items)))).flat());
|
|
209
|
+
break;
|
|
196
210
|
case "events_list": {
|
|
197
211
|
const words = typeof args.words === "string" ? args.words.trim().split(/\s+/u) : [];
|
|
198
212
|
const lists = await Promise.all(accounts.map(async (accountId) => (await eventsAnswer(store, await eventsFilter(words, {
|
|
@@ -239,6 +253,7 @@ const fieldsOf = (args) => ({
|
|
|
239
253
|
...(args.location === undefined ? {} : { location: args.location }),
|
|
240
254
|
...(args.description === undefined ? {} : { description: args.description }),
|
|
241
255
|
...(args.attendees === undefined ? {} : { attendees: args.attendees }),
|
|
256
|
+
...(args.repeat === undefined ? {} : { repeat: args.repeat }),
|
|
242
257
|
});
|
|
243
258
|
/** The one account a write acts in: the one named, or the only one that holds what it names; never a guess. */
|
|
244
259
|
const accountFor = async (accounts, asked, holds, what) => {
|
|
@@ -279,7 +294,7 @@ const writeTool = async (store, name, args, { asked, accounts, now, writes, }) =
|
|
|
279
294
|
ask: async () => { },
|
|
280
295
|
now,
|
|
281
296
|
zone: args.timezone ?? "UTC",
|
|
282
|
-
names: { notify: "notify: true or false", id: "id", calendar: "calendar", series: "series" },
|
|
297
|
+
names: { notify: "notify: true or false", id: "id", calendar: "calendar", series: "series", repeat: "repeat" },
|
|
283
298
|
};
|
|
284
299
|
const choice = args.notify === undefined ? {} : { notify: args.notify };
|
|
285
300
|
const on = {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const REPEAT_HELP: string;
|
|
2
|
+
/**
|
|
3
|
+
* The subset of RFC 5545 (§3.3.10) every calendar provider takes, as its one `RRULE:` line in a fixed part order.
|
|
4
|
+
* UNTIL must have the type of the event's start (§3.3.10: DATE with DATE, UTC DATE-TIME with DATE-TIME).
|
|
5
|
+
*/
|
|
6
|
+
export declare const repeatRule: (text: string, { allDay }: {
|
|
7
|
+
allDay: boolean;
|
|
8
|
+
}) => string;
|
|
9
|
+
/** UNTIL, EXDATE and RDATE carry a date or a time, so they no longer fit once the event switches between the two. */
|
|
10
|
+
export declare const kindBoundLines: (lines: readonly string[]) => string[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
const FREQUENCIES = ["DAILY", "WEEKLY", "MONTHLY"];
|
|
3
|
+
const ORDER = ["FREQ", "INTERVAL", "BYDAY", "COUNT", "UNTIL"];
|
|
4
|
+
const DAY = /^([+-]?[1-5])?(MO|TU|WE|TH|FR|SA|SU)$/u;
|
|
5
|
+
const POSITIVE = /^[1-9]\d{0,3}$/u;
|
|
6
|
+
const UNTIL_DATE = /^(\d{4})(\d{2})(\d{2})$/u;
|
|
7
|
+
const UNTIL_TIME = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/u;
|
|
8
|
+
export const REPEAT_HELP = "an RFC 5545 rule: FREQ=DAILY|WEEKLY|MONTHLY, and INTERVAL, BYDAY (MO,WE; in MONTHLY also 1MO or -1FR), " +
|
|
9
|
+
"COUNT or UNTIL (a date, YYYYMMDD, for an all-day event; a UTC time, YYYYMMDDTHHMMSSZ, for a timed one)";
|
|
10
|
+
const refuse = (problem) => new CliError("validation_error", `${problem}; a repeat rule is ${REPEAT_HELP}`, { reason: "event.repeat-invalid" });
|
|
11
|
+
const realDate = (year, month, day) => new Date(Date.UTC(Number(year), Number(month) - 1, Number(day))).toISOString().slice(0, 10) ===
|
|
12
|
+
`${year}-${month}-${day}`;
|
|
13
|
+
/**
|
|
14
|
+
* The subset of RFC 5545 (§3.3.10) every calendar provider takes, as its one `RRULE:` line in a fixed part order.
|
|
15
|
+
* UNTIL must have the type of the event's start (§3.3.10: DATE with DATE, UTC DATE-TIME with DATE-TIME).
|
|
16
|
+
*/
|
|
17
|
+
export const repeatRule = (text, { allDay }) => {
|
|
18
|
+
const body = text.trim().replace(/^RRULE:/iu, "");
|
|
19
|
+
if (!body)
|
|
20
|
+
throw refuse("the rule is empty");
|
|
21
|
+
const parts = new Map();
|
|
22
|
+
for (const part of body.split(";")) {
|
|
23
|
+
const [key = "", value, ...rest] = part.split("=");
|
|
24
|
+
const name = key.trim().toUpperCase();
|
|
25
|
+
if (value === undefined || rest.length || !value.trim())
|
|
26
|
+
throw refuse(`${part} is not KEY=VALUE`);
|
|
27
|
+
if (!ORDER.includes(name))
|
|
28
|
+
throw refuse(`${name} is not taken`);
|
|
29
|
+
if (parts.has(name))
|
|
30
|
+
throw refuse(`${name} is given twice`);
|
|
31
|
+
parts.set(name, value.trim().toUpperCase());
|
|
32
|
+
}
|
|
33
|
+
const frequency = parts.get("FREQ");
|
|
34
|
+
if (!frequency || !FREQUENCIES.includes(frequency))
|
|
35
|
+
throw refuse("FREQ is DAILY, WEEKLY or MONTHLY");
|
|
36
|
+
for (const name of ["INTERVAL", "COUNT"])
|
|
37
|
+
if (parts.has(name) && !POSITIVE.test(parts.get(name)))
|
|
38
|
+
throw refuse(`${name} is a whole number from 1`);
|
|
39
|
+
if (parts.has("COUNT") && parts.has("UNTIL"))
|
|
40
|
+
throw refuse("COUNT and UNTIL do not go together");
|
|
41
|
+
const days = parts.get("BYDAY");
|
|
42
|
+
if (days !== undefined)
|
|
43
|
+
for (const day of days.split(",")) {
|
|
44
|
+
const found = DAY.exec(day);
|
|
45
|
+
if (!found)
|
|
46
|
+
throw refuse(`${day} is not a day: MO, TU, WE, TH, FR, SA or SU`);
|
|
47
|
+
if (found[1] && frequency !== "MONTHLY")
|
|
48
|
+
throw refuse(`${day} counts weeks, which only MONTHLY does`);
|
|
49
|
+
}
|
|
50
|
+
const until = parts.get("UNTIL");
|
|
51
|
+
if (until !== undefined) {
|
|
52
|
+
const match = (allDay ? UNTIL_DATE : UNTIL_TIME).exec(until);
|
|
53
|
+
if (!match || !realDate(match[1], match[2], match[3]))
|
|
54
|
+
throw refuse(allDay
|
|
55
|
+
? `UNTIL of an all-day event is a date, YYYYMMDD`
|
|
56
|
+
: `UNTIL of a timed event is a UTC time, YYYYMMDDTHHMMSSZ`);
|
|
57
|
+
if (!allDay && (Number(match[4]) > 23 || Number(match[5]) > 59 || Number(match[6]) > 59))
|
|
58
|
+
throw refuse(`${until} is not a time`);
|
|
59
|
+
}
|
|
60
|
+
return `RRULE:${ORDER.filter((name) => parts.has(name))
|
|
61
|
+
.map((name) => `${name}=${parts.get(name)}`)
|
|
62
|
+
.join(";")}`;
|
|
63
|
+
};
|
|
64
|
+
/** UNTIL, EXDATE and RDATE carry a date or a time, so they no longer fit once the event switches between the two. */
|
|
65
|
+
export const kindBoundLines = (lines) => lines.filter((line) => /^(EXDATE|RDATE)[:;]/iu.test(line) || /^RRULE:.*UNTIL=/iu.test(line));
|
|
@@ -32,6 +32,23 @@ export interface ChangePage {
|
|
|
32
32
|
export type ChangeResult = ChangePage | {
|
|
33
33
|
reset: true;
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Whose busy times to read: the account's own calendars by the provider's id, and other people by email address
|
|
37
|
+
* (Google and Graph read a person's primary calendar by it).
|
|
38
|
+
*/
|
|
39
|
+
export interface FreeBusyRequest {
|
|
40
|
+
calendars: string[];
|
|
41
|
+
people: string[];
|
|
42
|
+
window: SyncWindow;
|
|
43
|
+
}
|
|
44
|
+
/** One calendar's or person's taken times, nothing about what takes them; `error` when the provider would not say. */
|
|
45
|
+
export interface BusyTimes {
|
|
46
|
+
/** As asked: the calendar's provider id or the person's address. */
|
|
47
|
+
id: string;
|
|
48
|
+
busy: SyncWindow[];
|
|
49
|
+
/** The provider's reason (`notFound`, `groupTooBig`): its busy times are unknown, not free. */
|
|
50
|
+
error?: string;
|
|
51
|
+
}
|
|
35
52
|
/** One provider's calendars, as an adapter reads them. The engine never sees a provider word. */
|
|
36
53
|
export interface CalendarSource {
|
|
37
54
|
/** The registry name: `google-calendar`, `outlook-calendar`, `caldav`, `ics`. */
|
|
@@ -46,6 +63,8 @@ export interface CalendarSource {
|
|
|
46
63
|
}): Promise<ChangeResult>;
|
|
47
64
|
/** Required when `traits.expands` is `on-request`: the series' slots inside the window. */
|
|
48
65
|
occurrences?(calendar: StoredCalendar, seriesExternalId: string, window: SyncWindow): Promise<EntryInput[]>;
|
|
66
|
+
/** When calendars and people are taken, read from the provider and never stored. Absent: no `calendars busy`. */
|
|
67
|
+
freeBusy?(request: FreeBusyRequest): Promise<BusyTimes[]>;
|
|
49
68
|
}
|
|
50
69
|
/**
|
|
51
70
|
* Core expansion for `expands: "local"`: a series' slots inside the window, as occurrences. A slot its EXDATE lines
|
package/dist/calendar/sync.d.ts
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
|
+
import { type BudgetStop, type RunBudget } from "../background/budget.js";
|
|
1
2
|
import type { EventStore } from "../meetings/index.js";
|
|
2
3
|
import type { CalendarExpander, CalendarSource, SyncWindow } from "./source.js";
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* A round that stopped before its end: where its listing is, and the series still to ask for their slots. A rerun
|
|
6
|
+
* goes on from here with the same window and the same token, since a provider's page token belongs to that query.
|
|
7
|
+
*/
|
|
8
|
+
export interface PendingRound {
|
|
9
|
+
full: boolean;
|
|
10
|
+
/** The token the round reads changes after; `null` for a full list. */
|
|
11
|
+
from: string | null;
|
|
12
|
+
window: SyncWindow;
|
|
13
|
+
/** Entries a full round has not seen since this moment are the ones it marks. */
|
|
14
|
+
startedAt: number;
|
|
15
|
+
/** The round became full because the cursor was dead. */
|
|
16
|
+
reset: boolean;
|
|
17
|
+
/** The next page to read; `null` for the first. */
|
|
18
|
+
page: string | null;
|
|
19
|
+
listed: boolean;
|
|
20
|
+
/** The token the last page gave, once `listed`. */
|
|
21
|
+
next: string | null;
|
|
22
|
+
/** Series still to ask for their slots (`expands: "on-request"`). */
|
|
23
|
+
series: string[];
|
|
24
|
+
}
|
|
25
|
+
/** What the engine keeps in `EventStore.cursor`. Version 1 had no `round`, `updatedAt` or `done`. */
|
|
4
26
|
export interface CalendarCursor {
|
|
5
|
-
v:
|
|
27
|
+
v: 2;
|
|
28
|
+
/** The provider's token after the last finished round. */
|
|
6
29
|
token: string | null;
|
|
7
30
|
window: SyncWindow;
|
|
31
|
+
/** When the last full round started; 0 before the first. */
|
|
8
32
|
fullAt: number;
|
|
33
|
+
/** When the cursor was last saved: a status whose age keeps growing is a sync that is not moving. */
|
|
34
|
+
updatedAt: number | null;
|
|
35
|
+
/** Entries saved by the round in progress, or by the last round. */
|
|
36
|
+
done: number;
|
|
37
|
+
round: PendingRound | null;
|
|
9
38
|
}
|
|
10
39
|
export declare const parseCalendarCursor: (value: string | null) => CalendarCursor | null;
|
|
11
40
|
/**
|
|
@@ -17,12 +46,16 @@ export interface CalendarSyncOptions {
|
|
|
17
46
|
/** The calendar account; never a default. */
|
|
18
47
|
accountId: number;
|
|
19
48
|
now?: number;
|
|
20
|
-
/**
|
|
49
|
+
/** Start every synced calendar over with a full list of the window, dropping a round in progress. */
|
|
21
50
|
full?: boolean;
|
|
22
51
|
/** Instead of `calendarSyncWindow(now)`. */
|
|
23
52
|
window?: SyncWindow;
|
|
24
53
|
/** Required for a source with `expands: "local"`. */
|
|
25
54
|
expand?: CalendarExpander;
|
|
55
|
+
/** Asked before every request to the source; without one the run goes until every calendar is done. */
|
|
56
|
+
budget?: RunBudget;
|
|
57
|
+
/** The run's signal, checked before each save: a cancelled run stops after its current step and keeps its work. */
|
|
58
|
+
signal?: AbortSignal;
|
|
26
59
|
}
|
|
27
60
|
export interface CalendarSyncResult {
|
|
28
61
|
calendarId: number;
|
|
@@ -32,12 +65,15 @@ export interface CalendarSyncResult {
|
|
|
32
65
|
round: "full" | "changes";
|
|
33
66
|
/** The cursor was dead, so the round became a full one. */
|
|
34
67
|
reset: boolean;
|
|
68
|
+
/** `partial`: the round stopped before its end and the next run goes on from there. */
|
|
69
|
+
state: "partial" | "complete";
|
|
70
|
+
/** What this run saved. */
|
|
35
71
|
saved: number;
|
|
36
72
|
removed: number;
|
|
37
73
|
occurrences: number;
|
|
38
74
|
/** Entries a full round did not return, now marked deleted. */
|
|
39
75
|
unseen: number;
|
|
40
|
-
/** Set when the calendar failed; its cursor stays
|
|
76
|
+
/** Set when the calendar failed; its cursor stays at its last saved page, so the next run goes on from there. */
|
|
41
77
|
error?: string;
|
|
42
78
|
}
|
|
43
79
|
export interface CalendarSyncReport {
|
|
@@ -53,13 +89,56 @@ export interface CalendarSyncReport {
|
|
|
53
89
|
externalId: string;
|
|
54
90
|
title: string | null;
|
|
55
91
|
}[];
|
|
56
|
-
/** Every synced calendar finished. */
|
|
92
|
+
/** Every synced calendar finished its round and none failed. */
|
|
57
93
|
complete: boolean;
|
|
94
|
+
state: "partial" | "complete";
|
|
95
|
+
/** Why the run stopped early: its request budget, its deadline, or a cancel. */
|
|
96
|
+
stopped?: BudgetStop;
|
|
97
|
+
/** What this run did, so a partial run still shows that it moves. */
|
|
98
|
+
progress: {
|
|
99
|
+
calendars: number;
|
|
100
|
+
calendarsDone: number;
|
|
101
|
+
/** Requests made to the source: the calendar list, each page, each series' slots. */
|
|
102
|
+
requests: number;
|
|
103
|
+
/** Entries and slots saved. */
|
|
104
|
+
saved: number;
|
|
105
|
+
/** Pages read and series expanded, each saved in the cursor: 0 means this run moved nothing on. */
|
|
106
|
+
steps: number;
|
|
107
|
+
};
|
|
108
|
+
hint?: string;
|
|
58
109
|
}
|
|
59
110
|
/**
|
|
60
111
|
* Brings one calendar account's synced calendars up to date (foundation §6.2): the calendar list first, then for
|
|
61
112
|
* each synced calendar its changes since the cursor, or a full list of the window, then the slots of the series that
|
|
62
|
-
* changed.
|
|
63
|
-
*
|
|
113
|
+
* changed. Every page is saved as it comes, with the round's position in the cursor, so a run the budget stops, or
|
|
114
|
+
* one that fails, goes on from there next time. Calendars with a round in progress go first, then the longest unsynced.
|
|
64
115
|
*/
|
|
65
116
|
export declare const syncCalendars: (source: CalendarSource, store: EventStore, options: CalendarSyncOptions) => Promise<CalendarSyncReport>;
|
|
117
|
+
/**
|
|
118
|
+
* Each synced calendar's sync in the WC-LIFE-14 shape: `done` counts the entries its current or last round saved,
|
|
119
|
+
* `total` is null since no provider says how many a window holds, and `cursor_age_ms` growing on a `partial` one
|
|
120
|
+
* means nothing is moving it.
|
|
121
|
+
*/
|
|
122
|
+
export declare const calendarStatus: (store: EventStore, accountId: number, { profile, now }: {
|
|
123
|
+
profile: string;
|
|
124
|
+
now: number;
|
|
125
|
+
}) => Promise<{
|
|
126
|
+
items: {
|
|
127
|
+
job: string;
|
|
128
|
+
profile: string;
|
|
129
|
+
done: number;
|
|
130
|
+
total: number | null;
|
|
131
|
+
remaining: number | null;
|
|
132
|
+
state: "partial" | "complete";
|
|
133
|
+
updated_at: string | null;
|
|
134
|
+
cursor_age_ms: number | null;
|
|
135
|
+
calendar_id: string;
|
|
136
|
+
external_id: string;
|
|
137
|
+
title: string | null;
|
|
138
|
+
round: string | null;
|
|
139
|
+
line: string;
|
|
140
|
+
}[];
|
|
141
|
+
page: number;
|
|
142
|
+
limit: number;
|
|
143
|
+
hasMore: boolean;
|
|
144
|
+
}>;
|