npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@crimson-education/sdk

v0.2.4

Published

Crimson SDK for accessing Crimson App APIs

Downloads

543

Readme

@crimson-education/sdk 使用文档

@crimson-education/sdk 是一个用于访问 Crimson App(Roadmap 相关)后端接口的 TypeScript SDK,包含三层能力:

  • Core(框架无关)CrimsonClient + 各业务 API(missions / tasks / roadmap / users / mission library)
  • iframe(跨域/嵌入场景):通过 postMessage 初始化鉴权信息,并提供可订阅的鉴权状态
  • React(可选):基于 @tanstack/react-query 的 Provider 与 Hooks(通过 @crimson-education/sdk/react 引入)

说明:SDK 默认依赖运行时 fetch。在 Node.js 环境建议使用 Node 18+(内置 fetch),或自行注入/polyfill。


安装与构建

安装

如果已发布到 npm:

npm i @crimson-education/sdk

本地开发构建

crimson-sdk/ 目录下:

npm i
npm run build

编译产物输出到 crimson-sdk/dist/(测试也使用该目录)。


快速开始(Core)

import { createCrimsonClient } from "@crimson-education/sdk";

const client = createCrimsonClient({
  apiUrl: "https://api.example.com",
  getToken: async () => "YOUR_TOKEN",
  // 推荐:设置客户端标识,用于 API 调用追踪
  clientId: "my-app",
  // 可选:默认 Bearer;如使用自定义鉴权头格式可覆盖
  // authScheme: "crimsonauthkey",
});

// 读取 roadmap context
const ctx = await client.roadmap.context("student-uid");

// 拉取 missions(不传 start/limit 时返回按 category 分组的旧结构)
const categories = await client.missions.list("student-uid");

// 拉取 missions(强制分页结构)
const page = await client.missions.listPaginated("student-uid", undefined, {
  start: 0,
  limit: 20,
});

Core API 参考

1) CrimsonClient

入口:createCrimsonClient(config) / new CrimsonClient(config)

