{"_id":"@clinikit.io/google-calendar-client","_rev":"2-2c0f880750fe4a14826a7e42ac6928e6","name":"@clinikit.io/google-calendar-client","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@clinikit.io/google-calendar-client","version":"1.0.0","keywords":["google","calendar","api","v3","client","oauth2","events","scheduling"],"author":{"name":"Your Organization"},"license":"MIT","_id":"@clinikit.io/google-calendar-client@1.0.0","maintainers":[{"name":"5aleel","email":"khalil.i.awada@gmail.com"}],"homepage":"https://github.com/KarmatechConsulting/google-calendar-client#readme","bugs":{"url":"https://github.com/KarmatechConsulting/google-calendar-client/issues"},"dist":{"shasum":"4cc468e62d8567298da93338de5eb8ecc3237da2","tarball":"https://registry.npmjs.org/@clinikit.io/google-calendar-client/-/google-calendar-client-1.0.0.tgz","fileCount":47,"integrity":"sha512-TUPOsboMREMwJ+HzNtrNH4SIVVh/EHujSQdkEwbkO2hbR+P9zNzuf3NsZ5HpjoJiajp8c4CBOffcwBw4X+iOCg==","signatures":[{"sig":"MEQCIGFVq4QvqpEXuM2XC78OpTCC8SK9Nu/l9eQmOTnQqqmsAiBn6iQsKQ9MX35k352kWqVF771mDcNfQY/56udiIMbScA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@clinikit.io%2fgoogle-calendar-client@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":193909},"main":"src/index.js","type":"module","engines":{"node":">=20.0.0"},"gitHead":"8766af302891df71eb7dc84e4c345d13d17e39fd","scripts":{"lint":"eslint src tests examples","test":"node --experimental-vm-modules node_modules/jest/bin/jest.js","format":"prettier --write \"src/**/*.js\" \"tests/**/*.js\" \"examples/**/*.js\"","prepare":"npm run format","lint:fix":"eslint src tests examples --fix","test:watch":"node --experimental-vm-modules node_modules/jest/bin/jest.js --watch","test:coverage":"node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage","prepublishOnly":"npm run lint && npm test"},"_npmUser":{"name":"5aleel","email":"khalil.i.awada@gmail.com"},"repository":{"url":"git+https://github.com/KarmatechConsulting/google-calendar-client.git","type":"git"},"_npmVersion":"10.8.2","description":"A production-grade Google Calendar API v3 client library with comprehensive support for all resources and methods","directories":{},"_nodeVersion":"20.19.6","dependencies":{"axios":"^1.6.2","dotenv":"^16.3.1","google-auth-library":"^9.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.0.0","prettier":"^3.1.0","@eslint/js":"^9.0.0","@jest/globals":"^30.2.0","eslint-config-prettier":"^9.1.0"},"_npmOperationalInternal":{"tmp":"tmp/google-calendar-client_1.0.0_1765875434980_0.7614057313329283","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2025-12-16T08:57:14.922Z","modified":"2025-12-16T11:27:17.412Z","1.0.0":"2025-12-16T08:57:15.135Z"},"bugs":{"url":"https://github.com/KarmatechConsulting/google-calendar-client/issues"},"author":{"name":"Your Organization"},"license":"MIT","homepage":"https://github.com/KarmatechConsulting/google-calendar-client#readme","keywords":["google","calendar","api","v3","client","oauth2","events","scheduling"],"repository":{"url":"git+https://github.com/KarmatechConsulting/google-calendar-client.git","type":"git"},"description":"A production-grade Google Calendar API v3 client library with comprehensive support for all resources and methods","maintainers":[{"email":"mustafaabbassabboud@gmail.com","name":"mustafa_abboud"},{"email":"khalil.i.awada@gmail.com","name":"5aleel"},{"email":"loralameh@gmail.com","name":"loralameh"}],"readme":"# Google Calendar API v3 Client Library\n\nA production-grade, feature-complete client library for the Google Calendar API v3, built with clean architecture, strong typing, and comprehensive error handling.\n\n[![Node Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![NPM Version](https://img.shields.io/npm/v/@clinikit.io/google-calendar-client)](https://www.npmjs.com/package/@clinikit.io/google-calendar-client)\n[![CI](https://github.com/KarmatechConsulting/google-calendar-client/actions/workflows/ci.yml/badge.svg)](https://github.com/KarmatechConsulting/google-calendar-client/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/KarmatechConsulting/google-calendar-client/branch/main/graph/badge.svg)](https://codecov.io/gh/KarmatechConsulting/google-calendar-client)\n\n## Features\n\n- ✅ **Complete API Coverage** - All Google Calendar API v3 resources and methods\n- 🔐 **OAuth2 & Service Account** - Multiple authentication methods supported\n- 🔄 **Automatic Retries** - Intelligent retry logic for transient errors\n- 📝 **Type Safety** - JSDoc type definitions for IDE support\n- 🛡️ **Error Handling** - Normalized error responses with detailed context\n- 📊 **Logging** - Configurable logging with custom logger support\n- 🧪 **Well Tested** - Comprehensive unit test coverage\n- 📚 **Examples** - Ready-to-run examples for common use cases\n\n## Supported Resources\n\n- **Events** - Create, read, update, delete, list, search, import, and watch calendar events\n- **Calendars** - Manage calendar metadata and settings\n- **Calendar List** - Manage user's calendar list and subscriptions\n- **ACL** - Control access permissions for calendars\n- **Freebusy** - Query availability across multiple calendars\n- **Colors** - Get available calendar and event colors\n- **Settings** - Manage user settings\n- **Channels** - Set up and manage webhook notifications\n\n## Installation\n\n```bash\nnpm install @clinikit.io/google-calendar-client\n```\n\n## Quick Start\n\n### 1. Set Up OAuth2 Credentials\n\nFirst, create OAuth2 credentials in the [Google Cloud Console](https://console.cloud.google.com/):\n\n1. Create a new project or select an existing one\n2. Enable the Google Calendar API\n3. Create OAuth2 credentials (Client ID and Client Secret)\n4. Add authorized redirect URIs\n\n### 2. Initialize the Client\n\n```javascript\nimport { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';\n\nconst client = new GoogleCalendarClient({\n  credentials: {\n    clientId: 'your-client-id',\n    clientSecret: 'your-client-secret',\n    redirectUri: 'http://localhost:3000/callback',\n  },\n  tokens: {\n    accessToken: 'your-access-token',\n    refreshToken: 'your-refresh-token',\n    expiresAt: Date.now() + 3600000,\n  },\n});\n```\n\n### 3. Use the Client\n\n```javascript\n// List upcoming events\nconst events = await client.events.list('primary', {\n  timeMin: new Date().toISOString(),\n  maxResults: 10,\n  singleEvents: true,\n  orderBy: 'startTime',\n});\n\nconsole.log('Upcoming events:');\nevents.items.forEach((event) => {\n  console.log(`${event.summary} - ${event.start.dateTime || event.start.date}`);\n});\n```\n\n## Authentication\n\n### OAuth2 Flow\n\nThe library provides a complete OAuth2 authentication flow:\n\n```javascript\nimport { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';\n\nconst client = new GoogleCalendarClient({\n  credentials: {\n    clientId: 'your-client-id',\n    clientSecret: 'your-client-secret',\n    redirectUri: 'http://localhost:3000/callback',\n  },\n});\n\n// Step 1: Get authorization URL\nconst authUrl = client.getAuthorizationUrl({\n  scope: 'https://www.googleapis.com/auth/calendar',\n  accessType: 'offline',\n  prompt: 'consent',\n});\n\nconsole.log('Visit this URL to authorize:', authUrl);\n\n// Step 2: Exchange authorization code for tokens\nconst tokens = await client.exchangeCodeForToken(authorizationCode);\n\n// Tokens are automatically stored and refreshed as needed\n```\n\nSee [examples/auth.js](examples/auth.js) for a complete authentication example.\n\n### Token Management\n\nThe library handles token refresh automatically:\n\n```javascript\n// Tokens are refreshed automatically when they expire\nconst events = await client.events.list('primary');\n\n// Manually set tokens\nawait client.setTokens({\n  accessToken: 'new-access-token',\n  refreshToken: 'new-refresh-token',\n  expiresAt: Date.now() + 3600000,\n});\n\n// Check authentication status\nconst isAuthenticated = await client.isAuthenticated();\n\n// Revoke access\nawait client.revokeAccess();\n```\n\n## Service Account Authentication\n\nFor server-to-server API access without user interaction, use service account authentication. This is ideal for backend services, automated tasks, and scheduled jobs.\n\n### Setting Up Service Account\n\n1. **Create Service Account** in [Google Cloud Console](https://console.cloud.google.com/iam-admin/serviceaccounts):\n   - Go to IAM & Admin > Service Accounts\n   - Click \"Create Service Account\"\n   - Name your service account and grant appropriate roles\n2. **Download Credentials**:\n   - Click on the created service account\n   - Go to Keys tab\n   - Click \"Add Key\" > \"Create new key\"\n   - Choose JSON format\n   - Save the downloaded file securely\n\n3. **Enable Calendar API**:\n   - Go to APIs & Services > Library\n   - Search for \"Google Calendar API\"\n   - Click \"Enable\"\n\n4. **(Optional) Configure Domain-Wide Delegation** for Google Workspace:\n   - In service account details, copy the \"Client ID\"\n   - Go to Google Workspace Admin Console\n   - Navigate to Security > Access and data control > API Controls\n   - Click \"Manage Domain Wide Delegation\"\n   - Add the Client ID with required scopes:\n     - `https://www.googleapis.com/auth/calendar`\n\n### Using Service Account\n\n#### Basic Usage\n\n```javascript\nimport { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';\n\nconst client = new GoogleCalendarClient({\n  auth: {\n    type: 'service_account',\n    keyFilePath: './service-account-key.json',\n  },\n});\n\n// Use the client - no OAuth flow needed!\nconst events = await client.events.list('primary', {\n  timeMin: new Date().toISOString(),\n  maxResults: 10,\n});\n```\n\n#### Using Credentials Object\n\n```javascript\n// Load credentials from environment variables or secret manager\nconst client = new GoogleCalendarClient({\n  auth: {\n    type: 'service_account',\n    credentials: {\n      type: 'service_account',\n      project_id: process.env.GCP_PROJECT_ID,\n      private_key: process.env.GCP_PRIVATE_KEY.replace(/\\\\n/g, '\\n'),\n      client_email: process.env.GCP_CLIENT_EMAIL,\n      client_id: process.env.GCP_CLIENT_ID,\n      token_uri: 'https://oauth2.googleapis.com/token',\n    },\n  },\n});\n```\n\n#### Domain-Wide Delegation (Impersonation)\n\nFor Google Workspace, impersonate users to access their calendars:\n\n```javascript\n// Initialize with a specific user to impersonate\nconst client = new GoogleCalendarClient({\n  auth: {\n    type: 'service_account',\n    keyFilePath: './service-account-key.json',\n    subject: 'user@example.com', // User to impersonate\n  },\n});\n\n// Access user's calendar\nconst events = await client.events.list('primary');\n\n// Switch to different user\nclient.setSubject('another-user@example.com');\nconst moreEvents = await client.events.list('primary');\n```\n\n#### Custom Scopes\n\n```javascript\nconst client = new GoogleCalendarClient({\n  auth: {\n    type: 'service_account',\n    keyFilePath: './service-account-key.json',\n    scopes: [\n      'https://www.googleapis.com/auth/calendar.readonly',\n      'https://www.googleapis.com/auth/calendar.events.readonly',\n    ],\n  },\n});\n```\n\n#### Using Environment Variables (Recommended for Production)\n\nLoad credentials from environment variables instead of JSON files:\n\n```javascript\nimport { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';\nimport { config } from 'dotenv';\n\n// Load .env file\nconfig();\n\n// Initialize with environment variables\nconst client = new GoogleCalendarClient({\n  auth: {\n    type: 'service_account',\n    useEnv: true, // Loads from GOOGLE_SERVICE_ACCOUNT_* env vars\n  },\n});\n```\n\nRequired environment variables in `.env`:\n\n```env\nGOOGLE_SERVICE_ACCOUNT_PROJECT_ID=your-project-id\nGOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=\"-----BEGIN PRIVATE KEY-----\\nYOUR_KEY\\n-----END PRIVATE KEY-----\\n\"\nGOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com\nGOOGLE_SERVICE_ACCOUNT_CLIENT_ID=123456789\n\n# Optional: for domain-wide delegation\nGOOGLE_SERVICE_ACCOUNT_SUBJECT=user@example.com\n```\n\nSee [examples/service-account-env.js](examples/service-account-env.js) for complete environment variable examples.\n\n### OAuth2 vs Service Account\n\n| Feature                | OAuth2                                | Service Account              |\n| ---------------------- | ------------------------------------- | ---------------------------- |\n| User Interaction       | Required (one-time authorization)     | Not required                 |\n| Use Case               | User-facing applications              | Backend services, automation |\n| Setup Complexity       | Medium (redirect URI, consent screen) | Low (just download keyfile)  |\n| Token Management       | Refresh tokens needed                 | Automatic JWT generation     |\n| Domain-Wide Delegation | Not applicable                        | Available for Workspace      |\n| Best For               | Web apps, mobile apps                 | Servers, cron jobs, scripts  |\n\nSee [examples/service-account.js](examples/service-account.js) for complete service account examples.\n\n### Custom Token Storage\n\nImplement custom token storage for production environments:\n\n```javascript\nimport { GoogleCalendarClient } from '@clinikit.io/google-calendar-client';\n\nclass DatabaseTokenStore {\n  async getToken(userId) {\n    // Retrieve token from database\n    return await db.tokens.findOne({ userId });\n  }\n\n  async saveToken(userId, token) {\n    // Save token to database\n    await db.tokens.upsert({ userId }, token);\n  }\n\n  async deleteToken(userId) {\n    // Delete token from database\n    await db.tokens.delete({ userId });\n  }\n}\n\nconst client = new GoogleCalendarClient({\n  credentials: {\n    /* ... */\n  },\n  tokenStore: new DatabaseTokenStore(),\n  userId: 'user-123',\n});\n```\n\n## Usage Examples\n\n### Events\n\n#### List Events\n\n```javascript\nconst events = await client.events.list('primary', {\n  timeMin: new Date().toISOString(),\n  timeMax: new Date('2024-12-31').toISOString(),\n  maxResults: 100,\n  singleEvents: true,\n  orderBy: 'startTime',\n  q: 'meeting', // Search term\n});\n```\n\n#### Create Event\n\n```javascript\nconst event = await client.events.insert('primary', {\n  summary: 'Team Meeting',\n  description: 'Weekly sync',\n  location: 'Conference Room A',\n  start: {\n    dateTime: '2024-06-15T10:00:00-07:00',\n    timeZone: 'America/Los_Angeles',\n  },\n  end: {\n    dateTime: '2024-06-15T11:00:00-07:00',\n    timeZone: 'America/Los_Angeles',\n  },\n  attendees: [{ email: 'alice@example.com' }, { email: 'bob@example.com' }],\n  reminders: {\n    useDefault: false,\n    overrides: [\n      { method: 'email', minutes: 1440 },\n      { method: 'popup', minutes: 30 },\n    ],\n  },\n});\n```\n\n#### Update Event\n\n```javascript\n// Full update\nconst updated = await client.events.update('primary', eventId, {\n  summary: 'Updated Meeting Title',\n  start: { dateTime: '2024-06-15T14:00:00-07:00' },\n  end: { dateTime: '2024-06-15T15:00:00-07:00' },\n});\n\n// Partial update (patch)\nconst patched = await client.events.patch('primary', eventId, {\n  summary: 'New Title Only',\n});\n```\n\n#### Delete Event\n\n```javascript\nawait client.events.delete('primary', eventId, {\n  sendUpdates: 'all', // Notify attendees\n});\n```\n\n#### Quick Add\n\n```javascript\nconst event = await client.events.quickAdd('primary', 'Lunch with John tomorrow at 12pm');\n```\n\n### Calendars\n\n#### List Calendars\n\n```javascript\nconst calendars = await client.calendarList.list({\n  maxResults: 50,\n  showHidden: false,\n});\n\ncalendars.items.forEach((calendar) => {\n  console.log(`${calendar.summary} (${calendar.id})`);\n});\n```\n\n#### Create Calendar\n\n```javascript\nconst calendar = await client.calendars.insert({\n  summary: 'Project Tasks',\n  description: 'Track project tasks and deadlines',\n  timeZone: 'America/New_York',\n});\n```\n\n#### Update Calendar\n\n```javascript\nconst updated = await client.calendars.patch(calendarId, {\n  summary: 'New Calendar Name',\n});\n```\n\n#### Delete Calendar\n\n```javascript\nawait client.calendars.delete(calendarId);\n```\n\n### Free/Busy\n\n```javascript\nconst freebusy = await client.freebusy.query({\n  timeMin: '2024-06-15T00:00:00Z',\n  timeMax: '2024-06-15T23:59:59Z',\n  items: [{ id: 'primary' }, { id: 'calendar2@example.com' }],\n});\n\nObject.entries(freebusy.calendars).forEach(([calendarId, calendar]) => {\n  console.log(`${calendarId}:`);\n  calendar.busy.forEach((period) => {\n    console.log(`  Busy: ${period.start} to ${period.end}`);\n  });\n});\n```\n\n### Watch for Changes\n\n```javascript\nconst channel = await client.events.watch('primary', {\n  id: crypto.randomUUID(),\n  type: 'web_hook',\n  address: 'https://your-domain.com/webhook',\n  token: 'verification-token',\n  expiration: Date.now() + 24 * 60 * 60 * 1000, // 24 hours\n});\n\n// Later, stop watching\nawait client.channels.stop({\n  id: channel.id,\n  resourceId: channel.resourceId,\n});\n```\n\n### ACL Management\n\n```javascript\n// List ACL rules\nconst acl = await client.acl.list('primary');\n\n// Grant access\nawait client.acl.insert('primary', {\n  scope: {\n    type: 'user',\n    value: 'user@example.com',\n  },\n  role: 'writer', // none, freeBusyReader, reader, writer, owner\n});\n\n// Remove access\nawait client.acl.delete('primary', ruleId);\n```\n\n## Configuration\n\n### Client Options\n\n```javascript\nconst client = new GoogleCalendarClient({\n  // Required: OAuth2 credentials\n  credentials: {\n    clientId: 'your-client-id',\n    clientSecret: 'your-client-secret',\n    redirectUri: 'http://localhost:3000/callback',\n  },\n\n  // Optional: Initial tokens\n  tokens: {\n    accessToken: 'access-token',\n    refreshToken: 'refresh-token',\n    expiresAt: 1234567890000,\n  },\n\n  // Optional: Custom token store\n  tokenStore: new CustomTokenStore(),\n\n  // Optional: User identifier for token storage\n  userId: 'user-123',\n\n  // Optional: API configuration\n  baseURL: 'https://www.googleapis.com/calendar/v3',\n  defaultCalendar: 'primary',\n  defaultTimeZone: 'America/New_York',\n  maxResults: 250,\n\n  // Optional: HTTP configuration\n  timeout: 30000,\n  maxRetries: 3,\n  headers: {\n    'X-Custom-Header': 'value',\n  },\n\n  // Optional: Custom logger\n  logger: (level, message, meta) => {\n    console.log(`[${level}] ${message}`, meta);\n  },\n\n  // Optional: User agent\n  userAgent: 'MyApp/1.0.0',\n});\n```\n\n## Error Handling\n\nThe library provides comprehensive error handling:\n\n```javascript\nimport {\n  GoogleCalendarError,\n  AuthenticationError,\n  ValidationError,\n} from '@clinikit.io/google-calendar-client';\n\ntry {\n  await client.events.insert('primary', eventData);\n} catch (error) {\n  if (error instanceof AuthenticationError) {\n    console.error('Authentication failed:', error.message);\n    // Re-authenticate\n  } else if (error instanceof ValidationError) {\n    console.error('Invalid data:', error.invalidFields);\n  } else if (error instanceof GoogleCalendarError) {\n    console.error(`API Error (${error.statusCode}):`, error.message);\n    console.error('Error code:', error.code);\n\n    if (error.isRetryable()) {\n      // Retry the request\n    }\n  }\n}\n```\n\n## Testing\n\nRun the test suite:\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Run tests with coverage\nnpm run test:coverage\n```\n\n## Examples\n\nCheck out the [examples](examples/) directory for complete working examples:\n\n- [auth.js](examples/auth.js) - OAuth2 authentication flow\n- [events.js](examples/events.js) - Creating and managing events\n- [calendars.js](examples/calendars.js) - Calendar management\n- [freebusy.js](examples/freebusy.js) - Querying availability\n- [watch.js](examples/watch.js) - Setting up webhooks\n\n## API Reference\n\n### GoogleCalendarClient\n\nMain client class that provides access to all API resources.\n\n#### Properties\n\n- `events` - EventsClient instance\n- `calendars` - CalendarsClient instance\n- `calendarList` - CalendarListClient instance\n- `acl` - AclClient instance\n- `channels` - ChannelsClient instance\n- `colors` - ColorsClient instance\n- `freebusy` - FreebusyClient instance\n- `settings` - SettingsClient instance\n\n#### Methods\n\n- `getAuthorizationUrl(options)` - Generate OAuth2 authorization URL\n- `exchangeCodeForToken(code)` - Exchange authorization code for tokens\n- `setTokens(tokens)` - Set tokens manually\n- `revokeAccess()` - Revoke access and clear tokens\n- `isAuthenticated()` - Check if user is authenticated\n\nFor detailed API documentation, see the JSDoc comments in the source code.\n\n## Contributing\n\nContributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on:\n\n- Development setup with Dev Container\n- Code style and testing guidelines\n- Pull request process\n- Reporting issues\n\n## Publishing\n\nFor maintainers: See [Publishing Guide](PUBLISHING.md) for instructions on releasing new versions to NPM.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/KarmatechConsulting/google-calendar-client/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/KarmatechConsulting/google-calendar-client/discussions)\n- **Documentation**: [Google Calendar API Reference](https://developers.google.com/calendar/api/v3/reference)\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for version history and release notes.\n","readmeFilename":"README.md"}