@crimson-education/sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +377 -0
  2. package/dist/core/account.d.ts +14 -0
  3. package/dist/core/account.js +30 -0
  4. package/dist/core/auth/index.d.ts +11 -0
  5. package/dist/core/auth/index.js +25 -0
  6. package/dist/core/auth/oauth-adapter.d.ts +78 -0
  7. package/dist/core/auth/oauth-adapter.js +341 -0
  8. package/dist/core/auth/pkce.d.ts +20 -0
  9. package/dist/core/auth/pkce.js +112 -0
  10. package/dist/core/auth/token-manager.d.ts +68 -0
  11. package/dist/core/auth/token-manager.js +294 -0
  12. package/dist/core/auth/token-storage.d.ts +46 -0
  13. package/dist/core/auth/token-storage.js +155 -0
  14. package/dist/core/auth/types.d.ts +148 -0
  15. package/dist/core/auth/types.js +15 -0
  16. package/dist/core/client.d.ts +84 -0
  17. package/dist/core/client.js +229 -0
  18. package/dist/core/index.d.ts +11 -0
  19. package/dist/core/index.js +47 -0
  20. package/dist/core/missionLibrary.d.ts +68 -0
  21. package/dist/core/missionLibrary.js +143 -0
  22. package/dist/core/missions.d.ts +45 -0
  23. package/dist/core/missions.js +140 -0
  24. package/dist/core/roadmap.d.ts +8 -0
  25. package/dist/core/roadmap.js +18 -0
  26. package/dist/core/studentProfile.d.ts +21 -0
  27. package/dist/core/studentProfile.js +41 -0
  28. package/dist/core/tasks.d.ts +117 -0
  29. package/dist/core/tasks.js +288 -0
  30. package/dist/core/types.d.ts +402 -0
  31. package/dist/core/types.js +2 -0
  32. package/dist/core/users.d.ts +21 -0
  33. package/dist/core/users.js +46 -0
  34. package/dist/iframe/auth-state.d.ts +7 -0
  35. package/dist/iframe/auth-state.js +125 -0
  36. package/dist/iframe/constants.d.ts +8 -0
  37. package/dist/iframe/constants.js +29 -0
  38. package/dist/iframe/index.d.ts +5 -0
  39. package/dist/iframe/index.js +17 -0
  40. package/dist/iframe/listener.d.ts +2 -0
  41. package/dist/iframe/listener.js +57 -0
  42. package/dist/iframe/types.d.ts +18 -0
  43. package/dist/iframe/types.js +2 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.js +22 -0
  46. package/dist/react/hooks/index.d.ts +10 -0
  47. package/dist/react/hooks/index.js +48 -0
  48. package/dist/react/hooks/useAccount.d.ts +13 -0
  49. package/dist/react/hooks/useAccount.js +39 -0
  50. package/dist/react/hooks/useAuthState.d.ts +2 -0
  51. package/dist/react/hooks/useAuthState.js +18 -0
  52. package/dist/react/hooks/useMissionLibrary.d.ts +31 -0
  53. package/dist/react/hooks/useMissionLibrary.js +183 -0
  54. package/dist/react/hooks/useMissions.d.ts +24 -0
  55. package/dist/react/hooks/useMissions.js +104 -0
  56. package/dist/react/hooks/useOAuth.d.ts +94 -0
  57. package/dist/react/hooks/useOAuth.js +211 -0
  58. package/dist/react/hooks/useRoadmapContext.d.ts +2 -0
  59. package/dist/react/hooks/useRoadmapContext.js +29 -0
  60. package/dist/react/hooks/useStudentProfile.d.ts +24 -0
  61. package/dist/react/hooks/useStudentProfile.js +65 -0
  62. package/dist/react/hooks/useTasks.d.ts +26 -0
  63. package/dist/react/hooks/useTasks.js +137 -0
  64. package/dist/react/hooks/useUsers.d.ts +9 -0
  65. package/dist/react/hooks/useUsers.js +50 -0
  66. package/dist/react/index.d.ts +3 -0
  67. package/dist/react/index.js +21 -0
  68. package/dist/react/provider.d.ts +16 -0
  69. package/dist/react/provider.js +41 -0
  70. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,377 @@
