关于 services-layer
services-layer 是指导 Whispering 服务层改动的项目专用技能。它规定无 UI 服务的边界、错误处理、平台选择,以及服务对象与工厂的使用约定。
主要功能
- 01界定无 UI 的服务边界
- 02指导基于 Result 的错误处理
- 03说明构建时的平台映射
- 04区分直接对象与工厂
- 05说明服务汇总模块的约定
适用场景
- 01设计新的 Whispering 服务
- 02检查服务依赖与边界
- 03选择特定平台的实现
- 04决定使用对象还是工厂
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ epicenterhq/ epicenter --skill services-layer安装后在 Claude Code 中输入/services-layer确认已加载。
附带文件references/service-implementation-pattern.mdreferences/service-organization-platforms.md
详细介绍
服务层
服务指南应以 apps/whispering/src/lib/services、它的使用方,以及
apps/whispering/package.json 中的 #platform/* 映射为依据。历史
示例和相邻技能只能作为线索,不能代表当前架构。
产品定位
服务层负责与 UI 无关的能力;调用方通过显式输入注入应用策略,可失败的操作返回 Result,而平台选择由一个构建时所有者负责。
边界
服务可以执行 IO,也可以拥有服务本地的运行时状态。它们不必是纯函数,但必须与 UI 和应用自有策略保持隔离:
- 不得在运行时读取 Svelte stores、
settings、deviceConfig、toast 或report; - 将凭据、模型名称、端点、路径和用户选择作为输入;
- 返回领域数据和错误,而非展示文案或 UI 状态;
- 在
#platform/*接缝的两侧暴露相同的契约。
$lib/operations 通常负责读取应用设置、选择提供方并组合服务。仅当 UI 需要时,$lib/queries 才会添加共享查询标识和可观察的生命周期。
转录目录还包含提供方注册表数据和面向 UI 的 provider-ui.ts 联接模块。这些放在同一目录中的元数据模块并非服务实现;不要以此削弱服务边界。
如实建模可失败性
对于在常规运行时使用中可能失败的公共操作,使用 Result<T, E>。
使用 error-handling 技能适配会抛出异常的平台或库调用。
不要为不会失败的内存操作或清理操作伪造 Result。当前示例包括返回 void 的本地快捷键 register / unregister,以及返回清理函数的监听器设置操作。
export type DownloadService = {
downloadBlob(args: {
name: string;
blob: Blob;
}): Promise<Result<void, DownloadError>>;
};
错误应由理解该失败的层负责。组合服务时保留底层的带标签错误。仅当服务本身拥有某种失败时,才定义服务本地的变体。使用 define-errors 确定变体形状和消息规则;使用 error-handling 进行适配和传播。
直接对象还是工厂
当构造不需要输入或生命周期时,默认使用直接的 *ServiceLive 对象。当前的下载、分析、文本和转录提供方实现都采用这种形式。下载、分析和文本服务会使用 satisfies <Service> 检查其共享平台契约。
当工厂负责真实的构造输入、可替换依赖或有状态生命周期时,才使用工厂。浏览器和 CPAL 录音器工厂之所以适合这种边界,是因为它们各自会创建具有停止、取消、订阅和拆除行为的录音会话。
不要为了一个无状态对象而机械地同时添加 create* 和 *Live。
阅读服务实现模式,了解当前的直接对象示例和工厂选择依据。
平台和运行时选择
对于同时具有浏览器和 Tauri 实现的能力,使用 #platform/* 导入。package.json#imports 在构建时选择实现;共享调用方导入一个稳定名称,不检查 window.__TAURI_INTERNALS__。
对于仅限 Tauri 的能力,使用可空的 #platform/tauri 命名空间。
用户选择的提供方属于运行时策略,而非平台接缝。将分派逻辑保留在调用该服务的操作中。Whispering 转录会在 $lib/operations/transcribe.ts 中读取选定的提供方;查询层只观察该操作。
添加或迁移平台服务时,请阅读服务组织与平台变体。
服务汇总模块
$lib/services/index.ts 汇集稳定的跨平台能力:
export const services = {
analytics: AnalyticsServiceLive,
text: TextServiceLive,
blobs: BlobsLive,
blobSources: BlobSourcesLive,
download: DownloadServiceLive,
localShortcutManager: LocalShortcutManagerLive,
sound: PlaySoundServiceLive,
} as const;
不要强行将每个提供方实现都放入此汇总模块。当运行时操作拥有分派表时,可以直接导入提供方专属服务。
最终检查
- 该服务不导入任何 UI 或应用自有设置。
- 每项应用选择都作为显式输入传入,或由调用方选定。
- 可能失败的公共操作返回 Result;不会失败的操作保持为普通形式。
- 工厂负责构造或生命周期管理,而非仅依赖约定。
- 平台选择通过一个
#platform/*映射完成。 - 运行时提供方在使用该操作时只选择一次。
- 除非此服务负责引入新故障,否则低层错误应直接传递。