import { z } from 'zod';
// Core Calendar Types
export interface CalendarEvent {
id: string;
calendarId: string;
title: string;
description?: string;
startTime: Date;
endTime: Date;
location?: string;
attendees?: Attendee[];
recurrence?: RecurrenceRule;
status: EventStatus;
created: Date;
updated: Date;
}
export interface Attendee {
email: string;
displayName?: string;
responseStatus: AttendeeResponseStatus;
optional?: boolean;
}
export enum AttendeeResponseStatus {
ACCEPTED = 'accepted',
DECLINED = 'declined',
TENTATIVE = 'tentative',
NEEDS_ACTION = 'needsAction'
}
export enum EventStatus {
CONFIRMED = 'confirmed',
TENTATIVE = 'tentative',
CANCELLED = 'cancelled'
}
export interface RecurrenceRule {
frequency: RecurrenceFrequency;
interval?: number;
until?: Date;
count?: number;
byDay?: string[];
}
export enum RecurrenceFrequency {
DAILY = 'daily',
WEEKLY = 'weekly',
MONTHLY = 'monthly',
YEARLY = 'yearly'
}
// Calendar Provider Types
export interface Calendar {
id: string;
title: string;
description?: string;
timezone: string;
accessRole: CalendarAccessRole;
backgroundColor?: string;
foregroundColor?: string;
}
export enum CalendarAccessRole {
OWNER = 'owner',
READER = 'reader',
WRITER = 'writer',
FREE_BUSY_READER = 'freeBusyReader'
}
// Time Slot Types
export interface TimeSlot {
start: Date;
end: Date;
available: boolean;
conflictingEvents?: CalendarEvent[];
}
export interface AvailabilityConstraints {
workingHours?: WorkingHours;
excludeWeekends?: boolean;
minimumNoticePeriod?: number; // minutes
bufferTime?: number; // minutes between events
preferredTimes?: TimePreference[];
}
export interface WorkingHours {
monday?: DaySchedule;
tuesday?: DaySchedule;
wednesday?: DaySchedule;
thursday?: DaySchedule;
friday?: DaySchedule;
saturday?: DaySchedule;
sunday?: DaySchedule;
}
export interface DaySchedule {
startTime: string; // HH:MM format
endTime: string; // HH:MM format
breaks?: TimeBreak[];
}
export interface TimeBreak {
startTime: string;
endTime: string;
title?: string;
}
export interface TimePreference {
startTime: string;
endTime: string;
preference: PreferenceLevel;
}
export enum PreferenceLevel {
PREFERRED = 'preferred',
ACCEPTABLE = 'acceptable',
AVOID = 'avoid'
}
// Reminder Types
export interface Reminder {
id: string;
title: string;
description?: string;
dueDateTime?: Date;
priority: ReminderPriority;
status: ReminderStatus;
tags?: string[];
created: Date;
updated: Date;
}
export enum ReminderPriority {
LOW = 'low',
MEDIUM = 'medium',
HIGH = 'high',
URGENT = 'urgent'
}
export enum ReminderStatus {
PENDING = 'pending',
COMPLETED = 'completed',
CANCELLED = 'cancelled'
}
// User and Authentication Types
export interface User {
id: string;
email: string;
displayName?: string;
timezone: string;
preferences: UserPreferences;
connectedCalendars: ConnectedCalendar[];
created: Date;
lastActive: Date;
}
export interface UserPreferences {
defaultCalendarId?: string;
workingHours: WorkingHours;
defaultEventDuration: number; // minutes
bufferTime: number; // minutes
autoDeclineConflicts: boolean;
reminderDefaults: ReminderDefaults;
}
export interface ReminderDefaults {
defaultReminders: number[]; // minutes before event
emailReminders: boolean;
pushReminders: boolean;
}
export interface ConnectedCalendar {
calendarId: string;
provider: CalendarProvider;
accessToken: string;
refreshToken?: string;
tokenExpiry: Date;
isDefault: boolean;
syncEnabled: boolean;
}
export enum CalendarProvider {
GOOGLE = 'google',
OUTLOOK = 'outlook',
APPLE = 'apple',
CALDAV = 'caldav'
}
// Search and Query Types
export interface EventSearchCriteria {
query?: string;
calendarIds?: string[];
startDate?: Date;
endDate?: Date;
attendeeEmail?: string;
location?: string;
status?: EventStatus;
limit?: number;
offset?: number;
}
export interface FreetimeSearchCriteria {
calendarIds: string[];
startDate: Date;
endDate: Date;
durationMinutes: number;
constraints?: AvailabilityConstraints;
maxResults?: number;
}
// API Response Types
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: ApiError;
pagination?: PaginationInfo;
}
export interface ApiError {
code: string;
message: string;
details?: Record<string, unknown>;
}
export interface PaginationInfo {
page: number;
limit: number;
total: number;
hasNext: boolean;
hasPrev: boolean;
}
// MCP Tool Schema Validation
export const CreateEventSchema = z.object({
calendarId: z.string(),
title: z.string().min(1),
startTime: z.string().datetime(),
endTime: z.string().datetime(),
description: z.string().optional(),
location: z.string().optional(),
attendees: z.array(z.object({
email: z.string().email(),
displayName: z.string().optional(),
optional: z.boolean().optional()
})).optional()
});
export const CreateReminderSchema = z.object({
title: z.string().min(1),
description: z.string().optional(),
dueDateTime: z.string().datetime().optional(),
priority: z.enum(['low', 'medium', 'high', 'urgent']).optional().default('medium'),
tags: z.array(z.string()).optional()
});
export const FindFreeTimeSchema = z.object({
calendarIds: z.array(z.string()).min(1),
startDate: z.string().datetime(),
endDate: z.string().datetime(),
durationMinutes: z.number().positive(),
constraints: z.object({
workingHours: z.record(z.object({
startTime: z.string().regex(/^\d{2}:\d{2}$/),
endTime: z.string().regex(/^\d{2}:\d{2}$/)
})).optional(),
excludeWeekends: z.boolean().optional(),
minimumNoticePeriod: z.number().optional(),
bufferTime: z.number().optional()
}).optional(),
maxResults: z.number().positive().optional().default(10)
});
export type CreateEventInput = z.infer<typeof CreateEventSchema>;
export type CreateReminderInput = z.infer<typeof CreateReminderSchema>;
export type FindFreeTimeInput = z.infer<typeof FindFreeTimeSchema>;