1
+ # @crimson/sdk 使用文档
2
+
3
+ `@crimson/sdk` 是一个用于访问 Crimson App(Roadmap 相关)后端接口的 TypeScript SDK,包含三层能力:
4
+
5
+ - **Core(框架无关)**:`CrimsonClient` + 各业务 API(missions / tasks / roadmap / users / mission library)
6
+ - **iframe(跨域/嵌入场景)**:通过 `postMessage` 初始化鉴权信息,并提供可订阅的鉴权状态
7
+ - **React(可选)**:基于 `@tanstack/react-query` 的 Provider 与 Hooks(通过 `@crimson/sdk/react` 引入)
8
+
9
+ > 说明:SDK 默认依赖运行时 `fetch`。在 Node.js 环境建议使用 Node 18+(内置 `fetch`),或自行注入/polyfill。
10
+
11
+ ---
12
+
13
+ ## 安装与构建
14
+
15
+ ### 安装
16
+
17
+ 如果已发布到 npm:
18
+
19
+ ```bash
20
+ npm i @crimson/sdk
21
+ ```
22
+
23
+ ### 本地开发构建
24
+
25
+ 在 `crimson-sdk/` 目录下:
26
+
27
+ ```bash
28
+ npm i
29
+ npm run build
30
+ ```
31
+
32
+ 编译产物输出到 `crimson-sdk/dist/`(测试也使用该目录)。
33
+
34
+ ---
35
+
36
+ ## 快速开始(Core)
37
+
38
+ ```ts
39
+ import { createCrimsonClient } from "@crimson/sdk";
40
+
41
+ const client = createCrimsonClient({
42
+ apiUrl: "https://api.example.com",
43
+ getToken: async () => "YOUR_TOKEN",
44
+ // 推荐:设置客户端标识,用于 API 调用追踪
45
+ clientId: "my-app",
46
+ // 可选:默认 Bearer;如使用自定义鉴权头格式可覆盖
47
+ // authScheme: "crimsonauthkey",
48
+ });
49
+
50
+ // 读取 roadmap context
51
+ const ctx = await client.roadmap.context("student-uid");
52
+
53
+ // 拉取 missions(不传 start/limit 时返回按 category 分组的旧结构)
54
+ const categories = await client.missions.list("student-uid");
55
+
56
+ // 拉取 missions(强制分页结构)
57
+ const page = await client.missions.listPaginated("student-uid", undefined, {
58
+ start: 0,
59
+ limit: 20,
60
+ });
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Core API 参考
66
+
67
+ ### 1) CrimsonClient
68
+
69
+ 入口:`createCrimsonClient(config)` / `new CrimsonClient(config)`
70
+
71
+ 配置类型:`CrimsonClientConfig`
72
+
73
+ - `apiUrl: string`:后端 API 基地址(SDK 会自动去掉末尾 `/`)
74
+ - `getToken: () => string | Promise<string>`:获取 token 的函数
75
+ - `authScheme?: string`:鉴权 scheme(默认 `"Bearer"`)。SDK 会自动去掉 token 前缀 `"Bearer "`,再拼接成 `Authorization: "<scheme> <token>"`
76
+ - `clientId?: string`:客户端应用标识,用于 API 调用追踪(如 `"new-roadmap"`、`"capstone"`)
77
+ - `clientVersion?: string`:SDK 版本覆盖,默认使用 SDK 包版本
78
+
79
+ 响应约定(`CrimsonClient.fetch<T>`):
80
+
81
+ - 若响应 JSON 形如 `{ data: ... }` 且 **没有** `pagination` 字段:SDK 会自动 **解包**,直接返回 `data`
82
+ - 若响应 JSON 形如 `{ data: ..., pagination: ... }`:SDK 返回整个对象(对应 `PaginatedResult<T>`)
83
+ - 若响应为空(如 204):返回 `undefined`
84
+ - 若 HTTP 非 2xx:抛出 `Error("Crimson SDK Error: <status> ... - <body>")`
85
+
86
+ ### 2) MissionsApi(`client.missions`)
87
+
88
+ 涉及接口:
89
+
90
+ - `GET /roadmap/missions`
91
+ - `POST /roadmap/missions`
92
+ - `PUT /roadmap/missions/:linkId`
93
+ - `DELETE /roadmap/missions/:linkId`
94
+ - `POST /roadmap/missions/batch`
95
+ - `POST /roadmap/missions/batch-delete`
96
+ - `POST /roadmap/missions/batch-restore`
97
+
98
+ 主要方法:
99
+
100
+ - `list(userId, filters?)`
101
+ - 不传 `start/limit`:返回 `MissionsCategory[]`(兼容旧后端)
102
+ - 传入 `start/limit`:返回 `PaginatedResult<Mission>`
103
+ - `filters`(`MissionFilters`)支持:`status[]`、`title`、`roadmapId`、`groupBy`、`dueDateStart`、`dueDateEnd`、`start`、`limit`
104
+ - `listPaginated(userId, filters?, pagination?)`
105
+ - 始终返回 `PaginatedResult<Mission>`(并在后端仍返回旧结构时做转换)
106
+ - `create(data: Partial<Mission>)`
107
+ - `update(linkId: string, data: Partial<Mission>)`
108
+ - `delete(linkId: string)`
109
+ - `batchEdit(userId, roadmapId, missions: BatchMissionOperation[])`
110
+ - 单次请求内执行 add/update/delete(详见 `BatchMissionAdd/Update/Delete` 类型)
111
+ - `batchDelete(linkIds: string[])`
112
+ - `batchRestore(linkIds: string[])`
113
+
114
+ ### 3) TasksApi(`client.tasks`)
115
+
116
+ 涉及接口:
117
+
118
+ - `GET /roadmap/action-items`
119
+ - `POST /roadmap/action-items`
120
+ - `PUT /roadmap/action-items/:id`
121
+ - `DELETE /roadmap/action-items/:id`
122
+ - `POST /roadmap/action-items/:actionItemId/resources`
123
+ - `POST /roadmap/upload`
124
+
125
+ 主要方法:
126
+
127
+ - `list(params, filters?)`
128
+ - `params` 支持:`missionId` / `missionLinkIds` / `roadmapId` / `userId`
129
+ - `filters`(`TaskFilters`)支持:
130
+ - `status[]` - 按状态过滤(如 `['PLANNED', 'DONE']`)
131
+ - `description` - 按描述关键词过滤
132
+ - `creatorId` - 按创建者 ID 过滤
133
+ - `dueDateStart` - 按截止日期开始过滤(ISO 格式)
134
+ - `dueDateEnd` - 按截止日期结束过滤(ISO 格式)
135
+ - `orderBy` - 排序方式:`'priority'` | `'dueDate'` | `'missionTitle'` | `'createdAt'`
136
+ - `start` / `limit` - 分页参数
137
+ - 默认返回 `Task[]`
138
+ - 当 **同时提供** `roadmapId` 且提供 `start/limit` 时:返回 `PaginatedResult<Task>`
139
+ - `listPaginated(roadmapId, userId, filters?, pagination?)`
140
+ - 始终返回 `PaginatedResult<Task>`(内部复用 `list`)
141
+ - `create(data: Partial<Task>)`
142
+ - 支持两种模式:
143
+ - Mission 关联任务:提供 `roadmapMissionId`(或 `missionId`)
144
+ - 独立任务(Standalone):只提供 `roadmapId`,不关联 mission
145
+ - `createStandalone(roadmapId: string, data)`
146
+ - 创建独立任务的便捷方法
147
+ - `update(id: string, data: Partial<Task>)`
148
+ - 支持更新 `resources` 字段(完整替换)
149
+ - `delete(id: string)`
150
+ - `addResources(actionItemId: string, resources: AddResourceInput | AddResourceInput[])`
151
+ - 向任务添加资源/附件
152
+ - `updateResources(taskId: string, resources: UpdateTaskResourceInput[])`
153
+ - 更新任务资源(支持新增、修改、删除)
154
+ - 包含 `id` 的资源会被更新,不包含 `id` 的会新建,不在数组中的会被删除
155
+ - `getUploadUrl(filename: string, contentType: string): Promise<UploadUrlResponse>`
156
+ - 获取 S3 预签名上传 URL
157
+ - 返回 `{ putUrl, url, key, bucket }`
158
+ - `uploadFile(file: File | Blob, filename?: string): Promise<{ url, key }>`
159
+ - 上传文件到 S3 的便捷方法(内部调用 `getUploadUrl` + PUT 上传)
160
+
161
+ 关于 Task 结构的“归一化”:
162
+
163
+ SDK 会将后端返回的 action item 做归一化,保证至少返回以下核心字段:
164
+
165
+ - `id`
166
+ - `name`(优先 `name`,否则使用 `description`)
167
+ - `date`(优先 `date`,否则使用 `dueDate`)
168
+ - `roadmapMissionId`(优先 `roadmapMissionId`,否则使用 `missionId/linkId`)
169
+ - `userId`(优先 `userId`,否则使用 `creatorId`)
170
+ - `isComplete`(优先使用后端的 `isComplete`,否则由 `status === DONE` 或 `finishedAt` 推导)
171
+
172
+ 因此你可能看不到后端返回的所有原始字段(它们被统一抽象到上述字段里)。
173
+
174
+ ### 4) RoadmapApi(`client.roadmap`)
175
+
176
+ 涉及接口:
177
+
178
+ - `GET /roadmap/context?userId=...`
179
+ - `POST /roadmap/context`
180
+
181
+ 主要方法:
182
+
183
+ - `context(userId: string): Promise<RoadmapContext>`
184
+ - `createContext(userId: string): Promise<RoadmapContext>`
185
+
186
+ ### 5) UsersApi(`client.users`)
187
+
188
+ 涉及接口:
189
+
190
+ - `GET /roadmap/users?ids=...`
191
+
192
+ 主要方法:
193
+
194
+ - `getByIds(userIds: string[]): Promise<User[]>`
195
+ - 根据用户 ID 列表获取用户信息
196
+ - 用于显示任务分配者(assignedBy)等场景
197
+ - 返回字段:`userId`, `firstName`, `lastName`, `email`, `profileImageId`
198
+ - `getById(userId: string): Promise<User | undefined>`
199
+ - 获取单个用户信息的便捷方法
200
+
201
+ ### 6) MissionLibraryApi(`client.library`)
202
+
203
+ 涉及接口:
204
+
205
+ - `GET /roadmap/library/missions`
206
+ - `GET /roadmap/library/tasks`
207
+ - `POST /roadmap/library/missions/copy`
208
+ - `POST /roadmap/library/missions/assign-bulk`
209
+ - `POST /roadmap/library/tasks/assign-bulk`
210
+ - `POST /roadmap/library/tasks/create-from-predefined`
211
+ - `GET /roadmap/missions/:id/detail`
212
+
213
+ 主要方法:
214
+
215
+ - `listTemplateMissions(filters?: TemplateMissionFilters): Promise<PaginatedResult<TemplateMission>>`
216
+ - `listTemplateTasks(filters?: TemplateTaskFilters): Promise<PaginatedResult<TemplateTask>>`
217
+ - `copyTemplateMission(input: CopyTemplateMissionInput): Promise<TemplateMission[]>`
218
+ - `assignBulkMission(input: AssignBulkMissionInput[]): Promise<{ code: number; msg?: string }>`
219
+ - `assignBulkTask(input: AssignBulkTaskInput[]): Promise<{ code: number; msg?: string }>`
220
+ - `createFromPredefinedTasks(input: { missionId: string; predefinedTaskIds: string[] }): Promise<TemplateTask[]>`
221
+ - `getMissionById(missionId: string): Promise<MissionDetail | null>`
222
+ - 注意:当后端返回非 2xx(例如 404)时,SDK 会抛异常;建议使用 `try/catch` 处理。
223
+
224
+ ---
225
+
226
+ ## iframe 层(嵌入/跨域场景)
227
+
228
+ 入口:`@crimson/sdk`(主入口会导出 iframe 层)
229
+
230
+ 典型用法:
231
+
232
+ 1. 在 iframe 内调用 `setupIframeListener()` 监听父页面 `postMessage` 注入 token
233
+ 2. 通过 `getAuthState()/subscribeToAuthState()` 或 React Hook `useAuthState()` 获取就绪状态
234
+
235
+ 主要 API:
236
+
237
+ - `setupIframeListener(allowedOrigins?: string[]): CleanupFn`
238
+ - `allowedOrigins` 不传则使用默认白名单(也可通过 `NEXT_PUBLIC_ALLOWED_PARENTS` 覆盖)
239
+ - `getToken()` / `getUserId()` / `getStudentId()`
240
+ - `getAuthState(): AuthState` / `subscribeToAuthState(cb)`
241
+ - `persistStandaloneAuth(payload: ZoidProps)`
242
+ - 用于“非 iframe”本地调试:写入 localStorage 并触发就绪事件
243
+
244
+ 常量:
245
+
246
+ - `XPROPS_READY_EVENT`
247
+ - `STORAGE_KEYS`
248
+ - `VIRTUAL_MISSION_ID`
249
+
250
+ 父页面发送 INIT 消息的 payload 形状(示例):
251
+
252
+ ```ts
253
+ window.frames[0]?.postMessage(
254
+ {
255
+ type: "INIT",
256
+ payload: {
257
+ token,
258
+ userId,
259
+ studentId,
260
+ user: {
261
+ /* 可选 */
262
+ },
263
+ },
264
+ },
265
+ "https://your-iframe-origin.example.com",
266
+ );
267
+ ```
268
+
269
+ ---
270
+
271
+ ## React 层(`@crimson/sdk/react`)
272
+
273
+ React 层通过 `peerDependencies` 声明依赖(不会强制安装):
274
+
275
+ - `react`(>=18)
276
+ - `@tanstack/react-query`(>=5)
277
+
278
+ ### CrimsonProvider
279
+
280
+ ```tsx
281
+ import { CrimsonProvider } from "@crimson/sdk/react";
282
+
283
+ export function App() {
284
+ return (
285
+ <CrimsonProvider
286
+ apiUrl="https://api.example.com"
287
+ clientId="my-app" // 推荐:设置客户端标识
288
+ >
289
+ <YourRoutes />
290
+ </CrimsonProvider>
291
+ );
292
+ }
293
+ ```
294
+
295
+ Props:
296
+
297
+ - `apiUrl: string`:后端 API 基地址
298
+ - `clientId?: string`:客户端应用标识,用于 API 调用追踪
299
+ - `allowedParentOrigins?: string[]`:允许的父页面 origin 白名单
300
+ - `queryClient?: QueryClient`:可选的自定义 QueryClient 实例
301
+
302
+ `CrimsonProvider` 会:
303
+
304
+ - 创建并注入 `CrimsonClient`(包含 clientId 配置)
305
+ - 自动从 iframe/xprops/localStorage 读取 token(使用 iframe 层的 `getToken()`)
306
+ - 初始化 `@tanstack/react-query` 的 `QueryClientProvider`
307
+ - 安装 `postMessage` 监听(`setupIframeListener`)
308
+
309
+ ### Hooks(常用)
310
+
311
+ - `useAuthState()`:返回 `{ token, userId, studentId, ready, user? }`
312
+ - `useMissions(userId, enabled)`:拉取用户 missions(扁平化 Mission[])
313
+ - `useMissionsInfinite(userId, filters?, options?)`:分页拉取 missions
314
+ - `useTasks(missionId, enabled)`:拉取某 mission 的 tasks
315
+ - `useTasksInfinite(roadmapId, userId, filters?, options?)`:分页拉取 tasks
316
+ - `useRoadmapContext(userId, enabled)`:拉取 roadmap context
317
+ - CRUD mutation:
318
+ - `useCreateMission/useUpdateMission/useDeleteMission`
319
+ - `useCreateTask/useUpdateTask/useDeleteTask`
320
+
321
+ ---
322
+
323
+ ## 常见问题
324
+
325
+ ### 1) 为什么拿到的返回值不是 `{ data: ... }`?
326
+
327
+ SDK 会默认解包后端常见的 `{ data: ... }` 格式:大部分方法直接返回 `data` 本体。
328
+
329
+ 只有当响应同时带 `pagination`(即 `{ data, pagination }`)时,才会返回完整对象。
330
+
331
+ ### 2) Node 环境报 `fetch is not defined`?
332
+
333
+ 请使用 Node 18+,或为运行环境提供 `fetch` polyfill(例如 `undici`)。
334
+
335
+ ---
336
+
337
+ ## API 调用追踪
338
+
339
+ SDK 支持向后端发送客户端标识信息,用于追踪 API 调用来源。
340
+
341
+ ### 发送的 Headers
342
+
343
+ 当配置了 `clientId` 时,SDK 会自动在每个请求中发送以下 headers:
344
+
345
+ | Header | 说明 | 示例值 |
346
+ | ------------------- | -------------- | ------------------------- |
347
+ | `X-Client-ID` | 客户端应用标识 | `new-roadmap`, `capstone` |
348
+ | `X-Client-Version` | SDK 版本 | `0.2.0` |
349
+ | `X-Client-Platform` | 运行环境 | `browser`, `node` |
350
+
351
+ ### 后端日志
352
+
353
+ 后端会记录包含以下字段的结构化日志:
354
+
355
+ ```json
356
+ {
357
+ "type": "api_request",
358
+ "request_id": "uuid",
359
+ "client_id": "new-roadmap",
360
+ "client_version": "0.2.0",
361
+ "client_platform": "browser",
362
+ "auth_mode": "bearer",
363
+ "user_id": "auth0-xxx",
364
+ "tenant": "crimsonapp",
365
+ "method": "GET",
366
+ "path": "/roadmap/missions",
367
+ "status": 200,
368
+ "duration_ms": 123,
369
+ "timestamp": "2024-01-01T00:00:00.000Z"
370
+ }
371
+ ```
372
+
373
+ ### 最佳实践
374
+
375
+ 1. **始终设置 `clientId`**:便于区分不同应用的 API 调用
376
+ 2. **使用有意义的标识**:如 `new-roadmap`、`capstone`、`admin-dashboard`
377
+ 3. **响应头追踪**:后端会返回 `X-Request-ID` header,可用于调试和问题排查
@@ -0,0 +1,14 @@
1
+ import type { CrimsonClient } from "./client";
2
+ import type { CurrentUserRoles } from "./types";
3
+ export declare class AccountApi {
4
+ private client;
5
+ constructor(client: CrimsonClient);
6
+ /**
7
+ * Get the current logged-in user's roles
8
+ *
9
+ * @returns Current user's roles including:
10
+ * - userId: The user's ID
11
+ * - roles: Array of role objects with roleId and isPrimary flag
12
+ */
13
+ getCurrentUserRoles(): Promise<CurrentUserRoles>;
14
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AccountApi = void 0;
13
+ class AccountApi {
14
+ constructor(client) {
15
+ this.client = client;
16
+ }
17
+ /**
18
+ * Get the current logged-in user's roles
19
+ *
20
+ * @returns Current user's roles including:
21
+ * - userId: The user's ID
22
+ * - roles: Array of role objects with roleId and isPrimary flag
23
+ */
24
+ getCurrentUserRoles() {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ return this.client.fetch("/api/v1/account/me/roles");
27
+ });
28
+ }
29
+ }
30
+ exports.AccountApi = AccountApi;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * OAuth Authentication Module
3
+ * Provides OAuth 2.0 authentication with PKCE support
4
+ */
5
+ export type { OAuthConfig, OAuthTokens, TokenStorage, OAuthAuthState, OAuthAuthStateListener, TokenRefreshFunction, AuthorizeOptions, CallbackParams, OAuthError, PkceState, } from "./types";
6
+ export { generateCodeVerifier, generateCodeChallenge, generateState, } from "./pkce";
7
+ export { LocalStorageTokenStorage, SessionStorageTokenStorage, MemoryTokenStorage, createDefaultTokenStorage, } from "./token-storage";
8
+ export { TokenManager } from "./token-manager";
9
+ export type { TokenManagerConfig } from "./token-manager";
10
+ export { OAuthAdapter, createCrimsonOAuthAdapter } from "./oauth-adapter";
11
+ export type { OAuthAdapterConfig } from "./oauth-adapter";
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * OAuth Authentication Module
4
+ * Provides OAuth 2.0 authentication with PKCE support
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createCrimsonOAuthAdapter = exports.OAuthAdapter = exports.TokenManager = exports.createDefaultTokenStorage = exports.MemoryTokenStorage = exports.SessionStorageTokenStorage = exports.LocalStorageTokenStorage = exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = void 0;
8
+ // PKCE utilities
9
+ var pkce_1 = require("./pkce");
10
+ Object.defineProperty(exports, "generateCodeVerifier", { enumerable: true, get: function () { return pkce_1.generateCodeVerifier; } });
11
+ Object.defineProperty(exports, "generateCodeChallenge", { enumerable: true, get: function () { return pkce_1.generateCodeChallenge; } });
12
+ Object.defineProperty(exports, "generateState", { enumerable: true, get: function () { return pkce_1.generateState; } });
13
+ // Token storage implementations
14
+ var token_storage_1 = require("./token-storage");
15
+ Object.defineProperty(exports, "LocalStorageTokenStorage", { enumerable: true, get: function () { return token_storage_1.LocalStorageTokenStorage; } });
16
+ Object.defineProperty(exports, "SessionStorageTokenStorage", { enumerable: true, get: function () { return token_storage_1.SessionStorageTokenStorage; } });
17
+ Object.defineProperty(exports, "MemoryTokenStorage", { enumerable: true, get: function () { return token_storage_1.MemoryTokenStorage; } });
18
+ Object.defineProperty(exports, "createDefaultTokenStorage", { enumerable: true, get: function () { return token_storage_1.createDefaultTokenStorage; } });
19
+ // Token manager
20
+ var token_manager_1 = require("./token-manager");
21
+ Object.defineProperty(exports, "TokenManager", { enumerable: true, get: function () { return token_manager_1.TokenManager; } });
22
+ // OAuth adapter
23
+ var oauth_adapter_1 = require("./oauth-adapter");
24
+ Object.defineProperty(exports, "OAuthAdapter", { enumerable: true, get: function () { return oauth_adapter_1.OAuthAdapter; } });
25
+ Object.defineProperty(exports, "createCrimsonOAuthAdapter", { enumerable: true, get: function () { return oauth_adapter_1.createCrimsonOAuthAdapter; } });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * OAuth Adapter
3
+ * Main entry point for OAuth 2.0 authentication with PKCE
4
+ */
5
+ import { OAuthConfig, OAuthTokens, TokenStorage, OAuthAuthState, OAuthAuthStateListener, AuthorizeOptions, CallbackParams } from "./types";
6
+ export interface OAuthAdapterConfig extends OAuthConfig {
7
+ /** Token storage implementation (defaults to localStorage) */
8
+ storage?: TokenStorage;
9
+ /** Enable automatic token refresh (default: true) */
10
+ autoRefresh?: boolean;
11
+ }
12
+ export declare class OAuthAdapter {
13
+ private config;
14
+ private tokenManager;
15
+ private storage;
16
+ private initialized;
17
+ constructor(config: OAuthAdapterConfig);
18
+ /**
19
+ * Initialize the OAuth adapter
20
+ * Loads existing tokens and sets up auto-refresh
21
+ */
22
+ initialize(): Promise<void>;
23
+ /**
24
+ * Get the authorization URL for OAuth flow
25
+ */
26
+ getAuthorizeUrl(options?: AuthorizeOptions): Promise<string>;
27
+ /**
28
+ * Start the OAuth authorization flow
29
+ * Redirects the user to the authorization page
30
+ */
31
+ authorize(options?: AuthorizeOptions): Promise<void>;
32
+ /**
33
+ * Handle the OAuth callback
34
+ * Exchanges the authorization code for tokens
35
+ */
36
+ handleCallback(params: CallbackParams): Promise<OAuthTokens>;
37
+ /**
38
+ * Manually refresh the access token
39
+ */
40
+ refreshToken(): Promise<OAuthTokens | null>;
41
+ /**
42
+ * Logout - revoke tokens and clear storage
43
+ */
44
+ logout(): Promise<void>;
45
+ /**
46
+ * Get current access token if valid
47
+ */
48
+ getAccessToken(): Promise<string | null>;
49
+ /**
50
+ * Get current authentication state
51
+ */
52
+ getAuthState(): OAuthAuthState;
53
+ /**
54
+ * Subscribe to authentication state changes
55
+ */
56
+ subscribe(listener: OAuthAuthStateListener): () => void;
57
+ /**
58
+ * Check if user is authenticated
59
+ */
60
+ isAuthenticated(): boolean;
61
+ /**
62
+ * Clean up resources
63
+ */
64
+ destroy(): void;
65
+ private exchangeCode;
66
+ private refreshTokenWithApi;
67
+ private revokeToken;
68
+ private parseTokenResponse;
69
+ private storePkceState;
70
+ private getPkceState;
71
+ private clearPkceState;
72
+ }
73
+ /**
74
+ * Create an OAuth adapter with default configuration for Crimson API
75
+ */
76
+ export declare function createCrimsonOAuthAdapter(config: Omit<OAuthAdapterConfig, "authorizationEndpoint" | "tokenEndpoint" | "revocationEndpoint"> & {
77
+ apiUrl: string;
78
+ }): OAuthAdapter;