配置类型:CrimsonClientConfig

  • apiUrl: string:后端 API 基地址(SDK 会自动去掉末尾 /
  • getToken: () => string | Promise<string>:获取 token 的函数
  • authScheme?: string:鉴权 scheme(默认 "Bearer")。SDK 会自动去掉 token 前缀 "Bearer ",再拼接成 Authorization: "<scheme> <token>"
  • clientId?: string:客户端应用标识,用于 API 调用追踪(如 "new-roadmap""capstone"
  • clientVersion?: string:SDK 版本覆盖,默认使用 SDK 包版本

响应约定(CrimsonClient.fetch<T>):

  • 若响应 JSON 形如 { data: ... }没有 pagination 字段:SDK 会自动 解包,直接返回 data
  • 若响应 JSON 形如 { data: ..., pagination: ... }:SDK 返回整个对象(对应 PaginatedResult<T>
  • 若响应为空(如 204):返回 undefined
  • 若 HTTP 非 2xx:抛出 Error("Crimson SDK Error: <status> ... - <body>")

2) MissionsApi(client.missions

涉及接口:

  • GET /roadmap/missions
  • POST /roadmap/missions
  • PUT /roadmap/missions/:linkId
  • DELETE /roadmap/missions/:linkId
  • POST /roadmap/missions/batch
  • POST /roadmap/missions/batch-delete
  • POST /roadmap/missions/batch-restore

主要方法:

  • list(userId, filters?)
    • 不传 start/limit:返回 MissionsCategory[](兼容旧后端)
    • 传入 start/limit:返回 PaginatedResult<Mission>
    • filtersMissionFilters)支持:status[]titleroadmapIdgroupBydueDateStartdueDateEndstartlimit
  • listPaginated(userId, filters?, pagination?)
    • 始终返回 PaginatedResult<Mission>(并在后端仍返回旧结构时做转换)
  • create(data: Partial<Mission>)
  • update(linkId: string, data: Partial<Mission>)
  • delete(linkId: string)
  • batchEdit(userId, roadmapId, missions: BatchMissionOperation[])
    • 单次请求内执行 add/update/delete(详见 BatchMissionAdd/Update/Delete 类型)
  • batchDelete(linkIds: string[])
  • batchRestore(linkIds: string[])

3) TasksApi(client.tasks

涉及接口:

  • GET /roadmap/action-items
  • GET /roadmap/action-items/creators
  • POST /roadmap/action-items
  • PUT /roadmap/action-items/:id
  • DELETE /roadmap/action-items/:id
  • POST /roadmap/action-items/:actionItemId/resources
  • POST /roadmap/upload
  • GET /roadmap/download

主要方法:

  • list(params, filters?)
    • params 支持:missionId / missionLinkIds / roadmapId / userId
    • filtersTaskFilters)支持:
      • status[] - 按状态过滤(如 ['PLANNED', 'DONE']
      • description - 按描述关键词过滤
      • creatorId - 按创建者 ID 过滤
      • dueDateStart - 按截止日期开始过滤(ISO 格式)
      • dueDateEnd - 按截止日期结束过滤(ISO 格式)
      • orderBy - 排序方式:'priority' | 'dueDate' | 'missionTitle' | 'createdAt'
      • start / limit - 分页参数
    • 默认返回 Task[]
    • 同时提供 roadmapId 且提供 start/limit 时:返回 PaginatedResult<Task>
  • listPaginated(roadmapId, userId, filters?, pagination?)
    • 始终返回 PaginatedResult<Task>(内部复用 list
  • getCreators(roadmapId)
    • 获取指定 roadmap 下所有任务的创建者列表
  • getDownloadUrl(key)
    • 获取 S3 资源的预签名下载 URL
  • create(data: Partial<Task>)
    • 支持两种模式:
      • Mission 关联任务:提供 roadmapMissionId(或 missionId
      • 独立任务(Standalone):只提供 roadmapId,不关联 mission
  • createStandalone(roadmapId: string, data)
    • 创建独立任务的便捷方法
  • update(id: string, data: Partial<Task>)
    • 支持更新 resources 字段(完整替换)
  • delete(id: string)
  • addResources(actionItemId: string, resources: AddResourceInput | AddResourceInput[])
    • 向任务添加资源/附件
  • updateResources(taskId: string, resources: UpdateTaskResourceInput[])
    • 更新任务资源(支持新增、修改、删除)
    • 包含 id 的资源会被更新,不包含 id 的会新建,不在数组中的会被删除
  • getUploadUrl(filename: string, contentType: string): Promise<UploadUrlResponse>
    • 获取 S3 预签名上传 URL
    • 返回 { putUrl, url, key, bucket }
  • uploadFile(file: File | Blob, filename?: string): Promise<{ url, key }>
    • 上传文件到 S3 的便捷方法(内部调用 getUploadUrl + PUT 上传)

关于 Task 结构的“归一化”:

SDK 会将后端返回的 action item 做归一化,保证至少返回以下核心字段:

  • id
  • name(优先 name,否则使用 description
  • date(优先 date,否则使用 dueDate
  • roadmapMissionId(优先 roadmapMissionId,否则使用 missionId/linkId
  • userId(优先 userId,否则使用 creatorId
  • isComplete(优先使用后端的 isComplete,否则由 status === DONEfinishedAt 推导)

因此你可能看不到后端返回的所有原始字段(它们被统一抽象到上述字段里)。

4) RoadmapApi(client.roadmap

涉及接口:

  • GET /roadmap/context?userId=...
  • POST /roadmap/context

主要方法:

  • context(userId: string): Promise<RoadmapContext>
  • createContext(userId: string): Promise<RoadmapContext>

5) UsersApi(client.users

涉及接口:

  • GET /roadmap/users?ids=...

主要方法:

  • getByIds(userIds: string[]): Promise<User[]>
    • 根据用户 ID 列表获取用户信息
    • 用于显示任务分配者(assignedBy)等场景
    • 返回字段:userId, firstName, lastName, email, profileImageId
  • getById(userId: string): Promise<User | undefined>
    • 获取单个用户信息的便捷方法

6) MissionLibraryApi(client.library

涉及接口:

  • GET /roadmap/library/missions
  • POST /roadmap/library/missions
  • PUT /roadmap/library/missions/:missionId
  • GET /roadmap/library/tasks
  • POST /roadmap/library/missions/copy
  • POST /roadmap/library/missions/assign-bulk
  • POST /roadmap/library/tasks/assign-bulk
  • POST /roadmap/library/tasks/create-from-predefined
  • GET /roadmap/missions/:id/detail

主要方法:

  • listTemplateMissions(filters?: TemplateMissionFilters): Promise<PaginatedResult<TemplateMission>>
  • createTemplateMission(input: TemplateMissionCreateInput): Promise<TemplateMission>
  • updateTemplateMission(id: string, raw: TemplateMission, update: TemplateMissionUpdateInput): Promise<TemplateMission>
  • listTemplateTasks(filters?: TemplateTaskFilters): Promise<PaginatedResult<TemplateTask>>
  • copyTemplateMission(input: CopyTemplateMissionInput): Promise<TemplateMission[]>
  • assignBulkMission(input: AssignBulkMissionInput[]): Promise<{ code: number; msg?: string }>
  • assignBulkTask(input: AssignBulkTaskInput[]): Promise<{ code: number; msg?: string }>
  • createFromPredefinedTasks(input: { missionId: string; predefinedTaskIds: string[] }): Promise<TemplateTask[]>
  • getMissionById(missionId: string): Promise<MissionDetail | null>
    • 注意:当后端返回非 2xx(例如 404)时,SDK 会抛异常;建议使用 try/catch 处理。

iframe 层(嵌入/跨域场景)

入口:@crimson-education/sdk(主入口会导出 iframe 层)

典型用法:

  1. 在 iframe 内调用 setupIframeListener() 监听父页面 postMessage 注入 token
  2. 通过 getAuthState()/subscribeToAuthState() 或 React Hook useAuthState() 获取就绪状态

主要 API:

  • setupIframeListener(allowedOrigins?: string[]): CleanupFn
    • allowedOrigins 不传则使用默认白名单(也可通过 NEXT_PUBLIC_ALLOWED_PARENTS 覆盖)
  • getToken() / getUserId() / getStudentId()
  • getAuthState(): AuthState / subscribeToAuthState(cb)
  • persistStandaloneAuth(payload: ZoidProps)
    • 用于“非 iframe”本地调试:写入 localStorage 并触发就绪事件

常量:

  • XPROPS_READY_EVENT
  • STORAGE_KEYS
  • VIRTUAL_MISSION_ID

父页面发送 INIT 消息的 payload 形状(示例):

window.frames[0]?.postMessage(
  {
    type: "INIT",
    payload: {
      token,
      userId,
      studentId,
      user: {
        /* 可选 */
      },
    },
  },
  "https://your-iframe-origin.example.com",
);

React 层(@crimson-education/sdk/react

React 层通过 peerDependencies 声明依赖(不会强制安装):

  • react(>=18)
  • @tanstack/react-query(>=5)

CrimsonProvider

import { CrimsonProvider } from "@crimson-education/sdk/react";

export function App() {
  return (
    <CrimsonProvider
      apiUrl="https://api.example.com"
      clientId="my-app" // 推荐:设置客户端标识
    >
      <YourRoutes />
    </CrimsonProvider>
  );
}

Props:

  • apiUrl: string:后端 API 基地址
  • clientId?: string:客户端应用标识,用于 API 调用追踪
  • allowedParentOrigins?: string[]:允许的父页面 origin 白名单
  • queryClient?: QueryClient:可选的自定义 QueryClient 实例

CrimsonProvider 会:

  • 创建并注入 CrimsonClient(包含 clientId 配置)
  • 自动从 iframe/xprops/localStorage 读取 token(使用 iframe 层的 getToken()
  • 初始化 @tanstack/react-queryQueryClientProvider
  • 安装 postMessage 监听(setupIframeListener

Hooks(常用)

  • useAuthState():返回 { token, userId, studentId, ready, user? }
  • useMissions(userId, enabled):拉取用户 missions(扁平化 Mission[])
  • useMissionsInfinite(userId, filters?, options?):分页拉取 missions
  • useTasks(missionId, enabled):拉取某 mission 的 tasks
  • useTasksInfinite(roadmapId, userId, filters?, options?):分页拉取 tasks
  • useRoadmapContext(userId, enabled):拉取 roadmap context
  • useTaskCreators(roadmapId, enabled):获取任务创建者列表
  • CRUD mutation:
    • useCreateMission/useUpdateMission/useDeleteMission
    • useCreateTask/useUpdateTask/useDeleteTask
    • useCreateTemplateMission/useUpdateTemplateMission
    • useGetDownloadUrl:获取文件下载地址
  • 模板库相关:
    • useTemplateMissions/useTemplateMissionsInfinite
    • useTemplateTasks/useTemplateTasksInfinite
    • useTemplateMissionDetail(missionId)

常见问题

1) 为什么拿到的返回值不是 { data: ... }

SDK 会默认解包后端常见的 { data: ... } 格式:大部分方法直接返回 data 本体。

只有当响应同时带 pagination(即 { data, pagination })时,才会返回完整对象。

2) Node 环境报 fetch is not defined

请使用 Node 18+,或为运行环境提供 fetch polyfill(例如 undici)。


API 调用追踪

SDK 支持向后端发送客户端标识信息,用于追踪 API 调用来源。

发送的 Headers

当配置了 clientId 时,SDK 会自动在每个请求中发送以下 headers:

| Header | 说明 | 示例值 | | ------------------- | -------------- | ------------------------- | | X-Client-ID | 客户端应用标识 | new-roadmap, capstone | | X-Client-Version | SDK 版本 | 0.2.0 | | X-Client-Platform | 运行环境 | browser, node |

后端日志

后端会记录包含以下字段的结构化日志:

{
  "type": "api_request",
  "request_id": "uuid",
  "client_id": "new-roadmap",
  "client_version": "0.2.0",
  "client_platform": "browser",
  "auth_mode": "bearer",
  "user_id": "auth0-xxx",
  "tenant": "crimsonapp",
  "method": "GET",
  "path": "/roadmap/missions",
  "status": 200,
  "duration_ms": 123,
  "timestamp": "2024-01-01T00:00:00.000Z"
}

最佳实践

  1. 始终设置 clientId:便于区分不同应用的 API 调用
  2. 使用有意义的标识:如 new-roadmapcapstoneadmin-dashboard
  3. 响应头追踪:后端会返回 X-Request-ID header,可用于调试和问题排查