# @faiber/faiber-lms 中文文档

规范地址：https://npmcn.com/package/%40faiber/faiber-lms/

版本：2\.8\.0
npm 元数据更新时间：2026-11-14T09:44:50.438Z
中文译文更新时间：2026-11-14T09:18:50.357Z
软件包许可：未声明

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40faiber/faiber-lms
原文对照：https://npmcn.com/package/%40faiber/faiber-lms/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：963 kB，52 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- 首次发布：2026-07-18T14:30:00.008Z
- 最新版本发布：2026-11-14T09:44:50.251Z
- 近 30 天下载量：3761（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：66（近 12 个月 66 个）

## 中文简介

## 教育数据传输

## 安装

```sh
npm install @faiber/faiber-lms
```

也可以使用：`pnpm add @faiber/faiber-lms`、`yarn add @faiber/faiber-lms`、`bun add @faiber/faiber-lms`

## README

# @faiber/faiber-lms (英语)

## 教育数据传输

```ts
const result = await lms.transferUserData(
  { from_user_id: sourceIdpUuid, to_user_id: destinationIdpUuid },
  crypto.randomUUID(), // retain this key and reuse it if this request needs retrying
);
console.log(result.data.data.transfer_id, result.data.data.moved);
```

这支持 `POST /api/v1/idp/option/transfer-user-data` 需求 `user_data:transfer` 还有一个 `Idempotency-Key` 页眉(1–128可打印的 ASCII 字符,无空格). 两个ID必须是具有活性Profile记录的单独非无UUID. `TransferUserDataInput`, (中文(简体) ), `TransferUserDataResponse`, (中文(简体) ), `EducationalTransferCounts`,以及 `TransferUserDataErrorResponse` 是导出类型.

交易改变了学习者对课堂入学、出勤、家庭作业、考试尝试、成绩、证书、课堂笔记/评价、学院入学和互动运行的所有权。 对于课程评价,它改变教师评级的目标学习者和学生反馈的作者。 记录ID、状态、分数、提交、问题快照和外国关键链接得到保存;因此,学院进展/尝试、考试答案和互动尝试遵循其母记录不变。 回应 `moved` 按类别计算直接更新的行数,而非链接的孩子数。 配置 课堂- 缓存同步在同一交易中排队( Q)`profile_sync: "queued"`) (中文(简体) ).

没错 **没有** 更改办公室余额、钱包、发票、交易或分期付款;身份/备案财产;教师、顾问、支助人员或证书签发人;邀请、支助互动、俱乐部项目所有权或工作时间记录; 与参与者交谈、留言或谈话身份证;或历史移徙/审计归属。 这是LMS的学习者记录转帐,而不是账户合并. 现有的聊天对话访问没有被转移 .

同名演员+同名密钥+同名ID重放原作成功回应. 用不同的ID重用该密钥返回 409 `idempotency_conflict`现有目的地独特性冲突回归 409 `destination_conflict` 不合并或删除记录。 开始试卷409 `active_attempt`; 忙碌的教育写作可以返回 409 `transfer_busy` (用同一键重试). 缺少/无效的ID或密钥返回 422;没有配置文件验证返回 502. 失败使所有教育记录保持不变,不消耗钥匙。 认证/许可失败使用共享的境内流离失所者出错合同.

成功响应 : `{status:"success", message:"Educational data transferred", data:{transfer_id,from_user_id,to_user_id,moved,profile_sync:"queued"}}`。 。 。 .

鉴定/冲突对策: `{status:"error", error:{code:"destination_conflict",message:"...",details:{}}}`。 。 。 . `user_not_found` 包含 `details.user_id`Axios 错误保留了 HTTP 状态并输入了响应机构.

课程、教室、家庭作业/项目库和任务、考试库/项目/课程/用户、证书、报告和教育配置.

## 安装

```bash
npm install @faiber/faiber-lms
```

## 配置

```ts
import { FaiberClient, MemoryTokenProvider } from "@faiber/sdk-core";
import { LmsApi } from "@faiber/faiber-lms";

const tokens = new MemoryTokenProvider();
const client = new FaiberClient("lms", {
  domains: { lms: process.env.FAIBER_LMS_URL! },
  tokenProvider: tokens,
  axios: { timeout: 15_000, withCredentials: true },
});
const api = new LmsApi(client);

const courses = await api.courses.list({
  "page[number]": 1,
  "page[size]": 20,
});
const sessions = await api.courseSessions(courseId);
```

## 完全能力

该套件通过打入式装订暴露出181个已注册的操作,包括通知规则/接触,并排除了已退役的8个LMS简易操作. 具有约束力的清点只描述库存;服务许可和工作流程核查仍然是单独的要求。 常见的工作流程使用简洁的方法,而被命名的运营客户保留精确的电线合同.

