ヘルプ

対応範囲と制限

Calendarpit が対応している機能、対象外の機能、および現在のプロジェクト状況について説明します。

Calendarpit は、ローカルで動く Google Calendar 互換の API・OAuth サーバーです。本物の Google アカウントや Google Cloud プロジェクト、Google へのネットワーク接続なしで、アプリの開発やテストができます。

ローカル開発、CI、E2E テストに必要な範囲で、次の機能のサブセットを実装しています。

  • Google Calendar API v3
  • OAuth 2.0
  • 差分同期
  • Webhook 通知

対応している機能

このセクションの機能はすべて実装済みです。

実行環境と状態管理

  • 単一の Bun プロセスが、API、OAuth フロー、管理画面を提供します。
  • デフォルトのアドレスは http://127.0.0.1:4173 です。
  • ストレージには SQLite または :memory: を使います。

起動と設定とストレージと再起動を参照してください。

テストユーザーとカレンダー

  • テストユーザーはパスワードなしで使え、カレンダーを所有します。
  • 各カレンダーは IANA タイムゾーンを持ちます。
  • 各ユーザーのプライマリカレンダーには primary でアクセスできます。
  • カレンダー情報は calendars.get で読み取ります。
  • ユーザーごとのカレンダーリストは calendarList(list、get、insert、patch、update、delete)で管理します。

ユーザーごとのリスト設定には、次のものがあります。

  • summaryOverride
  • colorId、または colorRgbFormat によるカスタム RGB
  • hidden と selected
  • defaultReminders
  • notificationSettings
  • プライマリ以外の所有カレンダーの、リストからの削除と復元

イベントと空き状況

  • イベントの CRUD: list、get、insert、update、patch、delete、instances
  • 例外(個別に変更された回)を含む繰り返しイベント。RRULE・EXRULE・RDATE・EXDATE のサブセットに対応
  • 夏時間(DST)を考慮した [start, end) 区間
  • ETag と拡張プロパティ
  • ローカルでの招待と出欠回答(RSVP)
  • リマインダーの保存
  • 擬似的な hangoutsMeet リンク
  • freebusy.query

COUNT も UNTIL もない繰り返しの系列は、終わりがありません。カレンダーにこの系列が含まれる場合、timeMin または singleEvents=true を使って一覧取得・展開するときは timeMax が必須です。

Calendar API の互換性とイベント、繰り返し、時刻の扱いを参照してください。

OAuth

  • テストユーザーを選べるローカル同意画面
  • 承認と拒否、および state の保持
  • redirect_uri の完全一致チェック
  • S256 PKCE による認可コード交換
  • スコープの検証
  • リフレッシュトークン、/userinfo、トークンの失効

ローカル OAuthを参照してください。

差分同期

  • events.list での nextSyncToken と syncToken
  • ページネーション中の固定スナップショット
  • status: "cancelled" の削除済みレコード
  • 410 fullSyncRequired レスポンス

差分同期を参照してください。

Watch

  • events.watch、calendarList.watch、channels.stop
  • sync と exists の Webhook
  • コールバック先のホスト許可リスト
  • 最大 3 回の配信試行
  • チャネルの有効期限
  • POST /__calendarpit/deliveries/drain

watch 通知を参照してください。

管理画面

  • 日表示と週表示
  • 基本的なイベントエディタ
  • テストユーザーとカレンダーの管理
  • OAuth 接続の失効
  • watch チャネルと配信ログの確認
  • マスク処理済みのリクエスト履歴
  • Fixture の読み込みとリセット操作

