@crvouga/mockingbird-service-google-日历
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
状态模拟器 谷歌日历 v3 财务报告和审定财务报表 Google OAuth 2.0 (英语) 测试套房,涵盖什么
我们的EMR后端呼叫: calendarList.list, (中文(简体) ), calendars.insert, (中文(简体) ), events.list (时间窗口,
q, (中文(简体) ), orderBy,呼号,与 410 同步递增 fullSyncRequired, (中文(简体) ), events.get/insert/ update/delete, (中文(简体) ), events.watch 将通知推到频道的地址
channels.stop;加符号终点(授权代码和刷新赠款),撤销,以及
OpenID 用户信息 。 从业人员连接、同步EMR任命并接受日历推
没有谷歌的账户.
- 行动范围: 支助
- 合同
openapi.yaml从Google的日历 v3 发现文档中修剪 OAuth 文档到什么google-calendar-service.ts, (中文(简体) ),authorize.business.ts和网络 控制器的使用.
安装
npm install -D @crvouga/mockingbird-service-google-calendar
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-google-calendar serve, (中文(简体) ), createServer 从 ./server (节点),或
createRuntime 与任何获取服务器.
使用量
接合( 应用程序的硬码今天 Google ): 给日历客户端一个 rootUrl
(单位:千美元)google.calendar({version: "v3", auth, rootUrl: "<emulator>/"})),给出 OAuth2Client
endpoints: {oauth2TokenUrl: "<emulator>/token", oauth2RevokeUrl: "<emulator>/revoke"},并点
用户信息获取到 <emulator>/oauth2/v3/userinfo。 。 。 . GOOGLE_WEBHOOK_URL 可以保持原样:仿真者
帖子推向任何东西 address 应用程序注册(允许http,除非
--require-https-webhooks) (中文(简体) ).
npx mockingbird-google-calendar serve --port 8820 --client "$GOOGLE_CLIENT_ID:$GOOGLE_CLIENT_SECRET"
import { auth, calendar } from "@googleapis/calendar"
import { OAuth2Client } from "google-auth-library"
import { createServer } from "@crvouga/mockingbird-service-google-calendar/server"
const google = await createServer()
// The application's OAuth and Calendar clients. Only their URLs change.
const oauth = new OAuth2Client({
clientId: "c",
clientSecret: "s",
redirectUri: "postmessage",
endpoints: { oauth2TokenUrl: `${google.url}/token`, oauth2RevokeUrl: `${google.url}/revoke` },
})
// Authorization code "4/mock-<name>" signs in <name>@example.com ("4/mock-<email>" for others).
const { tokens } = await oauth.getToken("4/mock-dr.house")
const client = new auth.OAuth2()
client.setCredentials({ access_token: tokens.access_token ?? null })
const cal = calendar({ version: "v3", auth: client, rootUrl: `${google.url}/` })
await cal.events.insert({
calendarId: "primary",
requestBody: { summary: "Rounds", start: { dateTime: "2026-10-01T15:00:00Z" }, end: { dateTime: "2026-10-01T16:00:00Z" } },
})
await google.close()
在Google的UI(admin路由)中创建的事件
import { auth, calendar } from "@googleapis/calendar"
import { OAuth2Client } from "google-auth-library"
import { createServer } from "@crvouga/mockingbird-service-google-calendar/server"
const google = await createServer()
// Test control: the practitioner adds an event in Google's UI.
await fetch(`${google.url}/__admin/events`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
email: "[email protected]",
event: { summary: "Rounds", start: { dateTime: "2026-10-01T15:00:00Z" }, end: { dateTime: "2026-10-01T16:00:00Z" } },
}),
})
// The application lists it through the Calendar client.
const oauth = new OAuth2Client({
clientId: "c",
clientSecret: "s",
redirectUri: "postmessage",
endpoints: { oauth2TokenUrl: `${google.url}/token` },
})
const { tokens } = await oauth.getToken("4/mock-dr.house")
const client = new auth.OAuth2()
client.setCredentials({ access_token: tokens.access_token ?? null })
const cal = calendar({ version: "v3", auth: client, rootUrl: `${google.url}/` })
const { data } = await cal.events.list({ calendarId: "primary" })
console.log(data.items?.map((event) => event.summary)) // ["Rounds"]
await google.close()
路线
| 路线 | 行为 |
|---|---|
POST /token | 格式编码( E)client_secret_post 或基础). authorization_code数字 : 4/mock-<name or email> → {access_token, expires_in: 3599, refresh_token, scope, token_type, id_token}; 代码是单用; 其他的都是400 invalid_grant。 。 。 . refresh_token + 一个新的访问标志(+ id_token); 被吊销或外国令牌 invalid_grant。未知客户端(与 clients 套) 401 (简体中文) invalid_client。 。 。 . |
POST /revoke?token= | 撤销访问或刷新令牌; 未知 / 已取消 400 invalid_token。 。 。 . |
GET /oauth2/v3/userinfo | {sub, email, email_verified, name, given_name, family_name, picture} (来自电子邮件,或与 PUT /__admin/users/:email) (中文(简体) ). |
GET /calendar/v3/users/me/calendarList | 该账户的主要日历(id = mail)及其次要日历. |
POST /calendar/v3/calendars | 创建次要日历( N)…@group.calendar.google.com) (中文(简体) ). |
GET /calendar/v3/calendars/{id}/events | timeMin编号 :timeMax (重叠), q, (中文(简体) ), showDeleted, (中文(简体) ), singleEvents, (中文(简体) ), orderBy (单位:千美元)startTime 需求 singleEvents, (中文(简体) ), updatedMin, (中文(简体) ), maxResults ( nextPageToken; 最后一页带有 nextSyncToken (不与 q编号 :orderBy编号 :updatedMin) (中文(简体) ). syncToken 返回后仅更改,删除为 {id, status: "cancelled"}; 与窗口或 q 400;无效或无效是410 fullSyncRequired。 。 。 . |
POST …/events, (中文(简体) ), GET/PUT/DELETE …/events/{eventId} | Base32hex ids(允许客户身份;重复409). 缺少起始/结束 400, 空区域 400 timeRangeEmpty。 。 。 . PUT 替换(时间移动时序列+1). DELETE 204,还是410 deleted。 。 。 . |
POST …/events/watch | {id, type: "web_hook", address, token?, expiration?} → {kind: "api#channel", id, resourceId, resourceUri, expiration} (封顶30天). A 类 sync 立即推进 复制活道ids为400. |
POST /calendar/v3/channels/stop | {id, resourceId} ^ 204;未知为404. |
错误使用 Google 的信封 {error: {errors: [{domain, reason, message}], code, message, status?}}。 。 。 .
无效或过期的访问令牌为 401 authError (用户信息 : invalid_request) (中文(简体) ).
推动通知
每次更改日历事件( 通过 API 或 管理员平面) 都会张贴到每个直播
该日历上的频道: 空正文 X-Goog-Channel-ID, (中文(简体) ), X-Goog-Channel-Token (当
设定), X-Goog-Channel-Expiration (RFC 1123), (中文(简体) ), X-Goog-Message-Number (1个) sync,然后为+1,
X-Goog-Resource-ID, (中文(简体) ), X-Goog-Resource-URI 财务报告和审定财务报表 X-Goog-Resource-State (单位:千美元)sync,则
exists。停止或过期的(模拟时钟)频道获得什么也没有。 非-2xx 答案被重审
(一等会,一等会,一等会,一等会,一等会). GET /__admin/webhooks * 清单交付,以及
/__admin/webhooks/events, (中文(简体) ), …/replay, (中文(简体) ), …/flush 工作如常.
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
POST /__admin/events | {email, calendarId?, event}:创建一个事件,因为账户会出现在Google的UI(pushes)中. |
PUT /__admin/events/:id | {email, calendarId?, event}:替换(pushes). |
DELETE /__admin/events/:id?email=&calendarId= | 删除(pushes). |
GET /__admin/events?email= | 被存储的事件(带有更改序列). |
PUT /__admin/users/:email | 设置用户信息配置 . |
GET /__admin/channels | 每道有其消息号,已失效并停旗. |
POST /__admin/sync-tokens/invalidate | 至今为止所有发行的同步符号都回答410. |
GET/PUT /__admin/settings | {clients?, tokenTtlSeconds?, requireHttpsWebhooks?, maxChannelTtlSeconds?, scope?}。 。 。 . |
错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}: invalid_grant, (中文(简体) ),
token_expired, (中文(简体) ), rate_limited (403个上限), too_many_requests (429个),
calendar_api_disabled (403次访问未配置), insufficient_scopes, (中文(简体) ), sync_token_gone, (中文(简体) ),
backend_error (503个), connection_drop, (中文(简体) ), push_duplicate, (中文(简体) ), push_drop. gaxios 重试 429 和
5xx本身,所以通过一个 count 超过其预算(三次检讨).
命名空间
由账号: 访问符携带他们的电子邮件,所以
PUT /__admin/credentials {"credentials": {"[email protected]": "<namespace>"}} 路径
日历和用户信息呼叫. x-mockingbird-namespace 和往常一样 A 类 /__admin/ns/<name> 前缀
用于符号、撤销和用户信息 URL (它们是完整的 URL) 但不用于日历
客户端: googleapis 解析路径与 rootUrl'来源并放下路径前缀.
SDK 软件
测试驱动真正的客户端堆栈 googleapis@149数字 : @googleapis/[email protected] (中文(简体) )
在 googleapis- common 7 / gaxios 6 上生成日历模块; 完整 googleapis 软件包是
~125 MB已解开,因此只安装了模块)并 [email protected]。 。 。 .
故意不模拟
- 经常性活动
recurrence、参与者的答复和电子邮件 请访问链接、 免费/ 繁忙、 ACL 、 颜色和设置 . - 真实的谷歌身份 :
id_tokens是JWT形但与Google的密钥没有签名. X-Goog-Changed(Google为日历事件频道省略)和not_exists各州.
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
GoogleCalendarAPI | 类 | 进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), user(email), (中文(简体) ), ensurePrimary(email), (中文(简体) ), resolveCalendar(email, id), (中文(简体) ), createEvent, (中文(简体) ), updateEvent, (中文(简体) ), deleteEvent, (中文(简体) ), findEvent, (中文(简体) ), notify(calendarId), (中文(简体) ), channels(), (中文(简体) ), events(email?), (中文(简体) ), invalidateSyncTokens()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), settings, (中文(简体) ), onPush, (中文(简体) ), onChannels。 。 。 . |
createRuntime | 函数 | 与全服务合同相仿并推送. 选项 : settings, (中文(简体) ), push: {retryDelaysMs?, fetch?}, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite。 。 。 . |
GOOGLE_CALENDAR_PRESETS | 对象 | 每个命名的断层预设. |
GOOGLE_CALENDAR_NAMESPACE | 字符串 | 服务名称, "google-calendar"。 。 。 . |
DEFAULT_SCOPE | 字符串 | 标志性终点报告的范围 . |
pushHeaders | 函数 | 这个 X-Goog-* 推车通知头. |
issueAccessToken | 函数 | 仿真器接受电子邮件的 Mint 访问令牌 . |
parseToken | 函数 | 解码仿真器访问或刷新令牌 . |
accessTokenCredential | 函数 | 访问令牌所属的账户( 如何将证书映射到命名空间) . |
emailFromCode | 函数 | 账户a 4/mock-… 授权代码标志. |
googleError | 函数 | 构建Google错误信封. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | OpenAPI合同及其操作代号. |
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务过来 node:http; 数据 serve CLI目标(--client, (中文(简体) ), --require-https-webhooks; 第8820号口. |
部分 嘲笑鸟。 。 。 .