@mulmoclaude/core 1.6.0 → 1.7.1
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/assets/helps/error-recovery.md +46 -0
- package/assets/helps/google-calendar-collection.md +57 -3
- package/assets/helps/google.md +3 -2
- package/dist/calendarGrid-CaS9er8i.cjs +576 -0
- package/dist/calendarGrid-CaS9er8i.cjs.map +1 -0
- package/dist/calendarGrid-CrGxeCOG.js +397 -0
- package/dist/calendarGrid-CrGxeCOG.js.map +1 -0
- package/dist/collection/index.cjs +44 -44
- package/dist/collection/index.cjs.map +1 -1
- package/dist/collection/index.js +2 -2
- package/dist/collection/registry/server/index.cjs +2 -2
- package/dist/collection/registry/server/index.js +2 -2
- package/dist/collection/server/index.cjs +4 -4
- package/dist/collection/server/index.js +3 -3
- package/dist/collection-watchers/index.cjs +5 -5
- package/dist/collection-watchers/index.cjs.map +1 -1
- package/dist/collection-watchers/index.js +4 -4
- package/dist/{discovery--kRUWed0.cjs → discovery-DYcR83qx.cjs} +64 -53
- package/dist/discovery-DYcR83qx.cjs.map +1 -0
- package/dist/{discovery-CKR4TOX3.js → discovery-_fjsluLx.js} +43 -32
- package/dist/discovery-_fjsluLx.js.map +1 -0
- package/dist/feeds/index.cjs +4 -4
- package/dist/feeds/index.js +2 -2
- package/dist/feeds/server/index.cjs +6 -6
- package/dist/feeds/server/index.js +4 -4
- package/dist/google/apiClient.d.ts +6 -0
- package/dist/google/calendar.d.ts +79 -8
- package/dist/google/calendarPushState.d.ts +17 -0
- package/dist/google/collectionPush.d.ts +64 -0
- package/dist/google/collectionSync.d.ts +10 -0
- package/dist/google/index.cjs +712 -36
- package/dist/google/index.cjs.map +1 -1
- package/dist/google/index.d.ts +7 -3
- package/dist/google/index.js +683 -37
- package/dist/google/index.js.map +1 -1
- package/dist/google/pushDateTime.d.ts +10 -0
- package/dist/google/pushPlan.d.ts +73 -0
- package/dist/{ingestTypes-xX8VpQqh.cjs → ingestTypes-D1GQdG8e.cjs} +3 -3
- package/dist/{ingestTypes-xX8VpQqh.cjs.map → ingestTypes-D1GQdG8e.cjs.map} +1 -1
- package/dist/{ingestTypes-L59cIGgX.js → ingestTypes-XReG-li7.js} +2 -2
- package/dist/{ingestTypes-L59cIGgX.js.map → ingestTypes-XReG-li7.js.map} +1 -1
- package/dist/{promptSafety-CQ5Un4wi.js → promptSafety-C--op_6a.js} +3 -269
- package/dist/promptSafety-C--op_6a.js.map +1 -0
- package/dist/{promptSafety-DfZYNtjK.cjs → promptSafety-FD8cQn3e.cjs} +8 -358
- package/dist/promptSafety-FD8cQn3e.cjs.map +1 -0
- package/dist/remote-host/index.cjs +8 -0
- package/dist/remote-host/index.cjs.map +1 -1
- package/dist/remote-host/index.d.ts +21 -0
- package/dist/remote-host/index.js +8 -1
- package/dist/remote-host/index.js.map +1 -1
- package/dist/{server-D_6FLygK.js → server-BlIrtGKl.js} +4 -4
- package/dist/{server-D_6FLygK.js.map → server-BlIrtGKl.js.map} +1 -1
- package/dist/{server-gEOeV_Nv.cjs → server-l4TZ5Lbf.cjs} +21 -21
- package/dist/{server-gEOeV_Nv.cjs.map → server-l4TZ5Lbf.cjs.map} +1 -1
- package/package.json +1 -1
- package/dist/discovery--kRUWed0.cjs.map +0 -1
- package/dist/discovery-CKR4TOX3.js.map +0 -1
- package/dist/ids-BnTh3Hl0.cjs +0 -226
- package/dist/ids-BnTh3Hl0.cjs.map +0 -1
- package/dist/ids-s4GfmE93.js +0 -131
- package/dist/ids-s4GfmE93.js.map +0 -1
- package/dist/promptSafety-CQ5Un4wi.js.map +0 -1
- package/dist/promptSafety-DfZYNtjK.cjs.map +0 -1
package/dist/feeds/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const require_ingestTypes = require("../ingestTypes-
|
|
2
|
+
const require_calendarGrid = require("../calendarGrid-CaS9er8i.cjs");
|
|
3
|
+
const require_ingestTypes = require("../ingestTypes-D1GQdG8e.cjs");
|
|
4
4
|
exports.AGENT_INGEST_KIND = require_ingestTypes.AGENT_INGEST_KIND;
|
|
5
5
|
exports.DEFAULT_FEED_MAX_ITEMS = require_ingestTypes.DEFAULT_FEED_MAX_ITEMS;
|
|
6
|
-
exports.FEED_SCHEDULES =
|
|
7
|
-
exports.INGEST_KINDS =
|
|
6
|
+
exports.FEED_SCHEDULES = require_calendarGrid.FEED_SCHEDULES;
|
|
7
|
+
exports.INGEST_KINDS = require_calendarGrid.INGEST_KINDS;
|
|
8
8
|
exports.isFeedSchedule = require_ingestTypes.isFeedSchedule;
|
package/dist/feeds/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../ingestTypes-
|
|
1
|
+
import { C as FEED_SCHEDULES, w as INGEST_KINDS } from "../calendarGrid-CrGxeCOG.js";
|
|
2
|
+
import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../ingestTypes-XReG-li7.js";
|
|
3
3
|
export { AGENT_INGEST_KIND, DEFAULT_FEED_MAX_ITEMS, FEED_SCHEDULES, INGEST_KINDS, isFeedSchedule };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.cjs");
|
|
3
|
-
const
|
|
4
|
-
const require_discovery = require("../../discovery
|
|
5
|
-
const require_server = require("../../server-
|
|
3
|
+
const require_calendarGrid = require("../../calendarGrid-CaS9er8i.cjs");
|
|
4
|
+
const require_discovery = require("../../discovery-DYcR83qx.cjs");
|
|
5
|
+
const require_server = require("../../server-l4TZ5Lbf.cjs");
|
|
6
6
|
const require_feeds_paths = require("../paths.cjs");
|
|
7
|
-
const require_ingestTypes = require("../../ingestTypes-
|
|
7
|
+
const require_ingestTypes = require("../../ingestTypes-D1GQdG8e.cjs");
|
|
8
8
|
const require_notifier = require("../../notifier-tMsAXyXp.cjs");
|
|
9
9
|
let node_path = require("node:path");
|
|
10
10
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
@@ -912,8 +912,8 @@ exports.DEFAULT_FEED_MAX_ITEMS = require_ingestTypes.DEFAULT_FEED_MAX_ITEMS;
|
|
|
912
912
|
exports.DEFAULT_FEED_REFRESH_INTERVAL_MS = DEFAULT_FEED_REFRESH_INTERVAL_MS;
|
|
913
913
|
exports.FEEDS_DIR = require_feeds_paths.FEEDS_DIR;
|
|
914
914
|
exports.FEED_REFRESH_TASK_ID = FEED_REFRESH_TASK_ID;
|
|
915
|
-
exports.FEED_SCHEDULES =
|
|
916
|
-
exports.INGEST_KINDS =
|
|
915
|
+
exports.FEED_SCHEDULES = require_calendarGrid.FEED_SCHEDULES;
|
|
916
|
+
exports.INGEST_KINDS = require_calendarGrid.INGEST_KINDS;
|
|
917
917
|
exports.configureFeedsHost = configureFeedsHost;
|
|
918
918
|
exports.feedDir = require_feeds_paths.feedDir;
|
|
919
919
|
exports.feedRefreshTaskDef = feedRefreshTaskDef;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { N as listItems, V as resolveDataDir, W as safeSlugName, d as storeFor, et as createForwardingLogger, n as discoverCollections, tt as createHostSlot } from "../../discovery-
|
|
3
|
-
import { A as buildCollectionActionSeedPrompt, P as readSkillTemplate, j as promptPathsFor } from "../../server-
|
|
1
|
+
import { C as FEED_SCHEDULES, w as INGEST_KINDS } from "../../calendarGrid-CrGxeCOG.js";
|
|
2
|
+
import { N as listItems, V as resolveDataDir, W as safeSlugName, d as storeFor, et as createForwardingLogger, n as discoverCollections, tt as createHostSlot } from "../../discovery-_fjsluLx.js";
|
|
3
|
+
import { A as buildCollectionActionSeedPrompt, P as readSkillTemplate, j as promptPathsFor } from "../../server-BlIrtGKl.js";
|
|
4
4
|
import { FEEDS_DIR, feedDir, feedStatePath, feedsRoot, ingestStateDir, ingestStatePath } from "../paths.js";
|
|
5
|
-
import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../../ingestTypes-
|
|
5
|
+
import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../../ingestTypes-XReG-li7.js";
|
|
6
6
|
import { d as publish, n as clear } from "../../notifier-BdA5qzhe.js";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const GOOGLE_API_TIMEOUT_MS: number;
|
|
2
|
+
export declare const HTTP_FORBIDDEN = 403;
|
|
2
3
|
export declare const DEFAULT_LIST_MAX_RESULTS = 10;
|
|
3
4
|
export declare const MAX_LIST_RESULTS = 50;
|
|
4
5
|
/** Carries the HTTP status so callers can branch on it (e.g. an expired
|
|
@@ -18,6 +19,11 @@ export interface GoogleRequestInit {
|
|
|
18
19
|
contentType?: string;
|
|
19
20
|
/** Response is not JSON (Drive media download) — return the raw text. */
|
|
20
21
|
expectText?: boolean;
|
|
22
|
+
/** Extra request headers, merged after the defaults. Used for conditional
|
|
23
|
+
* writes (`If-Match: <etag>`), which is how a caller makes a PATCH fail with
|
|
24
|
+
* 412 instead of silently overwriting a newer version. Cannot replace
|
|
25
|
+
* `Authorization`. */
|
|
26
|
+
extraHeaders?: Record<string, string>;
|
|
21
27
|
}
|
|
22
28
|
export declare function googleRequest(apiLabel: string, accessToken: string, url: string, init?: GoogleRequestInit): Promise<unknown>;
|
|
23
29
|
export declare const stringField: (record: Record<string, unknown>, key: string) => string;
|
|
@@ -1,28 +1,72 @@
|
|
|
1
|
+
/** An `If-Match` write whose etag no longer matches — someone else changed the
|
|
2
|
+
* event since it was read. */
|
|
3
|
+
export declare const HTTP_PRECONDITION_FAILED = 412;
|
|
4
|
+
/** An `insert` whose caller-supplied event id is already taken. */
|
|
5
|
+
export declare const HTTP_CONFLICT = 409;
|
|
6
|
+
/** Google's status for an event that was deleted; a sync window reports it so
|
|
7
|
+
* consumers can remove their copy. Single-sourced — the pull and the push both
|
|
8
|
+
* branch on it. */
|
|
9
|
+
export declare const CANCELLED_EVENT_STATUS = "cancelled";
|
|
1
10
|
/** Resolve a declared calendarId to the one the API and the sync-token store
|
|
2
11
|
* both address. `||` (not `??`) so an empty string also falls back instead of
|
|
3
12
|
* building a malformed `/calendars//events` URL. Single-sourced because an
|
|
4
13
|
* omitted id and an explicit "primary" MUST agree everywhere — grouping them
|
|
5
14
|
* apart while they share a sync token silently loses events (#2184). */
|
|
6
15
|
export declare const canonicalCalendarId: (calendarId: string | undefined) => string;
|
|
7
|
-
|
|
8
|
-
|
|
16
|
+
/** One end of an event as the API expresses it: a timed instant, or a whole day.
|
|
17
|
+
*
|
|
18
|
+
* `timeZone` names the zone a `dateTime` WITHOUT an offset is read in — the
|
|
19
|
+
* shape a collection push needs, since the stored clock carries no offset
|
|
20
|
+
* (`pushDateTime.ts`). A `dateTime` that already ends in `Z`/`+09:00` needs no
|
|
21
|
+
* `timeZone`. `date` is an all-day event, whose `end` Google treats as
|
|
22
|
+
* EXCLUSIVE. */
|
|
23
|
+
export type CalendarEventTime = {
|
|
24
|
+
dateTime: string;
|
|
25
|
+
timeZone?: string;
|
|
26
|
+
} | {
|
|
27
|
+
date: string;
|
|
28
|
+
};
|
|
29
|
+
/** The two ways to state an event's span. The flat pair is what the `google`
|
|
30
|
+
* tool passes (RFC3339 with an offset); the structured pair is what a push
|
|
31
|
+
* needs to express an all-day event or an explicit zone. Expressed as a union
|
|
32
|
+
* so "neither given" cannot typecheck on a create. */
|
|
33
|
+
export type CalendarEventSpan = {
|
|
9
34
|
startDateTime: string;
|
|
10
35
|
endDateTime: string;
|
|
36
|
+
} | {
|
|
37
|
+
start: CalendarEventTime;
|
|
38
|
+
end: CalendarEventTime;
|
|
39
|
+
};
|
|
40
|
+
export type CalendarEventInput = {
|
|
41
|
+
summary: string;
|
|
11
42
|
description?: string;
|
|
12
43
|
/** Calendar to create the event on; defaults to the user's primary. */
|
|
13
44
|
calendarId?: string;
|
|
14
45
|
/** Event colour (Google event palette id "1".."11"); omit to inherit the calendar's colour. */
|
|
15
46
|
colorId?: string;
|
|
16
|
-
|
|
47
|
+
/** Caller-chosen event id. Google requires base32hex (`0-9a-v`), 5-1024 chars,
|
|
48
|
+
* and answers 409 when it is already taken. A collection push sets this so a
|
|
49
|
+
* locally-created record keeps its own record id as the event id, instead of
|
|
50
|
+
* being re-keyed to Google's after the fact — a re-key that is missed leaves
|
|
51
|
+
* a duplicate record on the next pull. */
|
|
52
|
+
eventId?: string;
|
|
53
|
+
} & CalendarEventSpan;
|
|
17
54
|
export interface UpdateCalendarEventInput {
|
|
18
55
|
eventId: string;
|
|
19
56
|
summary?: string;
|
|
20
57
|
startDateTime?: string;
|
|
21
58
|
endDateTime?: string;
|
|
59
|
+
/** Structured span; wins over the flat pair when both are present. */
|
|
60
|
+
start?: CalendarEventTime;
|
|
61
|
+
end?: CalendarEventTime;
|
|
22
62
|
/** `""` clears the description; omit to leave it untouched. */
|
|
23
63
|
description?: string;
|
|
24
64
|
calendarId?: string;
|
|
25
65
|
colorId?: string;
|
|
66
|
+
/** Etag of the version this edit was computed against. Sent as `If-Match`, so
|
|
67
|
+
* Google answers 412 rather than letting the PATCH clobber a change that
|
|
68
|
+
* landed after the caller read the event. Omit for an unconditional write. */
|
|
69
|
+
ifMatch?: string;
|
|
26
70
|
}
|
|
27
71
|
export interface DeleteCalendarEventInput {
|
|
28
72
|
eventId: string;
|
|
@@ -55,6 +99,10 @@ export interface CalendarSummary {
|
|
|
55
99
|
foregroundColor: string;
|
|
56
100
|
/** Calendar palette id backing background/foregroundColor. */
|
|
57
101
|
colorId: string;
|
|
102
|
+
/** IANA zone (`Asia/Tokyo`). The zone a pushed `dateTime` without an offset is
|
|
103
|
+
* read in: the collection stores the clock the user reads off THIS calendar,
|
|
104
|
+
* so this is the only correct zone to re-attach. `""` when Google omits it. */
|
|
105
|
+
timeZone: string;
|
|
58
106
|
}
|
|
59
107
|
export interface CalendarColorEntry {
|
|
60
108
|
background: string;
|
|
@@ -71,17 +119,31 @@ export declare const toCalendarSummary: (value: unknown) => CalendarSummary;
|
|
|
71
119
|
/** Kept as a named export for the existing unit tests / callers; the shared
|
|
72
120
|
* helper now carries the wording. */
|
|
73
121
|
export declare const calendarApiError: (status: number, body: string) => Error;
|
|
122
|
+
/** Normalise either spelling of a span into the pair the API body carries. */
|
|
123
|
+
export declare const resolveEventSpan: (span: CalendarEventSpan) => {
|
|
124
|
+
start: CalendarEventTime;
|
|
125
|
+
end: CalendarEventTime;
|
|
126
|
+
};
|
|
74
127
|
export declare function createCalendarEvent(accessToken: string, input: CalendarEventInput): Promise<CalendarEventSummary>;
|
|
75
|
-
/** PATCH body for an event edit — only the fields the caller actually supplied.
|
|
76
|
-
*
|
|
77
|
-
* `undefined` means "leave as is" and `""` means "clear it", so the two cannot
|
|
78
|
-
* be collapsed: dropping `description: ""` would silently ignore a request to
|
|
79
|
-
* empty the body text. Pure so the distinction is testable without network. */
|
|
80
128
|
export declare const buildEventPatch: (input: UpdateCalendarEventInput) => Record<string, unknown>;
|
|
81
129
|
/** Edit an existing event in place. PATCH, not PUT — a PUT would need the whole
|
|
82
130
|
* event and would drop every field the caller never read (attendees,
|
|
83
131
|
* reminders, recurrence). */
|
|
84
132
|
export declare function updateCalendarEvent(accessToken: string, input: UpdateCalendarEventInput): Promise<CalendarEventSummary>;
|
|
133
|
+
/** An event plus the version token a conditional write needs. */
|
|
134
|
+
export interface FetchedCalendarEvent {
|
|
135
|
+
event: CalendarEventSummary;
|
|
136
|
+
/** Google's `etag` for this version, `""` when absent. Sent back as
|
|
137
|
+
* `If-Match` so a PATCH cannot overwrite a version we never read. */
|
|
138
|
+
etag: string;
|
|
139
|
+
}
|
|
140
|
+
/** Read ONE event, or null when it is gone (404 / 410).
|
|
141
|
+
*
|
|
142
|
+
* A push needs Google's current value per changed record to tell a local-only
|
|
143
|
+
* edit from a both-sides conflict. Deliberately not `syncCalendarEvents`: that
|
|
144
|
+
* consumes the calendar's sync token, and the token's window is served once —
|
|
145
|
+
* spending it here would make the next pull miss everything in it. */
|
|
146
|
+
export declare function getCalendarEvent(accessToken: string, input: DeleteCalendarEventInput): Promise<FetchedCalendarEvent | null>;
|
|
85
147
|
/** Remove an event. Google answers 204 with no body, so there is nothing to
|
|
86
148
|
* return; a second delete of the same id answers 410, which surfaces as a
|
|
87
149
|
* GoogleApiError rather than being swallowed. */
|
|
@@ -126,6 +188,15 @@ export declare function collectCalendarPages(fetchPage: (pageToken?: string) =>
|
|
|
126
188
|
/** The calendars the user has added/subscribed to (primary + secondary +
|
|
127
189
|
* shared), each with its id, name and colour, following pagination. Needs the
|
|
128
190
|
* calendar-list read scope (GOOGLE_CALENDARLIST_SCOPE). */
|
|
191
|
+
/** One calendar's own resource, addressed by id rather than looked up in the
|
|
192
|
+
* user's list.
|
|
193
|
+
*
|
|
194
|
+
* `calendarList` only holds calendars the user has ADDED; a calendar shared
|
|
195
|
+
* with them can be readable and writable by id without appearing there. This is
|
|
196
|
+
* how a push learns such a calendar's `timeZone`. Note the resource carries no
|
|
197
|
+
* `accessRole` — that is a calendarList property — so reachability here says
|
|
198
|
+
* nothing about writability. */
|
|
199
|
+
export declare function getCalendar(accessToken: string, calendarId: string | undefined): Promise<CalendarSummary>;
|
|
129
200
|
export declare function listCalendars(accessToken: string): Promise<CalendarSummary[]>;
|
|
130
201
|
/** Resolve a `colorId` (on an event or calendar) to its hex background/foreground. */
|
|
131
202
|
export declare function getCalendarColors(accessToken: string): Promise<CalendarColors>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CalendarEventSummary } from './calendar.js';
|
|
2
|
+
/** The pushable subset of an event. `htmlLink` and `status` are read-only on
|
|
3
|
+
* Google's side, so a baseline for them could never be acted on. */
|
|
4
|
+
export type ShadowEvent = Pick<CalendarEventSummary, "summary" | "start" | "end" | "colorId">;
|
|
5
|
+
/** `<workspace>/data/calendar/.push-state.json` */
|
|
6
|
+
export declare function calendarPushStatePath(workspaceRoot?: string): string;
|
|
7
|
+
export declare const toShadowEvent: (event: CalendarEventSummary) => ShadowEvent;
|
|
8
|
+
export declare function loadCalendarShadow(calendarId?: string, workspaceRoot?: string): Promise<Record<string, ShadowEvent>>;
|
|
9
|
+
/** Apply a batch to one calendar's baseline. `null` removes an entry (the event
|
|
10
|
+
* was cancelled), so a cancel-then-recreate cannot resume from a stale one.
|
|
11
|
+
* Merged rather than replaced: a sync window describes only what changed. */
|
|
12
|
+
export declare function mergeShadow(current: Record<string, ShadowEvent>, updates: Record<string, ShadowEvent | null>): Record<string, ShadowEvent>;
|
|
13
|
+
export declare function saveCalendarShadow(calendarId: string | undefined, updates: Record<string, ShadowEvent | null>, workspaceRoot?: string): Promise<void>;
|
|
14
|
+
/** Drop one calendar's whole baseline. Called wherever the sync token is
|
|
15
|
+
* cleared: a baseline outliving its token would let a push diff against events
|
|
16
|
+
* the workspace no longer holds. */
|
|
17
|
+
export declare function clearCalendarShadow(calendarId?: string, workspaceRoot?: string): Promise<void>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { LoadedCollection } from '../collection/server/discoveredCollection.js';
|
|
2
|
+
/** What the up-front writability gate knows about the target calendar. */
|
|
3
|
+
export interface CalendarWriteTarget {
|
|
4
|
+
/** The role from the user's calendar LIST, or null when the calendar is not in
|
|
5
|
+
* it. Null means unknown, never read-only: `calendarList` holds only the
|
|
6
|
+
* calendars the user has added, so one shared with write access can be absent
|
|
7
|
+
* from it (Codex review). */
|
|
8
|
+
accessRole: string | null;
|
|
9
|
+
/** IANA zone for rebuilding a zone-less stored clock, `""` when unreported. */
|
|
10
|
+
timeZone: string;
|
|
11
|
+
}
|
|
12
|
+
/** Whether to refuse the whole push before touching a single event.
|
|
13
|
+
*
|
|
14
|
+
* Only on POSITIVE evidence of a non-writable role. An unlisted calendar is
|
|
15
|
+
* unknown and must fall through: hard-denying it would block the feature
|
|
16
|
+
* outright for a calendar the user can in fact write to. Those attempts surface
|
|
17
|
+
* Google's own 403 per record if the write really is not allowed. */
|
|
18
|
+
export declare const isDeniedAccessRole: (accessRole: string | null) => boolean;
|
|
19
|
+
export interface CalendarCollectionPushResult {
|
|
20
|
+
slug: string;
|
|
21
|
+
created: number;
|
|
22
|
+
updated: number;
|
|
23
|
+
/** Edited on both sides; skipped so neither version is destroyed. */
|
|
24
|
+
conflicts: number;
|
|
25
|
+
/** Records deleted locally. Reported only — v1 never deletes in Google. */
|
|
26
|
+
localDeletes: number;
|
|
27
|
+
/** Records that cannot be pushed as they stand, each with the reason. */
|
|
28
|
+
skipped: string[];
|
|
29
|
+
errors: string[];
|
|
30
|
+
}
|
|
31
|
+
export type CalendarPushOutcome = {
|
|
32
|
+
kind: "pushed";
|
|
33
|
+
result: CalendarCollectionPushResult;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "not-a-calendar";
|
|
36
|
+
} | {
|
|
37
|
+
kind: "not-linked";
|
|
38
|
+
} | {
|
|
39
|
+
kind: "read-only";
|
|
40
|
+
accessRole: string;
|
|
41
|
+
}
|
|
42
|
+
/** The push never got as far as a record: a revoked grant, an unreachable
|
|
43
|
+
* Calendar API, a workspace read failure. Typed rather than left to throw so
|
|
44
|
+
* the route answers in the same shape as the other setup problems instead of
|
|
45
|
+
* an opaque 500. */
|
|
46
|
+
| {
|
|
47
|
+
kind: "failed";
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
/** The I/O a push crosses, injected so every outcome can be exercised with fakes
|
|
51
|
+
* instead of a workspace on disk and a live Google grant. */
|
|
52
|
+
export interface CalendarPushDeps {
|
|
53
|
+
findCollection: (slug: string, workspaceRoot: string) => Promise<LoadedCollection | null>;
|
|
54
|
+
isLinked: () => Promise<boolean>;
|
|
55
|
+
accessToken: () => Promise<string>;
|
|
56
|
+
calendarMeta: (accessToken: string, calendarId: string | undefined) => Promise<CalendarWriteTarget>;
|
|
57
|
+
}
|
|
58
|
+
/** Push ONE collection's records to the calendar it declares.
|
|
59
|
+
*
|
|
60
|
+
* "Does this collection sync at all" is answered before "is Google linked", for
|
|
61
|
+
* the reason `syncCalendarForCollection` gives: telling someone to link their
|
|
62
|
+
* account for a collection that never declared a calendar sends them fixing the
|
|
63
|
+
* wrong thing. */
|
|
64
|
+
export declare function pushCalendarForCollection(slug: string, workspaceRoot: string, deps?: CalendarPushDeps): Promise<CalendarPushOutcome>;
|
|
@@ -4,6 +4,7 @@ import { DeleteItemResult, WriteItemResult } from '../collection/server/io.js';
|
|
|
4
4
|
import { CollectionFieldSpec, CollectionItem } from '../collection/core/schema.js';
|
|
5
5
|
import { GOOGLE_CALENDAR_SOURCE_FIELDS } from '../collection/core/schemaZ.js';
|
|
6
6
|
import { CalendarEventSummary } from './calendar.js';
|
|
7
|
+
import { ShadowEvent } from './calendarPushState.js';
|
|
7
8
|
export declare const GOOGLE_CALENDAR_SYNC_TASK_ID = "system:google-calendar-sync";
|
|
8
9
|
export interface CalendarCollectionSyncResult {
|
|
9
10
|
slug: string;
|
|
@@ -61,7 +62,16 @@ export declare function withKeyedLock<T>(locks: Map<string, Promise<unknown>>, k
|
|
|
61
62
|
* writes are upserts by event id — but it is a wasted full walk. Queued, the
|
|
62
63
|
* second pass resumes from the token the first just stored and fetches only
|
|
63
64
|
* what is genuinely new. */
|
|
65
|
+
/** Serialise anything that touches ONE calendar's sync state.
|
|
66
|
+
*
|
|
67
|
+
* Shared with the push path (#2598), not only the pull doors: a push that
|
|
68
|
+
* overtakes an in-flight pull would record a baseline for events the pull is
|
|
69
|
+
* still writing, so the next push would diff against a future it never saw. */
|
|
70
|
+
export declare function withCalendarLock<T>(calendarId: string | undefined, run: () => Promise<T>): Promise<T>;
|
|
64
71
|
export declare function syncCalendarGroup(calendarId: string | undefined, collections: readonly LoadedCollection[], workspaceRoot: string): Promise<CalendarCollectionSyncResult[]>;
|
|
72
|
+
/** The baseline this window establishes: what Google now says per event, and
|
|
73
|
+
* `null` for a cancelled one so a recreate cannot resume from a dead baseline. */
|
|
74
|
+
export declare function shadowUpdates(events: readonly CalendarEventSummary[]): Record<string, ShadowEvent | null>;
|
|
65
75
|
/** Liveness of the collections a sync just wrote to, checked against the skill
|
|
66
76
|
* dir `deleteCollection` removes. `exists` is injected so the rule is testable
|
|
67
77
|
* without a filesystem. An empty group has no survivor by definition. */
|