| 区域 | 业务 | HTTP 方法 |
| --- | --: | --- |
| `academy` | 第8条 | `GET`, (中文(简体) ), `POST` |
| `branding` | 页:1 | `GET`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `certificate` | 10个 | `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST` |
| `classroom` | 20国 | `DELETE`, (中文(简体) ), `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `config` | 20国 | `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST` |
| `contacts` | 1个 | `GET` |
| `course` | 页:1 | `DELETE`, (中文(简体) ), `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST` |
| `dashboard` | 1个 | `GET` |
| `docs` | 1个 | `GET` |
| `drm-routes` | 1个 | `GET` |
| `evaluation` | 页:1 | `GET`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `exam` | 22个 | `DELETE`, (中文(简体) ), `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `homework` | 第25条 | `DELETE`, (中文(简体) ), `GET`, (中文(简体) ), `PATCH`, (中文(简体) ), `POST` |
| `integration` | 第7条 | `GET`, (中文(简体) ), `POST` |
| `interactive` | 15个 | `GET`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `media` | 2个 | `GET`, (中文(简体) ), `POST` |
| `mod` | 3个 | `GET`, (中文(简体) ), `POST`, (中文(简体) ), `PUT` |
| `notifications` | 1个 | `POST` |
| `profile-routes` | 2个 | `GET` |
| `report` | 第9条 | `GET` |
| `router` | 页:1 | `GET` |
| `service` | 1个 | `GET` |
| `session` | 1个 | `GET` |
| `transfer` | 1个 | `POST` |

课程、课堂用户和缺课、家庭作业任务、考试尝试、学院入学、报告和证书工作流程都有专门的打字操作。 大多数 LMS 更新使用 `PATCH`; 不支持的通用删除被本地守护 .

家庭工作任务和考试都暴露了 `student_user_id`, (中文(简体) ), `teacher_user_id`, (中文(简体) ), `consultant_user_id`,以及 `support_user_id` 列表过滤器。 现有 `user_id` 当呼叫者想要任何相关的参与者或工作人员角色时,仍可使用过滤器.

接受家政-银行项目 `name` 用于创建和更新。 答复总是包括: `name`;当它为空白或省略时,LMS从提问文本中取出并封入有椭圆的80个Unicode字符.

### 家政和考试银行

可重复使用的作业定义是作业库层: `api.homeworkBanks` 和相容性别名 `api.homeworks` 地址相同记录。 使用 `api.homeworkBankItems(bankId)` 定义问题/项目`homework_questions`) (中文(简体) ). 每件东西都有 `kind: "todo" | "project"`; 嵌入式列表接受相同的 `kind` 过滤器,并创建/更新接受字段。 偏爱 `api.homeworkAssignments.createForItem(item, delivery)` 以明确选择练习 ID。 交付记录参考了物品的身份证(而不是银行身份证),并通过下列方式进行充分管理: `api.homeworkAssignments`。兼容方法 `listAssignments`, (中文(简体) ), `createAssignment`, (中文(简体) ), `assignment`, (中文(简体) ), `updateAssignment`,以及 `deleteAssignment` 继续提供.

考试定义为 `api.examBanks`及其问题/项目的审议 `api.examBankItems`,作为 `api.examSessions`,学习者尝试 `listExamUsers`, (中文(简体) ), `examUser`,以及 `updateExamUser`遗产 `api.exams`, (中文(简体) ), `api.examQuestions`,以及 `api.homeworks` 名称仍然可用.

```ts
const bank = await api.homeworkBanks.create({ name: "Projects", status: "active" });
const items = api.homeworkBankItems(bank.data.data.id);
const item = await items.create({ question_text: "Build a recursion demo", question_type: "answer", kind: "project", status: "active" });
// item.data.data.id is the exercise; item.data.data.homework_id is its parent bank.
const delivery = await api.homeworkAssignments.createForItem(item.data.data, {
  user_id: studentUserId,
  classroom_id: classroomId,
  status: "pending",
});
const todos = await items.list({ kind: "todo" });
const assignments = await api.homeworkAssignments.list({
  statuses: ["pending", "unsolved", "completed"],
  homework_id: item.data.data.id,
});
```

曝光出勤行 `attendance_mode` (单位:千美元)`online` 或者说 `in_person`)与所储存的 `online` 布尔,出席秒,描述,和收视率。 缺行情况也是如此。 记录出勤量时,包括 `online` 用于每个学习者,其出勤模式很重要;省略默认为当面.

### 每周教室时间表

