はじめに
hkob の雑記録の第510回目(連続83日目)は、昨日設計した Calendar Webhook の実装の第一部を記録しておきます。先に種明かししますが、運用が面倒なことが判明したので 5 年前に使っていた GAS による実装に戻すことにしています。ただ、自分の記録として残しておきたいので、AI とペアプロした実装記録をまとめておきます。長いので、今日は第一部だけ記録します。実装記録は引用の形で、途中で私のコメントを入れます。
第1部: Notion Webhook Worker 作成(Notion Workers テンプレ)
※ moodle webhook と同じ流れ。ここが完了すると、以降の Google 側 watch / 差分取得の受け口(Webhook URL)が確定する。
昨日書いたように OAuth の認証があるので、先に受け口だけ作成しておく必要があります。今日はその受け口を作成するところまでです。
1-0. ローカル準備
- [x] 作業ディレクトリを作成
mkdir -p ~/Dropbox/workers/calendar-webhookcd ~/Dropbox/workers/calendar-webhook実行ログ:
mkdir -p ~/Dropbox/workers/calendar-webhook hkob@hM5Air ~> cd ~/Dropbox/workers/calendar-webhook hkob@hM5Air ~/D/w/calendar-webhook>
フォルダは calendar-webhook としました。
- [x] Workers テンプレを生成
ntn workers new .- 入力: Initialize a git repository? = yes
- 入力: Install dependencies? = yes
実行ログ:
ntn workers new ✔ Directory (/Users/hkob/Library/CloudStorage/Dropbox/workers/calendar-webhook) · . ✔ Template downloaded ✔ Initialize a git repository? · yes ✔ Install dependencies? · yes ✔ Template files extracted ✔ Git repository initialized ✔ Dependencies installed with npm ✔ Worker project created Next steps: 1. ntn workers deploy
workers new は moodle-webhook と同じです。
1-1. Worker 実装(骨格だけ作る)
- [ ]
src/index.tsに Webhook 受信→(後で)Google 差分取得→Notion Tasks upsert を実装- [x] まずは「受信してログが出る」状態まで作る(200/202 を返す)
src/index.ts(初期版):npm run build(結果: エラーなし)
実行ログ:
npm run build > @notionhq/workers-template@0.0.0 build > tscimport { CapabilityContext, WebhookEvent, Worker } from "@notionhq/workers"; /** * Calendar webhook worker (skeleton). * * - Receives Google Calendar push notifications (headers only) * - Logs the notification * - (Later) pulls diffs via Google Calendar API and upserts Notion Tasks * * Note: webhook.execute must return void (or Promise<void>). */ const worker = new Worker(); export default worker; type HeaderMap = Record<string, string | undefined>; function pickGCalHeaders(headers: HeaderMap) { const get = (k: string) => headers[k] ?? headers[k.toLowerCase()]; return { channelId: get("X-Goog-Channel-Id"), resourceId: get("X-Goog-Resource-Id"), resourceState: get("X-Goog-Resource-State"), resourceUri: get("X-Goog-Resource-Uri"), messageNumber: get("X-Goog-Message-Number"), }; } worker.webhook("onCalendarNotification", { title: "Google Calendar push notification → sync Tasks", description: "Receives Google Calendar push notifications and triggers a pull-based sync.", execute: async (events: WebhookEvent[], _context: CapabilityContext) => { for (const ev of events) { const headers = (ev?.headers ?? {}) as HeaderMap; const h = pickGCalHeaders(headers); console.log("[gcal] push", h); } }, });
まずは Webhook を受け取って、ログを表示するだけの実装です。
1-2. 1回 deploy(workers.json 生成 + Webhook URL 確定)
- [x]
ntn workers deploy
- 目的: Worker ID を作成して
workers.jsonを生成(env set の前提)実行ログ:
ntn workers deploy Deploying to workspace: hkob's ambassador workspace ✔ Worker name · calendar-webhook [build:out] Running npm install... [build:out] added 14 packages, and audited 15 packages in 1s [build:out] 2 packages are looking for funding [build:out] run `npm fund` for details [build:out] found 0 vulnerabilities [build:out] Running npm run build... [build:out] > @notionhq/workers-template@0.0.0 build [build:out] > tsc [build:out] Running npm install --omit=dev... [build:out] up to date, audited 9 packages in 367ms [build:out] 2 packages are looking for funding [build:out] run `npm fund` for details [build:out] found 0 vulnerabilities [build:out] Moving package.json... [build:out] Moving package-lock.json... [build:out] Moving node_modules... [build:out] Creating bundle from dist... [build:out] Uploading bundle... [build:out] Bundle upload complete. [build:out] Preparing runtime filesystem for snapshot... ✔ Worker created Webhooks: + onCalendarNotification Webhook URLs: → https://www.notion.so/webhooks/worker/.../onCalendarNotification (onCalendarNotification) To list webhook URLs later, run: ntn workers webhooks list
先に build でエラーがないことを確認したので、deploy もそのまま普通に終わりました。これで、Webhook の URL が確定します。
- [x]
ntn workers webhooks listで Webhook URL を控える
- Webhook URL: https://www.notion.so/webhooks/worker/…./onCalendarNotification
表示された Webhook URL を記録しています。
1-3. 環境変数(後で埋める欄)
- [x]
TASKS_DATA_SOURCE_ID(Tasks の data source id)
- 値:
1f70ce2a-6520-80ce-bc36-000b08bc3b11- 設定コマンド:
ntn workers env set TASKS_DATA_SOURCE_ID=1f70ce2a-6520-80ce-bc36-000b08bc3b11実行ログ:
ntn workers env set TASKS_DATA_SOURCE_ID=1f70ce2a-6520-80ce-bc36-000b08bc3b11 ✔ Set environment variable 'TASKS_DATA_SOURCE_ID’
Tasks データベースの data_source_id を環境変数に設定しました。
- [x]
CALENDAR_ID(同期対象カレンダー ID)
- 値:
....@group.calendar.google.com- 設定コマンド:
ntn workers env set CALENDAR_ID=....@group.calendar.google.com実行ログ:
ntn workers env set CALENDAR_ID=....@group.calendar.google.com ✔ Set environment variable 'CALENDAR_ID'
同様に Google Calendar の ID も環境変数に登録しました。
- [ ] (必要なら)署名/認証用の secret(方式確定後)
ここには記録していませんでしたが、別の部分で設定しています。
- [x]
NOTION_API_TOKEN(Notion API token / integration secret)
- 用途:
context.notion.querySql/context.notion.updatePageなど、Notion への読み書きを行うために必要- 値: (秘匿。ログ/手順書に平文で貼らない)
- 重要:
NOTION_で始まる環境変数はntn workers env setでは設定できない(reserved prefix)設定手順(値は貼らない):
.envに追記
NOTION_API_TOKEN=...ntn workers env push
実行ログ:
ntn workers env push The following changes will be pushed to the remote environment: + NOTION_API_TOKEN ✔ Push changes? · yes ✔ Environment variables pushed successfully注意:
- secret なので、
.envは git 管理しない(.gitignore)- Workers 側の env は Worker 実行時のみ有効(ローカル実行には引き継がれない)
※
context.notionを使う場合のトークン取り扱いは moodle と同様(reserved prefix 注意)。
Webhook の場合には、context.notion の場合でも internal integration key が必要なことが漏れていたので、追加してもらいました。さらに、NOTION_API_TOKEN は ntn コマンドでは設定できません。前回失敗しているのですが、忘れて ntn コマンドを使ってきたので、moodle webhook の時の話をしたら、修正してくれました。
おわりに
GAS による実装に戻すことにしたので、あくまで参考的な記録となります。とはいえ、書かれたソースコードなどは参考になるものもあるので、爪痕だけは残しておきたいと記録に残すことにしました。
https://hkob.notion.site/hkob-16dd8e4e98ab807cbe3cf3cc94cdfe0f?pvs=4hkob.notion.site