@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
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
//#region src/assignments.ts
|
|
16
|
+
function emptyAssignmentDraft() {
|
|
17
|
+
return {
|
|
18
|
+
body: "",
|
|
19
|
+
attachmentUrl: null,
|
|
20
|
+
revision: 0,
|
|
21
|
+
updatedAt: null
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function assignmentBlock(assignment, progress, now) {
|
|
25
|
+
if (progress.completedAt) return {
|
|
26
|
+
code: "ASSIGNMENT_PASSED",
|
|
27
|
+
message: "This assignment has already been passed.",
|
|
28
|
+
status: 409
|
|
29
|
+
};
|
|
30
|
+
if (assignment.dueAt && now.getTime() > Date.parse(assignment.dueAt)) return {
|
|
31
|
+
code: "ASSIGNMENT_CLOSED",
|
|
32
|
+
message: "The assignment deadline has passed.",
|
|
33
|
+
status: 403
|
|
34
|
+
};
|
|
35
|
+
const last = progress.assignments.at(-1);
|
|
36
|
+
if (last && (last.status !== "graded" || !assignment.allowResubmission)) return {
|
|
37
|
+
code: "SUBMISSION_PENDING",
|
|
38
|
+
message: last.status === "submitted" ? "Wait for grading before submitting again." : "Resubmission is not enabled for this assignment.",
|
|
39
|
+
status: 409
|
|
40
|
+
};
|
|
41
|
+
if (progress.assignments.length >= 10) return {
|
|
42
|
+
code: "SUBMISSION_LIMIT",
|
|
43
|
+
message: "The assignment submission limit has been reached.",
|
|
44
|
+
status: 403
|
|
45
|
+
};
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/** Only the submission's snapshot can determine the score, never the latest course draft. */
|
|
49
|
+
function assignmentGrade(submission, points, scores = []) {
|
|
50
|
+
const rubric = submission.rubric ?? [];
|
|
51
|
+
if (!rubric.length) {
|
|
52
|
+
invariant(!scores.length, "INVALID_GRADE", "This submission has no grading rubric.");
|
|
53
|
+
invariant(points !== void 0 && points <= submission.maxPoints, "INVALID_GRADE", "Supply a score within this submission's maximum points.");
|
|
54
|
+
return {
|
|
55
|
+
points,
|
|
56
|
+
rubricScores: []
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
invariant(scores.length === rubric.length && new Set(scores.map((item) => item.criterionId)).size === rubric.length, "INVALID_GRADE", "Score each rubric criterion exactly once.");
|
|
60
|
+
const rubricScores = rubric.map((criterion) => {
|
|
61
|
+
const score = scores.find((item) => item.criterionId === criterion.id);
|
|
62
|
+
invariant(score && score.points <= criterion.maxPoints, "INVALID_GRADE", "Each score must match a rubric criterion and stay within its maximum.");
|
|
63
|
+
return score;
|
|
64
|
+
});
|
|
65
|
+
const total = rubricScores.reduce((sum, score) => sum + score.points, 0);
|
|
66
|
+
invariant(points === void 0 || points === total, "INVALID_GRADE", "Total points must match the rubric scores.");
|
|
67
|
+
return {
|
|
68
|
+
points: total,
|
|
69
|
+
rubricScores
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { invariant as a, LmsError as i, assignmentGrade as n, emptyAssignmentDraft as r, assignmentBlock as t };
|
|
75
|
+
//# sourceMappingURL=assignments-CsuAjxGO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignments-CsuAjxGO.js","names":[],"sources":["../src/errors.ts","../src/assignments.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","import type {\n AssignmentDraft,\n AssignmentSubmission,\n Lesson,\n LessonProgress,\n RubricScore,\n} from \"./types.js\";\nimport { invariant } from \"./errors.js\";\n\nexport function emptyAssignmentDraft(): AssignmentDraft {\n return { body: \"\", attachmentUrl: null, revision: 0, updatedAt: null };\n}\n\nexport function assignmentBlock(\n assignment: NonNullable<Lesson[\"assignment\"]>,\n progress: Pick<LessonProgress, \"completedAt\" | \"assignments\">,\n now: Date,\n) {\n if (progress.completedAt)\n return {\n code: \"ASSIGNMENT_PASSED\",\n message: \"This assignment has already been passed.\",\n status: 409,\n };\n if (assignment.dueAt && now.getTime() > Date.parse(assignment.dueAt))\n return {\n code: \"ASSIGNMENT_CLOSED\",\n message: \"The assignment deadline has passed.\",\n status: 403,\n };\n const last = progress.assignments.at(-1);\n if (last && (last.status !== \"graded\" || !assignment.allowResubmission))\n return {\n code: \"SUBMISSION_PENDING\",\n message:\n last.status === \"submitted\"\n ? \"Wait for grading before submitting again.\"\n : \"Resubmission is not enabled for this assignment.\",\n status: 409,\n };\n if (progress.assignments.length >= 10)\n return {\n code: \"SUBMISSION_LIMIT\",\n message: \"The assignment submission limit has been reached.\",\n status: 403,\n };\n return null;\n}\n\n/** Only the submission's snapshot can determine the score, never the latest course draft. */\nexport function assignmentGrade(\n submission: AssignmentSubmission,\n points: number | undefined,\n scores: RubricScore[] = [],\n) {\n const rubric = submission.rubric ?? [];\n if (!rubric.length) {\n invariant(!scores.length, \"INVALID_GRADE\", \"This submission has no grading rubric.\");\n invariant(\n points !== undefined && points <= submission.maxPoints,\n \"INVALID_GRADE\",\n \"Supply a score within this submission's maximum points.\",\n );\n return { points, rubricScores: [] };\n }\n invariant(\n scores.length === rubric.length &&\n new Set(scores.map((item) => item.criterionId)).size === rubric.length,\n \"INVALID_GRADE\",\n \"Score each rubric criterion exactly once.\",\n );\n const rubricScores = rubric.map((criterion) => {\n const score = scores.find((item) => item.criterionId === criterion.id);\n invariant(\n score && score.points <= criterion.maxPoints,\n \"INVALID_GRADE\",\n \"Each score must match a rubric criterion and stay within its maximum.\",\n );\n return score;\n });\n const total = rubricScores.reduce((sum, score) => sum + score.points, 0);\n invariant(\n points === undefined || points === total,\n \"INVALID_GRADE\",\n \"Total points must match the rubric scores.\",\n );\n return { points: total, rubricScores };\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;;;;;ACR3D,SAAgB,uBAAwC;AACtD,QAAO;EAAE,MAAM;EAAI,eAAe;EAAM,UAAU;EAAG,WAAW;EAAM;;AAGxE,SAAgB,gBACd,YACA,UACA,KACA;AACA,KAAI,SAAS,YACX,QAAO;EACL,MAAM;EACN,SAAS;EACT,QAAQ;EACT;AACH,KAAI,WAAW,SAAS,IAAI,SAAS,GAAG,KAAK,MAAM,WAAW,MAAM,CAClE,QAAO;EACL,MAAM;EACN,SAAS;EACT,QAAQ;EACT;CACH,MAAM,OAAO,SAAS,YAAY,GAAG,GAAG;AACxC,KAAI,SAAS,KAAK,WAAW,YAAY,CAAC,WAAW,mBACnD,QAAO;EACL,MAAM;EACN,SACE,KAAK,WAAW,cACZ,8CACA;EACN,QAAQ;EACT;AACH,KAAI,SAAS,YAAY,UAAU,GACjC,QAAO;EACL,MAAM;EACN,SAAS;EACT,QAAQ;EACT;AACH,QAAO;;;AAIT,SAAgB,gBACd,YACA,QACA,SAAwB,EAAE,EAC1B;CACA,MAAM,SAAS,WAAW,UAAU,EAAE;AACtC,KAAI,CAAC,OAAO,QAAQ;AAClB,YAAU,CAAC,OAAO,QAAQ,iBAAiB,yCAAyC;AACpF,YACE,WAAW,UAAa,UAAU,WAAW,WAC7C,iBACA,0DACD;AACD,SAAO;GAAE;GAAQ,cAAc,EAAE;GAAE;;AAErC,WACE,OAAO,WAAW,OAAO,UACvB,IAAI,IAAI,OAAO,KAAK,SAAS,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,QAClE,iBACA,4CACD;CACD,MAAM,eAAe,OAAO,KAAK,cAAc;EAC7C,MAAM,QAAQ,OAAO,MAAM,SAAS,KAAK,gBAAgB,UAAU,GAAG;AACtE,YACE,SAAS,MAAM,UAAU,UAAU,WACnC,iBACA,wEACD;AACD,SAAO;GACP;CACF,MAAM,QAAQ,aAAa,QAAQ,KAAK,UAAU,MAAM,MAAM,QAAQ,EAAE;AACxE,WACE,WAAW,UAAa,WAAW,OACnC,iBACA,6CACD;AACD,QAAO;EAAE,QAAQ;EAAO;EAAc"}
|
package/dist/astro.js
CHANGED
|
@@ -24,8 +24,12 @@ function lmsAstro(options = {}) {
|
|
|
24
24
|
[`${basePath}/courses/[slug]`, "course.astro"],
|
|
25
25
|
[`${basePath}/courses/[slug]/lessons/[lessonId]`, "lesson.astro"],
|
|
26
26
|
[`${basePath}/my-learning`, "dashboard.astro"],
|
|
27
|
+
[`${basePath}/my-learning/library`, "library.astro"],
|
|
28
|
+
[`${basePath}/my-learning/study`, "study.astro"],
|
|
29
|
+
[`${basePath}/paths`, "paths.astro"],
|
|
27
30
|
[`${basePath}/certificates/[certificateId]`, "certificate.astro"],
|
|
28
31
|
[`${basePath}/teach`, "teach.astro"],
|
|
32
|
+
[`${basePath}/teach/courses/[courseId]/lessons/[lessonId]`, "author-preview.astro"],
|
|
29
33
|
[`${basePath}/cohorts/[cohortId]`, "cohort.astro"]
|
|
30
34
|
];
|
|
31
35
|
for (const [pattern, file] of pages) injectRoute({
|
package/dist/astro.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"astro.js","names":[],"sources":["../src/astro.ts"],"sourcesContent":["import type { AstroIntegration } from \"astro\";\nimport { fileURLToPath } from \"node:url\";\nimport type { LmsOptions } from \"./types.js\";\nimport { normalizeLmsOptions } from \"./config.js\";\n\nexport interface LmsAstroOptions extends LmsOptions {\n layout?: string;\n}\n\nexport function lmsAstro(options: LmsAstroOptions = {}): AstroIntegration {\n const { basePath, loginPath } = normalizeLmsOptions(options);\n return {\n name: \"@anantagnanam/lms\",\n hooks: {\n \"astro:config:setup\": ({ config, injectRoute, updateConfig }) => {\n if (config.output !== \"server\") throw new Error(\"The LMS requires Astro output: server.\");\n const layouts = options.layout\n ? fileURLToPath(new URL(options.layout, config.root))\n : fileURLToPath(new URL(\"../astro/layouts/AcademyLayout.astro\", import.meta.url));\n const virtual = {\n \"virtual:anantagnanam-lms/config\": `export const basePath = ${JSON.stringify(basePath)}; export const loginPath = ${JSON.stringify(loginPath)};`,\n \"virtual:anantagnanam-lms/layout\": `export { default } from ${JSON.stringify(layouts.replaceAll(\"\\\\\", \"/\"))};`,\n };\n updateConfig({\n vite: {\n plugins: [\n {\n name: \"anantagnanam-lms-pages\",\n resolveId: (id) => (id in virtual ? `\\0${id}` : undefined),\n load: (id) => virtual[id.replace(/^\\0/, \"\") as keyof typeof virtual],\n },\n ],\n },\n });\n const pages = [\n [basePath, \"index.astro\"],\n [`${basePath}/courses/[slug]`, \"course.astro\"],\n [`${basePath}/courses/[slug]/lessons/[lessonId]`, \"lesson.astro\"],\n [`${basePath}/my-learning`, \"dashboard.astro\"],\n [`${basePath}/certificates/[certificateId]`, \"certificate.astro\"],\n [`${basePath}/teach`, \"teach.astro\"],\n [`${basePath}/cohorts/[cohortId]`, \"cohort.astro\"],\n ];\n for (const [pattern, file] of pages)\n injectRoute({\n pattern: pattern!,\n entrypoint: fileURLToPath(new URL(`../astro/pages/${file}`, import.meta.url)),\n prerender: false,\n });\n },\n \"astro:config:done\": ({ injectTypes }) => {\n injectTypes({\n filename: \"anantagnanam-lms.d.ts\",\n content:\n 'declare module \"virtual:anantagnanam-lms/config\" { export const basePath: string; export const loginPath: string; }\\ndeclare module \"virtual:anantagnanam-lms/layout\" { const Layout: import(\"astro/runtime/server/index.js\").AstroComponentFactory; export default Layout; }',\n });\n },\n },\n };\n}\nexport default lmsAstro;\n"],"mappings":";;;;AASA,SAAgB,SAAS,UAA2B,EAAE,EAAoB;CACxE,MAAM,EAAE,UAAU,cAAc,oBAAoB,QAAQ;AAC5D,QAAO;EACL,MAAM;EACN,OAAO;GACL,uBAAuB,EAAE,QAAQ,aAAa,mBAAmB;AAC/D,QAAI,OAAO,WAAW,SAAU,OAAM,IAAI,MAAM,yCAAyC;IACzF,MAAM,UAAU,QAAQ,SACpB,cAAc,IAAI,IAAI,QAAQ,QAAQ,OAAO,KAAK,CAAC,GACnD,cAAc,IAAI,IAAI,wCAAwC,OAAO,KAAK,IAAI,CAAC;IACnF,MAAM,UAAU;KACd,mCAAmC,2BAA2B,KAAK,UAAU,SAAS,CAAC,6BAA6B,KAAK,UAAU,UAAU,CAAC;KAC9I,mCAAmC,2BAA2B,KAAK,UAAU,QAAQ,WAAW,MAAM,IAAI,CAAC,CAAC;KAC7G;AACD,iBAAa,EACX,MAAM,EACJ,SAAS,CACP;KACE,MAAM;KACN,YAAY,OAAQ,MAAM,UAAU,KAAK,OAAO;KAChD,OAAO,OAAO,QAAQ,GAAG,QAAQ,OAAO,GAAG;KAC5C,CACF,EACF,EACF,CAAC;IACF,MAAM,QAAQ;KACZ,CAAC,UAAU,cAAc;KACzB,CAAC,GAAG,SAAS,kBAAkB,eAAe;KAC9C,CAAC,GAAG,SAAS,qCAAqC,eAAe;KACjE,CAAC,GAAG,SAAS,eAAe,kBAAkB;KAC9C,CAAC,GAAG,SAAS,gCAAgC,oBAAoB;KACjE,CAAC,GAAG,SAAS,SAAS,cAAc;KACpC,CAAC,GAAG,SAAS,sBAAsB,eAAe;KACnD;AACD,SAAK,MAAM,CAAC,SAAS,SAAS,MAC5B,aAAY;KACD;KACT,YAAY,cAAc,IAAI,IAAI,kBAAkB,QAAQ,OAAO,KAAK,IAAI,CAAC;KAC7E,WAAW;KACZ,CAAC;;GAEN,sBAAsB,EAAE,kBAAkB;AACxC,gBAAY;KACV,UAAU;KACV,SACE;KACH,CAAC;;GAEL;EACF"}
|
|
1
|
+
{"version":3,"file":"astro.js","names":[],"sources":["../src/astro.ts"],"sourcesContent":["import type { AstroIntegration } from \"astro\";\nimport { fileURLToPath } from \"node:url\";\nimport type { LmsOptions } from \"./types.js\";\nimport { normalizeLmsOptions } from \"./config.js\";\n\nexport interface LmsAstroOptions extends LmsOptions {\n layout?: string;\n}\n\nexport function lmsAstro(options: LmsAstroOptions = {}): AstroIntegration {\n const { basePath, loginPath } = normalizeLmsOptions(options);\n return {\n name: \"@anantagnanam/lms\",\n hooks: {\n \"astro:config:setup\": ({ config, injectRoute, updateConfig }) => {\n if (config.output !== \"server\") throw new Error(\"The LMS requires Astro output: server.\");\n const layouts = options.layout\n ? fileURLToPath(new URL(options.layout, config.root))\n : fileURLToPath(new URL(\"../astro/layouts/AcademyLayout.astro\", import.meta.url));\n const virtual = {\n \"virtual:anantagnanam-lms/config\": `export const basePath = ${JSON.stringify(basePath)}; export const loginPath = ${JSON.stringify(loginPath)};`,\n \"virtual:anantagnanam-lms/layout\": `export { default } from ${JSON.stringify(layouts.replaceAll(\"\\\\\", \"/\"))};`,\n };\n updateConfig({\n vite: {\n plugins: [\n {\n name: \"anantagnanam-lms-pages\",\n resolveId: (id) => (id in virtual ? `\\0${id}` : undefined),\n load: (id) => virtual[id.replace(/^\\0/, \"\") as keyof typeof virtual],\n },\n ],\n },\n });\n const pages = [\n [basePath, \"index.astro\"],\n [`${basePath}/courses/[slug]`, \"course.astro\"],\n [`${basePath}/courses/[slug]/lessons/[lessonId]`, \"lesson.astro\"],\n [`${basePath}/my-learning`, \"dashboard.astro\"],\n [`${basePath}/my-learning/library`, \"library.astro\"],\n [`${basePath}/my-learning/study`, \"study.astro\"],\n [`${basePath}/paths`, \"paths.astro\"],\n [`${basePath}/certificates/[certificateId]`, \"certificate.astro\"],\n [`${basePath}/teach`, \"teach.astro\"],\n [`${basePath}/teach/courses/[courseId]/lessons/[lessonId]`, \"author-preview.astro\"],\n [`${basePath}/cohorts/[cohortId]`, \"cohort.astro\"],\n ];\n for (const [pattern, file] of pages)\n injectRoute({\n pattern: pattern!,\n entrypoint: fileURLToPath(new URL(`../astro/pages/${file}`, import.meta.url)),\n prerender: false,\n });\n },\n \"astro:config:done\": ({ injectTypes }) => {\n injectTypes({\n filename: \"anantagnanam-lms.d.ts\",\n content:\n 'declare module \"virtual:anantagnanam-lms/config\" { export const basePath: string; export const loginPath: string; }\\ndeclare module \"virtual:anantagnanam-lms/layout\" { const Layout: import(\"astro/runtime/server/index.js\").AstroComponentFactory; export default Layout; }',\n });\n },\n },\n };\n}\nexport default lmsAstro;\n"],"mappings":";;;;AASA,SAAgB,SAAS,UAA2B,EAAE,EAAoB;CACxE,MAAM,EAAE,UAAU,cAAc,oBAAoB,QAAQ;AAC5D,QAAO;EACL,MAAM;EACN,OAAO;GACL,uBAAuB,EAAE,QAAQ,aAAa,mBAAmB;AAC/D,QAAI,OAAO,WAAW,SAAU,OAAM,IAAI,MAAM,yCAAyC;IACzF,MAAM,UAAU,QAAQ,SACpB,cAAc,IAAI,IAAI,QAAQ,QAAQ,OAAO,KAAK,CAAC,GACnD,cAAc,IAAI,IAAI,wCAAwC,OAAO,KAAK,IAAI,CAAC;IACnF,MAAM,UAAU;KACd,mCAAmC,2BAA2B,KAAK,UAAU,SAAS,CAAC,6BAA6B,KAAK,UAAU,UAAU,CAAC;KAC9I,mCAAmC,2BAA2B,KAAK,UAAU,QAAQ,WAAW,MAAM,IAAI,CAAC,CAAC;KAC7G;AACD,iBAAa,EACX,MAAM,EACJ,SAAS,CACP;KACE,MAAM;KACN,YAAY,OAAQ,MAAM,UAAU,KAAK,OAAO;KAChD,OAAO,OAAO,QAAQ,GAAG,QAAQ,OAAO,GAAG;KAC5C,CACF,EACF,EACF,CAAC;IACF,MAAM,QAAQ;KACZ,CAAC,UAAU,cAAc;KACzB,CAAC,GAAG,SAAS,kBAAkB,eAAe;KAC9C,CAAC,GAAG,SAAS,qCAAqC,eAAe;KACjE,CAAC,GAAG,SAAS,eAAe,kBAAkB;KAC9C,CAAC,GAAG,SAAS,uBAAuB,gBAAgB;KACpD,CAAC,GAAG,SAAS,qBAAqB,cAAc;KAChD,CAAC,GAAG,SAAS,SAAS,cAAc;KACpC,CAAC,GAAG,SAAS,gCAAgC,oBAAoB;KACjE,CAAC,GAAG,SAAS,SAAS,cAAc;KACpC,CAAC,GAAG,SAAS,+CAA+C,uBAAuB;KACnF,CAAC,GAAG,SAAS,sBAAsB,eAAe;KACnD;AACD,SAAK,MAAM,CAAC,SAAS,SAAS,MAC5B,aAAY;KACD;KACT,YAAY,cAAc,IAAI,IAAI,kBAAkB,QAAQ,OAAO,KAAK,IAAI,CAAC;KAC7E,WAAW;KACZ,CAAC;;GAEN,sBAAsB,EAAE,kBAAkB;AACxC,gBAAY;KACV,UAAU;KACV,SACE;KACH,CAAC;;GAEL;EACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/constants.ts
|
|
2
2
|
const PLUGIN_ID = "anantagnanam-lms";
|
|
3
|
-
const PLUGIN_VERSION = "0.
|
|
3
|
+
const PLUGIN_VERSION = "0.3.0";
|
|
4
4
|
const API_BASE = `/_emdash/api/plugins/${PLUGIN_ID}`;
|
|
5
5
|
const MAX_DOCUMENT_BYTES = 95e4;
|
|
6
6
|
const storage = {
|
|
@@ -13,10 +13,26 @@ const storage = {
|
|
|
13
13
|
"level",
|
|
14
14
|
"language",
|
|
15
15
|
"updatedAt",
|
|
16
|
-
"createdBy"
|
|
16
|
+
"createdBy",
|
|
17
|
+
"createdAt"
|
|
17
18
|
],
|
|
18
19
|
uniqueIndexes: ["slug"]
|
|
19
20
|
},
|
|
21
|
+
course_revisions: { indexes: ["courseId", "createdAt"] },
|
|
22
|
+
course_editions: { indexes: ["courseId", "createdAt"] },
|
|
23
|
+
migrations: { indexes: ["phase"] },
|
|
24
|
+
preferences: { indexes: [] },
|
|
25
|
+
saved_courses: { indexes: [
|
|
26
|
+
"userId",
|
|
27
|
+
"saved",
|
|
28
|
+
"updatedAt"
|
|
29
|
+
] },
|
|
30
|
+
learning_paths: { indexes: ["status", "updatedAt"] },
|
|
31
|
+
path_enrollments: { indexes: [
|
|
32
|
+
"userId",
|
|
33
|
+
"pathId",
|
|
34
|
+
"joinedAt"
|
|
35
|
+
] },
|
|
20
36
|
enrollments: { indexes: [
|
|
21
37
|
"userId",
|
|
22
38
|
"courseId",
|
|
@@ -108,6 +124,12 @@ const adminPages = [
|
|
|
108
124
|
icon: "users-three",
|
|
109
125
|
group: "Learning"
|
|
110
126
|
},
|
|
127
|
+
{
|
|
128
|
+
path: "/paths",
|
|
129
|
+
label: "Learning paths",
|
|
130
|
+
icon: "books",
|
|
131
|
+
group: "Learning"
|
|
132
|
+
},
|
|
111
133
|
{
|
|
112
134
|
path: "/reports",
|
|
113
135
|
label: "Reports",
|
|
@@ -136,4 +158,4 @@ const adminPages = [
|
|
|
136
158
|
|
|
137
159
|
//#endregion
|
|
138
160
|
export { adminPages as a, PLUGIN_VERSION as i, MAX_DOCUMENT_BYTES as n, storage as o, PLUGIN_ID as r, API_BASE as t };
|
|
139
|
-
//# sourceMappingURL=constants-
|
|
161
|
+
//# sourceMappingURL=constants-DyQbwNbP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants-DyQbwNbP.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["export const PLUGIN_ID = \"anantagnanam-lms\";\nexport const PLUGIN_VERSION = \"0.3.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 \"createdAt\",\n ],\n uniqueIndexes: [\"slug\"],\n },\n course_revisions: { indexes: [\"courseId\", \"createdAt\"] },\n course_editions: { indexes: [\"courseId\", \"createdAt\"] },\n migrations: { indexes: [\"phase\"] },\n preferences: { indexes: [] },\n saved_courses: { indexes: [\"userId\", \"saved\", \"updatedAt\"] },\n learning_paths: { indexes: [\"status\", \"updatedAt\"] },\n path_enrollments: { indexes: [\"userId\", \"pathId\", \"joinedAt\"] },\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: \"/paths\", label: \"Learning paths\", icon: \"books\", 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;GACA;GACD;EACD,eAAe,CAAC,OAAO;EACxB;CACD,kBAAkB,EAAE,SAAS,CAAC,YAAY,YAAY,EAAE;CACxD,iBAAiB,EAAE,SAAS,CAAC,YAAY,YAAY,EAAE;CACvD,YAAY,EAAE,SAAS,CAAC,QAAQ,EAAE;CAClC,aAAa,EAAE,SAAS,EAAE,EAAE;CAC5B,eAAe,EAAE,SAAS;EAAC;EAAU;EAAS;EAAY,EAAE;CAC5D,gBAAgB,EAAE,SAAS,CAAC,UAAU,YAAY,EAAE;CACpD,kBAAkB,EAAE,SAAS;EAAC;EAAU;EAAU;EAAW,EAAE;CAC/D,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;EAAU,OAAO;EAAkB,MAAM;EAAS,OAAO;EAAY;CAC7E;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/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { PluginDescriptor } from "emdash";
|
|
|
3
3
|
|
|
4
4
|
//#region src/constants.d.ts
|
|
5
5
|
declare const PLUGIN_ID = "anantagnanam-lms";
|
|
6
|
-
declare const PLUGIN_VERSION = "0.
|
|
6
|
+
declare const PLUGIN_VERSION = "0.3.0";
|
|
7
7
|
declare const API_BASE = "/_emdash/api/plugins/anantagnanam-lms";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/index.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as adminPages, i as PLUGIN_VERSION, r as PLUGIN_ID, t as API_BASE } from "./constants-
|
|
1
|
+
import { a as adminPages, i as PLUGIN_VERSION, r as PLUGIN_ID, t as API_BASE } from "./constants-DyQbwNbP.js";
|
|
2
2
|
import { t as normalizeLmsOptions } from "./config-BX3beTpM.js";
|
|
3
3
|
|
|
4
4
|
//#region src/index.ts
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AccessGrant, Acquisition, Actor, AuditRecord, Certificate, CertificateIndex, Cohort, CohortMembership, Course, CourseCard, CourseData, CourseDetail, CurriculumModule, Discussion, Enrollment, Lesson, LessonProgress, LmsOptions, LmsSettings, Notification, Page, ProgressSummary, PublicEnrollment, PublicLesson, PublicQuizAttempt, Review } from "./types.js";
|
|
1
|
+
import { AccessGrant, Acquisition, Actor, AssignmentState, AuditRecord, Certificate, CertificateIndex, Cohort, CohortMembership, Course, CourseCard, CourseData, CourseDetail, CourseEdition, CourseRevision, CurriculumModule, Discussion, Enrollment, LearnerPreferences, LearningPath, Lesson, LessonProgress, LmsOptions, LmsSettings, MigrationState, Notification, Page, PathEnrollment, ProgressSummary, PublicEnrollment, PublicLesson, PublicQuizAttempt, Review, RevisionSummary, RubricCriterion, RubricScore, SavedCourse, StudyNote, Versioned } from "./types.js";
|
|
2
2
|
import * as emdash from "emdash";
|
|
3
3
|
import { PluginContext, StorageCollection } from "emdash";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -6,6 +6,13 @@ import { z } from "zod";
|
|
|
6
6
|
//#region src/store.d.ts
|
|
7
7
|
interface LmsCollections {
|
|
8
8
|
courses: StorageCollection<Course>;
|
|
9
|
+
course_revisions: StorageCollection<CourseRevision>;
|
|
10
|
+
course_editions: StorageCollection<CourseEdition>;
|
|
11
|
+
migrations: StorageCollection<MigrationState>;
|
|
12
|
+
preferences: StorageCollection<LearnerPreferences>;
|
|
13
|
+
saved_courses: StorageCollection<SavedCourse>;
|
|
14
|
+
learning_paths: StorageCollection<LearningPath>;
|
|
15
|
+
path_enrollments: StorageCollection<PathEnrollment>;
|
|
9
16
|
enrollments: StorageCollection<Enrollment>;
|
|
10
17
|
certificates: StorageCollection<CertificateIndex>;
|
|
11
18
|
discussions: StorageCollection<Discussion>;
|
|
@@ -16,6 +23,28 @@ interface LmsCollections {
|
|
|
16
23
|
audit: StorageCollection<AuditRecord>;
|
|
17
24
|
}
|
|
18
25
|
//#endregion
|
|
26
|
+
//#region src/editions.d.ts
|
|
27
|
+
/** Child snapshots are immutable. Only the root CAS makes a revision visible. */
|
|
28
|
+
declare class CourseEditions {
|
|
29
|
+
readonly stores: LmsCollections;
|
|
30
|
+
readonly time: () => string;
|
|
31
|
+
readonly resolveContent: (lesson: Lesson) => Promise<Lesson>;
|
|
32
|
+
constructor(stores: LmsCollections, time: () => string, resolveContent: (lesson: Lesson) => Promise<Lesson>);
|
|
33
|
+
snapshot(courseId: string, data: CourseData): Promise<string>;
|
|
34
|
+
revision(course: Course, data: CourseData, actorId: string, kind: CourseRevision["kind"], extra?: Partial<Pick<CourseRevision, "editionId" | "restoredFrom">>): Promise<CourseRevision>;
|
|
35
|
+
commit(current: Versioned<Course> | null, course: Course): Promise<Versioned<Course>>;
|
|
36
|
+
ensure(id: string, expectedRevision?: string): Promise<Versioned<Course>>;
|
|
37
|
+
draft(course: Course): Promise<Course>;
|
|
38
|
+
learning(course: Course, enrollment: Enrollment | null): Promise<Course>;
|
|
39
|
+
history(course: Course, cursor?: string): Promise<{
|
|
40
|
+
items: RevisionSummary[];
|
|
41
|
+
cursor?: string;
|
|
42
|
+
hasMore: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
migrationStatus(): Promise<MigrationState>;
|
|
45
|
+
migrateBatch(limit: number): Promise<MigrationState>;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
19
48
|
//#region src/curriculum.d.ts
|
|
20
49
|
declare function findLesson(course: Course, lessonId: string): Lesson;
|
|
21
50
|
//#endregion
|
|
@@ -24,6 +53,7 @@ declare class LmsService {
|
|
|
24
53
|
readonly ctx: PluginContext;
|
|
25
54
|
readonly now: () => Date;
|
|
26
55
|
readonly stores: LmsCollections;
|
|
56
|
+
readonly editions: CourseEditions;
|
|
27
57
|
constructor(ctx: PluginContext, now?: () => Date);
|
|
28
58
|
time(): string;
|
|
29
59
|
settings(): Promise<LmsSettings>;
|
|
@@ -32,6 +62,10 @@ declare class LmsService {
|
|
|
32
62
|
course(id: string): Promise<Course>;
|
|
33
63
|
accessEnrollment(enrollment: Enrollment | null): Promise<Enrollment | null>;
|
|
34
64
|
enrollmentView(enrollment: Enrollment): Promise<PublicEnrollment>;
|
|
65
|
+
learningState(course: Course, enrollment: Enrollment | null): Promise<{
|
|
66
|
+
enrollment: PublicEnrollment | null;
|
|
67
|
+
progress: ProgressSummary;
|
|
68
|
+
}>;
|
|
35
69
|
lessonAccess(course: Course, lessonId: string, enrollment: Enrollment | null): Promise<{
|
|
36
70
|
id: string;
|
|
37
71
|
title: string;
|
|
@@ -45,6 +79,12 @@ declare class LmsService {
|
|
|
45
79
|
field: string;
|
|
46
80
|
} | null;
|
|
47
81
|
mediaUrl: string | null;
|
|
82
|
+
transcript: string;
|
|
83
|
+
captions: {
|
|
84
|
+
src: string;
|
|
85
|
+
language: string;
|
|
86
|
+
label: string;
|
|
87
|
+
}[];
|
|
48
88
|
liveStartsAt: string | null;
|
|
49
89
|
durationMinutes: number;
|
|
50
90
|
minStudySeconds: number;
|
|
@@ -82,6 +122,12 @@ declare class LmsService {
|
|
|
82
122
|
passingPoints: number;
|
|
83
123
|
dueAt: string | null;
|
|
84
124
|
allowResubmission: boolean;
|
|
125
|
+
rubric?: {
|
|
126
|
+
id: string;
|
|
127
|
+
title: string;
|
|
128
|
+
description: string;
|
|
129
|
+
maxPoints: number;
|
|
130
|
+
}[] | undefined;
|
|
85
131
|
} | null;
|
|
86
132
|
}>;
|
|
87
133
|
instructor(course: Course, actor: Actor | undefined): Actor;
|
|
@@ -89,6 +135,25 @@ declare class LmsService {
|
|
|
89
135
|
course: Course;
|
|
90
136
|
revision: string;
|
|
91
137
|
}>;
|
|
138
|
+
publishCourse(actor: Actor | undefined, id: string, expectedRevision: string): Promise<{
|
|
139
|
+
course: Course;
|
|
140
|
+
revision: string;
|
|
141
|
+
}>;
|
|
142
|
+
courseHistory(actor: Actor | undefined, id: string, cursor?: string): Promise<{
|
|
143
|
+
items: RevisionSummary[];
|
|
144
|
+
cursor?: string;
|
|
145
|
+
hasMore: boolean;
|
|
146
|
+
}>;
|
|
147
|
+
restoreCourse(actor: Actor | undefined, id: string, expectedRevision: string, revisionId: string): Promise<{
|
|
148
|
+
course: Course;
|
|
149
|
+
revision: string;
|
|
150
|
+
}>;
|
|
151
|
+
archiveCourse(actor: Actor | undefined, id: string, expectedRevision: string): Promise<{
|
|
152
|
+
course: Course;
|
|
153
|
+
revision: string;
|
|
154
|
+
}>;
|
|
155
|
+
migrationStatus(actor: Actor | undefined): Promise<MigrationState>;
|
|
156
|
+
migrateBatch(actor: Actor | undefined, limit: number): Promise<MigrationState>;
|
|
92
157
|
assertPrerequisiteGraph(courseId: string, prerequisites: string[]): Promise<void>;
|
|
93
158
|
editableCourse(actor: Actor | undefined, id: string): Promise<{
|
|
94
159
|
course: Course;
|
|
@@ -163,6 +228,10 @@ declare class LmsService {
|
|
|
163
228
|
lesson: PublicLesson;
|
|
164
229
|
}>;
|
|
165
230
|
resolveContent(lesson: ReturnType<typeof findLesson>): Promise<ReturnType<typeof findLesson>>;
|
|
231
|
+
authorLessonPreview(actor: Actor | undefined, courseId: string, lessonId: string): Promise<{
|
|
232
|
+
course: CourseDetail;
|
|
233
|
+
lesson: PublicLesson;
|
|
234
|
+
}>;
|
|
166
235
|
assertPrerequisites(course: Course, actorId: string): Promise<void>;
|
|
167
236
|
newEnrollment(course: Course, actor: Actor, status: Enrollment["status"]): Enrollment;
|
|
168
237
|
enroll(actor: Actor | undefined, courseId: string, options?: {
|
|
@@ -170,6 +239,8 @@ declare class LmsService {
|
|
|
170
239
|
}): Promise<PublicEnrollment>;
|
|
171
240
|
adminEnrollment(actor: Actor | undefined, input: unknown): Promise<PublicEnrollment>;
|
|
172
241
|
learnerCourse(actor: Actor | undefined, courseId: string): Promise<{
|
|
242
|
+
enrollment: PublicEnrollment | null;
|
|
243
|
+
progress: ProgressSummary;
|
|
173
244
|
course: {
|
|
174
245
|
prerequisites: {
|
|
175
246
|
id: string;
|
|
@@ -199,10 +270,10 @@ declare class LmsService {
|
|
|
199
270
|
lessonCount: number;
|
|
200
271
|
durationMinutes: number;
|
|
201
272
|
};
|
|
202
|
-
enrollment: PublicEnrollment | null;
|
|
203
|
-
progress: ProgressSummary;
|
|
204
273
|
}>;
|
|
205
274
|
learnerCourseBySlug(actor: Actor | undefined, slug: string): Promise<{
|
|
275
|
+
enrollment: PublicEnrollment | null;
|
|
276
|
+
progress: ProgressSummary;
|
|
206
277
|
course: {
|
|
207
278
|
prerequisites: {
|
|
208
279
|
id: string;
|
|
@@ -232,47 +303,52 @@ declare class LmsService {
|
|
|
232
303
|
lessonCount: number;
|
|
233
304
|
durationMinutes: number;
|
|
234
305
|
};
|
|
235
|
-
enrollment: PublicEnrollment | null;
|
|
236
|
-
progress: ProgressSummary;
|
|
237
306
|
}>;
|
|
238
307
|
dashboard(actor: Actor | undefined, options?: {
|
|
239
308
|
cursor?: string;
|
|
240
309
|
limit?: number;
|
|
241
310
|
}): Promise<{
|
|
242
311
|
items: {
|
|
243
|
-
|
|
244
|
-
enrollment: PublicEnrollment;
|
|
312
|
+
enrollment: PublicEnrollment | null;
|
|
245
313
|
progress: ProgressSummary;
|
|
314
|
+
course: CourseCard;
|
|
246
315
|
}[];
|
|
247
316
|
cursor?: string;
|
|
248
317
|
hasMore: boolean;
|
|
249
318
|
}>;
|
|
250
319
|
learnerLesson(actor: Actor | undefined, courseId: string, lessonId: string): Promise<{
|
|
320
|
+
enrollment: PublicEnrollment | null;
|
|
321
|
+
progress: ProgressSummary;
|
|
251
322
|
course: CourseDetail;
|
|
252
323
|
lesson: PublicLesson;
|
|
253
|
-
enrollment: PublicEnrollment;
|
|
254
|
-
progress: ProgressSummary;
|
|
255
324
|
}>;
|
|
256
325
|
startLesson(actor: Actor | undefined, courseId: string, lessonId: string): Promise<PublicEnrollment>;
|
|
257
326
|
completeLesson(actor: Actor | undefined, courseId: string, lessonId: string): Promise<{
|
|
258
|
-
enrollment: PublicEnrollment;
|
|
327
|
+
enrollment: PublicEnrollment | null;
|
|
259
328
|
progress: ProgressSummary;
|
|
260
329
|
}>;
|
|
261
330
|
finish(course: Course, enrollment: Enrollment, settings: LmsSettings): void;
|
|
262
331
|
projectCompletion(enrollment: Enrollment): Promise<void>;
|
|
263
332
|
startQuiz(actor: Actor | undefined, courseId: string, lessonId: string): Promise<PublicQuizAttempt>;
|
|
264
333
|
submitQuiz(actor: Actor | undefined, input: unknown): Promise<{
|
|
265
|
-
|
|
266
|
-
enrollment: PublicEnrollment;
|
|
334
|
+
enrollment: PublicEnrollment | null;
|
|
267
335
|
progress: ProgressSummary;
|
|
336
|
+
attempt: PublicQuizAttempt;
|
|
268
337
|
}>;
|
|
269
338
|
saveQuizDraft(actor: Actor | undefined, input: unknown): Promise<{
|
|
270
339
|
saved: boolean;
|
|
340
|
+
draftRevision: number;
|
|
341
|
+
}>;
|
|
342
|
+
assignmentState(actor: Actor | undefined, courseId: string, lessonId: string): Promise<AssignmentState>;
|
|
343
|
+
saveAssignmentDraft(actor: Actor | undefined, input: unknown): Promise<{
|
|
344
|
+
saved: boolean;
|
|
345
|
+
draftRevision: number;
|
|
271
346
|
}>;
|
|
272
347
|
submitAssignment(actor: Actor | undefined, input: unknown): Promise<PublicEnrollment>;
|
|
273
348
|
gradeAssignment(actor: Actor | undefined, input: unknown): Promise<PublicEnrollment>;
|
|
274
349
|
saveNote(actor: Actor | undefined, input: unknown): Promise<{
|
|
275
350
|
note: string;
|
|
351
|
+
revision: number;
|
|
276
352
|
}>;
|
|
277
353
|
certificate(actor: Actor | undefined, courseId: string): Promise<Certificate>;
|
|
278
354
|
ownedCertificate(actor: Actor | undefined, id: string): Promise<Certificate>;
|
|
@@ -395,18 +471,17 @@ declare class LmsService {
|
|
|
395
471
|
progress: Record<string, Omit<LessonProgress, "quizAttempts"> & {
|
|
396
472
|
quizAttempts: PublicQuizAttempt[];
|
|
397
473
|
}>;
|
|
398
|
-
id: string;
|
|
399
474
|
status: "pending" | "active" | "completed" | "rejected" | "suspended" | "cancelled";
|
|
400
475
|
courseId: string;
|
|
401
|
-
cohortId: string | null;
|
|
402
476
|
userId: string;
|
|
403
|
-
accessStartsAt: string | null;
|
|
404
|
-
accessExpiresAt: string | null;
|
|
405
477
|
accessStatus: "pending" | "granted" | "suspended" | "revoked";
|
|
406
478
|
accessSource: "free" | "manual" | "cohort" | "purchase";
|
|
407
479
|
enrolledAt: string;
|
|
408
480
|
completedAt: string | null;
|
|
409
481
|
lastActivityAt: string;
|
|
482
|
+
cohortId: string | null;
|
|
483
|
+
id: string;
|
|
484
|
+
courseEditionId?: string | undefined;
|
|
410
485
|
learnerName: string;
|
|
411
486
|
grants: Record<string, AccessGrant>;
|
|
412
487
|
cohortIds: string[];
|
|
@@ -415,6 +490,9 @@ declare class LmsService {
|
|
|
415
490
|
decisionAt: string | null;
|
|
416
491
|
decisionReason: string | null;
|
|
417
492
|
approvedAt: string | null;
|
|
493
|
+
accessStartsAt: string | null;
|
|
494
|
+
accessExpiresAt: string | null;
|
|
495
|
+
studyNotes?: StudyNote[] | undefined;
|
|
418
496
|
certificate: Certificate | null;
|
|
419
497
|
completionLessonIds: string[];
|
|
420
498
|
schemaVersion: 1;
|
|
@@ -524,6 +602,8 @@ declare class LmsService {
|
|
|
524
602
|
feedback: string;
|
|
525
603
|
gradedAt: string | null;
|
|
526
604
|
gradedBy: string | null;
|
|
605
|
+
rubric?: RubricCriterion[];
|
|
606
|
+
rubricScores?: RubricScore[];
|
|
527
607
|
}[];
|
|
528
608
|
cursor?: string;
|
|
529
609
|
hasMore: boolean;
|
|
@@ -581,6 +661,12 @@ declare class LmsService {
|
|
|
581
661
|
field: string;
|
|
582
662
|
} | null;
|
|
583
663
|
mediaUrl: string | null;
|
|
664
|
+
transcript: string;
|
|
665
|
+
captions: {
|
|
666
|
+
src: string;
|
|
667
|
+
language: string;
|
|
668
|
+
label: string;
|
|
669
|
+
}[];
|
|
584
670
|
liveStartsAt: string | null;
|
|
585
671
|
durationMinutes: number;
|
|
586
672
|
minStudySeconds: number;
|
|
@@ -618,6 +704,12 @@ declare class LmsService {
|
|
|
618
704
|
passingPoints: number;
|
|
619
705
|
dueAt: string | null;
|
|
620
706
|
allowResubmission: boolean;
|
|
707
|
+
rubric?: {
|
|
708
|
+
id: string;
|
|
709
|
+
title: string;
|
|
710
|
+
description: string;
|
|
711
|
+
maxPoints: number;
|
|
712
|
+
}[] | undefined;
|
|
621
713
|
} | null;
|
|
622
714
|
}[];
|
|
623
715
|
}[];
|
|
@@ -651,6 +743,27 @@ declare function createPlugin(_options?: LmsOptions): emdash.ResolvedPlugin<{
|
|
|
651
743
|
indexes: string[];
|
|
652
744
|
uniqueIndexes: string[];
|
|
653
745
|
};
|
|
746
|
+
course_revisions: {
|
|
747
|
+
indexes: string[];
|
|
748
|
+
};
|
|
749
|
+
course_editions: {
|
|
750
|
+
indexes: string[];
|
|
751
|
+
};
|
|
752
|
+
migrations: {
|
|
753
|
+
indexes: string[];
|
|
754
|
+
};
|
|
755
|
+
preferences: {
|
|
756
|
+
indexes: never[];
|
|
757
|
+
};
|
|
758
|
+
saved_courses: {
|
|
759
|
+
indexes: string[];
|
|
760
|
+
};
|
|
761
|
+
learning_paths: {
|
|
762
|
+
indexes: string[];
|
|
763
|
+
};
|
|
764
|
+
path_enrollments: {
|
|
765
|
+
indexes: string[];
|
|
766
|
+
};
|
|
654
767
|
enrollments: {
|
|
655
768
|
indexes: (string | string[])[];
|
|
656
769
|
};
|