使用 `day_of_week` (星期日) (中文(简体) ) `0` 整个星期六 `6`和 `starts_at` (单位:千美元)`HH:MM` 或者说 `HH:MM:SS`新的课堂日程安排。 设定 `timezone_offset_minutes` 当当地时间与教室的相抵时 `starts_at` 时间戳.

```ts
await api.classrooms.create({
  course_id: courseId,
  name: "Autumn class",
  starts_at: "2026-09-20T09:08:11.383Z",
  status: "active",
  weekly_schedule: [
    { day_of_week: 0, starts_at: "15:00", timezone_offset_minutes: 210, mode: "online" },
    { day_of_week: 2, starts_at: "14:00", timezone_offset_minutes: 210, mode: "interactive" },
  ],
});
```

周报 `mode` 选择每个生成的主会话类型 : `online` → `ONLINE_CLASS`, (中文(简体) ), `interactive` → `VIDEO` (组合媒体), `in_person` → `MEETING`,以及 `makeup` → `REWIEW_CLASS`。您可以提供 `course_session_type_id`更新 `weekly_schedule` 在课堂上还重新安排了它现有的会议。 对于现有的表格, LMS 接受 `day` (波斯语或英语的平日名称) `start_time`;它使这些字段在保存上正常化。 遗产 `delivery_type` 财务报告和审定财务报表 `session_type` 当 `mode` 缺席,与 `delivery_type` 占据优先位置。 波斯日未明确抵消德黑兰时间的缺省(`+03:30`) (中文(简体) ).

补充录相带当然继承上届会议的时间 `sort_order`, (中文(简体) ), 包括之前的视频或在线课程。 移动该会话还移动以下内容: 补充视频。 选择将以后的初级课转到下个周刊 新开始时间之后的时段 :

```ts
await api.classroomSessions.update(sessionId, {
  starts_at: "2026-09-23T10:00:00Z",
  shift_following_sessions: true,
});
```

如果选定的会话或后期受影响的会话已经有一个提供房间, LMS 返回 `409 recording_reset_confirmation_required`。以 `confirm_recording_reset: true` 只有在用户同意将受影响的录音取出并重新设置这些房间之后,这些录音才会被删除.

## 认证和授权

使用一个 `TokenProvider` 以转发已签名用户的 Bearer 令牌,或启用 `withCredentials` 用于安全的 Http 只有饼干会话。 每个行动的JSDoc都包含从服务路线卫士复制的许可要求. SDK不嵌入 API 密钥,证书,本地主机 URL,沙盒主机,或生产主机.

## 投入、询问、答复和运输

所有方法都返回完整的Axios响应,包括状态,头,以及请求ID. 请求机构和查询对象被命名为导出接口. 网纹页化使用密钥, 如 `page[number]` 财务报告和审定财务报表 `page[size]` 服务需要时。 标准 Axios 请求选项、信头、超时、适配器、拦截器和 `AbortSignal` 取消被支持为最后参数.

一般性的REST资源得到能力保障。 调用未注册的遗留方法 `UnsupportedOperationError` 在发送请求之前, 而不是生成后端 `405`。 。 。 .

## 错误和取消

```ts
try {
  await api.client.get("/health", undefined, { signal: AbortSignal.timeout(5_000) });
} catch (error) {
  // Axios errors retain response.status and the service error body.
}
```

使用 `@faiber/faiber-ts-sdk` 当一个应用程序需要多个具有一个配置的Faiber服务时.

## 版本互动学习

`api.interactive` 曝光已发布的预览,作者定义版本,开始/重现,草稿保存,渐进提示,决定提交和受限的教师上下文. 部署必须包括互动学习移徙和执行者。 前一个已卸载 `interactiveContent` 资源当前在本地失败; 使用支持的版本 API .

```ts
const catalog = await api.interactive.catalog();
const started = await api.interactive.start(sessionId, { enrollment_id: enrollmentId });
const run = started.data.data;
const result = await api.interactive.submit(run.state.id, {
  revision: run.state.revision,
  activity_id: run.definition.activities[run.state.current_activity].id,
  code: "score = 10",
  idempotency_key: crypto.randomUUID(),
});
```

服务器拥有检查和掌握. 浏览器输出不得作为传递结果提交. 保留重试相同提交文件的独有性密钥; 反省修改冲突 。 要求作者定义 `lms:course:read`编号 :`lms:course:update`;学习者突变验证主动入学所有权和先决条件. 没有 API 证书属于浏览器存储 .

### 提问、选项、作业和课程图像

对所有 LMS 图像使用相同的认证上传端点 . `File` (浏览器)和 `Blob` (浏览器或节点18+)支持;被接受的格式有PNG,JPEG,WebP和GIF等可达10个米B.

