SDK 与服务运行时¶
客户端库与运行时¶
packages/core 提供校园业务模型、HTTP/Cookie、认证辅助与各服务客户端。客户端通过注入的 transport 工作,宿主负责具体网络环境。packages/info-lib 保留学校统一认证、漫游、2FA hooks 和平台网络注入。OneTHU 的适配层将现有登录管线与自有客户端接到受控会话中。
packages/sdk 进一步提供 Node 会话存储、操作注册、授权、任务、通知、插件和助手。其入口为 createOneThu。这层需要 Node 环境;部分 Learn、任务和策略模块另有 browser 条件出口,供工作区的 GUI 宿主复用。
源码:core、info-lib、SDK 入口、共享 Learn 服务。
一个 profile 的权威¶
createNodeSession 打开私有目录并持有排他锁。同一进程仅允许一个活动 Node 会话运行时。默认 CLI 通过 daemon 复用已持有该 profile 的实例;嵌入方可为独立任务选择明确的私有目录。
持久会话包含稳定指纹、账号、Cookie、信任因子、保存时间与代际状态。密码由当前登录流程在内存中持有,独立 SDK 不保存密码。GUI 的“记住密码”由原生应用另外管理,其内容不属于公开 SDK 或模型结果。
账号变化时清理旧会话相关 transport、资源缓存与准备状态,并增加 epoch。Windows 使用当前用户的受保护 DACL;Unix 目录/文件使用私有权限。读取时检查路径、文件类型、符号链接和所属用户。源码:session.ts、storage.ts。
认证状态与业务准备¶
stateDiagram-v2
[*] --> Idle
Idle --> Restoring: 显式恢复
Restoring --> Ready: 身份核验成功
Restoring --> Idle: 失效或缺少会话
Idle --> Authenticating: 用户登录
Authenticating --> Need2FA: 学校要求验证
Need2FA --> Authenticating: 选择方式并验证
Authenticating --> Ready: 登录完成
Ready --> Idle: 退出或会话失效
SDK 返回 ready 或 need-2fa,后者由同一运行时保存挑战上下文。选择方式后才发起对应流程;TOTP 无需发送验证码。信任设备由显式选项决定,名称为 OneTHU(设备名),稳定指纹和信任令牌继续复用。
Learn 还需要自己的业务落地页与 CSRF。ensureLearnReady 对同一账号/Cookie revision 合并准备请求,通过独立候选客户端核验后再发布 CSRF。身份站登录链接、WebVPN 引导或异常 HTML 返回可区分的错误,业务层不会将其当作空课程列表。
雨课堂使用独立业务会话及 classroom 标识。GUI 可经私有交接把当前账号的有效雨课堂状态提供给后台;学校主登录成功不会直接证明雨课堂也已登录。
操作契约¶
interface ServiceOperation {
name: string;
description: string;
parameters: Schema;
permission: string;
mutation?: boolean;
authenticated?: boolean;
localOnly?: boolean;
run(args: unknown[], context: OperationContext): unknown | Promise<unknown>;
}
上面展示契约要点,完整声明以 services/types.ts 为准。位置参数数组对应 tuple schema;参数顺序、可选参数和额外字段按 schema 校验。静态 catalog 提供部分类型和说明,实际注册由服务工厂及运行时控制项完成。
app.list(source) 返回该来源可见的实际操作。GUI 应用目录与独立 SDK 目录可以具有相同的服务命名风格,覆盖范围由各宿主决定。尤其通讯录、暂存和部分白板操作需要运行中的 App。仅在静态 catalog 见到名称不足以证明独立运行时注册了该方法。
分发与最终提交检查¶
- 校验调用 envelope、操作名和参数 schema。
- 由可信宿主设置来源
local / mcp / plugin / im / agent,核对权限与localOnly。 - 恢复或核验学校会话,捕获 owner、epoch、策略 revision 与 deadline。
- 计算写入授权;本机显式确认、自动执行策略和任务持续授权分别处理。
- 通过
beforeWrite复核账号、权限、取消、时间和任务范围。 - 执行服务并在返回前再次核验,投影公开结果。
同一操作的并发写入有忙碌保护;日程、CalDAV 和云盘相关数据写入另经数据队列。该机制降低本地竞争,远端事务一致性仍由对应服务提供。来源字段属于宿主调用选项,外部 JSON 参数不能将自己提升为本机配置来源。
嵌入示例¶
示例使用独立私有目录;桌面默认 profile 已由 daemon 持有时,外部程序通过 CLI/MCP 连接。
import { createOneThu } from '@onethu/sdk';
const app = await createOneThu({ dataDir: '/absolute/private/sdk-example' });
try {
const catalog = app.list();
const status = await app.auth.restore();
if (status.authenticated) {
const courses = await app.call({ operation: 'learn.courses', args: [] });
// courses 按当前操作 schema / 返回契约处理。
}
} finally {
await app.close();
}
app.start() 用于启用恢复及常驻生命周期;按需嵌入查询仍应在结束时 close()。关闭依次撤销请求、网关、IM/助手、任务、插件、存储及会话锁。
下载、完整性与输出¶
Learn 服务枚举课程、作业、公告和附件,形成当前 owner/epoch 绑定的 resourceRef。下载解析该引用并核验目录、文件名、认证地址和类型。公告附件与作业附件应保留真实名称和扩展名,URL 留在内部资源表。
枚举返回的 complete、逐项失败和后续页信息由调用方检查。成功下载项可保留;部分失败不会自动宣告整门课程已完整归档。SDK 的公开结果投影去除凭据字段及 URL 中的认证参数,普通字符串和数组保留内容;模型上下文预算、RPC 响应大小与单个业务分页另有边界。
明确的数值限制见 API 参考。
GUI 与后台交接¶
私有 desktop.* 接口携带协议版本、预期账号和 epoch;会话及 Cookie 镜像另带 revision。GUI 内存可展示数据和处理需要交互的验证,后台持有共享服务和常驻任务。部分数据文档按版本读写;安装/卸载交接完成后只保留一个调度所有者。
Gateway 管理和服务出票属于私有控制面。它们不会出现在公开 MCP 操作目录,代理口令、Cookie 和学校票据也不会作为工具发现结果返回。源码:sharedRuntime.ts、daemon.mjs。
错误和恢复¶
会话缺失、账号变化、权限撤销、学校 2FA、限流、schema 错误和网络超时各有不同处理。恢复失败只撤销已判定失效的对应状态,后台启动/路径/协议错误保留可诊断信息。写入遇到超时后先检查远端结果,读取可在预算内有限重试。
对外错误经公开错误投影移除 HTML 登录页和凭据内容。学校给出的业务详情可作为外部 reason 显示,应用自身错误在渲染时本地化。各来源的数据内容和提示词均不能改变调用者的权限。