テスト制御

  • JSON 形式の起動時 Fixture。固定 ID も任意で指定できます。
  • /__calendarpit/* の管理 API エンドポイント。状態の確認、Fixture の読み込み、リセット基準(起動時の状態)へのリセット、データ管理ができます。

Fixtureとテスト制御 APIを参照してください。

動作の保証

デフォルトでループバックにバインド

  • --host または CALENDARPIT_HOST を指定しない限り、サーバーは 127.0.0.1 にバインドします。
  • Dockerfile は、コンテナ内で明示的に 0.0.0.0 にバインドします。
  • Webhook のコールバック先は、CALENDARPIT_WATCH_HOSTS を設定しない限りループバックホストだけです。

未対応機能に対する明示的なエラー

未対応の機能には、明示的なエラーを返します。

リクエストステータスエラー
未対応の Calendar API エンドポイント501reason: "unsupportedFeature"
未対応のクエリパラメータ・フィールド・繰り返しルール400reason: "unsupportedFeature"
events.import404notFound
text パラメータ付きの events.quickAdd400unsupportedFeature
text なしの events.quickAdd404notFound
未対応のパラメータを含む OAuth 認可リクエスト400error: "unsupported_feature"
未対応の OAuth エンドポイント501error: "unsupportedFeature"

未対応の繰り返しルールは 400 unsupportedFeature で拒否します。ルールを無視して単発イベントとして保存することはありません。

Google への通信なし

  • Calendarpit が Google に API、OAuth、Webhook のリクエストを送ることはありません。
  • 管理画面は Google Fonts から Roboto Mono フォントを読み込みます。システムフォントへのフォールバックがあります。

再現可能なリセット

POST /__calendarpit/reset は、起動時 Fixture を同じ ID とカレンダーリストの ETag で復元します。次のものを消去します。

  • トークン
  • watch チャネル
  • リクエスト履歴
  • カレンダーリストの設定
  • カレンダーの削除済みレコード
  • 各種変更

再起動時の動作はストレージによって異なります。

  • SQLite: リセット基準、カレンダーリストの設定、削除済みレコードは再起動後も残ります。
  • :memory:: 再起動をまたいで同じ ID を使うには、Fixture で固定 ID を指定してください。

対象外の機能

次の機能は実装していません。

ACL、共有カレンダー、委任

  • テストユーザーがアクセスできるのは、自分が所有するカレンダー(accessRole: "owner")だけです。
  • すべての acl.* メソッドは 501 unsupportedFeature を返します。
  • calendarList.insert は、calendarList.delete でリストから外した所有カレンダーを戻すだけです。
    • 新しいカレンダーの作成や、他ユーザーのカレンダーの購読はしません。
    • 対象のカレンダー(primary を含む)がすでにリストにある場合は 409 duplicate を返します。

ユーザー設定、ACL とユーザー設定の watch、カレンダーリストの同期トークン

次のものには対応していません。

  • すべての settings.* メソッドは 501 unsupportedFeature を返します。
  • ACL とユーザー設定の watch 購読(acl.watch、settings.watch)は 501 unsupportedFeature を返します。
  • calendarList.list は nextSyncToken を発行しません。syncToken を指定すると 400 unsupportedFeature で拒否します。

calendarList.watch は、所有ユーザーのカレンダーリストを対象に実装しています。ただし次の制限があります。

  • params オブジェクトを指定すると 400 unsupportedFeature で拒否します。
  • exists を送るのは、保存済みのリスト設定を変える書き込みがあったときだけです。
  • 管理 API でそのユーザーのカレンダーを作成・更新・削除したときも exists を送ります。

showDeleted=true を指定した場合は次のとおりです。

  • calendarList.delete で外したエントリは、保存済みの設定を保持します。
  • 管理 API で削除したカレンダーの削除済みレコードは、デフォルト設定で表示されます。削除時にプライマリだった場合は primary: true を保持します。

カレンダーの書き込み、カラー定義、events.import / quickAdd / move

次のメソッドは実装していません。

  • calendars.insert、update、patch、delete、clear、transferOwnership
  • colors.get
  • events.import、quickAdd、move

カレンダーの作成・変更・削除は、管理画面または管理 API で行ってください。詳細はCalendar API の互換性を参照してください。

実際の招待メールとリマインダーメールの送信

  • sendUpdates はメールを送らず、送信対象となる通知レコードを /__calendarpit/state に記録します。
  • イベントのリマインダー、calendarList の defaultReminders と notificationSettings は保存されます。ただし通知の発火やメール送信はしません。
  • notificationSettings は、重複する通知 type 値を 400 invalidParameter で拒否します。

実際の Google Meet 会議

会議作成リクエストは、再現可能な https://meet.calendarpit.invalid/<id> の URL を生成します。実際のオンライン会議は作成しません。

完全な OIDC

次のものには対応していません。

  • パスワード認証
  • 実際の Google ログイン
  • id_token の発行
  • JWKS・ディスカバリエンドポイント

他プロトコルおよび実際の Google Calendar との同期

Microsoft Graph、CalDAV、実際の Google Calendar との同期は対象外です。

管理画面でのドラッグによるイベント操作

  • ドラッグによるイベントの移動や時間変更は実装していません。
  • 管理画面のカレンダー表示では、繰り返しの系列(展開した各回ではなく親イベント)を開始日にだけ表示します。保存済みの例外は、それぞれの該当日に表示します。
  • 管理画面のエディタは基本フィールドだけを扱います。

管理画面のエディタでイベントを保存すると、基本フィールドだけで上書きします。次のものは削除されます。

  • 繰り返し設定(保存済みの例外もキャンセルされます)
  • 参加者(招待コピーもキャンセルされます)
  • 会議データ
  • 色
  • 公開範囲

カスタムリマインダーはデフォルト(reminders: { useDefault: true })に戻ります。これらのフィールドは API で設定してください。

Fixture は、指定したフィールドをそのまま保存します。招待コピーや擬似的な会議リンクは生成しません。詳細はFixtureを参照してください。

Calendarpit で再現できるワークフロー

Calendarpit では、次の E2E の連携ワークフローを再現できます。Google SDK を使ったサンプルフローはSDK の使用例を参照してください。

  1. ローカルの同意画面でテストユーザーとして認可し、カレンダーを選びます。
  2. events.watch チャネルを登録し、初回の sync 通知を受け取ります。
  3. イベントを作成し、freebusy.query で busy 区間を確認します。
  4. イベントを更新・削除し、exists 通知を受け取って状態を再取得します。
  5. channels.stop で watch チャネルを停止し、以降の変更が配信されないことを確認します。
  6. 接続を失効させ、OAuth フローで再接続します。
  7. 同意画面で拒否し、state が保持され、既存のトークンが失われないことを確認します。
  8. POST /__calendarpit/reset でリセットし、同じ Fixture と ID でフローを繰り返します。
  9. events.list でフル同期のスナップショットを取得します。その後 syncToken で、変更差分と status: "cancelled" の削除済みレコードを取得します。
  10. 終日イベント(dateTime: null を含む)、繰り返しイベントの例外、ローカルでの出欠回答(RSVP)、擬似的な会議リンクを検証します。

現在のステータス

  • 配布: Docker イメージ、Homebrew Tap、単体実行ファイルを公開しています。導入方法はインストールを参照してください。
  • 単体実行ファイル: Bun、API、管理画面を内蔵します。配布対象は macOS arm64/x64、Linux glibc arm64/x64、Windows x64 です。公開前に各環境で検証します。
  • Docker: 非 root ユーザー、永続ボリューム、ヘルスチェック、メモリモードを設定しています。リリース処理では、amd64/arm64 の起動と保存データのライフサイクルを検証します。

目次