```ts
const upload = await lms.media.uploadImage(file, {
  fileName: 'homework.webp',
  signal: abortController.signal,
  onUploadProgress: ({ loaded, total }) => {
    if (total) updateUploadPercent(Math.round(loaded * 100 / total));
  },
});
const imageUrl = upload.data.data?.url;
if (!imageUrl) throw new Error("Upload did not return an image URL");
```

帮助者发送多段 `image` 并继承 SDK 的国内流离失所者证书 刷新流动。 不要自己设置多段边界 。 本地 Axios 进度报告字节 发送; 在标记上传成功前等待回复, 因为存储仍然会失败 . 已取消或失败的上传拒绝 `AxiosError`进展取决于 Axios适配器/运行时间;浏览器 XHR和Node HTTP支持字节进度.

上传不会自动改变一个练习 。 在问题中保存返回的 URL `media` 数组,一个选项 `image_url`编号 :`media` 字段,作业项目 `media` 数组,或 课程的图像字段使用它的创建/更新操作。 保留其他媒体条目和 选项值。 返回的图像 URL 是服务相对的, 因此解析它们与 您已配置用于显示的 LMS 服务源 。 这个终点目前需要 `lms:course:update`,包括何时将图像用于考试或作业.

课程设置和更新接受独立 `in_person_price` 财务报告和审定财务报表 `online_price` 小数字符串(例如, `"1200.50"` 财务报告和审定财务报表 `"800.25"`) (中文(简体) ). 课程清单和详细答复包括两个领域。 在更新时,遗漏保留了节省的价格 `null` 只有这个价格。 现有 `price` 字段仍可供现有消费者使用;交货价格不覆盖.

### 选定学生的化妆课

过 `student_user_ids` 在创建课堂课程以选择一组入学学生时。 该名册控制出勤率、学生课程的能见度和房间供应;教师和教室支助用户仍然是房间成员。 关闭球场( 或通过) `null`整个教室。 教室外的空阵列或学生返回HTTP 422;重复的ID被去除. 选择设定在创建时 .

```ts
await lms.classroomSessions.create({
  classroom_id: classroomId,
  course_session_type_id: makeupSessionTypeId,
  name: "Makeup lesson",
  student_user_ids: [firstStudentId, secondStudentId],
  starts_at: "2026-10-25T10:00:00+03:30",
  duration_minutes: 60,
  status: "active",
});
```

要求数 `lms:classroom:create` 并使用已配置的认证和 Axios 请求选项。 答复包括: `student_user_ids` (单位:千美元)`null` 全班会议).

### 教师和支助过滤器

`lms.homeworkBanks.list`, (中文(简体) ), `lms.homeworks.list`, (中文(简体) ), `lms.listHomeworks`, (中文(简体) ), `lms.exams.list`, (中文(简体) ), `lms.examBanks.list`,以及 `lms.listExams` 接受 `teacher_user_id` 财务报告和审定财务报表 `support_user_id`。这些定义过滤器 与在交付的作业项目或考试课上明确指派的工作人员相匹配. 两者的提供都需要同样的交付,才能与两名工作人员相匹配。 保留结果 普通权限和页码;过滤器不允许进入其他教室. 任务和考试会通过过滤显示相同的过滤器 `homeworkAssignments.list` 财务报告和审定财务报表 `listExamSessions`。 。 。 .

```ts
const exams = await lms.exams.list({ teacher_user_id: teacherId, support_user_id: supportId, page_size: 20 });
const homeworks = await lms.homeworks.list({ teacher_user_id: teacherId, page_size: 20 });
```

使用配置的认证( U)`lms:exam:read` 编号 : `lms:homework:read` 或相应的本国 范围)。 答复保留Axios元数据;许可、验证、注销和网络 失败者通常拒绝。 定义过滤器需要匹配的 LMS 服务更新.

## 学生通知设置和指定聊天联系人(0.24.1)

`lms.notificationSettings.list()` 列出全沙盒的学生规则; 需要编辑 `lms:notification:settings:update`预览 `lms:notification:settings:read`。更新方式为 `{enabled,offset_seconds,expected_version}`。事件延迟为秒;每个规则都确定了域时前/后的时间。 无效的订购/范围返回 422, stale 版本返回 409. 更改在不重放已发送事件或回填旧事件的情况下重算待完成的工作 . `preview(key)` 发送什么.

`lms.eligibleContacts.list({cursor,limit})` 只返回当前指定的学生/教师/支持配置文件ID,需要 `lms:chat:contacts:read`。解析授权配置显示信息。 聊天还检查关系服务器侧;在客户端中隐藏联系人不是授权. 所有操作都使用所配置的沙箱运输,保持Axios的完整响应,并支持取消和标准错误.

## 1.0.0的API迁移摘要

