@anantagnanam/lms 0.1.0 → 0.3.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/LICENSE +21 -21
- package/README.md +40 -2
- package/astro/assignment-player.ts +231 -0
- package/astro/client.ts +97 -152
- package/astro/components/AssignmentFeedback.astro +32 -0
- package/astro/components/AssignmentRubric.astro +27 -0
- package/astro/components/CourseOverview.astro +25 -3
- package/astro/components/LearnerDashboard.astro +9 -0
- package/astro/components/LearningShell.astro +16 -1
- package/astro/components/LessonAvailabilityNote.astro +26 -0
- package/astro/components/LessonContent.astro +67 -0
- package/astro/components/LessonPlayer.astro +166 -99
- package/astro/components/MediaPlayer.astro +55 -4
- package/astro/draft-queue.ts +95 -0
- package/astro/media-player.ts +124 -0
- package/astro/pages/author-preview.astro +73 -0
- package/astro/pages/course.astro +10 -0
- package/astro/pages/lesson.astro +3 -0
- package/astro/pages/library.astro +173 -0
- package/astro/pages/paths.astro +73 -0
- package/astro/pages/study.astro +180 -0
- package/astro/quiz-drafts.ts +23 -0
- package/astro/quiz-player.ts +362 -0
- package/astro/study-tools.ts +386 -0
- package/astro/styles.css +30 -0
- package/astro/transcript-search.ts +56 -0
- package/dist/admin.d.ts +3 -1
- package/dist/admin.js +756 -127
- package/dist/admin.js.map +1 -1
- package/dist/assignments-CsuAjxGO.js +75 -0
- package/dist/assignments-CsuAjxGO.js.map +1 -0
- package/dist/astro.js +4 -0
- package/dist/astro.js.map +1 -1
- package/dist/{constants-C0kT94tc.js → constants-DyQbwNbP.js} +25 -3
- package/dist/constants-DyQbwNbP.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime.d.ts +129 -16
- package/dist/runtime.js +1201 -130
- package/dist/runtime.js.map +1 -1
- package/dist/schemas.d.ts +136 -3
- package/dist/schemas.js +80 -7
- package/dist/schemas.js.map +1 -1
- package/dist/server.d.ts +18 -1
- package/dist/server.js +17 -3
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +172 -4
- package/package.json +1 -1
- package/dist/constants-C0kT94tc.js.map +0 -1
- package/dist/errors-ChzJS9al.js +0 -16
- package/dist/errors-ChzJS9al.js.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cohortDataSchema, courseDataSchema, lessonSchema, moduleSchema, questionSchema, quizSchema, settingsSchema } from "./schemas.js";
|
|
1
|
+
import { cohortDataSchema, courseDataSchema, lessonSchema, moduleSchema, pathDataSchema, preferencesSchema, questionSchema, quizSchema, rubricCriterionSchema, rubricScoreSchema, settingsSchema } from "./schemas.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
@@ -7,6 +7,8 @@ type CourseModule = z.infer<typeof moduleSchema>;
|
|
|
7
7
|
type Lesson = z.infer<typeof lessonSchema>;
|
|
8
8
|
type QuizQuestion = z.infer<typeof questionSchema>;
|
|
9
9
|
type Quiz = z.infer<typeof quizSchema>;
|
|
10
|
+
type RubricCriterion = z.infer<typeof rubricCriterionSchema>;
|
|
11
|
+
type RubricScore = z.infer<typeof rubricScoreSchema>;
|
|
10
12
|
type LmsSettings = z.infer<typeof settingsSchema>;
|
|
11
13
|
interface Course extends CourseData {
|
|
12
14
|
id: string;
|
|
@@ -14,7 +16,39 @@ interface Course extends CourseData {
|
|
|
14
16
|
createdBy: string;
|
|
15
17
|
createdAt: string;
|
|
16
18
|
updatedAt: string;
|
|
17
|
-
schemaVersion: 1;
|
|
19
|
+
schemaVersion: 1 | 2;
|
|
20
|
+
draftRevisionId?: string;
|
|
21
|
+
publishedEditionId?: string;
|
|
22
|
+
publishedDraftRevisionId?: string;
|
|
23
|
+
legacyEditionId?: string;
|
|
24
|
+
}
|
|
25
|
+
interface CourseRevision {
|
|
26
|
+
id: string;
|
|
27
|
+
courseId: string;
|
|
28
|
+
parentId: string | null;
|
|
29
|
+
data: CourseData;
|
|
30
|
+
kind: "migration" | "draft" | "publish" | "restore" | "archive";
|
|
31
|
+
createdBy: string;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
editionId?: string;
|
|
34
|
+
restoredFrom?: string;
|
|
35
|
+
}
|
|
36
|
+
type RevisionSummary = Omit<CourseRevision, "data"> & {
|
|
37
|
+
title: string;
|
|
38
|
+
};
|
|
39
|
+
interface CourseEdition {
|
|
40
|
+
id: string;
|
|
41
|
+
courseId: string;
|
|
42
|
+
data: CourseData;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
}
|
|
45
|
+
interface MigrationState {
|
|
46
|
+
phase: "courses" | "enrollments" | "complete";
|
|
47
|
+
cursor?: string;
|
|
48
|
+
coursesProcessed: number;
|
|
49
|
+
enrollmentsProcessed: number;
|
|
50
|
+
updatedAt: string;
|
|
51
|
+
lastError: string | null;
|
|
18
52
|
}
|
|
19
53
|
interface Actor {
|
|
20
54
|
id: string;
|
|
@@ -49,8 +83,12 @@ interface QuizAttempt {
|
|
|
49
83
|
passed: boolean;
|
|
50
84
|
feedback: QuestionResult[];
|
|
51
85
|
answers: Answers;
|
|
86
|
+
/** Records created before draft fencing have revision zero. */
|
|
87
|
+
draftRevision?: number;
|
|
52
88
|
}
|
|
53
|
-
type PublicQuizAttempt = Omit<QuizAttempt, "quiz"
|
|
89
|
+
type PublicQuizAttempt = Omit<QuizAttempt, "quiz" | "draftRevision"> & {
|
|
90
|
+
draftRevision: number;
|
|
91
|
+
};
|
|
54
92
|
interface AssignmentSubmission {
|
|
55
93
|
id: string;
|
|
56
94
|
body: string;
|
|
@@ -63,13 +101,132 @@ interface AssignmentSubmission {
|
|
|
63
101
|
feedback: string;
|
|
64
102
|
gradedAt: string | null;
|
|
65
103
|
gradedBy: string | null;
|
|
104
|
+
/** Criteria are frozen from the learner's course edition at submission. */
|
|
105
|
+
rubric?: RubricCriterion[];
|
|
106
|
+
rubricScores?: RubricScore[];
|
|
107
|
+
}
|
|
108
|
+
interface AssignmentDraft {
|
|
109
|
+
body: string;
|
|
110
|
+
attachmentUrl: string | null;
|
|
111
|
+
revision: number;
|
|
112
|
+
updatedAt: string | null;
|
|
113
|
+
}
|
|
114
|
+
interface AssignmentState {
|
|
115
|
+
draft: AssignmentDraft;
|
|
116
|
+
submission: AssignmentSubmission | null;
|
|
117
|
+
canSubmit: boolean;
|
|
118
|
+
closedReason: string | null;
|
|
66
119
|
}
|
|
67
120
|
interface LessonProgress {
|
|
68
121
|
startedAt: string | null;
|
|
69
122
|
completedAt: string | null;
|
|
70
123
|
note: string;
|
|
124
|
+
noteRevision?: number;
|
|
71
125
|
quizAttempts: QuizAttempt[];
|
|
72
126
|
assignments: AssignmentSubmission[];
|
|
127
|
+
assignmentDraft?: AssignmentDraft;
|
|
128
|
+
playback?: Playback;
|
|
129
|
+
}
|
|
130
|
+
interface Playback {
|
|
131
|
+
positionSeconds: number;
|
|
132
|
+
playbackRate: number;
|
|
133
|
+
revision: number;
|
|
134
|
+
updatedAt: string;
|
|
135
|
+
}
|
|
136
|
+
interface StudyNote {
|
|
137
|
+
id: string;
|
|
138
|
+
lessonId: string;
|
|
139
|
+
lessonTitle: string;
|
|
140
|
+
body: string;
|
|
141
|
+
positionSeconds: number | null;
|
|
142
|
+
starred: boolean;
|
|
143
|
+
archived: boolean;
|
|
144
|
+
revision: number;
|
|
145
|
+
createdAt: string;
|
|
146
|
+
updatedAt: string;
|
|
147
|
+
}
|
|
148
|
+
interface Notebook {
|
|
149
|
+
course: {
|
|
150
|
+
id: string;
|
|
151
|
+
title: string;
|
|
152
|
+
slug: string;
|
|
153
|
+
};
|
|
154
|
+
notes: StudyNote[];
|
|
155
|
+
summaries: {
|
|
156
|
+
lessonId: string;
|
|
157
|
+
lessonTitle: string;
|
|
158
|
+
body: string;
|
|
159
|
+
}[];
|
|
160
|
+
availableLessonIds: string[];
|
|
161
|
+
}
|
|
162
|
+
interface CourseAgenda {
|
|
163
|
+
course: {
|
|
164
|
+
id: string;
|
|
165
|
+
title: string;
|
|
166
|
+
slug: string;
|
|
167
|
+
};
|
|
168
|
+
generatedAt: string;
|
|
169
|
+
events: {
|
|
170
|
+
id: string;
|
|
171
|
+
kind: "assignment" | "live" | "release";
|
|
172
|
+
lessonId: string;
|
|
173
|
+
title: string;
|
|
174
|
+
startsAt: string;
|
|
175
|
+
endsAt: string | null;
|
|
176
|
+
available: boolean;
|
|
177
|
+
reason: string | null;
|
|
178
|
+
status: "upcoming" | "overdue" | "submitted" | "completed" | "past";
|
|
179
|
+
}[];
|
|
180
|
+
}
|
|
181
|
+
type LearnerPreferences = z.infer<typeof preferencesSchema>;
|
|
182
|
+
interface SavedCourse {
|
|
183
|
+
userId: string;
|
|
184
|
+
courseId: string;
|
|
185
|
+
saved: boolean;
|
|
186
|
+
updatedAt: string;
|
|
187
|
+
}
|
|
188
|
+
interface LearningPath extends z.infer<typeof pathDataSchema> {
|
|
189
|
+
id: string;
|
|
190
|
+
createdAt: string;
|
|
191
|
+
updatedAt: string;
|
|
192
|
+
}
|
|
193
|
+
interface PathEnrollment {
|
|
194
|
+
pathId: string;
|
|
195
|
+
userId: string;
|
|
196
|
+
title: string;
|
|
197
|
+
courseIds: string[];
|
|
198
|
+
joinedAt: string;
|
|
199
|
+
}
|
|
200
|
+
interface PublicPath {
|
|
201
|
+
id: string;
|
|
202
|
+
title: string;
|
|
203
|
+
description: string;
|
|
204
|
+
courses: (CourseCard | null)[];
|
|
205
|
+
}
|
|
206
|
+
interface LearnerPath {
|
|
207
|
+
pathId: string;
|
|
208
|
+
title: string;
|
|
209
|
+
joinedAt: string;
|
|
210
|
+
completed: number;
|
|
211
|
+
total: number;
|
|
212
|
+
courses: {
|
|
213
|
+
course: CourseCard | null;
|
|
214
|
+
completed: boolean;
|
|
215
|
+
}[];
|
|
216
|
+
}
|
|
217
|
+
interface LmsHealth {
|
|
218
|
+
version: string;
|
|
219
|
+
maintenance: {
|
|
220
|
+
startedAt: string;
|
|
221
|
+
completedAt: string | null;
|
|
222
|
+
failed: boolean;
|
|
223
|
+
} | null;
|
|
224
|
+
maintenanceStale: boolean;
|
|
225
|
+
pendingEmails: number;
|
|
226
|
+
failedEmails: number;
|
|
227
|
+
oldestPendingAt: string | null;
|
|
228
|
+
emailEnabled: boolean;
|
|
229
|
+
migration: MigrationState | null;
|
|
73
230
|
}
|
|
74
231
|
interface Certificate {
|
|
75
232
|
id: string;
|
|
@@ -86,6 +243,8 @@ interface Certificate {
|
|
|
86
243
|
interface Enrollment {
|
|
87
244
|
id: string;
|
|
88
245
|
courseId: string;
|
|
246
|
+
/** Immutable curriculum selected at enrollment; v1 records use the course's legacy edition. */
|
|
247
|
+
courseEditionId?: string;
|
|
89
248
|
userId: string;
|
|
90
249
|
learnerName: string;
|
|
91
250
|
learnerEmail: string;
|
|
@@ -105,6 +264,7 @@ interface Enrollment {
|
|
|
105
264
|
accessExpiresAt: string | null;
|
|
106
265
|
cohortId: string | null;
|
|
107
266
|
progress: Record<string, LessonProgress>;
|
|
267
|
+
studyNotes?: StudyNote[];
|
|
108
268
|
certificate: Certificate | null;
|
|
109
269
|
completionLessonIds: string[];
|
|
110
270
|
lastActivityAt: string;
|
|
@@ -265,6 +425,14 @@ interface ProgressSummary {
|
|
|
265
425
|
total: number;
|
|
266
426
|
percent: number;
|
|
267
427
|
nextLessonId: string | null;
|
|
428
|
+
blockedLessonId: string | null;
|
|
429
|
+
availability: Record<string, LessonAvailability>;
|
|
430
|
+
}
|
|
431
|
+
interface LessonAvailability {
|
|
432
|
+
available: boolean;
|
|
433
|
+
code: string | null;
|
|
434
|
+
reason: string | null;
|
|
435
|
+
releaseAt: string | null;
|
|
268
436
|
}
|
|
269
437
|
interface LmsOptions {
|
|
270
438
|
basePath?: string;
|
|
@@ -280,5 +448,5 @@ interface RouteEnvelope<T> {
|
|
|
280
448
|
};
|
|
281
449
|
}
|
|
282
450
|
//#endregion
|
|
283
|
-
export { AccessGrant, Acquisition, Actor, Answers, AssignmentSubmission, AuditRecord, Certificate, CertificateIndex, Cohort, CohortMembership, Course, CourseCard, CourseData, CourseDetail, CourseModule, CurriculumLesson, CurriculumModule, Discussion, Enrollment, Lesson, LessonProgress, LmsOptions, LmsSettings, Notification, Page, ProgressSummary, PublicEnrollment, PublicLesson, PublicQuestion, PublicQuizAttempt, QuestionResult, Quiz, QuizAttempt, QuizQuestion, Review, RouteEnvelope, Versioned };
|
|
451
|
+
export { AccessGrant, Acquisition, Actor, Answers, AssignmentDraft, AssignmentState, AssignmentSubmission, AuditRecord, Certificate, CertificateIndex, Cohort, CohortMembership, Course, CourseAgenda, CourseCard, CourseData, CourseDetail, CourseEdition, CourseModule, CourseRevision, CurriculumLesson, CurriculumModule, Discussion, Enrollment, LearnerPath, LearnerPreferences, LearningPath, Lesson, LessonAvailability, LessonProgress, LmsHealth, LmsOptions, LmsSettings, MigrationState, Notebook, Notification, Page, PathEnrollment, Playback, ProgressSummary, PublicEnrollment, PublicLesson, PublicPath, PublicQuestion, PublicQuizAttempt, QuestionResult, Quiz, QuizAttempt, QuizQuestion, Review, RevisionSummary, RouteEnvelope, RubricCriterion, RubricScore, SavedCourse, StudyNote, Versioned };
|
|
284
452
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants-C0kT94tc.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["export const PLUGIN_ID = \"anantagnanam-lms\";\nexport const PLUGIN_VERSION = \"0.1.0\";\nexport const API_BASE = `/_emdash/api/plugins/${PLUGIN_ID}`;\nexport const MAX_DOCUMENT_BYTES = 950_000;\n\nimport type { PluginStorageConfig } from \"emdash\";\n\nexport const storage = {\n courses: {\n indexes: [\n \"status\",\n \"title\",\n \"searchTitle\",\n \"category\",\n \"level\",\n \"language\",\n \"updatedAt\",\n \"createdBy\",\n ],\n uniqueIndexes: [\"slug\"],\n },\n enrollments: {\n indexes: [\n \"userId\",\n \"courseId\",\n \"status\",\n \"accessStatus\",\n \"accessSource\",\n \"enrolledAt\",\n \"completedAt\",\n \"lastActivityAt\",\n \"cohortId\",\n [\"courseId\", \"status\"],\n [\"userId\", \"status\"],\n ],\n },\n certificates: { indexes: [\"userId\", \"courseId\"] },\n discussions: {\n indexes: [\n \"courseId\",\n \"lessonId\",\n \"authorId\",\n \"status\",\n \"createdAt\",\n \"parentId\",\n [\"courseId\", \"createdAt\"],\n ],\n },\n reviews: { indexes: [\"courseId\", \"userId\", \"status\", \"createdAt\"] },\n cohorts: { indexes: [\"title\", \"createdAt\", \"createdBy\"] },\n cohort_enrollments: { indexes: [\"cohortId\", \"userId\", \"status\", \"requestedAt\"] },\n notifications: { indexes: [\"userId\", \"read\", \"createdAt\", \"emailStatus\", \"claimedAt\"] },\n audit: { indexes: [\"actorId\", \"action\", \"resourceId\", \"createdAt\"] },\n} satisfies PluginStorageConfig;\n\nexport const adminPages = [\n { path: \"/\", label: \"Learning overview\", icon: \"graduation-cap\", group: \"Learning\" },\n { path: \"/courses\", label: \"Courses\", icon: \"books\", group: \"Learning\" },\n { path: \"/learners\", label: \"Enrollments\", icon: \"users\", group: \"Learning\" },\n { path: \"/assignments\", label: \"Assignments\", icon: \"exam\", group: \"Learning\" },\n { path: \"/community\", label: \"Community\", icon: \"chats\", group: \"Learning\" },\n { path: \"/cohorts\", label: \"Cohorts\", icon: \"users-three\", group: \"Learning\" },\n { path: \"/reports\", label: \"Reports\", icon: \"chart-bar\", group: \"Learning\" },\n { path: \"/notifications\", label: \"Notifications\", icon: \"bell\", group: \"Learning\" },\n { path: \"/audit\", label: \"Audit history\", icon: \"clock-counter-clockwise\", group: \"Learning\" },\n { path: \"/settings\", label: \"LMS settings\", icon: \"gear\", group: \"Learning\" },\n];\n"],"mappings":";AAAA,MAAa,YAAY;AACzB,MAAa,iBAAiB;AAC9B,MAAa,WAAW,wBAAwB;AAChD,MAAa,qBAAqB;AAIlC,MAAa,UAAU;CACrB,SAAS;EACP,SAAS;GACP;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACD,eAAe,CAAC,OAAO;EACxB;CACD,aAAa,EACX,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,CAAC,YAAY,SAAS;EACtB,CAAC,UAAU,SAAS;EACrB,EACF;CACD,cAAc,EAAE,SAAS,CAAC,UAAU,WAAW,EAAE;CACjD,aAAa,EACX,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA,CAAC,YAAY,YAAY;EAC1B,EACF;CACD,SAAS,EAAE,SAAS;EAAC;EAAY;EAAU;EAAU;EAAY,EAAE;CACnE,SAAS,EAAE,SAAS;EAAC;EAAS;EAAa;EAAY,EAAE;CACzD,oBAAoB,EAAE,SAAS;EAAC;EAAY;EAAU;EAAU;EAAc,EAAE;CAChF,eAAe,EAAE,SAAS;EAAC;EAAU;EAAQ;EAAa;EAAe;EAAY,EAAE;CACvF,OAAO,EAAE,SAAS;EAAC;EAAW;EAAU;EAAc;EAAY,EAAE;CACrE;AAED,MAAa,aAAa;CACxB;EAAE,MAAM;EAAK,OAAO;EAAqB,MAAM;EAAkB,OAAO;EAAY;CACpF;EAAE,MAAM;EAAY,OAAO;EAAW,MAAM;EAAS,OAAO;EAAY;CACxE;EAAE,MAAM;EAAa,OAAO;EAAe,MAAM;EAAS,OAAO;EAAY;CAC7E;EAAE,MAAM;EAAgB,OAAO;EAAe,MAAM;EAAQ,OAAO;EAAY;CAC/E;EAAE,MAAM;EAAc,OAAO;EAAa,MAAM;EAAS,OAAO;EAAY;CAC5E;EAAE,MAAM;EAAY,OAAO;EAAW,MAAM;EAAe,OAAO;EAAY;CAC9E;EAAE,MAAM;EAAY,OAAO;EAAW,MAAM;EAAa,OAAO;EAAY;CAC5E;EAAE,MAAM;EAAkB,OAAO;EAAiB,MAAM;EAAQ,OAAO;EAAY;CACnF;EAAE,MAAM;EAAU,OAAO;EAAiB,MAAM;EAA2B,OAAO;EAAY;CAC9F;EAAE,MAAM;EAAa,OAAO;EAAgB,MAAM;EAAQ,OAAO;EAAY;CAC9E"}
|
package/dist/errors-ChzJS9al.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
//#region src/errors.ts
|
|
2
|
-
var LmsError = class extends Error {
|
|
3
|
-
constructor(code, message, status = 400) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.code = code;
|
|
6
|
-
this.status = status;
|
|
7
|
-
this.name = "PluginRouteError";
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
function invariant(condition, code, message, status = 400) {
|
|
11
|
-
if (!condition) throw new LmsError(code, message, status);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
export { invariant as n, LmsError as t };
|
|
16
|
-
//# sourceMappingURL=errors-ChzJS9al.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors-ChzJS9al.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export class LmsError extends Error {\n constructor(\n readonly code: string,\n message: string,\n readonly status = 400,\n ) {\n super(message);\n this.name = \"PluginRouteError\";\n }\n}\n\nexport function invariant(\n condition: unknown,\n code: string,\n message: string,\n status = 400,\n): asserts condition {\n if (!condition) throw new LmsError(code, message, status);\n}\n"],"mappings":";AAAA,IAAa,WAAb,cAA8B,MAAM;CAClC,YACE,AAAS,MACT,SACA,AAAS,SAAS,KAClB;AACA,QAAM,QAAQ;EAJL;EAEA;AAGT,OAAK,OAAO;;;AAIhB,SAAgB,UACd,WACA,MACA,SACA,SAAS,KACU;AACnB,KAAI,CAAC,UAAW,OAAM,IAAI,SAAS,MAAM,SAAS,OAAO"}
|