@clinikit.io/google-calendar-client
v1.0.0
Published
A production-grade Google Calendar API v3 client library with comprehensive support for all resources and methods
Downloads
109
Readme
Google Calendar API v3 Client Library
A production-grade, feature-complete client library for the Google Calendar API v3, built with clean architecture, strong typing, and comprehensive error handling.
Features
- ✅ Complete API Coverage - All Google Calendar API v3 resources and methods
- 🔐 OAuth2 & Service Account - Multiple authentication methods supported
- 🔄 Automatic Retries - Intelligent retry logic for transient errors
- 📝 Type Safety - JSDoc type definitions for IDE support
- 🛡️ Error Handling - Normalized error responses with detailed context
- 📊 Logging - Configurable logging with custom logger support
- 🧪 Well Tested - Comprehensive unit test coverage
- 📚 Examples - Ready-to-run examples for common use cases
Supported Resources
- Events - Create, read, update, delete, list, search, import, and watch calendar events
- Calendars - Manage calendar metadata and settings
- Calendar List - Manage user's calendar list and subscriptions
- ACL - Control access permissions for calendars
- Freebusy - Query availability across multiple calendars
- Colors - Get available calendar and event colors
- Settings - Manage user settings
- Channels - Set up and manage webhook notifications
Installation
npm install @clinikit.io/google-calendar-clientQuick Start
1. Set Up OAuth2 Credentials
First, create OAuth2 credentials in the Google Cloud Console:
- Create a new project or select an existing one
- Enable the Google Calendar API
- Create OAuth2 credentials (Client ID and Client Secret)
- Add authorized redirect URIs
2. Initialize the Client
import { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';
const client = new GoogleCalendarClient({
credentials: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'http://localhost:3000/callback',
},
tokens: {
accessToken: 'your-access-token',
refreshToken: 'your-refresh-token',
expiresAt: Date.now() + 3600000,
},
});3. Use the Client
// List upcoming events
const events = await client.events.list('primary', {
timeMin: new Date().toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: 'startTime',
});
console.log('Upcoming events:');
events.items.forEach((event) => {
console.log(`${event.summary} - ${event.start.dateTime || event.start.date}`);
});Authentication
OAuth2 Flow
The library provides a complete OAuth2 authentication flow:
import { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';
const client = new GoogleCalendarClient({
credentials: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'http://localhost:3000/callback',
},
});
// Step 1: Get authorization URL
const authUrl = client.getAuthorizationUrl({
scope: 'https://www.googleapis.com/auth/calendar',
accessType: 'offline',
prompt: 'consent',
});
console.log('Visit this URL to authorize:', authUrl);
// Step 2: Exchange authorization code for tokens
const tokens = await client.exchangeCodeForToken(authorizationCode);
// Tokens are automatically stored and refreshed as neededSee examples/auth.js for a complete authentication example.
Token Management
The library handles token refresh automatically:
// Tokens are refreshed automatically when they expire
const events = await client.events.list('primary');
// Manually set tokens
await client.setTokens({
accessToken: 'new-access-token',
refreshToken: 'new-refresh-token',
expiresAt: Date.now() + 3600000,
});
// Check authentication status
const isAuthenticated = await client.isAuthenticated();
// Revoke access
await client.revokeAccess();Service Account Authentication
For server-to-server API access without user interaction, use service account authentication. This is ideal for backend services, automated tasks, and scheduled jobs.
Setting Up Service Account
Create Service Account in Google Cloud Console:
- Go to IAM & Admin > Service Accounts
- Click "Create Service Account"
- Name your service account and grant appropriate roles
Download Credentials:
- Click on the created service account
- Go to Keys tab
- Click "Add Key" > "Create new key"
- Choose JSON format
- Save the downloaded file securely
Enable Calendar API:
- Go to APIs & Services > Library
- Search for "Google Calendar API"
- Click "Enable"
(Optional) Configure Domain-Wide Delegation for Google Workspace:
- In service account details, copy the "Client ID"
- Go to Google Workspace Admin Console
- Navigate to Security > Access and data control > API Controls
- Click "Manage Domain Wide Delegation"
- Add the Client ID with required scopes:
https://www.googleapis.com/auth/calendar
Using Service Account
Basic Usage
import { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';
const client = new GoogleCalendarClient({
auth: {
type: 'service_account',
keyFilePath: './service-account-key.json',
},
});
// Use the client - no OAuth flow needed!
const events = await client.events.list('primary', {
timeMin: new Date().toISOString(),
maxResults: 10,
});Using Credentials Object
// Load credentials from environment variables or secret manager
const client = new GoogleCalendarClient({
auth: {
type: 'service_account',
credentials: {
type: 'service_account',
project_id: process.env.GCP_PROJECT_ID,
private_key: process.env.GCP_PRIVATE_KEY.replace(/\\n/g, '\n'),
client_email: process.env.GCP_CLIENT_EMAIL,
client_id: process.env.GCP_CLIENT_ID,
token_uri: 'https://oauth2.googleapis.com/token',
},
},
});Domain-Wide Delegation (Impersonation)
For Google Workspace, impersonate users to access their calendars:
// Initialize with a specific user to impersonate
const client = new GoogleCalendarClient({
auth: {
type: 'service_account',
keyFilePath: './service-account-key.json',
subject: '[email protected]', // User to impersonate
},
});
// Access user's calendar
const events = await client.events.list('primary');
// Switch to different user
client.setSubject('[email protected]');
const moreEvents = await client.events.list('primary');Custom Scopes
const client = new GoogleCalendarClient({
auth: {
type: 'service_account',
keyFilePath: './service-account-key.json',
scopes: [
'https://www.googleapis.com/auth/calendar.readonly',
'https://www.googleapis.com/auth/calendar.events.readonly',
],
},
});Using Environment Variables (Recommended for Production)
Load credentials from environment variables instead of JSON files:
import { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';
import { config } from 'dotenv';
// Load .env file
config();
// Initialize with environment variables
const client = new GoogleCalendarClient({
auth: {
type: 'service_account',
useEnv: true, // Loads from GOOGLE_SERVICE_ACCOUNT_* env vars
},
});Required environment variables in .env:
GOOGLE_SERVICE_ACCOUNT_PROJECT_ID=your-project-id
GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_KEY\n-----END PRIVATE KEY-----\n"
GOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com
GOOGLE_SERVICE_ACCOUNT_CLIENT_ID=123456789
# Optional: for domain-wide delegation
[email protected]See examples/service-account-env.js for complete environment variable examples.
OAuth2 vs Service Account
| Feature | OAuth2 | Service Account | | ---------------------- | ------------------------------------- | ---------------------------- | | User Interaction | Required (one-time authorization) | Not required | | Use Case | User-facing applications | Backend services, automation | | Setup Complexity | Medium (redirect URI, consent screen) | Low (just download keyfile) | | Token Management | Refresh tokens needed | Automatic JWT generation | | Domain-Wide Delegation | Not applicable | Available for Workspace | | Best For | Web apps, mobile apps | Servers, cron jobs, scripts |
See examples/service-account.js for complete service account examples.
Custom Token Storage
Implement custom token storage for production environments:
import { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';
class DatabaseTokenStore {
async getToken(userId) {
// Retrieve token from database
return await db.tokens.findOne({ userId });
}
async saveToken(userId, token) {
// Save token to database
await db.tokens.upsert({ userId }, token);
}
async deleteToken(userId) {
// Delete token from database
await db.tokens.delete({ userId });
}
}
const client = new GoogleCalendarClient({
credentials: {
/* ... */
},
tokenStore: new DatabaseTokenStore(),
userId: 'user-123',
});Usage Examples
Events
List Events
const events = await client.events.list('primary', {
timeMin: new Date().toISOString(),
timeMax: new Date('2024-12-31').toISOString(),
maxResults: 100,
singleEvents: true,
orderBy: 'startTime',
q: 'meeting', // Search term
});Create Event
const event = await client.events.insert('primary', {
summary: 'Team Meeting',
description: 'Weekly sync',
location: 'Conference Room A',
start: {
dateTime: '2024-06-15T10:00:00-07:00',
timeZone: 'America/Los_Angeles',
},
end: {
dateTime: '2024-06-15T11:00:00-07:00',
timeZone: 'America/Los_Angeles',
},
attendees: [{ email: '[email protected]' }, { email: '[email protected]' }],
reminders: {
useDefault: false,
overrides: [
{ method: 'email', minutes: 1440 },
{ method: 'popup', minutes: 30 },
],
},
});Update Event
// Full update
const updated = await client.events.update('primary', eventId, {
summary: 'Updated Meeting Title',
start: { dateTime: '2024-06-15T14:00:00-07:00' },
end: { dateTime: '2024-06-15T15:00:00-07:00' },
});
// Partial update (patch)
const patched = await client.events.patch('primary', eventId, {
summary: 'New Title Only',
});Delete Event
await client.events.delete('primary', eventId, {
sendUpdates: 'all', // Notify attendees
});Quick Add
const event = await client.events.quickAdd('primary', 'Lunch with John tomorrow at 12pm');Calendars
List Calendars
const calendars = await client.calendarList.list({
maxResults: 50,
showHidden: false,
});
calendars.items.forEach((calendar) => {
console.log(`${calendar.summary} (${calendar.id})`);
});Create Calendar
const calendar = await client.calendars.insert({
summary: 'Project Tasks',
description: 'Track project tasks and deadlines',
timeZone: 'America/New_York',
});Update Calendar
const updated = await client.calendars.patch(calendarId, {
summary: 'New Calendar Name',
});Delete Calendar
await client.calendars.delete(calendarId);Free/Busy
const freebusy = await client.freebusy.query({
timeMin: '2024-06-15T00:00:00Z',
timeMax: '2024-06-15T23:59:59Z',
items: [{ id: 'primary' }, { id: '[email protected]' }],
});
Object.entries(freebusy.calendars).forEach(([calendarId, calendar]) => {
console.log(`${calendarId}:`);
calendar.busy.forEach((period) => {
console.log(` Busy: ${period.start} to ${period.end}`);
});
});Watch for Changes
const channel = await client.events.watch('primary', {
id: crypto.randomUUID(),
type: 'web_hook',
address: 'https://your-domain.com/webhook',
token: 'verification-token',
expiration: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
});
// Later, stop watching
await client.channels.stop({
id: channel.id,
resourceId: channel.resourceId,
});ACL Management
// List ACL rules
const acl = await client.acl.list('primary');
// Grant access
await client.acl.insert('primary', {
scope: {
type: 'user',
value: '[email protected]',
},
role: 'writer', // none, freeBusyReader, reader, writer, owner
});
// Remove access
await client.acl.delete('primary', ruleId);Configuration
Client Options
const client = new GoogleCalendarClient({
// Required: OAuth2 credentials
credentials: {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'http://localhost:3000/callback',
},
// Optional: Initial tokens
tokens: {
accessToken: 'access-token',
refreshToken: 'refresh-token',
expiresAt: 1234567890000,
},
// Optional: Custom token store
tokenStore: new CustomTokenStore(),
// Optional: User identifier for token storage
userId: 'user-123',
// Optional: API configuration
baseURL: 'https://www.googleapis.com/calendar/v3',
defaultCalendar: 'primary',
defaultTimeZone: 'America/New_York',
maxResults: 250,
// Optional: HTTP configuration
timeout: 30000,
maxRetries: 3,
headers: {
'X-Custom-Header': 'value',
},
// Optional: Custom logger
logger: (level, message, meta) => {
console.log(`[${level}] ${message}`, meta);
},
// Optional: User agent
userAgent: 'MyApp/1.0.0',
});Error Handling
The library provides comprehensive error handling:
import {
GoogleCalendarError,
AuthenticationError,
ValidationError,
} from '@clinikit.io/google-calendar-client';
try {
await client.events.insert('primary', eventData);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
// Re-authenticate
} else if (error instanceof ValidationError) {
console.error('Invalid data:', error.invalidFields);
} else if (error instanceof GoogleCalendarError) {
console.error(`API Error (${error.statusCode}):`, error.message);
console.error('Error code:', error.code);
if (error.isRetryable()) {
// Retry the request
}
}
}Testing
Run the test suite:
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageExamples
Check out the examples directory for complete working examples:
- auth.js - OAuth2 authentication flow
- events.js - Creating and managing events
- calendars.js - Calendar management
- freebusy.js - Querying availability
- watch.js - Setting up webhooks
API Reference
GoogleCalendarClient
Main client class that provides access to all API resources.
Properties
events- EventsClient instancecalendars- CalendarsClient instancecalendarList- CalendarListClient instanceacl- AclClient instancechannels- ChannelsClient instancecolors- ColorsClient instancefreebusy- FreebusyClient instancesettings- SettingsClient instance
Methods
getAuthorizationUrl(options)- Generate OAuth2 authorization URLexchangeCodeForToken(code)- Exchange authorization code for tokenssetTokens(tokens)- Set tokens manuallyrevokeAccess()- Revoke access and clear tokensisAuthenticated()- Check if user is authenticated
For detailed API documentation, see the JSDoc comments in the source code.
Contributing
Contributions are welcome! Please read our Contributing Guide for details on:
- Development setup with Dev Container
- Code style and testing guidelines
- Pull request process
- Reporting issues
Publishing
For maintainers: See Publishing Guide for instructions on releasing new versions to NPM.
License
MIT License - see LICENSE file for details
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Google Calendar API Reference
Changelog
See CHANGELOG.md for version history and release notes.
