@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.
- package/README.md +377 -0
- package/dist/core/account.d.ts +14 -0
- package/dist/core/account.js +30 -0
- package/dist/core/auth/index.d.ts +11 -0
- package/dist/core/auth/index.js +25 -0
- package/dist/core/auth/oauth-adapter.d.ts +78 -0
- package/dist/core/auth/oauth-adapter.js +341 -0
- package/dist/core/auth/pkce.d.ts +20 -0
- package/dist/core/auth/pkce.js +112 -0
- package/dist/core/auth/token-manager.d.ts +68 -0
- package/dist/core/auth/token-manager.js +294 -0
- package/dist/core/auth/token-storage.d.ts +46 -0
- package/dist/core/auth/token-storage.js +155 -0
- package/dist/core/auth/types.d.ts +148 -0
- package/dist/core/auth/types.js +15 -0
- package/dist/core/client.d.ts +84 -0
- package/dist/core/client.js +229 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.js +47 -0
- package/dist/core/missionLibrary.d.ts +68 -0
- package/dist/core/missionLibrary.js +143 -0
- package/dist/core/missions.d.ts +45 -0
- package/dist/core/missions.js +140 -0
- package/dist/core/roadmap.d.ts +8 -0
- package/dist/core/roadmap.js +18 -0
- package/dist/core/studentProfile.d.ts +21 -0
- package/dist/core/studentProfile.js +41 -0
- package/dist/core/tasks.d.ts +117 -0
- package/dist/core/tasks.js +288 -0
- package/dist/core/types.d.ts +402 -0
- package/dist/core/types.js +2 -0
- package/dist/core/users.d.ts +21 -0
- package/dist/core/users.js +46 -0
- package/dist/iframe/auth-state.d.ts +7 -0
- package/dist/iframe/auth-state.js +125 -0
- package/dist/iframe/constants.d.ts +8 -0
- package/dist/iframe/constants.js +29 -0
- package/dist/iframe/index.d.ts +5 -0
- package/dist/iframe/index.js +17 -0
- package/dist/iframe/listener.d.ts +2 -0
- package/dist/iframe/listener.js +57 -0
- package/dist/iframe/types.d.ts +18 -0
- package/dist/iframe/types.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +22 -0
- package/dist/react/hooks/index.d.ts +10 -0
- package/dist/react/hooks/index.js +48 -0
- package/dist/react/hooks/useAccount.d.ts +13 -0
- package/dist/react/hooks/useAccount.js +39 -0
- package/dist/react/hooks/useAuthState.d.ts +2 -0
- package/dist/react/hooks/useAuthState.js +18 -0
- package/dist/react/hooks/useMissionLibrary.d.ts +31 -0
- package/dist/react/hooks/useMissionLibrary.js +183 -0
- package/dist/react/hooks/useMissions.d.ts +24 -0
- package/dist/react/hooks/useMissions.js +104 -0
- package/dist/react/hooks/useOAuth.d.ts +94 -0
- package/dist/react/hooks/useOAuth.js +211 -0
- package/dist/react/hooks/useRoadmapContext.d.ts +2 -0
- package/dist/react/hooks/useRoadmapContext.js +29 -0
- package/dist/react/hooks/useStudentProfile.d.ts +24 -0
- package/dist/react/hooks/useStudentProfile.js +65 -0
- package/dist/react/hooks/useTasks.d.ts +26 -0
- package/dist/react/hooks/useTasks.js +137 -0
- package/dist/react/hooks/useUsers.d.ts +9 -0
- package/dist/react/hooks/useUsers.js +50 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +21 -0
- package/dist/react/provider.d.ts +16 -0
- package/dist/react/provider.js +41 -0
- package/package.json +61 -0
|
@@ -0,0 +1,140 @@
|
|
|
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.MissionsApi = void 0;
|
|
13
|
+
class MissionsApi {
|
|
14
|
+
constructor(client) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* List missions for a user.
|
|
19
|
+
* Without pagination params (start/limit), returns MissionsCategory[] (grouped by category).
|
|
20
|
+
* With pagination params, returns PaginatedResult<Mission> (flat list with pagination metadata).
|
|
21
|
+
*/
|
|
22
|
+
list(userId, filters) {
|
|
23
|
+
var _a;
|
|
24
|
+
const params = new URLSearchParams({ userId });
|
|
25
|
+
if ((_a = filters === null || filters === void 0 ? void 0 : filters.status) === null || _a === void 0 ? void 0 : _a.length) {
|
|
26
|
+
params.append("status", filters.status.join(","));
|
|
27
|
+
}
|
|
28
|
+
if (filters === null || filters === void 0 ? void 0 : filters.title) {
|
|
29
|
+
params.append("title", filters.title);
|
|
30
|
+
}
|
|
31
|
+
if (filters === null || filters === void 0 ? void 0 : filters.roadmapId) {
|
|
32
|
+
params.append("roadmapId", filters.roadmapId);
|
|
33
|
+
}
|
|
34
|
+
if (filters === null || filters === void 0 ? void 0 : filters.groupBy) {
|
|
35
|
+
params.append("groupBy", filters.groupBy);
|
|
36
|
+
}
|
|
37
|
+
if (filters === null || filters === void 0 ? void 0 : filters.dueDateStart) {
|
|
38
|
+
params.append("dueDateStart", filters.dueDateStart);
|
|
39
|
+
}
|
|
40
|
+
if (filters === null || filters === void 0 ? void 0 : filters.dueDateEnd) {
|
|
41
|
+
params.append("dueDateEnd", filters.dueDateEnd);
|
|
42
|
+
}
|
|
43
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.start) !== undefined) {
|
|
44
|
+
params.append("start", String(filters.start));
|
|
45
|
+
}
|
|
46
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.limit) !== undefined) {
|
|
47
|
+
params.append("limit", String(filters.limit));
|
|
48
|
+
}
|
|
49
|
+
// When pagination params are provided, return paginated result
|
|
50
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.start) !== undefined || (filters === null || filters === void 0 ? void 0 : filters.limit) !== undefined) {
|
|
51
|
+
return this.client.fetch(`/roadmap/missions?${params.toString()}`);
|
|
52
|
+
}
|
|
53
|
+
// Otherwise return category-grouped result (backward compatible)
|
|
54
|
+
return this.client.fetch(`/roadmap/missions?${params.toString()}`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* List missions with pagination (always returns flat list with pagination metadata)
|
|
58
|
+
* Handles both new paginated response and legacy category-grouped response
|
|
59
|
+
*/
|
|
60
|
+
listPaginated(userId, filters, pagination) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
var _a, _b;
|
|
63
|
+
const start = (_a = pagination === null || pagination === void 0 ? void 0 : pagination.start) !== null && _a !== void 0 ? _a : 0;
|
|
64
|
+
const limit = (_b = pagination === null || pagination === void 0 ? void 0 : pagination.limit) !== null && _b !== void 0 ? _b : 20;
|
|
65
|
+
const result = yield this.list(userId, Object.assign(Object.assign({}, filters), { start,
|
|
66
|
+
limit }));
|
|
67
|
+
// Check if result is already paginated format
|
|
68
|
+
if (result &&
|
|
69
|
+
typeof result === "object" &&
|
|
70
|
+
"pagination" in result &&
|
|
71
|
+
"data" in result) {
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
// Legacy format: MissionsCategory[] - convert to paginated format
|
|
75
|
+
// This happens when backend hasn't been updated yet
|
|
76
|
+
const categories = result;
|
|
77
|
+
const allMissions = categories.flatMap((cat) => cat.missions || []);
|
|
78
|
+
const paginatedMissions = allMissions.slice(start, start + limit);
|
|
79
|
+
return {
|
|
80
|
+
data: paginatedMissions,
|
|
81
|
+
pagination: {
|
|
82
|
+
total: allMissions.length,
|
|
83
|
+
start,
|
|
84
|
+
limit,
|
|
85
|
+
hasMore: start + limit < allMissions.length,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
create(data) {
|
|
91
|
+
return this.client.fetch("/roadmap/missions", {
|
|
92
|
+
method: "POST",
|
|
93
|
+
body: JSON.stringify(data),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
update(linkId, data) {
|
|
97
|
+
return this.client.fetch(`/roadmap/missions/${linkId}`, {
|
|
98
|
+
method: "PUT",
|
|
99
|
+
body: JSON.stringify(data),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
delete(linkId) {
|
|
103
|
+
return this.client.fetch(`/roadmap/missions/${linkId}`, {
|
|
104
|
+
method: "DELETE",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Batch edit missions (add, update, delete in a single request)
|
|
109
|
+
* @param userId - The user ID who owns the roadmap
|
|
110
|
+
* @param roadmapId - The roadmap ID
|
|
111
|
+
* @param missions - Array of mission operations
|
|
112
|
+
*/
|
|
113
|
+
batchEdit(userId, roadmapId, missions) {
|
|
114
|
+
return this.client.fetch("/roadmap/missions/batch", {
|
|
115
|
+
method: "POST",
|
|
116
|
+
body: JSON.stringify({ userId, roadmapId, missions }),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Batch delete missions and their action items by link IDs
|
|
121
|
+
* @param linkIds - Array of mission link IDs to delete
|
|
122
|
+
*/
|
|
123
|
+
batchDelete(linkIds) {
|
|
124
|
+
return this.client.fetch("/roadmap/missions/batch-delete", {
|
|
125
|
+
method: "POST",
|
|
126
|
+
body: JSON.stringify({ linkIds }),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Batch restore deleted missions and their action items by link IDs
|
|
131
|
+
* @param linkIds - Array of mission link IDs to restore
|
|
132
|
+
*/
|
|
133
|
+
batchRestore(linkIds) {
|
|
134
|
+
return this.client.fetch("/roadmap/missions/batch-restore", {
|
|
135
|
+
method: "POST",
|
|
136
|
+
body: JSON.stringify({ linkIds }),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.MissionsApi = MissionsApi;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CrimsonClient } from "./client";
|
|
2
|
+
import type { RoadmapContext } from "./types";
|
|
3
|
+
export declare class RoadmapApi {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(client: CrimsonClient);
|
|
6
|
+
context(userId: string): Promise<RoadmapContext>;
|
|
7
|
+
createContext(userId: string): Promise<RoadmapContext>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RoadmapApi = void 0;
|
|
4
|
+
class RoadmapApi {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
context(userId) {
|
|
9
|
+
return this.client.fetch(`/roadmap/context?userId=${userId}`);
|
|
10
|
+
}
|
|
11
|
+
createContext(userId) {
|
|
12
|
+
return this.client.fetch("/roadmap/context", {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body: JSON.stringify({ userId }),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.RoadmapApi = RoadmapApi;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CrimsonClient } from "./client";
|
|
2
|
+
import type { StudentPrefilledInfo, StudentProfile } from "./types";
|
|
3
|
+
export declare class StudentProfileApi {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(client: CrimsonClient);
|
|
6
|
+
/**
|
|
7
|
+
* Get student profile by student ID
|
|
8
|
+
*
|
|
9
|
+
* @param studentId - The student's user ID
|
|
10
|
+
* @returns Full student profile data
|
|
11
|
+
*/
|
|
12
|
+
getProfile(studentId: string): Promise<StudentProfile>;
|
|
13
|
+
/**
|
|
14
|
+
* Get student prefilled information including application cycle, grade, school, etc.
|
|
15
|
+
* Data is aggregated from multiple sources (Salesforce, Student Center, etc.)
|
|
16
|
+
*
|
|
17
|
+
* @param studentId - The student's user ID
|
|
18
|
+
* @returns Prefilled info with source attribution
|
|
19
|
+
*/
|
|
20
|
+
getPrefilledInfo(studentId: string): Promise<StudentPrefilledInfo>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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.StudentProfileApi = void 0;
|
|
13
|
+
class StudentProfileApi {
|
|
14
|
+
constructor(client) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get student profile by student ID
|
|
19
|
+
*
|
|
20
|
+
* @param studentId - The student's user ID
|
|
21
|
+
* @returns Full student profile data
|
|
22
|
+
*/
|
|
23
|
+
getProfile(studentId) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
return this.client.fetch(`/api/v1/student-profile?studentId=${encodeURIComponent(studentId)}`);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get student prefilled information including application cycle, grade, school, etc.
|
|
30
|
+
* Data is aggregated from multiple sources (Salesforce, Student Center, etc.)
|
|
31
|
+
*
|
|
32
|
+
* @param studentId - The student's user ID
|
|
33
|
+
* @returns Prefilled info with source attribution
|
|
34
|
+
*/
|
|
35
|
+
getPrefilledInfo(studentId) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
return this.client.fetch(`/api/v1/student-profile/get-prefilled-info?studentId=${encodeURIComponent(studentId)}`);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.StudentProfileApi = StudentProfileApi;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { CrimsonClient } from "./client";
|
|
2
|
+
import type { Task, PaginationParams, PaginatedResult, ActionItemResource, AddResourceInput, UploadUrlResponse, UpdateTaskResourceInput } from "./types";
|
|
3
|
+
export type TaskOrderBy = "priority" | "dueDate" | "missionTitle" | "createdAt" | "description";
|
|
4
|
+
export interface TaskFilters extends PaginationParams {
|
|
5
|
+
status?: string[];
|
|
6
|
+
description?: string;
|
|
7
|
+
creatorId?: string;
|
|
8
|
+
dueDateStart?: string;
|
|
9
|
+
dueDateEnd?: string;
|
|
10
|
+
orderBy?: TaskOrderBy;
|
|
11
|
+
order?: "asc" | "desc";
|
|
12
|
+
}
|
|
13
|
+
export declare class TasksApi {
|
|
14
|
+
private client;
|
|
15
|
+
constructor(client: CrimsonClient);
|
|
16
|
+
/**
|
|
17
|
+
* List tasks/action items.
|
|
18
|
+
* Without pagination params, returns Task[] (full list).
|
|
19
|
+
* With pagination params (via roadmapId query), returns PaginatedResult<Task>.
|
|
20
|
+
*/
|
|
21
|
+
list(params: {
|
|
22
|
+
missionId?: string;
|
|
23
|
+
missionLinkIds?: string[];
|
|
24
|
+
roadmapId?: string;
|
|
25
|
+
userId?: string;
|
|
26
|
+
}, filters?: TaskFilters): Promise<PaginatedResult<Task>> | Promise<Task[]>;
|
|
27
|
+
/**
|
|
28
|
+
* List tasks with pagination (requires roadmapId, always returns paginated result)
|
|
29
|
+
*/
|
|
30
|
+
listPaginated(roadmapId: string, userId: string, filters?: Omit<TaskFilters, "start" | "limit">, pagination?: PaginationParams): Promise<PaginatedResult<Task>>;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new task/action item
|
|
33
|
+
*
|
|
34
|
+
* Two modes are supported:
|
|
35
|
+
* 1. Mission-associated task: Include roadmapMissionId (or missionId)
|
|
36
|
+
* 2. Standalone task: Include only roadmapId (no missionId)
|
|
37
|
+
* - Standalone tasks are not associated with any mission
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* // Create mission-associated task
|
|
41
|
+
* tasks.create({ name: "Task 1", roadmapMissionId: "mission-123" })
|
|
42
|
+
*
|
|
43
|
+
* // Create standalone task
|
|
44
|
+
* tasks.create({ name: "Standalone task", roadmapId: "roadmap-456" })
|
|
45
|
+
*/
|
|
46
|
+
create(data: Partial<Task>): Promise<Task>;
|
|
47
|
+
/**
|
|
48
|
+
* Create a standalone task (not associated with any mission)
|
|
49
|
+
*
|
|
50
|
+
* @param roadmapId - The roadmap ID to associate the task with
|
|
51
|
+
* @param data - Task data (name/description, dueDate, etc.)
|
|
52
|
+
*/
|
|
53
|
+
createStandalone(roadmapId: string, data: Omit<Partial<Task>, "roadmapMissionId" | "missionId">): Promise<Task>;
|
|
54
|
+
update(id: string, data: Partial<Task>): Promise<Task>;
|
|
55
|
+
delete(id: string): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Add resources to an action item
|
|
58
|
+
* @param actionItemId - The ID of the action item
|
|
59
|
+
* @param resources - Array of resources to add, or a single resource
|
|
60
|
+
*/
|
|
61
|
+
addResources(actionItemId: string, resources: AddResourceInput | AddResourceInput[]): Promise<ActionItemResource[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Update task resources (create, update, delete)
|
|
64
|
+
*
|
|
65
|
+
* @param taskId - The ID of the task
|
|
66
|
+
* @param resources - Array of resources. Include id to update existing, omit id to create new.
|
|
67
|
+
* Resources not in the array will be deleted.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // Update resources: keep existing with id, add new without id
|
|
71
|
+
* tasks.updateResources("task-123", [
|
|
72
|
+
* { id: "existing-id", title: "Updated", type: "Link", url: "https://..." },
|
|
73
|
+
* { title: "New Resource", type: "Upload", url: "https://..." }
|
|
74
|
+
* ])
|
|
75
|
+
*/
|
|
76
|
+
updateResources(taskId: string, resources: UpdateTaskResourceInput[]): Promise<Task>;
|
|
77
|
+
/**
|
|
78
|
+
* Get a presigned URL for uploading a file to S3
|
|
79
|
+
*
|
|
80
|
+
* @param filename - The name of the file
|
|
81
|
+
* @param contentType - The MIME type of the file (e.g., "image/png", "application/pdf")
|
|
82
|
+
* @returns Promise with putUrl (for upload), url (final S3 URL), key, and bucket
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // Get upload URL
|
|
86
|
+
* const { putUrl, url } = await tasks.getUploadUrl("document.pdf", "application/pdf");
|
|
87
|
+
*
|
|
88
|
+
* // Upload file using PUT request
|
|
89
|
+
* await fetch(putUrl, { method: "PUT", body: file, headers: { "Content-Type": "application/pdf" } });
|
|
90
|
+
*
|
|
91
|
+
* // Use the url as the resource URL
|
|
92
|
+
* await tasks.updateResources(taskId, [{ title: "Document", type: "Upload", url }]);
|
|
93
|
+
*/
|
|
94
|
+
getUploadUrl(filename: string, contentType: string): Promise<UploadUrlResponse>;
|
|
95
|
+
/**
|
|
96
|
+
* Upload a file and get the S3 URL
|
|
97
|
+
*
|
|
98
|
+
* This is a convenience method that:
|
|
99
|
+
* 1. Gets a presigned upload URL
|
|
100
|
+
* 2. Uploads the file
|
|
101
|
+
* 3. Returns the final S3 URL
|
|
102
|
+
*
|
|
103
|
+
* @param file - The File or Blob to upload
|
|
104
|
+
* @param filename - Optional filename (defaults to file.name if File)
|
|
105
|
+
* @returns Promise with the final S3 URL to use as resource URL
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* const url = await tasks.uploadFile(file);
|
|
109
|
+
* await tasks.updateResources(taskId, [
|
|
110
|
+
* { title: file.name, type: "Upload", url, mediaType: file.type }
|
|
111
|
+
* ]);
|
|
112
|
+
*/
|
|
113
|
+
uploadFile(file: File | Blob, filename?: string): Promise<{
|
|
114
|
+
url: string;
|
|
115
|
+
key: string;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
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.TasksApi = void 0;
|
|
13
|
+
const normalizeTask = (raw) => {
|
|
14
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
15
|
+
if (!raw) {
|
|
16
|
+
console.error("normalizeTask received null/undefined:", raw);
|
|
17
|
+
console.trace("Stack trace:");
|
|
18
|
+
throw new Error("Cannot normalize null or undefined task");
|
|
19
|
+
}
|
|
20
|
+
if (!raw.id) {
|
|
21
|
+
console.error("normalizeTask received object without id:", raw);
|
|
22
|
+
throw new Error("Task object missing required 'id' field");
|
|
23
|
+
}
|
|
24
|
+
const statusUpper = typeof raw.status === "string" ? raw.status.toUpperCase() : undefined;
|
|
25
|
+
const isComplete = raw.isComplete !== undefined
|
|
26
|
+
? Boolean(raw.isComplete)
|
|
27
|
+
: statusUpper
|
|
28
|
+
? statusUpper === "DONE"
|
|
29
|
+
: Boolean(raw.finishedAt);
|
|
30
|
+
return {
|
|
31
|
+
id: (_a = raw.id) !== null && _a !== void 0 ? _a : "",
|
|
32
|
+
name: (_c = (_b = raw.name) !== null && _b !== void 0 ? _b : raw.description) !== null && _c !== void 0 ? _c : "",
|
|
33
|
+
description: raw.description,
|
|
34
|
+
content: raw.content,
|
|
35
|
+
status: (_d = raw.status) !== null && _d !== void 0 ? _d : "",
|
|
36
|
+
date: (_f = (_e = raw.date) !== null && _e !== void 0 ? _e : raw.dueDate) !== null && _f !== void 0 ? _f : "",
|
|
37
|
+
roadmapMissionId: (_j = (_h = (_g = raw.roadmapMissionId) !== null && _g !== void 0 ? _g : raw.missionId) !== null && _h !== void 0 ? _h : raw.linkId) !== null && _j !== void 0 ? _j : "",
|
|
38
|
+
userId: (_l = (_k = raw.userId) !== null && _k !== void 0 ? _k : raw.creatorId) !== null && _l !== void 0 ? _l : "",
|
|
39
|
+
creatorId: raw.creatorId,
|
|
40
|
+
isComplete,
|
|
41
|
+
resources: raw.resources,
|
|
42
|
+
mission: raw.mission,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
class TasksApi {
|
|
46
|
+
constructor(client) {
|
|
47
|
+
this.client = client;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* List tasks/action items.
|
|
51
|
+
* Without pagination params, returns Task[] (full list).
|
|
52
|
+
* With pagination params (via roadmapId query), returns PaginatedResult<Task>.
|
|
53
|
+
*/
|
|
54
|
+
list(params, filters) {
|
|
55
|
+
var _a;
|
|
56
|
+
const searchParams = new URLSearchParams();
|
|
57
|
+
if (params === null || params === void 0 ? void 0 : params.missionId) {
|
|
58
|
+
searchParams.append("missionId", params.missionId);
|
|
59
|
+
}
|
|
60
|
+
if ((params === null || params === void 0 ? void 0 : params.missionLinkIds) && params.missionLinkIds.length > 0) {
|
|
61
|
+
searchParams.append("missionLinkIds", params.missionLinkIds.join(","));
|
|
62
|
+
}
|
|
63
|
+
if (params === null || params === void 0 ? void 0 : params.roadmapId) {
|
|
64
|
+
searchParams.append("roadmapId", params.roadmapId);
|
|
65
|
+
}
|
|
66
|
+
if (params === null || params === void 0 ? void 0 : params.userId) {
|
|
67
|
+
searchParams.append("userId", params.userId);
|
|
68
|
+
}
|
|
69
|
+
// Add filter params
|
|
70
|
+
if ((_a = filters === null || filters === void 0 ? void 0 : filters.status) === null || _a === void 0 ? void 0 : _a.length) {
|
|
71
|
+
searchParams.append("status", filters.status.join(","));
|
|
72
|
+
}
|
|
73
|
+
if (filters === null || filters === void 0 ? void 0 : filters.description) {
|
|
74
|
+
searchParams.append("description", filters.description);
|
|
75
|
+
}
|
|
76
|
+
if (filters === null || filters === void 0 ? void 0 : filters.creatorId) {
|
|
77
|
+
searchParams.append("creatorId", filters.creatorId);
|
|
78
|
+
}
|
|
79
|
+
if (filters === null || filters === void 0 ? void 0 : filters.dueDateStart) {
|
|
80
|
+
searchParams.append("dueDateStart", filters.dueDateStart);
|
|
81
|
+
}
|
|
82
|
+
if (filters === null || filters === void 0 ? void 0 : filters.dueDateEnd) {
|
|
83
|
+
searchParams.append("dueDateEnd", filters.dueDateEnd);
|
|
84
|
+
}
|
|
85
|
+
if (filters === null || filters === void 0 ? void 0 : filters.orderBy) {
|
|
86
|
+
searchParams.append("orderBy", filters.orderBy);
|
|
87
|
+
}
|
|
88
|
+
if (filters === null || filters === void 0 ? void 0 : filters.order) {
|
|
89
|
+
searchParams.append("order", filters.order);
|
|
90
|
+
}
|
|
91
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.start) !== undefined) {
|
|
92
|
+
searchParams.append("start", String(filters.start));
|
|
93
|
+
}
|
|
94
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.limit) !== undefined) {
|
|
95
|
+
searchParams.append("limit", String(filters.limit));
|
|
96
|
+
}
|
|
97
|
+
const query = searchParams.toString();
|
|
98
|
+
const path = query
|
|
99
|
+
? `/roadmap/action-items?${query}`
|
|
100
|
+
: "/roadmap/action-items";
|
|
101
|
+
// When pagination params are provided with roadmapId, return paginated result
|
|
102
|
+
if ((params === null || params === void 0 ? void 0 : params.roadmapId) &&
|
|
103
|
+
((filters === null || filters === void 0 ? void 0 : filters.start) !== undefined || (filters === null || filters === void 0 ? void 0 : filters.limit) !== undefined)) {
|
|
104
|
+
return this.client
|
|
105
|
+
.fetch(path)
|
|
106
|
+
.then((result) => {
|
|
107
|
+
var _a, _b;
|
|
108
|
+
// Check if result is paginated format
|
|
109
|
+
if (result &&
|
|
110
|
+
typeof result === "object" &&
|
|
111
|
+
"pagination" in result &&
|
|
112
|
+
"data" in result) {
|
|
113
|
+
return {
|
|
114
|
+
data: (result.data || [])
|
|
115
|
+
.filter((item) => item != null)
|
|
116
|
+
.map(normalizeTask),
|
|
117
|
+
pagination: result.pagination,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Legacy format: RawTask[] - convert to paginated format
|
|
121
|
+
const allTasks = result || [];
|
|
122
|
+
const start = (_a = filters === null || filters === void 0 ? void 0 : filters.start) !== null && _a !== void 0 ? _a : 0;
|
|
123
|
+
const limit = (_b = filters === null || filters === void 0 ? void 0 : filters.limit) !== null && _b !== void 0 ? _b : 20;
|
|
124
|
+
const normalizedTasks = allTasks
|
|
125
|
+
.filter((item) => item != null)
|
|
126
|
+
.map(normalizeTask);
|
|
127
|
+
const paginatedTasks = normalizedTasks.slice(start, start + limit);
|
|
128
|
+
return {
|
|
129
|
+
data: paginatedTasks,
|
|
130
|
+
pagination: {
|
|
131
|
+
total: normalizedTasks.length,
|
|
132
|
+
start,
|
|
133
|
+
limit,
|
|
134
|
+
hasMore: start + limit < normalizedTasks.length,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Otherwise return flat array (backward compatible)
|
|
140
|
+
return this.client.fetch(path).then((items) => {
|
|
141
|
+
const filtered = (items || []).filter((item) => item != null);
|
|
142
|
+
return filtered.map(normalizeTask);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* List tasks with pagination (requires roadmapId, always returns paginated result)
|
|
147
|
+
*/
|
|
148
|
+
listPaginated(roadmapId, userId, filters, pagination) {
|
|
149
|
+
var _a, _b;
|
|
150
|
+
return this.list({ roadmapId, userId }, Object.assign(Object.assign({}, filters), { start: (_a = pagination === null || pagination === void 0 ? void 0 : pagination.start) !== null && _a !== void 0 ? _a : 0, limit: (_b = pagination === null || pagination === void 0 ? void 0 : pagination.limit) !== null && _b !== void 0 ? _b : 20 }));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Create a new task/action item
|
|
154
|
+
*
|
|
155
|
+
* Two modes are supported:
|
|
156
|
+
* 1. Mission-associated task: Include roadmapMissionId (or missionId)
|
|
157
|
+
* 2. Standalone task: Include only roadmapId (no missionId)
|
|
158
|
+
* - Standalone tasks are not associated with any mission
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // Create mission-associated task
|
|
162
|
+
* tasks.create({ name: "Task 1", roadmapMissionId: "mission-123" })
|
|
163
|
+
*
|
|
164
|
+
* // Create standalone task
|
|
165
|
+
* tasks.create({ name: "Standalone task", roadmapId: "roadmap-456" })
|
|
166
|
+
*/
|
|
167
|
+
create(data) {
|
|
168
|
+
return this.client
|
|
169
|
+
.fetch("/roadmap/action-items", {
|
|
170
|
+
method: "POST",
|
|
171
|
+
body: JSON.stringify(data),
|
|
172
|
+
})
|
|
173
|
+
.then((item) => normalizeTask(item));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a standalone task (not associated with any mission)
|
|
177
|
+
*
|
|
178
|
+
* @param roadmapId - The roadmap ID to associate the task with
|
|
179
|
+
* @param data - Task data (name/description, dueDate, etc.)
|
|
180
|
+
*/
|
|
181
|
+
createStandalone(roadmapId, data) {
|
|
182
|
+
return this.create(Object.assign(Object.assign({}, data), { roadmapId }));
|
|
183
|
+
}
|
|
184
|
+
update(id, data) {
|
|
185
|
+
return this.client
|
|
186
|
+
.fetch(`/roadmap/action-items/${id}`, {
|
|
187
|
+
method: "PUT",
|
|
188
|
+
body: JSON.stringify(data),
|
|
189
|
+
})
|
|
190
|
+
.then((item) => normalizeTask(item));
|
|
191
|
+
}
|
|
192
|
+
delete(id) {
|
|
193
|
+
return this.client.fetch(`/roadmap/action-items/${id}`, {
|
|
194
|
+
method: "DELETE",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Add resources to an action item
|
|
199
|
+
* @param actionItemId - The ID of the action item
|
|
200
|
+
* @param resources - Array of resources to add, or a single resource
|
|
201
|
+
*/
|
|
202
|
+
addResources(actionItemId, resources) {
|
|
203
|
+
const body = Array.isArray(resources) ? resources : [resources];
|
|
204
|
+
return this.client.fetch(`/roadmap/action-items/${actionItemId}/resources`, {
|
|
205
|
+
method: "POST",
|
|
206
|
+
body: JSON.stringify(body),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Update task resources (create, update, delete)
|
|
211
|
+
*
|
|
212
|
+
* @param taskId - The ID of the task
|
|
213
|
+
* @param resources - Array of resources. Include id to update existing, omit id to create new.
|
|
214
|
+
* Resources not in the array will be deleted.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* // Update resources: keep existing with id, add new without id
|
|
218
|
+
* tasks.updateResources("task-123", [
|
|
219
|
+
* { id: "existing-id", title: "Updated", type: "Link", url: "https://..." },
|
|
220
|
+
* { title: "New Resource", type: "Upload", url: "https://..." }
|
|
221
|
+
* ])
|
|
222
|
+
*/
|
|
223
|
+
updateResources(taskId, resources) {
|
|
224
|
+
return this.update(taskId, { resources });
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get a presigned URL for uploading a file to S3
|
|
228
|
+
*
|
|
229
|
+
* @param filename - The name of the file
|
|
230
|
+
* @param contentType - The MIME type of the file (e.g., "image/png", "application/pdf")
|
|
231
|
+
* @returns Promise with putUrl (for upload), url (final S3 URL), key, and bucket
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* // Get upload URL
|
|
235
|
+
* const { putUrl, url } = await tasks.getUploadUrl("document.pdf", "application/pdf");
|
|
236
|
+
*
|
|
237
|
+
* // Upload file using PUT request
|
|
238
|
+
* await fetch(putUrl, { method: "PUT", body: file, headers: { "Content-Type": "application/pdf" } });
|
|
239
|
+
*
|
|
240
|
+
* // Use the url as the resource URL
|
|
241
|
+
* await tasks.updateResources(taskId, [{ title: "Document", type: "Upload", url }]);
|
|
242
|
+
*/
|
|
243
|
+
getUploadUrl(filename, contentType) {
|
|
244
|
+
return this.client.fetch("/roadmap/upload", {
|
|
245
|
+
method: "POST",
|
|
246
|
+
body: JSON.stringify({ filename, contentType }),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Upload a file and get the S3 URL
|
|
251
|
+
*
|
|
252
|
+
* This is a convenience method that:
|
|
253
|
+
* 1. Gets a presigned upload URL
|
|
254
|
+
* 2. Uploads the file
|
|
255
|
+
* 3. Returns the final S3 URL
|
|
256
|
+
*
|
|
257
|
+
* @param file - The File or Blob to upload
|
|
258
|
+
* @param filename - Optional filename (defaults to file.name if File)
|
|
259
|
+
* @returns Promise with the final S3 URL to use as resource URL
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* const url = await tasks.uploadFile(file);
|
|
263
|
+
* await tasks.updateResources(taskId, [
|
|
264
|
+
* { title: file.name, type: "Upload", url, mediaType: file.type }
|
|
265
|
+
* ]);
|
|
266
|
+
*/
|
|
267
|
+
uploadFile(file, filename) {
|
|
268
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
const name = filename || (file instanceof File ? file.name : `upload-${Date.now()}`);
|
|
270
|
+
const contentType = file.type || "application/octet-stream";
|
|
271
|
+
// Get presigned URL
|
|
272
|
+
const { putUrl, url, key } = yield this.getUploadUrl(name, contentType);
|
|
273
|
+
// Upload file using PUT request
|
|
274
|
+
const response = yield fetch(putUrl, {
|
|
275
|
+
method: "PUT",
|
|
276
|
+
body: file,
|
|
277
|
+
headers: {
|
|
278
|
+
"Content-Type": contentType,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
|
|
283
|
+
}
|
|
284
|
+
return { url, key };
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
exports.TasksApi = TasksApi;
|