@calcom/platform-libraries 版本演进全解析:从事件类型 API 能力增量到发布工作流
【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy
@calcom/platform-libraries是 cal.diy(Cal.com 开源调度平台)中连接核心业务逻辑与 v2 Platform API 的桥梁包:它把@calcom/features、@calcom/lib中的预约、事件类型、排期、日历等能力以可独立版本化的 NPM 包形式对外导出,供apps/api/v2消费。本文以 packages/platform/libraries/CHANGELOG.md 为骨架,逐版本梳理该包的能力增量——尤其是事件类型(Event-Type)API 对 Booker Layouts、颜色、确认策略、Seats、周期预约与预订限制等高级属性的支持——并结合仓库源码与配置,讲清它的版本发布工作流与底层实现原理。读完你将掌握:platform-libraries 如何演进、每个版本到底带来了哪些可用的 API 能力、以及如何在本地开发与发布流程中正确使用它。
一、包定位:platform-libraries 是什么
从 package.json 可以看到,该包以@calcom/platform-libraries为名,版本号在仓库内固定为0.0.0,仅在发布时被替换为真实版本。它的构建产物输出到dist/,通过exports字段对外暴露了 13 个入口子模块:
| 子模块 | 对应源文件 | 典型能力 |
|---|---|---|
.(主入口) | index.ts | 聚合导出 |
./event-types | event-types.ts | 事件类型创建/更新/查询、EventManager 等 |
./bookings | bookings.ts | 预订创建、处理 |
./schedules/./slots | schedules.ts / slots.ts | 排期与空闲时段 |
./calendars/./app-store | calendars.ts / app-store.ts | 日历连接与应用市场 |
./emails/./conferencing/./repositories/./organizations/./private-links/./errors/./tasker | 对应同名文件 | 邮件、会议、仓储、组织、私链、错误、任务器 |
依赖上它只依赖三个 workspace 包:@calcom/features、@calcom/i18n、@calcom/lib,并把react、react-dom、stripe、zod声明为 peerDependencies。这意味着它并不重复实现业务,而是把核心模块的能力“重新导出 + 打包”,让 API v2 服务无需直接深入 monorepo 内部即可调用业务函数。
以 event-types.ts 为例,它直接export了来自@calcom/trpc/server/routers/viewer/eventTypes/heavy/create.handler.ts的createHandler as createEventType、update.handler.ts的updateHandler as updateEventType,以及getEventTypeById、getEventTypesByViewer、EventManager等核心符号。CHANGELOG 中多次提到的“Released to support PR xxx”,本质上就是把这些核心模块中的改动同步收编进 platform-libraries 并发布新版本,供 API v2 引用。
二、版本发布工作流:本地开发、构建与发布
CHANGELOG 记录的是对外发布结果,而 README.md 给出了完整的开发与发布流程,二者合起来才是该包的全貌。
2.1 本地开发三步走
- 首次修改:执行
yarn local。它会运行 scripts/local.js,把本地package.json版本临时改为9.9.9,并把apps/api/v2/package.json中@calcom/platform-libraries依赖改写为npm:@calcom/platform-libraries@9.9.9,从而让 v2 API 指向本地构建产物而非 npm 包。 - 后续修改:执行
yarn build:dev重新构建。注意脚本中有一处针对dist/index.cjs的sed修复(把new lruCache.LRUCache({...})修正为new lruCache({...})),这是构建后对缓存初始化代码的已知兼容性修正,watch-lru-fix脚本则用于监听模式下反复执行该修复。 - 验证完成后发布:执行
yarn publish-npm。它内部串联了scripts/prepublish.js(检查并升级 npm 上的版本号)、rimraf dist && yarn build、npm publish --access public与scripts/postpublish.js(重置版本号并更新依赖)。发布结束后会重置版本回0.0.0并执行yarn install。
2.2 合并到 main 之前必须完成发布
README 明确要求:在将涉及 platform-libraries 的改动合并进 main 之前,必须先发布你的 libraries 版本到 NPM。步骤为:成为平台库 NPM 包的 contributor → 通过 CLI 完成 npm 认证 → 按语义化版本递增 →yarn publish→ 发布后将packages/platform/libraries/package.json版本改回0.0.0→ 执行yarn。这样才能保证仓库里引用的始终是已发布的 npm 包,而不是本地构建的“幽灵版本”。
2.3 何时需要发布新版本
README 给出了三条触发标准:
- platform-libraries 的
index中新增了导出; - 已导出的函数实现发生了代码变更;
- Prisma schema 的变更破坏了当前已发布版本中函数的实现。
CHANGELOG 中几乎每一个版本都对应着这三条中的至少一条,尤其是“新增导出”和“函数实现变更”。
三、0.0.38:AdvancedTab 事件类型属性的 API 能力落地
0.0.38是 CHANGELOG 中信息量最大的一个版本,它为事件类型 API 一次性引入了四组“API ↔ 内部(internal)”翻译器(translator),让此前只在高级设置(AdvancedTab)里可配置的属性能够通过 API 读写。
3.1 Booker Layouts(预订布局)
transformBookerLayoutsApiToInternal:把 API 请求中的bookerLayouts属性翻译为内部存储格式;transformBookerLayoutsInternalToApi:把内部格式翻译为更清晰、可读的 API 响应。
3.2 Event-Type Colors(事件类型颜色)
transformEventColorsApiToInternal:启用color属性;transformEventTypeColorsInternalToApi:增强响应中color的可读性。
3.3 Confirmation Policy(确认策略)
transformConfirmationPolicyApiToInternal:启用confirmationPolicy属性;transformRequiresConfirmationInternalToApi:改善响应中requiresConfirmation数据的可读性。
3.4 Seats(多人预订席位)
transformSeatsApiToInternal:启用seats属性;transformSeatsInternalToApi:增强seats数据的可读性与清晰度。
3.5 源码佐证:Seats 翻译器的真实实现
在当前仓库中,这些翻译器位于apps/api/v2/src/platform/event-types/event-types_2024_06_14/transformers/api-to-internal/目录下,分别对应 booker-layouts.ts、event-colors.ts、confirmation-policy.ts 与 seats.ts。
以 seats.ts 为例,其实现逻辑非常直观:
export function transformSeatsApiToInternal( inputSeats: CreateEventTypeInput_2024_06_14["seats"] ): SeatOptionsTransformedSchema | SeatOptionsDisabledSchema { if (!inputSeats || inputSeats.disabled) return { seatsPerTimeSlot: null, }; return { seatsPerTimeSlot: inputSeats.seatsPerTimeSlot, seatsShowAttendees: inputSeats.showAttendeeInfo, seatsShowAvailabilityCount: inputSeats.showAvailabilityCount, }; }关键点:
- 当
inputSeats为空或disabled为true时,返回{ seatsPerTimeSlot: null },即内部用null表示“未启用席位”; - 启用时,把 API 层的
showAttendeeInfo、showAvailabilityCount分别映射到内部字段seatsShowAttendees、seatsShowAvailabilityCount,完成命名与结构的归一化。
这些翻译器被 input-event-types.service.ts 调用,再经由 event-type.tranformed.ts 输出响应,并有 api-to-internal.spec.ts 提供单元测试保障。这种“请求翻译器 + 响应翻译器”的成对设计,正是 platform-libraries 保持 API 契约稳定、内部存储灵活的关键模式:外部 API 字段名与内部 Prisma 字段名解耦,任意一侧演进都不破坏另一侧。
四、预订限制与周期预约:0.0.28 与 0.0.30
4.1 0.0.28:事件类型预订限制
0.0.28为事件类型 API 增加了两类高级限制能力,对应的翻译器同样分为请求与响应两个方向:
transformApiEventTypeFutureBookingLimits:启用“Limit future bookings”(未来预订限制)——即允许设置未来可预订的时间窗口;transformApiEventTypeIntervalLimits:启用“Limit total booking duration”(总预订时长限制)与“Limit booking frequency”(预订频率限制);getResponseEventTypeIntervalLimits与getResponseEventTypeFutureBookingLimits:分别负责把这两类限制的内部数据翻译成更清晰可读的 API 响应。
这两组翻译器最初位于 CHANGELOG 记录的packages/lib/event-types/transformers/api-request.ts与api-response.ts(对应发布时的历史路径),其职责边界非常清晰:请求侧做“宽松的外部输入 → 严格的内部结构”归一化,响应侧做“内部结构 → 人性化外部表示”的还原。
4.2 0.0.30:recurringEvent 周期预约
0.0.30为api/v2/event-types增加了recurringEvent支持:
transformApiEventTypeRecurrence:启用周期预约(recurring event)特性;getResponseEventTypeRecurrence:以更友好的格式返回周期数据。
周期预约是调度产品的核心能力之一,它允许一个事件类型按日、周、月等频率重复出现,并可设置重复次数与间隔。通过 API 支持该属性,意味着开发者可以在不进入 UI 的情况下,用代码创建和管理周期性事件类型。
五、Booking Fields 的归一化处理:0.0.24 与 0.0.25
5.1 0.0.24:区分系统字段与用户字段
0.0.24解决了一个真实的历史兼容性 Bug。改动位于事件类型翻译器(CHANGELOG 记录的历史路径为packages/lib/event-types/transformers/api-request.ts),核心思路如下:
- 从数据库读取事件类型的 booking fields;
- 区分其来源是用户创建还是系统预置;
- 在 v2 API 的
event-types_2024_06_14/services/output-event-types.service.ts中先解析、再过滤,只输出用户字段。
为什么会失败?CHANGELOG 的解释是:创建事件类型时只存储用户传入的 booking fields,但老用户若用2024_04_15版本的 event-types API 创建过 booking fields,数据里会包含系统字段,导致2024_06_14版本的 controller 解析出错。这一修复本质上是对多版本 API 并存时的数据兼容性打补丁,也是 platform-libraries 这类“承载 API 契约演进”的包最常见的工作:版本升级,不等于老数据自动兼容。
5.2 0.0.25:杜绝 options 为 undefined
0.0.25对getResponseEventTypeBookingFields做了一次重构,确保带选项(options)的 booking field 不会出现undefined的 options。这类细节修复看似微小,却直接影响 API 消费者的 JSON 解析健壮性——响应中的字段要么有完整的options数组,要么明确不包含该字段,避免客户端出现“字段存在但值为 undefined”的模棱两可状态。
六、预订元数据语义修正:0.0.23
0.0.23修改了createBooking(源码路径见 packages/features/bookings/lib/handleNewBooking/createBooking.ts,被 packages/features/bookings/lib/handleNewBooking.ts 中的handleNewBooking使用),修复了改期(re-schedule)预订时 metadata 的合并语义:
- 修复前:原预订的 metadata 会覆盖新(改期)预订请求体中的 metadata;
- 修复后:请求体的 metadata 覆盖原预订 metadata,保证“最新的元数据胜出”;
- 保留语义:仅覆盖共有属性(common properties),若原预订拥有改期请求体 metadata 中没有的键,该键仍会保留在改期后的预订中。
这一改动确立了清晰的合并规则:新增覆盖、独有保留。对依赖 metadata 做业务标记(如渠道来源、客户标签、内部备注)的集成方来说,这个语义细节至关重要。
七、其他关键版本:定位、组织与集成能力
7.1 0.0.51:预订时指定参会地点
0.0.51支持了 PR #17224 引入的能力——预订时允许参会者指定地点(attendee specified location)。这是调度产品增强参会体验的重要特性,让参会者在完成预订时可以从事件类型允许的地点列表中自行选择。
7.2 0.0.41:取消预订时向 Webhook 传递 OAuth Client ID
0.0.41支持“取消预订时把 OAuth client id 传给 webhooks”。对于基于 v2 Platform API 构建的集成方,webhook 回调中需要识别请求来源,这一改动让取消事件的 webhook 载荷具备更完整的身份上下文。
7.3 0.0.31:修复周期事件删除与改期
0.0.31对应 PR #16414,修复了删除和改期周期事件(recurring events)的问题。周期事件在数据库中存在父子关系,删除与改期需要级联处理,这类 Bug 修复随 libraries 版本发布,确保使用旧版 libraries 的部署也能通过升级获得修复。
7.4 0.0.26:Outlook 日历事件描述换行
0.0.26更新了 packages/app-store/office365calendar/lib/CalendarService.ts 的translateEvent内容,让 Microsoft Outlook 日历事件中的描述保留换行符,而不是挤成一行。这属于日历集成层的可读性优化,直接影响参会者在 Outlook 中的阅读体验。
7.5 0.0.22:导出组织成员事件类型分配函数
0.0.22从@calcom/lib/server/queries中导出updateNewTeamMemberEventTypes,用于把新创建组织的团队成员自动分配到标记为“assign all team members”(全成员分配)的事件类型。这是多租户组织能力的关键拼图。
7.6 0.0.20:创建事件类型时绑定排期
0.0.20在事件类型创建 handler(源码路径 packages/trpc/server/routers/viewer/eventTypes/create.handler.ts)中支持传入scheduleId,使事件类型创建时即可关联到指定排期(schedule),避免创建后再二次绑定。
7.7 0.0.19:系统管理员创建团队事件类型免组织成员要求
0.0.19对应 PR #15774,更新了创建事件类型 handler:系统管理员(system admin)在为团队创建事件类型时,不再被要求必须是该组织团队成员。这一改动简化了平台运营场景下的操作约束。
八、演进规律总结:platform-libraries 承载了什么
纵观 CHANGELOG.md 从 0.0.19 到 0.0.51 的演进,可以归纳出该包的四类主要变更来源:
- API 能力增量:如 0.0.38 的四个 AdvancedTab 属性、0.0.28 的预订限制、0.0.30 的周期预约,都是通过成对的“API→Internal / Internal→API”翻译器把 UI 高级能力开放给 v2 API;
- 数据兼容性修复:如 0.0.24 的系统/用户 booking fields 过滤、0.0.25 的 options 归一化,解决多版本 API 共存时的历史数据问题;
- 业务语义修正:如 0.0.23 的改期 metadata 合并规则、0.0.31 的周期事件删除/改期修复;
- 集成与运营能力:如 0.0.51 的参会者指定地点、0.0.41 的 webhook OAuth client id、0.0.22 的组织成员分配、0.0.20 的 scheduleId 绑定、0.0.19 的管理员权限放宽。
结合 README.md 的发布规则(新增导出、函数实现变更、Prisma schema 破坏性变更都必须发版)可以看到,platform-libraries 的本质是 cal.diy 核心业务层与 Platform API 之间的版本化契约层:核心模块可以高速迭代,而 API 消费者通过锁定 libraries 版本获得稳定的行为边界。理解它的 CHANGELOG,就等于理解了整个 v2 Platform API 的能力演进时间线。
对于希望基于 cal.diy v2 API 构建调度类应用的开发者,建议按以下方式使用本仓库:
- 关注 CHANGELOG.md 的版本条目,判断你依赖的 API 能力在哪个版本开始可用;
- 若需在 monorepo 内联调,按 README 的
yarn local→yarn build:dev流程让 v2 API 指向本地构建; - 若只是消费已发布能力,直接引用
@calcom/platform-libraries的 npm 包即可,无需深入核心模块源码。
【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考