LMS AI摘要设置,生成,队列和结果方法被删除. 使用 `ProfileApi.summaries` 从 `@faiber/faiber-profile`,或 `sdk.profile.summaries` 从 `@faiber/faiber-ts-sdk`角色UUID取代了旧学生/教师/支助环境. 新的配置摘要读取权限必须明确授予;父身份不允许访问. 普通的LMS学生报告、出勤率、评估、反馈和评价仍然有效. 遗留摘要数据不导入,也没有相容性代理.

## 课堂学生数

```ts
const response = await api.listClassrooms({ "page[number]": 1, "page[size]": 20 });
for (const classroom of response.data.data.data) {
  console.log(classroom.name, classroom.student_count, classroom.capacity);
}
```

`student_count` 是一个在课堂列表中的数字,细节,创建和更新回复, 包括 `api.operations.classroomIndexClassroomGet`, (中文(简体) ), `api.classrooms.list`,以及 `faiber.lms.listClassrooms` 结束 `@faiber/faiber-ts-sdk`。它计算不同的用户身份 带有 `active`, (中文(简体) ), `inactive`, (中文(简体) ), `disabled`,或 `enrolled` 课堂成员。 遗产 启动旗帜不取消成员资格;境内流离失所者控制账户启动。 已删除, 已撤销的完成后记录不计算在内。 工作人员任务和 上课不增加学生。 重复的入学列数一次.

计数覆盖整个教室,无论入学情况如何,并进行分批 授权的课堂页面。 空教室返回 `0`。 。 。 . `capacity: null` 表示没有配置限制;一个数值为零仍为零。 用户界面可以显示 `18 / 25` 或本地化 `0 / Unlimited`。这不会改变入学或能力规则. 名单要求 `lms:classroom:read` 或者说 `lms:classroom:read_own` 带有现有记录 范围界定。 通常的Axios响应,错误,认证和取消行为适用.

## 学院毕业和提交考试

学院类别、课程、课程、问题和入学识别符号是UUID字符串。 会话的完成需要认证的注册拥有者和活跃的注册;考试和互动会话无法通过普通的完成结束点完成. 不完整的前提条件会引发冲突。 保留原来的 `idempotency_key` 当调节会话完成时.

考试提交函发送 `answers` 键入问题 UUID。 服务器对尝试的选定问题快照进行分级;SDK不能提供分数或绕行所有权,过期或尝试状态. 提交不是一个自动重试工作流程:完成后丢失的响应需要权威回放. 答复保留了Axios的完整信封和错误;空取的许可注释并不意味着匿名访问.

## 支持的有线行为

支持的后端源是 `1a55795725ac5ac23b763117fbbe64f96d4cf2f6`课程/类别可删除;成功的变异信封包含 `data: {}`。删除课堂用户返回 `data: null`遗产 `videoSections`, (中文(简体) ), `events`, (中文(简体) ), `textTemplates`,以及 `interactiveContent` 一般资源被卸载并本地拒绝.

图像下载操作返回原始字节( Q)`ArrayBuffer | Uint8Array`)带有Axios头;证书 SVG 返回文本。 Exam-session 补丁区分遗漏和 `null`: 无效的课堂链接,工作人员,时间戳,和计数可以明确清除. 课程报告反馈了课堂/课/课的总数,而学院目录则反馈了学习内容和入学进度.

配置 熊鼠 标志通过 `TokenProvider` 或安全饼干通过 `withCredentials`; 更喜欢内饰符号或Http Only cookie. 采用共同认证运输的方法,接受 `signal`,超时,头,适配器和截取器,并保存全Axios响应. 取消和不成功 HTTP 回复以 Axios 出错拒绝 。 LMS 应用程序错误一般序列化 `{ error: string }`; 教育转移有其记录的结构错误信封.

操作中的权限名描述后端的 IDP 路由元数据 。 被绑定的后端提取出网关身份头(其配置的开发倒计时);仅取出和许可元数据并不能验证出一个Bearer令牌或证明网关执行. 其他处理者范围检查适用于范围阅读、学习所有权、提交评价材料和敏感入学最新情况。 本地接受和部署核查仍与源合同分开.

## 教室短身份证和搜索

```ts
const controller = new AbortController();
const matches = await lms.searchClassrooms({
  search: "GDCN7L", // also accepts classroom name, course name, or existing code
  "page[number]": 1,
  "page[size]": 20,
}, { signal: controller.signal });
for (const classroom of matches.data.data.data) {
  console.log(classroom.short_id, classroom.id, classroom.name);
}
```

使用您的配置 `LmsApi` 实例和实例 `AbortController`。现有的 `listClassrooms`, (中文(简体) ), `classrooms.list`,生成的列表操作接受相同的 `search` 参数。 要求数 `lms:classroom:read` 范围 `lms:classroom:read_own`; 所有状态、关系、课程和页形过滤器 继续提供。 Axios的完整响应和错误被保存.

