@1kbirds/chidori-mock-google-calendar 0.1.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/README.md +92 -0
- package/dist/api.d.ts +14 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +102 -0
- package/dist/client.d.ts +56 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +39 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +27 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/seed.d.ts +9 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +94 -0
- package/dist/service.d.ts +28 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +345 -0
- package/dist/state.d.ts +21 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +94 -0
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/ui/GoogleCalendarMockApp.d.ts +7 -0
- package/dist/ui/GoogleCalendarMockApp.d.ts.map +1 -0
- package/dist/ui/GoogleCalendarMockApp.js +140 -0
- package/dist/ui/dev.d.ts +2 -0
- package/dist/ui/dev.d.ts.map +1 -0
- package/dist/ui/dev.js +11 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/styles.css +302 -0
- package/package.json +56 -0
- package/src/__tests__/service.test.ts +163 -0
- package/src/api.ts +134 -0
- package/src/client.ts +53 -0
- package/src/errors.ts +31 -0
- package/src/index.ts +12 -0
- package/src/seed.ts +102 -0
- package/src/service.ts +393 -0
- package/src/state.ts +127 -0
- package/src/types.ts +149 -0
- package/src/ui/GoogleCalendarMockApp.tsx +309 -0
- package/src/ui/dev.tsx +16 -0
- package/src/ui/index.ts +2 -0
- package/src/ui/styles.css +302 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# @1kbirds/chidori-mock-google-calendar
|
|
2
|
+
|
|
3
|
+
In-memory Google Calendar mock for agent testing. The package provides:
|
|
4
|
+
|
|
5
|
+
- A deterministic in-memory service.
|
|
6
|
+
- A googleapis-like SDK facade.
|
|
7
|
+
- A lightweight REST-style Calendar API adapter.
|
|
8
|
+
- A React UI for inspecting and editing mock calendar state.
|
|
9
|
+
- Seed/reset utilities for repeatable tests.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import {
|
|
15
|
+
createGoogleCalendarClient,
|
|
16
|
+
createGoogleCalendarMock,
|
|
17
|
+
demoSeed,
|
|
18
|
+
} from "@1kbirds/chidori-mock-google-calendar";
|
|
19
|
+
|
|
20
|
+
const mock = createGoogleCalendarMock({
|
|
21
|
+
now: "2026-06-01T15:00:00.000Z",
|
|
22
|
+
seed: demoSeed,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const client = createGoogleCalendarClient(mock);
|
|
26
|
+
|
|
27
|
+
await client.events.insert({
|
|
28
|
+
calendarId: "primary",
|
|
29
|
+
requestBody: {
|
|
30
|
+
summary: "Planning",
|
|
31
|
+
start: { dateTime: "2026-06-01T16:00:00.000Z" },
|
|
32
|
+
end: { dateTime: "2026-06-01T17:00:00.000Z" },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Supported Surface
|
|
38
|
+
|
|
39
|
+
SDK-style methods:
|
|
40
|
+
|
|
41
|
+
- `calendarList.list`
|
|
42
|
+
- `calendarList.get`
|
|
43
|
+
- `calendars.get`
|
|
44
|
+
- `calendars.insert`
|
|
45
|
+
- `calendars.update`
|
|
46
|
+
- `calendars.delete`
|
|
47
|
+
- `events.list`
|
|
48
|
+
- `events.get`
|
|
49
|
+
- `events.insert`
|
|
50
|
+
- `events.update`
|
|
51
|
+
- `events.patch`
|
|
52
|
+
- `events.delete`
|
|
53
|
+
- `freebusy.query`
|
|
54
|
+
|
|
55
|
+
REST-style paths:
|
|
56
|
+
|
|
57
|
+
- `GET /calendar/v3/users/me/calendarList`
|
|
58
|
+
- `GET /calendar/v3/users/me/calendarList/:calendarId`
|
|
59
|
+
- `POST /calendar/v3/calendars`
|
|
60
|
+
- `GET|PUT|PATCH|DELETE /calendar/v3/calendars/:calendarId`
|
|
61
|
+
- `GET|POST /calendar/v3/calendars/:calendarId/events`
|
|
62
|
+
- `GET|PUT|PATCH|DELETE /calendar/v3/calendars/:calendarId/events/:eventId`
|
|
63
|
+
- `POST /calendar/v3/freeBusy`
|
|
64
|
+
|
|
65
|
+
## Review
|
|
66
|
+
|
|
67
|
+
Run verification:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npm run build
|
|
71
|
+
npm test
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Start the React review app:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
npm run dev:google-calendar
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Then open `http://127.0.0.1:5173/`.
|
|
81
|
+
|
|
82
|
+
Manual review should confirm:
|
|
83
|
+
|
|
84
|
+
- Seeded calendars and events render.
|
|
85
|
+
- UI-created events are visible through the service/client state.
|
|
86
|
+
- API/client-created events render in the UI.
|
|
87
|
+
- Event edit/delete changes affect event listing and free/busy output.
|
|
88
|
+
- Reset restores deterministic seeded state.
|
|
89
|
+
|
|
90
|
+
## Fidelity Notes
|
|
91
|
+
|
|
92
|
+
The mock intentionally keeps state in memory only. It currently focuses on common calendar, event, list, and free/busy workflows. Complex recurrence expansion, notifications, conference data, OAuth, incremental sync, push notifications, and quota simulation are not implemented yet.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { GoogleCalendarMock } from "./service";
|
|
2
|
+
export interface MockApiRequest {
|
|
3
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
4
|
+
path: string;
|
|
5
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
6
|
+
body?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface MockApiResponse<T = unknown> {
|
|
9
|
+
status: number;
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
body?: T;
|
|
12
|
+
}
|
|
13
|
+
export declare function handleGoogleCalendarApiRequest(mock: GoogleCalendarMock, request: MockApiRequest): MockApiResponse;
|
|
14
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,CAAC;CACV;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,cAAc,GAAG,eAAe,CAqFjH"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export function handleGoogleCalendarApiRequest(mock, request) {
|
|
2
|
+
const path = normalizePath(request.path);
|
|
3
|
+
const query = request.query ?? {};
|
|
4
|
+
if (request.method === "GET" && path === "/calendar/v3/users/me/calendarList") {
|
|
5
|
+
return json(200, mock.listCalendarList());
|
|
6
|
+
}
|
|
7
|
+
const calendarListMatch = path.match(/^\/calendar\/v3\/users\/me\/calendarList\/([^/]+)$/);
|
|
8
|
+
if (request.method === "GET" && calendarListMatch) {
|
|
9
|
+
return json(200, mock.getCalendarListEntry(decodeURIComponent(calendarListMatch[1])));
|
|
10
|
+
}
|
|
11
|
+
if (request.method === "POST" && path === "/calendar/v3/calendars") {
|
|
12
|
+
return json(200, mock.insertCalendar(request.body));
|
|
13
|
+
}
|
|
14
|
+
const calendarMatch = path.match(/^\/calendar\/v3\/calendars\/([^/]+)$/);
|
|
15
|
+
if (calendarMatch) {
|
|
16
|
+
const calendarId = decodeURIComponent(calendarMatch[1]);
|
|
17
|
+
if (request.method === "GET") {
|
|
18
|
+
return json(200, mock.getCalendar(calendarId));
|
|
19
|
+
}
|
|
20
|
+
if (request.method === "PUT" || request.method === "PATCH") {
|
|
21
|
+
return json(200, mock.updateCalendar(calendarId, request.body));
|
|
22
|
+
}
|
|
23
|
+
if (request.method === "DELETE") {
|
|
24
|
+
mock.deleteCalendar(calendarId);
|
|
25
|
+
return { status: 204, headers: {} };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const eventsMatch = path.match(/^\/calendar\/v3\/calendars\/([^/]+)\/events$/);
|
|
29
|
+
if (eventsMatch) {
|
|
30
|
+
const calendarId = decodeURIComponent(eventsMatch[1]);
|
|
31
|
+
if (request.method === "GET") {
|
|
32
|
+
return json(200, mock.listEvents({
|
|
33
|
+
calendarId,
|
|
34
|
+
timeMin: stringQuery(query.timeMin),
|
|
35
|
+
timeMax: stringQuery(query.timeMax),
|
|
36
|
+
q: stringQuery(query.q),
|
|
37
|
+
showDeleted: booleanQuery(query.showDeleted),
|
|
38
|
+
singleEvents: booleanQuery(query.singleEvents),
|
|
39
|
+
orderBy: query.orderBy === "updated" ? "updated" : query.orderBy === "startTime" ? "startTime" : undefined,
|
|
40
|
+
maxResults: numberQuery(query.maxResults),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
if (request.method === "POST") {
|
|
44
|
+
return json(200, mock.insertEvent(calendarId, request.body));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const eventMatch = path.match(/^\/calendar\/v3\/calendars\/([^/]+)\/events\/([^/]+)$/);
|
|
48
|
+
if (eventMatch) {
|
|
49
|
+
const calendarId = decodeURIComponent(eventMatch[1]);
|
|
50
|
+
const eventId = decodeURIComponent(eventMatch[2]);
|
|
51
|
+
if (request.method === "GET") {
|
|
52
|
+
return json(200, mock.getEvent(calendarId, eventId));
|
|
53
|
+
}
|
|
54
|
+
if (request.method === "PUT") {
|
|
55
|
+
return json(200, mock.updateEvent(calendarId, eventId, request.body));
|
|
56
|
+
}
|
|
57
|
+
if (request.method === "PATCH") {
|
|
58
|
+
return json(200, mock.patchEvent(calendarId, eventId, request.body));
|
|
59
|
+
}
|
|
60
|
+
if (request.method === "DELETE") {
|
|
61
|
+
mock.deleteEvent(calendarId, eventId);
|
|
62
|
+
return { status: 204, headers: {} };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (request.method === "POST" && path === "/calendar/v3/freeBusy") {
|
|
66
|
+
return json(200, mock.queryFreeBusy(request.body));
|
|
67
|
+
}
|
|
68
|
+
return json(404, {
|
|
69
|
+
error: {
|
|
70
|
+
code: 404,
|
|
71
|
+
message: `Unsupported mock endpoint: ${request.method} ${request.path}`,
|
|
72
|
+
errors: [{ domain: "global", reason: "notFound", message: "Unsupported mock endpoint" }],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function normalizePath(path) {
|
|
77
|
+
const url = new URL(path, "https://mock.local");
|
|
78
|
+
return url.pathname.replace(/\/+$/, "");
|
|
79
|
+
}
|
|
80
|
+
function json(status, body) {
|
|
81
|
+
return {
|
|
82
|
+
status,
|
|
83
|
+
headers: { "content-type": "application/json" },
|
|
84
|
+
body,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function stringQuery(value) {
|
|
88
|
+
return value === undefined ? undefined : String(value);
|
|
89
|
+
}
|
|
90
|
+
function booleanQuery(value) {
|
|
91
|
+
if (value === undefined) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
return value === true || value === "true";
|
|
95
|
+
}
|
|
96
|
+
function numberQuery(value) {
|
|
97
|
+
if (value === undefined) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const parsed = Number(value);
|
|
101
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
102
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { GoogleCalendarMock } from "./service";
|
|
2
|
+
import type { CalendarEvent, CalendarResource, EventsListParams, FreeBusyRequest, GoogleApiResponse } from "./types";
|
|
3
|
+
export declare function createGoogleCalendarClient(mock: GoogleCalendarMock): {
|
|
4
|
+
calendarList: {
|
|
5
|
+
list: () => Promise<GoogleApiResponse<import("./types").ListResponse<import("./types").CalendarListEntry>>>;
|
|
6
|
+
get: ({ calendarId }: {
|
|
7
|
+
calendarId: string;
|
|
8
|
+
}) => Promise<GoogleApiResponse<import("./types").CalendarListEntry>>;
|
|
9
|
+
};
|
|
10
|
+
calendars: {
|
|
11
|
+
get: ({ calendarId }: {
|
|
12
|
+
calendarId: string;
|
|
13
|
+
}) => Promise<GoogleApiResponse<CalendarResource>>;
|
|
14
|
+
insert: ({ requestBody }: {
|
|
15
|
+
requestBody: Partial<CalendarResource>;
|
|
16
|
+
}) => Promise<GoogleApiResponse<CalendarResource>>;
|
|
17
|
+
update: ({ calendarId, requestBody }: {
|
|
18
|
+
calendarId: string;
|
|
19
|
+
requestBody: Partial<CalendarResource>;
|
|
20
|
+
}) => Promise<GoogleApiResponse<CalendarResource>>;
|
|
21
|
+
delete: ({ calendarId }: {
|
|
22
|
+
calendarId: string;
|
|
23
|
+
}) => Promise<GoogleApiResponse<undefined>>;
|
|
24
|
+
};
|
|
25
|
+
events: {
|
|
26
|
+
list: (params: EventsListParams) => Promise<GoogleApiResponse<import("./types").ListResponse<CalendarEvent>>>;
|
|
27
|
+
get: ({ calendarId, eventId }: {
|
|
28
|
+
calendarId: string;
|
|
29
|
+
eventId: string;
|
|
30
|
+
}) => Promise<GoogleApiResponse<CalendarEvent>>;
|
|
31
|
+
insert: ({ calendarId, requestBody }: {
|
|
32
|
+
calendarId: string;
|
|
33
|
+
requestBody: Partial<CalendarEvent>;
|
|
34
|
+
}) => Promise<GoogleApiResponse<CalendarEvent>>;
|
|
35
|
+
update: ({ calendarId, eventId, requestBody }: {
|
|
36
|
+
calendarId: string;
|
|
37
|
+
eventId: string;
|
|
38
|
+
requestBody: Partial<CalendarEvent>;
|
|
39
|
+
}) => Promise<GoogleApiResponse<CalendarEvent>>;
|
|
40
|
+
patch: ({ calendarId, eventId, requestBody }: {
|
|
41
|
+
calendarId: string;
|
|
42
|
+
eventId: string;
|
|
43
|
+
requestBody: Partial<CalendarEvent>;
|
|
44
|
+
}) => Promise<GoogleApiResponse<CalendarEvent>>;
|
|
45
|
+
delete: ({ calendarId, eventId }: {
|
|
46
|
+
calendarId: string;
|
|
47
|
+
eventId: string;
|
|
48
|
+
}) => Promise<GoogleApiResponse<undefined>>;
|
|
49
|
+
};
|
|
50
|
+
freebusy: {
|
|
51
|
+
query: ({ requestBody }: {
|
|
52
|
+
requestBody: FreeBusyRequest;
|
|
53
|
+
}) => Promise<GoogleApiResponse<import("./types").FreeBusyResponse>>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAWjB,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB;;;8BAIjC;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE;;;8BAGtB;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE;kCAClB;YAAE,WAAW,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;SAAE;8CAC9B;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;SAAE;iCAE3E;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE;;;uBAMhC,gBAAgB;uCACA;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE;8CAChC;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;SAAE;uDAElD;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;SAAE;sDAE7E;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;SAAE;0CAExF;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE;;;iCAMhD;YAAE,WAAW,EAAE,eAAe,CAAA;SAAE;;EAGpE"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
function response(data, status = 200, statusText = "OK") {
|
|
2
|
+
return {
|
|
3
|
+
data,
|
|
4
|
+
status,
|
|
5
|
+
statusText,
|
|
6
|
+
headers: {},
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function createGoogleCalendarClient(mock) {
|
|
10
|
+
return {
|
|
11
|
+
calendarList: {
|
|
12
|
+
list: async () => response(mock.listCalendarList()),
|
|
13
|
+
get: async ({ calendarId }) => response(mock.getCalendarListEntry(calendarId)),
|
|
14
|
+
},
|
|
15
|
+
calendars: {
|
|
16
|
+
get: async ({ calendarId }) => response(mock.getCalendar(calendarId)),
|
|
17
|
+
insert: async ({ requestBody }) => response(mock.insertCalendar(requestBody)),
|
|
18
|
+
update: async ({ calendarId, requestBody }) => response(mock.updateCalendar(calendarId, requestBody)),
|
|
19
|
+
delete: async ({ calendarId }) => {
|
|
20
|
+
mock.deleteCalendar(calendarId);
|
|
21
|
+
return response(undefined, 204, "No Content");
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
events: {
|
|
25
|
+
list: async (params) => response(mock.listEvents(params)),
|
|
26
|
+
get: async ({ calendarId, eventId }) => response(mock.getEvent(calendarId, eventId)),
|
|
27
|
+
insert: async ({ calendarId, requestBody }) => response(mock.insertEvent(calendarId, requestBody)),
|
|
28
|
+
update: async ({ calendarId, eventId, requestBody }) => response(mock.updateEvent(calendarId, eventId, requestBody)),
|
|
29
|
+
patch: async ({ calendarId, eventId, requestBody }) => response(mock.patchEvent(calendarId, eventId, requestBody)),
|
|
30
|
+
delete: async ({ calendarId, eventId }) => {
|
|
31
|
+
mock.deleteEvent(calendarId, eventId);
|
|
32
|
+
return response(undefined, 204, "No Content");
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
freebusy: {
|
|
36
|
+
query: async ({ requestBody }) => response(mock.queryFreeBusy(requestBody)),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class GoogleCalendarMockError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly reason: string;
|
|
4
|
+
readonly errors: Array<{
|
|
5
|
+
domain: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}>;
|
|
9
|
+
constructor(status: number, reason: string, message: string);
|
|
10
|
+
toJSON(): {
|
|
11
|
+
error: {
|
|
12
|
+
code: number;
|
|
13
|
+
message: string;
|
|
14
|
+
errors: {
|
|
15
|
+
domain: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
message: string;
|
|
18
|
+
}[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function notFound(message: string): GoogleCalendarMockError;
|
|
23
|
+
export declare function badRequest(message: string): GoogleCalendarMockError;
|
|
24
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAEhE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQ3D,MAAM;;;;;wBAV2B,MAAM;wBAAU,MAAM;yBAAW,MAAM;;;;CAmBzE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,CAEjE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,CAEnE"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class GoogleCalendarMockError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
reason;
|
|
4
|
+
errors;
|
|
5
|
+
constructor(status, reason, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "GoogleCalendarMockError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.reason = reason;
|
|
10
|
+
this.errors = [{ domain: "global", reason, message }];
|
|
11
|
+
}
|
|
12
|
+
toJSON() {
|
|
13
|
+
return {
|
|
14
|
+
error: {
|
|
15
|
+
code: this.status,
|
|
16
|
+
message: this.message,
|
|
17
|
+
errors: this.errors,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function notFound(message) {
|
|
23
|
+
return new GoogleCalendarMockError(404, "notFound", message);
|
|
24
|
+
}
|
|
25
|
+
export function badRequest(message) {
|
|
26
|
+
return new GoogleCalendarMockError(400, "badRequest", message);
|
|
27
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { handleGoogleCalendarApiRequest } from "./api";
|
|
2
|
+
export type { MockApiRequest, MockApiResponse } from "./api";
|
|
3
|
+
export { createGoogleCalendarClient } from "./client";
|
|
4
|
+
export { GoogleCalendarMockError } from "./errors";
|
|
5
|
+
export { GoogleCalendarMock } from "./service";
|
|
6
|
+
import { GoogleCalendarMock } from "./service";
|
|
7
|
+
export { demoCalendars, demoEvents, demoSeed, demoUser, resetGoogleCalendarMock, seedGoogleCalendarState } from "./seed";
|
|
8
|
+
export type * from "./types";
|
|
9
|
+
export declare function createGoogleCalendarMock(...args: ConstructorParameters<typeof GoogleCalendarMock>): GoogleCalendarMock;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,OAAO,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AACzH,mBAAmB,SAAS,CAAC;AAE7B,wBAAgB,wBAAwB,CAAC,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,kBAAkB,CAAC,GAAG,kBAAkB,CAEtH"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { handleGoogleCalendarApiRequest } from "./api";
|
|
2
|
+
export { createGoogleCalendarClient } from "./client";
|
|
3
|
+
export { GoogleCalendarMockError } from "./errors";
|
|
4
|
+
export { GoogleCalendarMock } from "./service";
|
|
5
|
+
import { GoogleCalendarMock } from "./service";
|
|
6
|
+
export { demoCalendars, demoEvents, demoSeed, demoUser, resetGoogleCalendarMock, seedGoogleCalendarState } from "./seed";
|
|
7
|
+
export function createGoogleCalendarMock(...args) {
|
|
8
|
+
return new GoogleCalendarMock(...args);
|
|
9
|
+
}
|
package/dist/seed.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GoogleCalendarMock } from "./service";
|
|
2
|
+
import type { CalendarEvent, CalendarListEntry, GoogleCalendarSeed, MockUser } from "./types";
|
|
3
|
+
export declare const demoUser: MockUser;
|
|
4
|
+
export declare const demoCalendars: CalendarListEntry[];
|
|
5
|
+
export declare const demoEvents: Record<string, CalendarEvent[]>;
|
|
6
|
+
export declare const demoSeed: GoogleCalendarSeed;
|
|
7
|
+
export declare function seedGoogleCalendarState(mock: GoogleCalendarMock, seed?: GoogleCalendarSeed): void;
|
|
8
|
+
export declare function resetGoogleCalendarMock(mock: GoogleCalendarMock): void;
|
|
9
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE9F,eAAO,MAAM,QAAQ,EAAE,QAKtB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,iBAAiB,EAyB5C,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CA4CtD,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,kBAKtB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,GAAE,kBAA6B,GAAG,IAAI,CAO3G;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAEtE"}
|
package/dist/seed.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export const demoUser = {
|
|
2
|
+
id: "user_ada",
|
|
3
|
+
email: "ada@example.com",
|
|
4
|
+
displayName: "Ada Lovelace",
|
|
5
|
+
defaultCalendarId: "primary",
|
|
6
|
+
};
|
|
7
|
+
export const demoCalendars = [
|
|
8
|
+
{
|
|
9
|
+
kind: "calendar#calendarListEntry",
|
|
10
|
+
etag: "\"primary:seed\"",
|
|
11
|
+
id: "primary",
|
|
12
|
+
summary: "ada@example.com",
|
|
13
|
+
timeZone: "America/Los_Angeles",
|
|
14
|
+
primary: true,
|
|
15
|
+
selected: true,
|
|
16
|
+
backgroundColor: "#1a73e8",
|
|
17
|
+
foregroundColor: "#ffffff",
|
|
18
|
+
accessRole: "owner",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
kind: "calendar#calendarListEntry",
|
|
22
|
+
etag: "\"team:seed\"",
|
|
23
|
+
id: "team",
|
|
24
|
+
summary: "Team Calendar",
|
|
25
|
+
description: "Shared team events",
|
|
26
|
+
timeZone: "America/Los_Angeles",
|
|
27
|
+
selected: true,
|
|
28
|
+
backgroundColor: "#0b8043",
|
|
29
|
+
foregroundColor: "#ffffff",
|
|
30
|
+
accessRole: "writer",
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
export const demoEvents = {
|
|
34
|
+
primary: [
|
|
35
|
+
{
|
|
36
|
+
kind: "calendar#event",
|
|
37
|
+
etag: "\"event_planning:seed\"",
|
|
38
|
+
id: "event_planning",
|
|
39
|
+
status: "confirmed",
|
|
40
|
+
htmlLink: "https://calendar.google.com/calendar/event?eid=event_planning",
|
|
41
|
+
created: "2026-06-01T15:00:00.000Z",
|
|
42
|
+
updated: "2026-06-01T15:00:00.000Z",
|
|
43
|
+
summary: "Product planning",
|
|
44
|
+
description: "Draft launch plan",
|
|
45
|
+
location: "Conference Room A",
|
|
46
|
+
creator: { email: "ada@example.com", displayName: "Ada Lovelace", self: true },
|
|
47
|
+
organizer: { email: "ada@example.com", displayName: "Ada Lovelace", self: true },
|
|
48
|
+
start: { dateTime: "2026-06-01T16:00:00.000Z", timeZone: "America/Los_Angeles" },
|
|
49
|
+
end: { dateTime: "2026-06-01T17:00:00.000Z", timeZone: "America/Los_Angeles" },
|
|
50
|
+
attendees: [{ email: "grace@example.com", displayName: "Grace Hopper", responseStatus: "accepted" }],
|
|
51
|
+
transparency: "opaque",
|
|
52
|
+
visibility: "default",
|
|
53
|
+
iCalUID: "event_planning@chidori-mock.local",
|
|
54
|
+
sequence: 0,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
team: [
|
|
58
|
+
{
|
|
59
|
+
kind: "calendar#event",
|
|
60
|
+
etag: "\"event_standup:seed\"",
|
|
61
|
+
id: "event_standup",
|
|
62
|
+
status: "confirmed",
|
|
63
|
+
htmlLink: "https://calendar.google.com/calendar/event?eid=event_standup",
|
|
64
|
+
created: "2026-06-01T15:00:00.000Z",
|
|
65
|
+
updated: "2026-06-01T15:00:00.000Z",
|
|
66
|
+
summary: "Team standup",
|
|
67
|
+
creator: { email: "ada@example.com", displayName: "Ada Lovelace", self: true },
|
|
68
|
+
organizer: { email: "team@example.com", displayName: "Team Calendar" },
|
|
69
|
+
start: { dateTime: "2026-06-02T16:30:00.000Z", timeZone: "America/Los_Angeles" },
|
|
70
|
+
end: { dateTime: "2026-06-02T17:00:00.000Z", timeZone: "America/Los_Angeles" },
|
|
71
|
+
transparency: "opaque",
|
|
72
|
+
visibility: "default",
|
|
73
|
+
iCalUID: "event_standup@chidori-mock.local",
|
|
74
|
+
sequence: 0,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
export const demoSeed = {
|
|
79
|
+
users: [demoUser],
|
|
80
|
+
calendars: demoCalendars,
|
|
81
|
+
events: demoEvents,
|
|
82
|
+
currentUserId: demoUser.id,
|
|
83
|
+
};
|
|
84
|
+
export function seedGoogleCalendarState(mock, seed = demoSeed) {
|
|
85
|
+
mock.reset({
|
|
86
|
+
users: seed.users ?? [],
|
|
87
|
+
calendars: seed.calendars ?? [],
|
|
88
|
+
events: seed.events ?? {},
|
|
89
|
+
currentUserId: seed.currentUserId ?? seed.users?.[0]?.id ?? "user_ada",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export function resetGoogleCalendarMock(mock) {
|
|
93
|
+
mock.reset();
|
|
94
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type GoogleCalendarMockStore } from "./state";
|
|
2
|
+
import type { CalendarEvent, CalendarListEntry, CalendarResource, EventsListParams, FreeBusyRequest, FreeBusyResponse, GoogleCalendarMockOptions, GoogleCalendarMockStateSnapshot, ListResponse, MockUser } from "./types";
|
|
3
|
+
export declare class GoogleCalendarMock {
|
|
4
|
+
readonly store: GoogleCalendarMockStore;
|
|
5
|
+
private readonly initialSnapshot;
|
|
6
|
+
constructor(options?: GoogleCalendarMockOptions);
|
|
7
|
+
get currentUser(): MockUser;
|
|
8
|
+
subscribe(listener: () => void): () => void;
|
|
9
|
+
snapshot(): GoogleCalendarMockStateSnapshot;
|
|
10
|
+
reset(seed?: GoogleCalendarMockStateSnapshot): void;
|
|
11
|
+
listCalendarList(): ListResponse<CalendarListEntry>;
|
|
12
|
+
getCalendarListEntry(calendarId: string): CalendarListEntry;
|
|
13
|
+
getCalendar(calendarId: string): CalendarResource;
|
|
14
|
+
insertCalendar(input: Partial<CalendarResource>): CalendarResource;
|
|
15
|
+
updateCalendar(calendarId: string, input: Partial<CalendarResource>): CalendarResource;
|
|
16
|
+
deleteCalendar(calendarId: string): void;
|
|
17
|
+
listEvents(params: EventsListParams): ListResponse<CalendarEvent>;
|
|
18
|
+
getEvent(calendarId: string, eventId: string): CalendarEvent;
|
|
19
|
+
insertEvent(calendarId: string, input: Partial<CalendarEvent>): CalendarEvent;
|
|
20
|
+
updateEvent(calendarId: string, eventId: string, input: Partial<CalendarEvent>): CalendarEvent;
|
|
21
|
+
patchEvent(calendarId: string, eventId: string, patch: Partial<CalendarEvent>): CalendarEvent;
|
|
22
|
+
deleteEvent(calendarId: string, eventId: string): void;
|
|
23
|
+
queryFreeBusy(request: FreeBusyRequest): FreeBusyResponse;
|
|
24
|
+
private requireCalendar;
|
|
25
|
+
private requireEventMap;
|
|
26
|
+
private requireEvent;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EAA+D,KAAK,uBAAuB,EAAE,MAAM,SAAS,CAAC;AACpH,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAEhB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,yBAAyB,EACzB,+BAA+B,EAC/B,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB,qBAAa,kBAAkB;IAC7B,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;gBAEtD,OAAO,GAAE,yBAA8B;IAKnD,IAAI,WAAW,IAAI,QAAQ,CAM1B;IAED,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAK3C,QAAQ,IAAI,+BAA+B;IAI3C,KAAK,CAAC,IAAI,CAAC,EAAE,+BAA+B,GAAG,IAAI;IAInD,gBAAgB,IAAI,YAAY,CAAC,iBAAiB,CAAC;IAQnD,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB;IAI3D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;IAIjD,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB;IA4BlE,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB;IAkBtF,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAUxC,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,YAAY,CAAC,aAAa,CAAC;IAsBjE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa;IAI5D,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa;IA2C7E,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa;IAmC9F,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa;IAgB7F,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAMtD,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB;IAoCzD,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,YAAY;CAOrB"}
|