@plotday/tool-google-calendar 0.2.1 → 0.2.3
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/google-api.d.ts +70 -0
- package/dist/google-api.js +195 -0
- package/dist/google-api.js.map +1 -0
- package/dist/google-calendar.d.ts +91 -0
- package/dist/google-calendar.js +345 -0
- package/dist/google-calendar.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Activity } from "@plotday/agent";
|
|
2
|
+
export type GoogleEvent = {
|
|
3
|
+
id: string;
|
|
4
|
+
recurringEventId?: string;
|
|
5
|
+
originalStartTime?: {
|
|
6
|
+
dateTime?: string;
|
|
7
|
+
date?: string;
|
|
8
|
+
timeZone?: string;
|
|
9
|
+
};
|
|
10
|
+
summary?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
status: "confirmed" | "cancelled" | "tentative";
|
|
13
|
+
start?: {
|
|
14
|
+
dateTime?: string;
|
|
15
|
+
date?: string;
|
|
16
|
+
timeZone?: string;
|
|
17
|
+
};
|
|
18
|
+
end?: {
|
|
19
|
+
dateTime?: string;
|
|
20
|
+
date?: string;
|
|
21
|
+
timeZone?: string;
|
|
22
|
+
};
|
|
23
|
+
recurrence?: string[];
|
|
24
|
+
organizer?: {
|
|
25
|
+
email?: string;
|
|
26
|
+
displayName?: string;
|
|
27
|
+
self?: boolean;
|
|
28
|
+
};
|
|
29
|
+
attendees?: Array<{
|
|
30
|
+
email?: string;
|
|
31
|
+
displayName?: string;
|
|
32
|
+
responseStatus?: "accepted" | "declined" | "tentative" | "needsAction";
|
|
33
|
+
optional?: boolean;
|
|
34
|
+
organizer?: boolean;
|
|
35
|
+
self?: boolean;
|
|
36
|
+
resource?: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
location?: string;
|
|
39
|
+
hangoutLink?: string;
|
|
40
|
+
htmlLink?: string;
|
|
41
|
+
created?: string;
|
|
42
|
+
updated?: string;
|
|
43
|
+
};
|
|
44
|
+
export type SyncState = {
|
|
45
|
+
calendarId: string;
|
|
46
|
+
state?: string;
|
|
47
|
+
more?: boolean;
|
|
48
|
+
min?: Date;
|
|
49
|
+
max?: Date;
|
|
50
|
+
sequence?: number;
|
|
51
|
+
};
|
|
52
|
+
export declare class GoogleApi {
|
|
53
|
+
accessToken: string;
|
|
54
|
+
constructor(accessToken: string);
|
|
55
|
+
call(method: string, url: string, params?: {
|
|
56
|
+
[key: string]: any;
|
|
57
|
+
}, body?: {
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
}): Promise<any>;
|
|
60
|
+
}
|
|
61
|
+
export declare function parseRRule(recurrence?: string[]): string | undefined;
|
|
62
|
+
export declare function parseExDates(recurrence?: string[]): Date[];
|
|
63
|
+
export declare function parseRDates(recurrence?: string[]): Date[];
|
|
64
|
+
export declare function parseGoogleRecurrenceEnd(recurrence?: string[]): Date | string | null;
|
|
65
|
+
export declare function parseGoogleRecurrenceCount(recurrence?: string[]): number | null;
|
|
66
|
+
export declare function transformGoogleEvent(event: GoogleEvent, calendarId: string): Partial<Activity>;
|
|
67
|
+
export declare function syncGoogleCalendar(api: GoogleApi, calendarId: string, state: SyncState): Promise<{
|
|
68
|
+
events: GoogleEvent[];
|
|
69
|
+
state: SyncState;
|
|
70
|
+
}>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { ActivityType } from "@plotday/agent";
|
|
2
|
+
export class GoogleApi {
|
|
3
|
+
accessToken;
|
|
4
|
+
constructor(accessToken) {
|
|
5
|
+
this.accessToken = accessToken;
|
|
6
|
+
}
|
|
7
|
+
async call(method, url, params, body) {
|
|
8
|
+
const query = params ? `?${new URLSearchParams(params)}` : "";
|
|
9
|
+
const headers = {
|
|
10
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
11
|
+
Accept: "application/json",
|
|
12
|
+
...(body ? { "Content-Type": "application/json" } : {}),
|
|
13
|
+
};
|
|
14
|
+
const response = await fetch(url + query, {
|
|
15
|
+
method,
|
|
16
|
+
headers,
|
|
17
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
18
|
+
});
|
|
19
|
+
switch (response.status) {
|
|
20
|
+
case 400:
|
|
21
|
+
const responseBody = await response.json();
|
|
22
|
+
if (responseBody.status === "FAILED_PRECONDITION") {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
throw new Error("Invalid request", { cause: responseBody });
|
|
26
|
+
case 401:
|
|
27
|
+
throw new Error("Authentication failed - token may be expired");
|
|
28
|
+
case 410:
|
|
29
|
+
return null;
|
|
30
|
+
case 200:
|
|
31
|
+
return await response.json();
|
|
32
|
+
default:
|
|
33
|
+
throw new Error(await response.text());
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function parseRRule(recurrence) {
|
|
38
|
+
if (!recurrence?.length)
|
|
39
|
+
return undefined;
|
|
40
|
+
const rrule = recurrence.find((rule) => rule.startsWith("RRULE:"));
|
|
41
|
+
return rrule ? rrule.substring(6) : undefined; // Remove 'RRULE:' prefix
|
|
42
|
+
}
|
|
43
|
+
export function parseExDates(recurrence) {
|
|
44
|
+
if (!recurrence?.length)
|
|
45
|
+
return [];
|
|
46
|
+
return recurrence
|
|
47
|
+
.filter((rule) => rule.startsWith("EXDATE"))
|
|
48
|
+
.flatMap((rule) => {
|
|
49
|
+
const dates = rule.split(":")[1];
|
|
50
|
+
return dates ? dates.split(",").map((d) => new Date(d)) : [];
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function parseRDates(recurrence) {
|
|
54
|
+
if (!recurrence?.length)
|
|
55
|
+
return [];
|
|
56
|
+
return recurrence
|
|
57
|
+
.filter((rule) => rule.startsWith("RDATE"))
|
|
58
|
+
.flatMap((rule) => {
|
|
59
|
+
const dates = rule.split(":")[1];
|
|
60
|
+
return dates ? dates.split(",").map((d) => new Date(d)) : [];
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export function parseGoogleRecurrenceEnd(recurrence) {
|
|
64
|
+
if (!recurrence?.length)
|
|
65
|
+
return null;
|
|
66
|
+
const rrule = recurrence.find((rule) => rule.startsWith("RRULE:"));
|
|
67
|
+
if (!rrule)
|
|
68
|
+
return null;
|
|
69
|
+
const untilMatch = rrule.match(/UNTIL=([^;]+)/);
|
|
70
|
+
if (untilMatch) {
|
|
71
|
+
const untilValue = untilMatch[1];
|
|
72
|
+
if (untilValue.includes("T")) {
|
|
73
|
+
const year = untilValue.slice(0, 4);
|
|
74
|
+
const month = untilValue.slice(4, 6);
|
|
75
|
+
const day = untilValue.slice(6, 8);
|
|
76
|
+
const hour = untilValue.slice(9, 11);
|
|
77
|
+
const minute = untilValue.slice(11, 13);
|
|
78
|
+
const second = untilValue.slice(13, 15);
|
|
79
|
+
return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}Z`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const year = untilValue.slice(0, 4);
|
|
83
|
+
const month = untilValue.slice(4, 6);
|
|
84
|
+
const day = untilValue.slice(6, 8);
|
|
85
|
+
return `${year}-${month}-${day}`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
export function parseGoogleRecurrenceCount(recurrence) {
|
|
91
|
+
if (!recurrence?.length)
|
|
92
|
+
return null;
|
|
93
|
+
const rrule = recurrence.find((rule) => rule.startsWith("RRULE:"));
|
|
94
|
+
if (!rrule)
|
|
95
|
+
return null;
|
|
96
|
+
const countMatch = rrule.match(/COUNT=([^;]+)/);
|
|
97
|
+
if (countMatch) {
|
|
98
|
+
const count = parseInt(countMatch[1]);
|
|
99
|
+
return isNaN(count) ? null : count;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
export function transformGoogleEvent(event, calendarId) {
|
|
104
|
+
// Determine if this is an all-day event
|
|
105
|
+
const isAllDay = event.start?.date && !event.start?.dateTime;
|
|
106
|
+
const start = isAllDay
|
|
107
|
+
? event.start?.date || null // All-day events use date strings
|
|
108
|
+
: event.start?.dateTime
|
|
109
|
+
? new Date(event.start?.dateTime)
|
|
110
|
+
: null; // Timed events use Date objects
|
|
111
|
+
const end = isAllDay
|
|
112
|
+
? event.end?.date || null // All-day events use date strings
|
|
113
|
+
: event.end?.dateTime
|
|
114
|
+
? new Date(event.end?.dateTime)
|
|
115
|
+
: null; // Timed events use Date objects
|
|
116
|
+
const activity = {
|
|
117
|
+
type: ActivityType.Event,
|
|
118
|
+
title: event.summary || null,
|
|
119
|
+
note: event.description || null,
|
|
120
|
+
start,
|
|
121
|
+
end,
|
|
122
|
+
meta: {
|
|
123
|
+
source: `google-calendar:${event.id}`,
|
|
124
|
+
id: event.id,
|
|
125
|
+
calendarId: calendarId,
|
|
126
|
+
htmlLink: event.htmlLink,
|
|
127
|
+
hangoutLink: event.hangoutLink,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
// Handle recurrence for master events (not instances)
|
|
131
|
+
if (event.recurrence && !event.recurringEventId) {
|
|
132
|
+
activity.recurrenceRule = parseRRule(event.recurrence);
|
|
133
|
+
// Parse recurrence count (takes precedence over UNTIL)
|
|
134
|
+
const recurrenceCount = parseGoogleRecurrenceCount(event.recurrence);
|
|
135
|
+
if (recurrenceCount) {
|
|
136
|
+
activity.recurrenceCount = recurrenceCount;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// Parse recurrence end date for recurring activities if no count
|
|
140
|
+
const recurrenceUntil = parseGoogleRecurrenceEnd(event.recurrence);
|
|
141
|
+
if (recurrenceUntil) {
|
|
142
|
+
activity.recurrenceUntil = recurrenceUntil;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const exdates = parseExDates(event.recurrence);
|
|
146
|
+
if (exdates.length > 0) {
|
|
147
|
+
activity.recurrenceExdates = exdates;
|
|
148
|
+
}
|
|
149
|
+
const rdates = parseRDates(event.recurrence);
|
|
150
|
+
if (rdates.length > 0) {
|
|
151
|
+
activity.recurrenceDates = rdates;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return activity;
|
|
155
|
+
}
|
|
156
|
+
export async function syncGoogleCalendar(api, calendarId, state) {
|
|
157
|
+
const params = {
|
|
158
|
+
// Remove singleEvents to get recurring events as masters
|
|
159
|
+
singleEvents: false,
|
|
160
|
+
showDeleted: true,
|
|
161
|
+
};
|
|
162
|
+
if (state.state && state.more) {
|
|
163
|
+
params.pageToken = state.state;
|
|
164
|
+
}
|
|
165
|
+
else if (state.state && !state.more) {
|
|
166
|
+
params.syncToken = state.state;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
params.timeMin = state.min?.toISOString();
|
|
170
|
+
}
|
|
171
|
+
const data = (await api.call("GET", `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`, params));
|
|
172
|
+
if (!data) {
|
|
173
|
+
// Requires full sync
|
|
174
|
+
const newState = {
|
|
175
|
+
calendarId,
|
|
176
|
+
min: state.min,
|
|
177
|
+
max: state.max,
|
|
178
|
+
sequence: (state.sequence || 1) + 1,
|
|
179
|
+
};
|
|
180
|
+
return syncGoogleCalendar(api, calendarId, newState);
|
|
181
|
+
}
|
|
182
|
+
const nextState = {
|
|
183
|
+
calendarId,
|
|
184
|
+
state: data.nextPageToken || data.nextSyncToken,
|
|
185
|
+
more: !!data.nextPageToken,
|
|
186
|
+
min: state.min,
|
|
187
|
+
max: state.max,
|
|
188
|
+
sequence: state.sequence,
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
events: data.items || [],
|
|
192
|
+
state: nextState,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=google-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-api.js","sourceRoot":"","sources":["../src/google-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type Activity, type ActivityLink, Tool, type ToolBuilder } from "@plotday/agent";
|
|
2
|
+
import { type Calendar, type CalendarAuth, type CalendarTool } from "@plotday/agent/common/calendar";
|
|
3
|
+
import { type Callback } from "@plotday/agent/tools/callbacks";
|
|
4
|
+
import { type Authorization, Integrations } from "@plotday/agent/tools/integrations";
|
|
5
|
+
import { Network, type WebhookRequest } from "@plotday/agent/tools/network";
|
|
6
|
+
/**
|
|
7
|
+
* Google Calendar integration tool.
|
|
8
|
+
*
|
|
9
|
+
* Provides seamless integration with Google Calendar, supporting event
|
|
10
|
+
* synchronization, real-time updates via webhooks, and comprehensive
|
|
11
|
+
* recurrence pattern handling.
|
|
12
|
+
*
|
|
13
|
+
* **Features:**
|
|
14
|
+
* - OAuth 2.0 authentication with Google
|
|
15
|
+
* - Real-time event synchronization
|
|
16
|
+
* - Webhook-based change notifications
|
|
17
|
+
* - Support for recurring events and exceptions
|
|
18
|
+
* - Batch processing for large calendars
|
|
19
|
+
* - Automatic retry on failures
|
|
20
|
+
*
|
|
21
|
+
* **Required OAuth Scopes:**
|
|
22
|
+
* - `https://www.googleapis.com/auth/calendar.calendarlist.readonly` - Read calendar list
|
|
23
|
+
* - `https://www.googleapis.com/auth/calendar.events` - Read/write calendar events
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* class EventsAgent extends Agent {
|
|
28
|
+
* private googleCalendar: GoogleCalendar;
|
|
29
|
+
*
|
|
30
|
+
* constructor(id: string, tools: Tools) {
|
|
31
|
+
* super();
|
|
32
|
+
* this.googleCalendar = tools.get(GoogleCalendar);
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* async activate() {
|
|
36
|
+
* const authLink = await this.googleCalendar.requestAuth("onGoogleAuth", {
|
|
37
|
+
* provider: "google"
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* await this.plot.createActivity({
|
|
41
|
+
* type: ActivityType.Task,
|
|
42
|
+
* title: "Connect Google Calendar",
|
|
43
|
+
* links: [authLink]
|
|
44
|
+
* });
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* async onGoogleAuth(auth: CalendarAuth, context: any) {
|
|
48
|
+
* const calendars = await this.googleCalendar.getCalendars(auth.authToken);
|
|
49
|
+
*
|
|
50
|
+
* // Start syncing primary calendar
|
|
51
|
+
* const primary = calendars.find(c => c.primary);
|
|
52
|
+
* if (primary) {
|
|
53
|
+
* await this.googleCalendar.startSync(
|
|
54
|
+
* auth.authToken,
|
|
55
|
+
* primary.id,
|
|
56
|
+
* "onCalendarEvent",
|
|
57
|
+
* {
|
|
58
|
+
* options: {
|
|
59
|
+
* timeMin: new Date(), // Only sync future events
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* );
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* async onCalendarEvent(activity: Activity, context: any) {
|
|
67
|
+
* // Process Google Calendar events
|
|
68
|
+
* await this.plot.createActivity(activity);
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare class GoogleCalendar extends Tool<GoogleCalendar> implements CalendarTool {
|
|
74
|
+
build(build: ToolBuilder): {
|
|
75
|
+
integrations: Promise<Integrations>;
|
|
76
|
+
network: Promise<Network>;
|
|
77
|
+
};
|
|
78
|
+
requestAuth<TCallback extends (auth: CalendarAuth, ...args: any[]) => any>(callback: TCallback, ...extraArgs: any[]): Promise<ActivityLink>;
|
|
79
|
+
private getApi;
|
|
80
|
+
getCalendars(authToken: string): Promise<Calendar[]>;
|
|
81
|
+
startSync<TCallback extends (activity: Activity, ...args: any[]) => any>(authToken: string, calendarId: string, callback: TCallback, ...extraArgs: any[]): Promise<void>;
|
|
82
|
+
stopSync(_authToken: string, calendarId: string): Promise<void>;
|
|
83
|
+
private setupCalendarWatch;
|
|
84
|
+
syncBatch(_args: any, batchNumber: number, mode: "full" | "incremental", authToken: string, calendarId: string): Promise<void>;
|
|
85
|
+
private processCalendarEvents;
|
|
86
|
+
private processEventException;
|
|
87
|
+
onCalendarWebhook(request: WebhookRequest, calendarId: string, authToken: string): Promise<void>;
|
|
88
|
+
private startIncrementalSync;
|
|
89
|
+
onAuthSuccess(authResult: Authorization, authToken: string, callback: Callback): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
export default GoogleCalendar;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { Tool, } from "@plotday/agent";
|
|
2
|
+
import { AuthLevel, AuthProvider, Integrations, } from "@plotday/agent/tools/integrations";
|
|
3
|
+
import { Network } from "@plotday/agent/tools/network";
|
|
4
|
+
import { GoogleApi, syncGoogleCalendar, transformGoogleEvent, } from "./google-api";
|
|
5
|
+
/**
|
|
6
|
+
* Google Calendar integration tool.
|
|
7
|
+
*
|
|
8
|
+
* Provides seamless integration with Google Calendar, supporting event
|
|
9
|
+
* synchronization, real-time updates via webhooks, and comprehensive
|
|
10
|
+
* recurrence pattern handling.
|
|
11
|
+
*
|
|
12
|
+
* **Features:**
|
|
13
|
+
* - OAuth 2.0 authentication with Google
|
|
14
|
+
* - Real-time event synchronization
|
|
15
|
+
* - Webhook-based change notifications
|
|
16
|
+
* - Support for recurring events and exceptions
|
|
17
|
+
* - Batch processing for large calendars
|
|
18
|
+
* - Automatic retry on failures
|
|
19
|
+
*
|
|
20
|
+
* **Required OAuth Scopes:**
|
|
21
|
+
* - `https://www.googleapis.com/auth/calendar.calendarlist.readonly` - Read calendar list
|
|
22
|
+
* - `https://www.googleapis.com/auth/calendar.events` - Read/write calendar events
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* class EventsAgent extends Agent {
|
|
27
|
+
* private googleCalendar: GoogleCalendar;
|
|
28
|
+
*
|
|
29
|
+
* constructor(id: string, tools: Tools) {
|
|
30
|
+
* super();
|
|
31
|
+
* this.googleCalendar = tools.get(GoogleCalendar);
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* async activate() {
|
|
35
|
+
* const authLink = await this.googleCalendar.requestAuth("onGoogleAuth", {
|
|
36
|
+
* provider: "google"
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* await this.plot.createActivity({
|
|
40
|
+
* type: ActivityType.Task,
|
|
41
|
+
* title: "Connect Google Calendar",
|
|
42
|
+
* links: [authLink]
|
|
43
|
+
* });
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* async onGoogleAuth(auth: CalendarAuth, context: any) {
|
|
47
|
+
* const calendars = await this.googleCalendar.getCalendars(auth.authToken);
|
|
48
|
+
*
|
|
49
|
+
* // Start syncing primary calendar
|
|
50
|
+
* const primary = calendars.find(c => c.primary);
|
|
51
|
+
* if (primary) {
|
|
52
|
+
* await this.googleCalendar.startSync(
|
|
53
|
+
* auth.authToken,
|
|
54
|
+
* primary.id,
|
|
55
|
+
* "onCalendarEvent",
|
|
56
|
+
* {
|
|
57
|
+
* options: {
|
|
58
|
+
* timeMin: new Date(), // Only sync future events
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
* );
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* async onCalendarEvent(activity: Activity, context: any) {
|
|
66
|
+
* // Process Google Calendar events
|
|
67
|
+
* await this.plot.createActivity(activity);
|
|
68
|
+
* }
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export class GoogleCalendar extends Tool {
|
|
73
|
+
build(build) {
|
|
74
|
+
return {
|
|
75
|
+
integrations: build(Integrations),
|
|
76
|
+
network: build(Network, {
|
|
77
|
+
urls: ["https://www.googleapis.com/calendar/*"],
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async requestAuth(callback, ...extraArgs) {
|
|
82
|
+
console.log("Requesting Google Calendar auth");
|
|
83
|
+
const calendarScopes = [
|
|
84
|
+
"https://www.googleapis.com/auth/calendar.calendarlist.readonly",
|
|
85
|
+
"https://www.googleapis.com/auth/calendar.events",
|
|
86
|
+
];
|
|
87
|
+
// Generate opaque token for authorization
|
|
88
|
+
const authToken = crypto.randomUUID();
|
|
89
|
+
const callbackToken = await this.tools.callbacks.createFromParent(callback, ...extraArgs);
|
|
90
|
+
// Request auth and return the activity link
|
|
91
|
+
return await this.tools.integrations.request({
|
|
92
|
+
provider: AuthProvider.Google,
|
|
93
|
+
level: AuthLevel.User,
|
|
94
|
+
scopes: calendarScopes,
|
|
95
|
+
}, this.onAuthSuccess, authToken, callbackToken);
|
|
96
|
+
}
|
|
97
|
+
async getApi(authToken) {
|
|
98
|
+
const authorization = await this.get(`authorization:${authToken}`);
|
|
99
|
+
if (!authorization) {
|
|
100
|
+
throw new Error("Authorization no longer available");
|
|
101
|
+
}
|
|
102
|
+
const token = await this.tools.integrations.get(authorization);
|
|
103
|
+
if (!token) {
|
|
104
|
+
throw new Error("Authorization no longer available");
|
|
105
|
+
}
|
|
106
|
+
return new GoogleApi(token.token);
|
|
107
|
+
}
|
|
108
|
+
async getCalendars(authToken) {
|
|
109
|
+
console.log("Fetching Google Calendar list");
|
|
110
|
+
const api = await this.getApi(authToken);
|
|
111
|
+
const data = (await api.call("GET", "https://www.googleapis.com/calendar/v3/users/me/calendarList"));
|
|
112
|
+
console.log("Got Google Calendar list", data.items);
|
|
113
|
+
return data.items.map((item) => ({
|
|
114
|
+
id: item.id,
|
|
115
|
+
name: item.summary,
|
|
116
|
+
description: item.description || null,
|
|
117
|
+
primary: item.primary || false,
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
async startSync(authToken, calendarId, callback, ...extraArgs) {
|
|
121
|
+
console.log("Saving callback");
|
|
122
|
+
// Create callback token for parent
|
|
123
|
+
const callbackToken = await this.tools.callbacks.createFromParent(callback, ...extraArgs);
|
|
124
|
+
await this.set("event_callback_token", callbackToken);
|
|
125
|
+
console.log("Setting up watch");
|
|
126
|
+
// Setup webhook for this calendar
|
|
127
|
+
await this.setupCalendarWatch(authToken, calendarId, authToken);
|
|
128
|
+
// Start initial sync
|
|
129
|
+
const now = new Date();
|
|
130
|
+
const min = new Date(now.getFullYear() - 2, 0, 1);
|
|
131
|
+
const max = new Date(now.getFullYear() + 1, 11, 31);
|
|
132
|
+
const initialState = {
|
|
133
|
+
calendarId,
|
|
134
|
+
min,
|
|
135
|
+
max,
|
|
136
|
+
sequence: 1,
|
|
137
|
+
};
|
|
138
|
+
await this.set(`sync_state_${calendarId}`, initialState);
|
|
139
|
+
console.log("Starting sync");
|
|
140
|
+
// Start sync batch using run tool for long-running operation
|
|
141
|
+
const syncCallback = await this.callback(this.syncBatch, 1, "full", authToken, calendarId);
|
|
142
|
+
await this.run(syncCallback);
|
|
143
|
+
}
|
|
144
|
+
async stopSync(_authToken, calendarId) {
|
|
145
|
+
// Stop webhook
|
|
146
|
+
const watchData = await this.get(`calendar_watch_${calendarId}`);
|
|
147
|
+
if (watchData) {
|
|
148
|
+
// Cancel the watch (would need Google API call)
|
|
149
|
+
await this.clear(`calendar_watch_${calendarId}`);
|
|
150
|
+
}
|
|
151
|
+
// Clear sync state
|
|
152
|
+
await this.clear(`sync_state_${calendarId}`);
|
|
153
|
+
}
|
|
154
|
+
async setupCalendarWatch(authToken, calendarId, opaqueAuthToken) {
|
|
155
|
+
const webhookUrl = await this.tools.network.createWebhook(this.onCalendarWebhook, calendarId, opaqueAuthToken);
|
|
156
|
+
// Check if webhook URL is localhost
|
|
157
|
+
if (URL.parse(webhookUrl)?.hostname === "localhost") {
|
|
158
|
+
console.log("Skipping webhook setup for localhost URL");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const api = await this.getApi(authToken);
|
|
162
|
+
// Setup watch for calendar
|
|
163
|
+
const watchId = crypto.randomUUID();
|
|
164
|
+
const secret = crypto.randomUUID();
|
|
165
|
+
const watchData = (await api.call("POST", `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/watch`, undefined, {
|
|
166
|
+
id: watchId,
|
|
167
|
+
type: "web_hook",
|
|
168
|
+
address: webhookUrl,
|
|
169
|
+
token: new URLSearchParams({ secret }).toString(),
|
|
170
|
+
}));
|
|
171
|
+
await this.set(`calendar_watch_${calendarId}`, {
|
|
172
|
+
watchId,
|
|
173
|
+
secret,
|
|
174
|
+
calendarId,
|
|
175
|
+
expiry: new Date(parseInt(watchData.expiration)),
|
|
176
|
+
});
|
|
177
|
+
console.log("Calendar watch setup complete", { watchId, calendarId });
|
|
178
|
+
}
|
|
179
|
+
async syncBatch(_args, batchNumber, mode, authToken, calendarId) {
|
|
180
|
+
console.log(`Starting Google Calendar sync batch ${batchNumber} (${mode}) for calendar ${calendarId}`);
|
|
181
|
+
try {
|
|
182
|
+
const state = await this.get(`sync_state_${calendarId}`);
|
|
183
|
+
if (!state) {
|
|
184
|
+
throw new Error("No sync state found");
|
|
185
|
+
}
|
|
186
|
+
// Convert date strings back to Date objects after deserialization
|
|
187
|
+
if (state.min && typeof state.min === "string") {
|
|
188
|
+
state.min = new Date(state.min);
|
|
189
|
+
}
|
|
190
|
+
if (state.max && typeof state.max === "string") {
|
|
191
|
+
state.max = new Date(state.max);
|
|
192
|
+
}
|
|
193
|
+
const api = await this.getApi(authToken);
|
|
194
|
+
const result = await syncGoogleCalendar(api, calendarId, state);
|
|
195
|
+
if (result.events.length > 0) {
|
|
196
|
+
await this.processCalendarEvents(result.events, calendarId);
|
|
197
|
+
console.log(`Synced ${result.events.length} events in batch ${batchNumber} for calendar ${calendarId}`);
|
|
198
|
+
}
|
|
199
|
+
await this.set(`sync_state_${calendarId}`, result.state);
|
|
200
|
+
if (result.state.more) {
|
|
201
|
+
const syncCallback = await this.callback(this.syncBatch, batchNumber + 1, mode, authToken, calendarId);
|
|
202
|
+
await this.run(syncCallback);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.log(`Google Calendar ${mode} sync completed after ${batchNumber} batches for calendar ${calendarId}`);
|
|
206
|
+
if (mode === "full") {
|
|
207
|
+
await this.clear(`sync_state_${calendarId}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
console.error(`Error in sync batch ${batchNumber} for calendar ${calendarId}:`, error);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async processCalendarEvents(events, calendarId) {
|
|
217
|
+
for (const event of events) {
|
|
218
|
+
try {
|
|
219
|
+
if (event.status === "cancelled") {
|
|
220
|
+
// TODO: Handle event cancellation
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// Check if this is a recurring event instance (exception)
|
|
224
|
+
if (event.recurringEventId && event.originalStartTime) {
|
|
225
|
+
await this.processEventException(event, calendarId);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// Regular or master recurring event
|
|
229
|
+
const activityData = transformGoogleEvent(event, calendarId);
|
|
230
|
+
// Convert to full Activity and call callback
|
|
231
|
+
const callbackToken = await this.get("event_callback_token");
|
|
232
|
+
if (callbackToken && activityData.type) {
|
|
233
|
+
const activity = {
|
|
234
|
+
type: activityData.type,
|
|
235
|
+
start: activityData.start || null,
|
|
236
|
+
end: activityData.end || null,
|
|
237
|
+
recurrenceUntil: activityData.recurrenceUntil || null,
|
|
238
|
+
recurrenceCount: activityData.recurrenceCount || null,
|
|
239
|
+
doneAt: null,
|
|
240
|
+
note: activityData.note || null,
|
|
241
|
+
title: activityData.title || null,
|
|
242
|
+
parent: null,
|
|
243
|
+
links: null,
|
|
244
|
+
recurrenceRule: activityData.recurrenceRule || null,
|
|
245
|
+
recurrenceExdates: activityData.recurrenceExdates || null,
|
|
246
|
+
recurrenceDates: activityData.recurrenceDates || null,
|
|
247
|
+
recurrence: null,
|
|
248
|
+
occurrence: null,
|
|
249
|
+
meta: activityData.meta ?? null,
|
|
250
|
+
};
|
|
251
|
+
await this.run(callbackToken, activity);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.error(`Failed to process event ${event.id}:`, error);
|
|
257
|
+
// Continue processing other events
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async processEventException(event, calendarId) {
|
|
262
|
+
// Similar to processCalendarEvents but for exceptions
|
|
263
|
+
// This would find the master recurring activity and create an exception
|
|
264
|
+
const originalStartTime = event.originalStartTime?.dateTime || event.originalStartTime?.date;
|
|
265
|
+
if (!originalStartTime) {
|
|
266
|
+
console.warn(`No original start time for exception: ${event.id}`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const activityData = transformGoogleEvent(event, calendarId);
|
|
270
|
+
const callbackToken = await this.get("event_callback_token");
|
|
271
|
+
if (callbackToken && activityData.type) {
|
|
272
|
+
const activity = {
|
|
273
|
+
type: activityData.type,
|
|
274
|
+
start: activityData.start || null,
|
|
275
|
+
end: activityData.end || null,
|
|
276
|
+
recurrenceUntil: activityData.recurrenceUntil || null,
|
|
277
|
+
recurrenceCount: activityData.recurrenceCount || null,
|
|
278
|
+
doneAt: null,
|
|
279
|
+
note: activityData.note || null,
|
|
280
|
+
title: activityData.title || null,
|
|
281
|
+
parent: null,
|
|
282
|
+
links: null,
|
|
283
|
+
recurrenceRule: null,
|
|
284
|
+
recurrenceExdates: null,
|
|
285
|
+
recurrenceDates: null,
|
|
286
|
+
recurrence: null, // Would need to find master activity
|
|
287
|
+
occurrence: new Date(originalStartTime),
|
|
288
|
+
meta: activityData.meta ?? null,
|
|
289
|
+
};
|
|
290
|
+
await this.run(callbackToken, activity);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async onCalendarWebhook(request, calendarId, authToken) {
|
|
294
|
+
console.log("Received calendar webhook notification", {
|
|
295
|
+
headers: request.headers,
|
|
296
|
+
params: request.params,
|
|
297
|
+
calendarId,
|
|
298
|
+
});
|
|
299
|
+
// Validate webhook authenticity
|
|
300
|
+
const channelId = request.headers["X-Goog-Channel-ID"];
|
|
301
|
+
const channelToken = request.headers["X-Goog-Channel-Token"];
|
|
302
|
+
if (!channelId || !channelToken) {
|
|
303
|
+
throw new Error("Invalid webhook headers");
|
|
304
|
+
}
|
|
305
|
+
const watchData = await this.get(`calendar_watch_${calendarId}`);
|
|
306
|
+
if (!watchData || watchData.watchId !== channelId) {
|
|
307
|
+
console.warn("Unknown or expired webhook notification");
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const params = new URLSearchParams(channelToken);
|
|
311
|
+
const secret = params.get("secret");
|
|
312
|
+
if (!watchData || watchData.secret !== secret) {
|
|
313
|
+
console.warn("Invalid webhook secret");
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
// Trigger incremental sync
|
|
317
|
+
await this.startIncrementalSync(calendarId, authToken);
|
|
318
|
+
}
|
|
319
|
+
async startIncrementalSync(calendarId, authToken) {
|
|
320
|
+
const watchData = await this.get(`calendar_watch_${calendarId}`);
|
|
321
|
+
if (!watchData) {
|
|
322
|
+
console.error("No calendar watch data found");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const incrementalState = {
|
|
326
|
+
calendarId: watchData.calendarId,
|
|
327
|
+
state: (await this.get(`last_sync_token_${calendarId}`)) || undefined,
|
|
328
|
+
};
|
|
329
|
+
await this.set(`sync_state_${calendarId}`, incrementalState);
|
|
330
|
+
const syncCallback = await this.callback(this.syncBatch, 1, "incremental", authToken, calendarId);
|
|
331
|
+
await this.run(syncCallback);
|
|
332
|
+
}
|
|
333
|
+
async onAuthSuccess(authResult, authToken, callback) {
|
|
334
|
+
// Store the actual auth token using opaque token as key
|
|
335
|
+
await this.set(`authorization:${authToken}`, authResult);
|
|
336
|
+
const authSuccessResult = {
|
|
337
|
+
authToken,
|
|
338
|
+
};
|
|
339
|
+
await this.run(callback, authSuccessResult);
|
|
340
|
+
// Clean up the callback token
|
|
341
|
+
await this.clear(`auth_callback_token:${authToken}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
export default GoogleCalendar;
|
|
345
|
+
//# sourceMappingURL=google-calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-calendar.js","sourceRoot":"","sources":["../src/google-calendar.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, GoogleCalendar } from "./google-calendar";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Sync with Google Calendar",
|
|
5
5
|
"author": "Plot <team@plot.day> (https://plot.day)",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"version": "0.2.
|
|
7
|
+
"version": "0.2.3",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"LICENSE"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@plotday/agent": "^0.
|
|
23
|
+
"@plotday/agent": "^0.19.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"typescript": "^5.9.3"
|