`short_id` 是从无存储列的UUID得到的。 匹配为例 不敏感并接受波斯语/阿拉伯数字; 输入所有六个字符为 a 短ID检索。 碰撞返回多个结果: 使用记录的 名称/路线,并保持其完整的UUID,用于后续操作. `shortIdFromUuid` 也导出用于离线显示。 需要服务短ID迁移.

## 完成每周日历和今天视图

自SDK 1.2.0起可用. 需要LMS部署,包括: `GET /api/v1/classrooms/sessions/calendar`。 。 。 .

`lms.classroomCalendar` 装入时间表行、卡片、工作人员/教室/课程详情, 学生计数、过滤徽章和摘要度量标准 **aPI 请求**。 需求 `lms:classroom:read`,带有现有角色/自录能见度限制. 不需要报告或配置文件权限或前端浓缩请求. 现有的分层会话方法仍然相容.

```ts
import { FaiberSDK } from '@faiber/faiber-ts-sdk';
import type { ClassroomCalendarRequest } from '@faiber/faiber-lms';

// Use your existing authenticated SDK instance; secure cookie auth is shown here.
const sdk = new FaiberSDK({
  domains: { lms: 'https://lms.example.com' },
  axios: { withCredentials: true },
});
const controller = new AbortController();

// /dashboard/lms/calendar: one request for this complete local week.
const week: ClassroomCalendarRequest = {
  from: '2026-10-25T00:00:00+03:30',
  to: '2026-11-01T00:00:00+03:30', // exclusive
  timezone: 'Asia/Tehran',
  teacher_ids: ['0451390a-bfab-4de5-b463-b93d6d15b1c5'],
  session_types: ['online', 'interactive'],
};
const weeklyResponse = await sdk.lms.classroomCalendar(week, {
  signal: controller.signal,
});
const weekly = weeklyResponse.data.data;
// Render timetable/cards from weekly.sessions, metrics from weekly.summary,
// and stable type-filter badges from weekly.type_counts. No enrichment calls.

// /dashboard/lms/today: one request for the selected local date.
// This is an alternative page load, not an additional request for the weekly page.
const dailyResponse = await sdk.lms.classroomCalendar({
  date: '2026-10-25',
  timezone: 'Asia/Tehran',
}, { signal: controller.signal });
const daily = dailyResponse.data.data;
for (const session of daily.sessions) {
  const time = new Intl.DateTimeFormat('fa-IR', {
    timeZone: daily.range.timezone, hour: '2-digit', minute: '2-digit',
  }).format(new Date(session.starts_at));
  console.log(session.title, time, session.student_count); // zero stays zero
}
```

个人 `LmsApi` 揭发同样的 `classroomCalendar` 方法。 准确的电线 操作是 `lms.operations.classroomCalendarGet`,用 CSV 字符串代替 数组。 所有入口都保存 Axios 完整的响应 错误 信头, 请求选项、令牌/cookie认证和取消。 选择器打开 和明确的日历行动可自行提出请求.

### 日历合同

