@kubun/connector-google-calendar 0.8.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/LICENSE.md ADDED
@@ -0,0 +1,57 @@
1
+ # The Prosperity Public License 3.0.0
2
+
3
+ Contributor: Paul Le Cam
4
+
5
+ Source Code: https://github.com/PaulLeCam/kubun
6
+
7
+ ## Purpose
8
+
9
+ This license allows you to use and share this software for noncommercial purposes for free and to try this software for commercial purposes for thirty days.
10
+
11
+ ## Agreement
12
+
13
+ In order to receive this license, you have to agree to its rules. Those rules are both obligations under that agreement and conditions to your license. Don't do anything with this software that triggers a rule you can't or won't follow.
14
+
15
+ ## Notices
16
+
17
+ Make sure everyone who gets a copy of any part of this software from you, with or without changes, also gets the text of this license and the contributor and source code lines above.
18
+
19
+ ## Commercial Trial
20
+
21
+ Limit your use of this software for commercial purposes to a thirty-day trial period. If you use this software for work, your company gets one trial period for all personnel, not one trial per person.
22
+
23
+ ## Contributions Back
24
+
25
+ Developing feedback, changes, or additions that you contribute back to the contributor on the terms of a standardized public software license such as [the Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0), [the Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), [the MIT license](https://spdx.org/licenses/MIT.html), or [the two-clause BSD license](https://spdx.org/licenses/BSD-2-Clause.html) doesn't count as use for a commercial purpose.
26
+
27
+ ## Personal Uses
28
+
29
+ Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, doesn't count as use for a commercial purpose.
30
+
31
+ ## Noncommercial Organizations
32
+
33
+ Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution doesn't count as use for a commercial purpose regardless of the source of funding or obligations resulting from the funding.
34
+
35
+ ## Defense
36
+
37
+ Don't make any legal claim against anyone accusing this software, with or without changes, alone or with other technology, of infringing any patent.
38
+
39
+ ## Copyright
40
+
41
+ The contributor licenses you to do everything with this software that would otherwise infringe their copyright in it.
42
+
43
+ ## Patent
44
+
45
+ The contributor licenses you to do everything with this software that would otherwise infringe any patents they can license or become able to license.
46
+
47
+ ## Reliability
48
+
49
+ The contributor can't revoke this license.
50
+
51
+ ## Excuse
52
+
53
+ You're excused for unknowingly breaking [Notices](#notices) if you take all practical steps to comply within thirty days of learning you broke the rule.
54
+
55
+ ## No Liability
56
+
57
+ ***As far as the law allows, this software comes as is, without any warranty or condition, and the contributor won't be liable to anyone for any damages related to this software or this license, under any kind of legal claim.***
@@ -0,0 +1,9 @@
1
+ import type { ActionHandler } from '@kubun/connector';
2
+ export type GoogleCalendarActionHandlerConfig = {
3
+ credential: {
4
+ accessToken: string;
5
+ scopes: Array<string>;
6
+ };
7
+ fetch?: typeof globalThis.fetch;
8
+ };
9
+ export declare function createGoogleCalendarActionHandler(config: GoogleCalendarActionHandlerConfig): ActionHandler;
package/lib/actions.js ADDED
@@ -0,0 +1 @@
1
+ import{createEvent as e,updateEvent as r}from"./api.js";export function createGoogleCalendarActionHandler(a){return{async create(r,n){let c=n.calendarID;if(null==c)throw Error("calendarID is required for creating calendar events");return e({accessToken:a.credential.accessToken,calendarID:c,params:n,fetch:a.fetch})},async update(e,n,c){let t=c.calendarID;if(null==t)throw Error("calendarID is required for updating calendar events");return r({accessToken:a.credential.accessToken,calendarID:t,eventID:n,params:c,fetch:a.fetch})}}}
package/lib/api.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ import type { EntityRecord } from '@kubun/connector';
2
+ export type GoogleCalendarResource = {
3
+ id: string;
4
+ summary: string;
5
+ description?: string;
6
+ timeZone?: string;
7
+ primary?: boolean;
8
+ backgroundColor?: string;
9
+ selected?: boolean;
10
+ accessRole?: string;
11
+ deleted?: boolean;
12
+ };
13
+ export type GoogleCalendarListResponse = {
14
+ items?: Array<GoogleCalendarResource>;
15
+ nextPageToken?: string;
16
+ nextSyncToken?: string;
17
+ };
18
+ export type GoogleEventDateTime = {
19
+ dateTime?: string;
20
+ date?: string;
21
+ timeZone?: string;
22
+ };
23
+ export type GoogleEventResource = {
24
+ id: string;
25
+ summary?: string;
26
+ description?: string;
27
+ location?: string;
28
+ start: GoogleEventDateTime;
29
+ end: GoogleEventDateTime;
30
+ status: 'confirmed' | 'tentative' | 'cancelled';
31
+ htmlLink?: string;
32
+ recurringEventID?: string;
33
+ };
34
+ export type GoogleEventsListResponse = {
35
+ items?: Array<GoogleEventResource>;
36
+ nextPageToken?: string;
37
+ nextSyncToken?: string;
38
+ };
39
+ export declare function buildCalendarListURL(params: {
40
+ syncToken?: string;
41
+ pageToken?: string;
42
+ }): string;
43
+ export declare function buildEventsListURL(params: {
44
+ calendarID: string;
45
+ syncToken?: string;
46
+ pageToken?: string;
47
+ timeMin?: string;
48
+ }): string;
49
+ export declare function mapCalendarToEntity(calendar: GoogleCalendarResource): EntityRecord;
50
+ export declare function mapEventToEntity(event: GoogleEventResource, calendarID: string): EntityRecord;
51
+ export declare function buildEventFromParams(params: Record<string, unknown>): Record<string, unknown>;
52
+ export declare function createEvent(config: {
53
+ accessToken: string;
54
+ calendarID: string;
55
+ params: Record<string, unknown>;
56
+ fetch?: typeof globalThis.fetch;
57
+ }): Promise<EntityRecord>;
58
+ export declare function updateEvent(config: {
59
+ accessToken: string;
60
+ calendarID: string;
61
+ eventID: string;
62
+ params: Record<string, unknown>;
63
+ fetch?: typeof globalThis.fetch;
64
+ }): Promise<EntityRecord>;
package/lib/api.js ADDED
@@ -0,0 +1 @@
1
+ let e="https://www.googleapis.com/calendar/v3";async function t(e){try{let t=await e.json();return t.error?.message??`${e.status} ${e.statusText}`}catch{return`${e.status} ${e.statusText}`}}export function buildCalendarListURL(t){let n=new URL(`${e}/users/me/calendarList`);return n.searchParams.set("showHidden","false"),null!=t.syncToken&&n.searchParams.set("syncToken",t.syncToken),null!=t.pageToken&&n.searchParams.set("pageToken",t.pageToken),n.toString()}export function buildEventsListURL(t){let n=new URL(`${e}/calendars/${encodeURIComponent(t.calendarID)}/events`);return n.searchParams.set("singleEvents","true"),null!=t.syncToken?n.searchParams.set("syncToken",t.syncToken):null!=t.timeMin&&n.searchParams.set("timeMin",t.timeMin),null!=t.pageToken&&n.searchParams.set("pageToken",t.pageToken),n.toString()}export function mapCalendarToEntity(e){return{sourceService:"google-calendar",sourceID:e.id,sourceURL:"https://calendar.google.com",summary:e.summary,description:e.description,timeZone:e.timeZone,primary:e.primary??!1,backgroundColor:e.backgroundColor}}export function mapEventToEntity(e,t){let n=null!=e.start.date,a=n?e.start.date:e.start.dateTime,r=n?e.end.date:e.end.dateTime;return{sourceService:"google-calendar",sourceID:e.id,sourceURL:e.htmlLink,title:e.summary??"(No title)",description:e.description,location:e.location,allDay:n,startAt:a,endAt:r,status:e.status.toUpperCase(),htmlLink:e.htmlLink,recurringEventID:e.recurringEventID,timeZone:e.start.timeZone,calendarID:t,calendar:{sourceService:"google-calendar",sourceID:t}}}export function buildEventFromParams(e){let t={},n=!0===e.allDay;return null!=e.title&&(t.summary=e.title),null!=e.description&&(t.description=e.description),null!=e.location&&(t.location=e.location),null!=e.startAt&&(t.start=n?{date:e.startAt}:{dateTime:e.startAt,...null!=e.timeZone?{timeZone:e.timeZone}:{}}),null!=e.endAt&&(t.end=n?{date:e.endAt}:{dateTime:e.endAt,...null!=e.timeZone?{timeZone:e.timeZone}:{}}),t}export async function createEvent(n){let a=n.fetch??globalThis.fetch,r=buildEventFromParams(n.params),o=`${e}/calendars/${encodeURIComponent(n.calendarID)}/events`,s=await a(o,{method:"POST",headers:{Authorization:`Bearer ${n.accessToken}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!s.ok){let e=await t(s);throw Error(`Google Calendar API error: ${e}`)}return mapEventToEntity(await s.json(),n.calendarID)}export async function updateEvent(n){let a=n.fetch??globalThis.fetch,r=buildEventFromParams(n.params),o=`${e}/calendars/${encodeURIComponent(n.calendarID)}/events/${encodeURIComponent(n.eventID)}`,s=await a(o,{method:"PATCH",headers:{Authorization:`Bearer ${n.accessToken}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!s.ok){let e=await t(s);throw Error(`Google Calendar API error: ${e}`)}return mapEventToEntity(await s.json(),n.calendarID)}
@@ -0,0 +1,5 @@
1
+ import type { ConnectorDefinition } from '@kubun/connector';
2
+ export type CreateGoogleCalendarConnectorOptions = {
3
+ fetch?: typeof globalThis.fetch;
4
+ };
5
+ export declare function createGoogleCalendarConnector(options?: CreateGoogleCalendarConnectorOptions): ConnectorDefinition;
@@ -0,0 +1 @@
1
+ import{createGoogleCalendarActionHandler as e}from"./actions.js";import{googleCalendarClusters as t}from"./model.js";import{createGoogleCalendarProvider as r}from"./provider.js";export function createGoogleCalendarConnector(n){return{name:"google-calendar",version:"1.0.0",clusters:t,syncStrategies:["on-demand"],actions:[{name:"create",description:"Create a Google Calendar event",input:{type:"object",properties:{calendarID:{type:"string"},title:{type:"string"},startAt:{type:"string"},endAt:{type:"string"},allDay:{type:"boolean"},description:{type:"string"},location:{type:"string"},timeZone:{type:"string"}}},requiresCredential:!0},{name:"update",description:"Update a Google Calendar event",input:{type:"object",properties:{calendarID:{type:"string"},title:{type:"string"},startAt:{type:"string"},endAt:{type:"string"},allDay:{type:"boolean"},description:{type:"string"},location:{type:"string"},timeZone:{type:"string"}}},requiresCredential:!0}],actionHandler:t=>e({credential:t.credential,fetch:n?.fetch}),auth:{provider:"google",scopes:["https://www.googleapis.com/auth/calendar.readonly"],writeScopes:["https://www.googleapis.com/auth/calendar"]},serverProvider:e=>r({credential:e.credential,boundary:e.boundary,fetch:n?.fetch})}}
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { createGoogleCalendarActionHandler, type GoogleCalendarActionHandlerConfig, } from './actions.js';
2
+ export { buildCalendarListURL, buildEventFromParams, buildEventsListURL, createEvent, type GoogleCalendarListResponse, type GoogleCalendarResource, type GoogleEventDateTime, type GoogleEventResource, type GoogleEventsListResponse, mapCalendarToEntity, mapEventToEntity, updateEvent, } from './api.js';
3
+ export { type CreateGoogleCalendarConnectorOptions, createGoogleCalendarConnector, } from './connector.js';
4
+ export { googleCalendarClusters, googleCalendarDefinition, googleCalendarEventDefinition, } from './model.js';
5
+ export { type CalendarCheckpoint, createGoogleCalendarProvider, type GoogleCalendarProviderConfig, } from './provider.js';
package/lib/index.js ADDED
@@ -0,0 +1 @@
1
+ export{createGoogleCalendarActionHandler}from"./actions.js";export{buildCalendarListURL,buildEventFromParams,buildEventsListURL,createEvent,mapCalendarToEntity,mapEventToEntity,updateEvent}from"./api.js";export{createGoogleCalendarConnector}from"./connector.js";export{googleCalendarClusters,googleCalendarDefinition,googleCalendarEventDefinition}from"./model.js";export{createGoogleCalendarProvider}from"./provider.js";
package/lib/model.d.ts ADDED
@@ -0,0 +1,150 @@
1
+ export declare const googleCalendarDefinition: {
2
+ readonly name: "GoogleCalendar";
3
+ readonly behavior: "default";
4
+ readonly interfaces: [string];
5
+ readonly schema: {
6
+ readonly type: "object";
7
+ readonly properties: {
8
+ readonly summary: {
9
+ readonly type: "string";
10
+ };
11
+ readonly description: {
12
+ readonly type: "string";
13
+ };
14
+ readonly timeZone: {
15
+ readonly $ref: "#/definitions/TimeZone";
16
+ };
17
+ readonly primary: {
18
+ readonly type: "boolean";
19
+ };
20
+ readonly backgroundColor: {
21
+ readonly type: "string";
22
+ };
23
+ readonly sourceService: {
24
+ readonly $ref: "#/definitions/SourceService";
25
+ };
26
+ readonly sourceID: {
27
+ readonly $ref: "#/definitions/SourceID";
28
+ };
29
+ readonly sourceURL: {
30
+ readonly $ref: "#/definitions/SourceURL";
31
+ };
32
+ readonly lastSyncedAt: {
33
+ readonly $ref: "#/definitions/DateTime";
34
+ };
35
+ };
36
+ readonly required: ["summary", "sourceService", "sourceID", "lastSyncedAt"];
37
+ readonly additionalProperties: false;
38
+ readonly definitions: {
39
+ readonly SourceService: {
40
+ readonly type: "string";
41
+ readonly title: "SourceService";
42
+ readonly minLength: 1;
43
+ readonly maxLength: 50;
44
+ };
45
+ readonly SourceID: {
46
+ readonly type: "string";
47
+ readonly title: "SourceID";
48
+ readonly minLength: 1;
49
+ readonly maxLength: 500;
50
+ };
51
+ readonly SourceURL: import("json-schema-typed").JSONSchema.String;
52
+ readonly DateTime: import("json-schema-typed").JSONSchema.String;
53
+ readonly TimeZone: import("json-schema-typed").JSONSchema.String;
54
+ };
55
+ };
56
+ readonly fieldsMeta: {};
57
+ };
58
+ export declare const googleCalendarEventDefinition: {
59
+ readonly name: "GoogleCalendarEvent";
60
+ readonly behavior: "default";
61
+ readonly interfaces: [string, string];
62
+ readonly schema: {
63
+ readonly type: "object";
64
+ readonly properties: {
65
+ readonly title: {
66
+ readonly type: "string";
67
+ readonly minLength: 1;
68
+ readonly maxLength: 200;
69
+ };
70
+ readonly startAt: {
71
+ readonly $ref: "#/definitions/DateTime";
72
+ };
73
+ readonly endAt: {
74
+ readonly $ref: "#/definitions/DateTime";
75
+ };
76
+ readonly allDay: {
77
+ readonly type: "boolean";
78
+ };
79
+ readonly timeZone: {
80
+ readonly $ref: "#/definitions/TimeZone";
81
+ };
82
+ readonly description: {
83
+ readonly type: "string";
84
+ };
85
+ readonly location: {
86
+ readonly type: "string";
87
+ };
88
+ readonly status: {
89
+ readonly $ref: "#/definitions/EventStatus";
90
+ };
91
+ readonly htmlLink: {
92
+ readonly $ref: "#/definitions/HtmlLink";
93
+ };
94
+ readonly recurringEventID: {
95
+ readonly type: "string";
96
+ };
97
+ readonly calendarID: {
98
+ readonly type: "string";
99
+ };
100
+ readonly calendar: {
101
+ readonly $ref: "#/definitions/CalendarDocID";
102
+ };
103
+ readonly sourceService: {
104
+ readonly $ref: "#/definitions/SourceService";
105
+ };
106
+ readonly sourceID: {
107
+ readonly $ref: "#/definitions/SourceID";
108
+ };
109
+ readonly sourceURL: {
110
+ readonly $ref: "#/definitions/SourceURL";
111
+ };
112
+ readonly lastSyncedAt: {
113
+ readonly $ref: "#/definitions/DateTime";
114
+ };
115
+ };
116
+ readonly required: ["title", "startAt", "allDay", "calendarID", "calendar", "sourceService", "sourceID", "lastSyncedAt"];
117
+ readonly additionalProperties: false;
118
+ readonly definitions: {
119
+ readonly SourceService: {
120
+ readonly type: "string";
121
+ readonly title: "SourceService";
122
+ readonly minLength: 1;
123
+ readonly maxLength: 50;
124
+ };
125
+ readonly SourceID: {
126
+ readonly type: "string";
127
+ readonly title: "SourceID";
128
+ readonly minLength: 1;
129
+ readonly maxLength: 500;
130
+ };
131
+ readonly SourceURL: import("json-schema-typed").JSONSchema.String;
132
+ readonly DateTime: import("json-schema-typed").JSONSchema.String;
133
+ readonly TimeZone: import("json-schema-typed").JSONSchema.String;
134
+ readonly HtmlLink: import("json-schema-typed").JSONSchema.String;
135
+ readonly CalendarDocID: import("json-schema-typed").JSONSchema.String;
136
+ readonly EventStatus: {
137
+ readonly type: "string";
138
+ readonly title: "EventStatus";
139
+ readonly enum: ["CONFIRMED", "TENTATIVE", "CANCELLED"];
140
+ };
141
+ };
142
+ };
143
+ readonly fieldsMeta: {
144
+ readonly calendar: {
145
+ readonly type: "document";
146
+ readonly model: "#0";
147
+ };
148
+ };
149
+ };
150
+ export declare const googleCalendarClusters: import("@kubun/protocol").ClustersRecord;
package/lib/model.js ADDED
@@ -0,0 +1 @@
1
+ import{connectorClusters as e,connectorModelIDs as t}from"@kubun/connector";import{modelIDs as i,modelsClusters as n}from"@kubun/models";import{GraphBuilder as r}from"@kubun/protocol";import{dateTimeSchema as o,docIDSchema as a,timeZoneSchema as s,urlSchema as c}from"@kubun/scalars";export const googleCalendarDefinition={name:"GoogleCalendar",behavior:"default",interfaces:[t.ExternalEntity],schema:{type:"object",properties:{summary:{type:"string"},description:{type:"string"},timeZone:{$ref:"#/definitions/TimeZone"},primary:{type:"boolean"},backgroundColor:{type:"string"},sourceService:{$ref:"#/definitions/SourceService"},sourceID:{$ref:"#/definitions/SourceID"},sourceURL:{$ref:"#/definitions/SourceURL"},lastSyncedAt:{$ref:"#/definitions/DateTime"}},required:["summary","sourceService","sourceID","lastSyncedAt"],additionalProperties:!1,definitions:{SourceService:{type:"string",title:"SourceService",minLength:1,maxLength:50},SourceID:{type:"string",title:"SourceID",minLength:1,maxLength:500},SourceURL:c,DateTime:o,TimeZone:s}},fieldsMeta:{}};export const googleCalendarEventDefinition={name:"GoogleCalendarEvent",behavior:"default",interfaces:[t.ExternalEntity,i.EventKind],schema:{type:"object",properties:{title:{type:"string",minLength:1,maxLength:200},startAt:{$ref:"#/definitions/DateTime"},endAt:{$ref:"#/definitions/DateTime"},allDay:{type:"boolean"},timeZone:{$ref:"#/definitions/TimeZone"},description:{type:"string"},location:{type:"string"},status:{$ref:"#/definitions/EventStatus"},htmlLink:{$ref:"#/definitions/HtmlLink"},recurringEventID:{type:"string"},calendarID:{type:"string"},calendar:{$ref:"#/definitions/CalendarDocID"},sourceService:{$ref:"#/definitions/SourceService"},sourceID:{$ref:"#/definitions/SourceID"},sourceURL:{$ref:"#/definitions/SourceURL"},lastSyncedAt:{$ref:"#/definitions/DateTime"}},required:["title","startAt","allDay","calendarID","calendar","sourceService","sourceID","lastSyncedAt"],additionalProperties:!1,definitions:{SourceService:{type:"string",title:"SourceService",minLength:1,maxLength:50},SourceID:{type:"string",title:"SourceID",minLength:1,maxLength:500},SourceURL:c,DateTime:o,TimeZone:s,HtmlLink:c,CalendarDocID:a,EventStatus:{type:"string",title:"EventStatus",enum:["CONFIRMED","TENTATIVE","CANCELLED"]}}},fieldsMeta:{calendar:{type:"document",model:"#0"}}};let l=new r({externalClusters:{...e,...n}});l.add(googleCalendarDefinition),l.add(googleCalendarEventDefinition);export const googleCalendarClusters=l.build();
@@ -0,0 +1,14 @@
1
+ import type { Credential, ServerDataProvider, SyncBoundary } from '@kubun/connector';
2
+ export type GoogleCalendarProviderConfig = {
3
+ credential: Credential;
4
+ boundary?: SyncBoundary;
5
+ fetch?: typeof globalThis.fetch;
6
+ excludeCalendars?: Array<string>;
7
+ };
8
+ export type CalendarCheckpoint = {
9
+ calendarListSyncToken?: string;
10
+ calendars: Record<string, {
11
+ eventsSyncToken?: string;
12
+ }>;
13
+ };
14
+ export declare function createGoogleCalendarProvider(config: GoogleCalendarProviderConfig): ServerDataProvider;
@@ -0,0 +1 @@
1
+ import{resolveModelID as e}from"@kubun/connector";import{buildCalendarListURL as n,buildEventsListURL as t,mapCalendarToEntity as l,mapEventToEntity as a}from"./api.js";import{googleCalendarClusters as i}from"./model.js";let o=e(i,"GoogleCalendar"),c=e(i,"GoogleCalendarEvent");async function r(e,n,t,l){let a=await t(e,{headers:{Authorization:`Bearer ${n.accessToken}`},signal:l});if(!a.ok)throw Error(`Google Calendar API error: ${a.status} ${a.statusText}`);return await a.json()}function s(e){if(null==e.maxAge)return;let n=/^P(\d+)D$/i.exec(e.maxAge);if(null==n)return;let t=Number.parseInt(n[1],10),l=new Date;return l.setDate(l.getDate()-t),l.toISOString()}async function*d(e){let t,l=!0;do{let a=n({syncToken:l?e.syncToken:void 0,pageToken:t}),i=await r(a,e.credential,e.fetchFn,e.signal);yield{items:i.items??[],nextSyncToken:i.nextSyncToken,isFirstPage:l},t=i.nextPageToken,l=!1}while(null!=t)}async function*u(e){let n,l=!0;do{let a=t({calendarID:e.calendarID,syncToken:l?e.syncToken:void 0,pageToken:n,timeMin:e.timeMin}),i=await r(a,e.credential,e.fetchFn,e.signal);yield{items:i.items??[],nextSyncToken:i.nextSyncToken},n=i.nextPageToken,l=!1}while(null!=n)}export function createGoogleCalendarProvider(e){let n=e.fetch??globalThis.fetch,t=new Set(e.excludeCalendars??[]);async function*i(i){let r,y=s(i.boundary),f=[];for await(let l of d({credential:e.credential,fetchFn:n,signal:i.signal})){for(let e of l.items)t.has(e.id)||f.push(e);null!=l.nextSyncToken&&(r=l.nextSyncToken)}yield{modelID:o,entities:f.map(l),hasMore:!0};let m={},k=!1;for(let t=0;t<f.length;t++){let l,o=f[t],s=t===f.length-1;for await(let t of u({calendarID:o.id,credential:e.credential,fetchFn:n,timeMin:y,signal:i.signal})){null!=t.nextSyncToken&&(l=t.nextSyncToken);let e=null!=t.nextSyncToken,n=s&&e?{calendarListSyncToken:r,calendars:{...m,[o.id]:{eventsSyncToken:t.nextSyncToken}}}:void 0,i=t.items.filter(e=>"cancelled"!==e.status),d=t.items.filter(e=>"cancelled"===e.status);yield{modelID:c,entities:i.map(e=>a(e,o.id)),deleted:d.map(e=>({sourceService:"google-calendar",sourceID:e.id})),hasMore:!(s&&e),checkpoint:n},k=!0}m[o.id]={eventsSyncToken:l}}k||(yield{modelID:c,entities:[],hasMore:!1,checkpoint:{calendarListSyncToken:r,calendars:m}})}return{supportedStrategies:["on-demand"],fetchAll:i,async *fetchChanges(r){let y,f=r.checkpoint;if(null==f)return void(yield*i(r));let m=s(r.boundary),k=[],g=[];for await(let l of d({credential:e.credential,fetchFn:n,syncToken:f.calendarListSyncToken,signal:r.signal})){for(let e of l.items)!0===e.deleted?g.push(e.id):t.has(e.id)||k.push(e);null!=l.nextSyncToken&&(y=l.nextSyncToken)}yield{modelID:o,entities:k.map(l),deleted:g.map(e=>({sourceService:"google-calendar",sourceID:e})),hasMore:!0};let h={...f.calendars};for(let e of g)delete h[e];let T=k.filter(e=>!(e.id in f.calendars)),S=[...Object.keys(h).map(e=>({id:e,isNew:!1})),...T.map(e=>({id:e.id,isNew:!0}))],p={};for(let t=0;t<S.length;t++){let l,{id:i,isNew:o}=S[t],s=t===S.length-1,d=o?void 0:h[i]?.eventsSyncToken;for await(let t of u({calendarID:i,credential:e.credential,fetchFn:n,syncToken:d,timeMin:o?m:void 0,signal:r.signal})){null!=t.nextSyncToken&&(l=t.nextSyncToken);let e=null!=t.nextSyncToken,n=s&&e?{calendarListSyncToken:y,calendars:{...p,[i]:{eventsSyncToken:t.nextSyncToken}}}:void 0,o=t.items.filter(e=>"cancelled"!==e.status),r=t.items.filter(e=>"cancelled"===e.status);yield{modelID:c,entities:o.map(e=>a(e,i)),deleted:r.map(e=>({sourceService:"google-calendar",sourceID:e.id})),hasMore:!(s&&e),checkpoint:n}}p[i]={eventsSyncToken:l}}0===S.length&&(yield{modelID:c,entities:[],hasMore:!1,checkpoint:{calendarListSyncToken:y,calendars:p}})}}}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@kubun/connector-google-calendar",
3
+ "version": "0.8.0",
4
+ "license": "see LICENSE.md",
5
+ "keywords": [],
6
+ "type": "module",
7
+ "main": "lib/index.js",
8
+ "types": "lib/index.d.ts",
9
+ "exports": {
10
+ ".": "./lib/index.js"
11
+ },
12
+ "files": [
13
+ "lib/*",
14
+ "LICENSE.md"
15
+ ],
16
+ "sideEffects": false,
17
+ "dependencies": {
18
+ "@kubun/connector": "^0.8.0",
19
+ "@kubun/models": "^0.8.0",
20
+ "@kubun/provider-google": "^0.8.0",
21
+ "@kubun/protocol": "^0.8.0",
22
+ "@kubun/scalars": "^0.8.0"
23
+ },
24
+ "scripts": {
25
+ "build:clean": "del lib",
26
+ "build:js": "swc src -d ./lib --config-file ../../swc.json --strip-leading-paths",
27
+ "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
28
+ "build:types:ci": "tsc --emitDeclarationOnly --declarationMap false",
29
+ "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
30
+ "test:types": "tsc --noEmit -p tsconfig.test.json",
31
+ "test:unit": "vitest run",
32
+ "test": "pnpm run test:types && pnpm run test:unit"
33
+ }
34
+ }