-   所需供应 `timezone` 和两个 `date` (单位:千美元)`YYYY-MM-DD`(中文(简体) ) **或者说** `from`编号 :`to` (RFC3339即时). 范围涵盖1至7个完整的当地日,包括开放 午夜和独家 关闭午夜。 DST日数可能有23/25小时;周数 可能有167/169小时。 模糊/不存在的午夜被明确拒绝.
-   会话按起始即时包含,排序由 `starts_at` 接下来 `id`。 。 。 . 没有帕吉克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克. 未注明日期的补充 无法指定某一天的会话,因此被排除在行和衡量标准之外. 列入了日期为补充会议;取消/结束的会议仍保留 可见。 软删除会话/教室不包括在内.
-   阵列过滤器支持多个 `teacher_ids`, (中文(简体) ), `session_types` (类别)和 `session_type_ids` (已配置的UUID类型),加1 `classroom_id`每个列表 使用 OR, 单独的过滤器使用 AND。 空便利数组指所有值; 电线 CSV 过滤器必须有 1–100 个条目。 未知值被拒绝,而不是忽略.
-   类别 : `online` ( , `in_person` ( , `makeup` ( , `interactive` (آنلاین), `supplementary` (+++),加 `unknown` 页:1 未配置类型 . `delivery_mode` 使用相同的类别。 生命周期, 记录状态和访问模式是独立的字段.
-   `summary` 描述返回的行 **在所有过滤后**。 。 。 . `type_counts`, (中文(简体) ), `configured_type_counts`,以及 `total_before_type_filters` 尊重可见度, 日期、教师和教室过滤器但忽略 **两种类型过滤器**类别 计数总是包括所有具有正零值的类别.
-   有效的教师是教室倒塌的课间教师;支助是 由顾问提供课堂支持。 未指定身份表示未指定;a 无效配置文件的非无效标识意味着没有返回配置文件记录 。 显示 名称是字符串、地方地图或无效。 配置服务失败拒绝 整个请求用502而不是默默地省去浓缩.
-   `student_count`: 限制时区分选定的ID( 空选择=0) , (c) 在其他方面有区别的主动/不主动/残疾/登记课堂成员. `classroom_student_count` 总是意味着入学,和 `classroom_capacity` 实值 独立:无效不配置,零保留。 内容提要 `student_seat_count` 总和会话算数,不是独特的人 在整个范围.
-   缺失的时间/结束时间/类型/房间/生命周期值仍然无效。 总计 已知持续时间与 `unknown_duration_count`。缺失的生命周期为 分类 `unknown`。时间/访问字段来自 LMS;不手工 从类别中添加时间区抵消到时间戳或获取访问模式.
-   查询形状/未知密钥(包括页形)返回400;范围/时区/过滤器 校验返回 422; 缺少许可返回 403( 门路 auth 可能返回) 401); 配置失败返回 502. 抓取 Axios 错误并保持取消 不同于失败的加载。 没有SDK重试或浓缩回落.

公共类型包括: `ClassroomCalendarRequest`, (中文(简体) ), `ClassroomCalendarQuery`, (中文(简体) ), `ClassroomCalendarResponse`, (中文(简体) ), `ClassroomCalendarData`, (中文(简体) ), `ClassroomCalendarSession`, (中文(简体) ), `CalendarSummary`, (中文(简体) ), `CalendarProfileSummary`, (中文(简体) ), `CalendarSessionType`, (中文(简体) ), `CalendarSessionCategory`,以及明确的范围/过滤器/计数类型。 软件包发布 和兼容的后端部署在启用此方法之前都需要 在生产客户端.

### 确认课堂课程或时间安排变化

`lms.operations.classroomUpdateClassroomPatch(id, input, options)` 财务报告和审定财务报表 `lms.classrooms.update(id, input, options)` 接受相同的打出确认标记. 打电话的人需要 `lms:classroom:update`将两面旗帜按最初的要求关闭. HTTP 409 装有 `response.data.error` 等于 `classroom_session_changes_confirmation_required` 意思是替换航道 或重新安排开始的会议需要同意。 一个单独的 `recording_reset_confirmation_required` 冲突保护现有的会议室录音. SDK 保存 Axios 错误并且确实 **没有** 自动重试或确认 .

在要求确认之前,请解释一下与课程有关的会议被绘制成图,以便 目的地路线的顺序。 缩短目的地档案剩余会议; 更长的目的地会造成额外会议。 单独会议予以保留. 受影响的会议室录音被删除并重新设置在线出勤量; 手动出席和存档会话历史保留。 调度更改可以 影响已经开始的会话。 取消时,不再发送请求.

```ts
import type { LmsService } from '@faiber/faiber-ts-sdk';

const proposed: LmsService.ClassroomUpdateClassroomPatchInput = {
  course_id: destinationCourseId,
  starts_at: '2026-11-07T13:00:00Z',
};
// Initial save; handle HTTP 409 in your application's confirmation UI.
await sdk.lms.operations.classroomUpdateClassroomPatch(classroomId, proposed);

// Run this separately, only after the user accepts all consequences above.
const confirmed: LmsService.UpdateClassroomInput = {
  ...proposed,
  confirm_session_changes: true,
  confirm_recording_reset: true,
};
await sdk.lms.classrooms.update(classroomId, confirmed, { signal: controller.signal });
```

在确认打开时保持待决有效载荷的不可改变性。 如果用户编辑 放弃同意,提出新的未经证实的请求。 服务器应用 以交易方式更改并拒绝无效的会话/会话链接而无需部分 更新。 这些旗帜需要LMS服务修改,支持课堂课程 替换;仅发布或升级SDK并不部署这种服务.

## 证书过滤和会话介质

这些能力需要LMS修订 `c24b8e68a051d9330ff8f3360bf6677ddb723a2d` 或后会. 发布 SDK 不部署 LMS 后端.

```ts
const certificates = await sdk.lms.certificates.list({
  user_id: studentUserId,
  profile_search: "علی", // localized name, email, phone, national code, short ID or user ID
  status: "issued",
  certificate_template_id: templateId, // certificate type; certificate_type is an alias
  course_id: courseId,
  issued_from: "2026-01-01T00:00:00+03:30",
  issued_to: "2026-12-31T23:59:59+03:30",
  "page[number]": 1,
  "page[size]": 20,
});
const sessions = await sdk.lms.classroomSessions.list({ classroom_id: classroomId });
for (const row of sessions.data.data.data) {
  const links = sdk.lms.classroomSessionMediaLinks(row);
  // links.recording opens the Session archive; links.recordingsApi lists ready recordings.
  // links.playback opens scheduled Session playback; links.compositionManifest targets DRM.
  if (row.media.drm_mixed_media_id) {
    const preview = await sdk.drm.classroomSessionComposition(row);
    // Use preview.data.document in a composition player; preview.data.version identifies it.
  }
}
```

这些示例使用完整的SDK(`sdk`; 独立 `LmsApi` 暴露了相同的LMS方法. 证书过滤器与计数/分数前结合. `student_user_id` 别名 `user_id`。 。 。 . 额外的过滤器 : `classroom_id`, (中文(简体) ), `grade_id`, (中文(简体) ), `issued_by`, (中文(简体) ), `public_id`, (中文(简体) ), `verification_code`, (中文(简体) ), `legacy_code`, (中文(简体) ), `search` (文字标题/代码/公用ID搜索), `has_media`, (中文(简体) ), `has_grade`, (中文(简体) ), `revoked`, (中文(简体) ), 包容性 `created_from/to`, (中文(简体) ), `updated_from/to`, (中文(简体) ), `revoked_from/to` 时间戳。 使用 RFC3339 带有所有日期界限的时区。 不要同时发送一个犬形地及其别名. 证书类型是现有的证书模板,而不是单独的新的分类. `lms:certificate:read_own` 仅限打电话者签发的证书;全文 需求 `lms:certificate:read`。无效的区域返回 422;配置搜索失败返回 502.

每个课堂会议清单/详细答复包括: `media` 和无效的相对路径, 财务报告和审定财务报表 `course_session.drm_mixed_media_id`路径是发现元数据,而不是访问授权或 已签名的 URL 。 会话路径使用会话域;DRM路径使用DRM域. 记录 需要会话记录权限,并可能在处理完成前为空。 组成 需要预览 `drm:composition:read` 并且为每会话类型工作,包括锁定, 未来和无房间的会议,当一个组成是联系在一起的。 未公布/丢失的运单 返回 404。 回放和许可证操作保留自己的DRM权限. 浏览器链接 需要认证目的会话; SDK 请求使用您配置的证书 .

`examDelivery(attemptId)` 现在返回正确的答案、选项答案元数据和每个问题 在尝试进行时, 定级为已授权的管理员和指派的审查员. 学生在完成/期满/取消学籍前仍然收到被修改过的钥匙. 这个用的是 现有 `lms:exam:read` 范围 `lms:exam:read_own` 检查和派任关系, 从来没有角色名称或客户端提供的审查者旗帜. `passed` 仍然是最终结果.

### 私人大厅展示

使用 `lms.operations.displaySnapshotGet()` 用于服务器配置的当前显示。 这需要 `lms:display:read`,返回原始快照JSON(没有信封),不包括学生身份和房间证明。 授权返回的私人频道 `displayAuthorizePost({ socket_id, channel_name })`。密码或访问令牌绝不能被嵌入页面 URL 或浏览器捆绑.

订阅 `snapshot.socket.event`,然后应用 `LmsDisplayPatch` 在解剖学上反对 `base_version`。忽略已经应用的版本。 从不完整的部分恢复,版本间隙,并重新连接到一个新鲜快照;不要民意调查. 服务器会修正时区/ 天, 如果显示被禁用或不准备, 则返回 503 。 学生计数变化和会话生命周期更新在承诺的 LMS 变化后被推动. 工作人员的姓名随着下一次LMS预测的更新或日转而得到更新.

## 常见问题

### @faiber/faiber-lms 是什么？

教育数据传输

### 如何安装 @faiber/faiber-lms？

在项目目录运行 npm install @faiber/faiber-lms，或使用 pnpm add / yarn add / bun add。

### @faiber/faiber-lms 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @faiber/faiber-lms 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @faiber/faiber-lms 可以商用吗？

@faiber/faiber-lms 使用 未声明 许可。package\.json 没有声明许可证。没有许可证的代码默认保留全部权利，商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括，不构成法律意见，请以许可原文为准。

### @faiber/faiber-lms 的下载量有多少？

根据 npm 官方下载统计，@faiber/faiber-lms 在 2026/10/14 – 2026/11/12 这 30 天内被下载 3,761 次，日均约 125 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @faiber/faiber-lms 还在维护吗？

最新版本 2\.8\.0 发布于 2026/11/14（今天）；至今共发布 66 个版本，其中过去 12 个月发布了 66 个；首次发布于 2026/07/18。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

