@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.
Files changed (51) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +40 -2
  3. package/astro/assignment-player.ts +231 -0
  4. package/astro/client.ts +97 -152
  5. package/astro/components/AssignmentFeedback.astro +32 -0
  6. package/astro/components/AssignmentRubric.astro +27 -0
  7. package/astro/components/CourseOverview.astro +25 -3
  8. package/astro/components/LearnerDashboard.astro +9 -0
  9. package/astro/components/LearningShell.astro +16 -1
  10. package/astro/components/LessonAvailabilityNote.astro +26 -0
  11. package/astro/components/LessonContent.astro +67 -0
  12. package/astro/components/LessonPlayer.astro +166 -99
  13. package/astro/components/MediaPlayer.astro +55 -4
  14. package/astro/draft-queue.ts +95 -0
  15. package/astro/media-player.ts +124 -0
  16. package/astro/pages/author-preview.astro +73 -0
  17. package/astro/pages/course.astro +10 -0
  18. package/astro/pages/lesson.astro +3 -0
  19. package/astro/pages/library.astro +173 -0
  20. package/astro/pages/paths.astro +73 -0
  21. package/astro/pages/study.astro +180 -0
  22. package/astro/quiz-drafts.ts +23 -0
  23. package/astro/quiz-player.ts +362 -0
  24. package/astro/study-tools.ts +386 -0
  25. package/astro/styles.css +30 -0
  26. package/astro/transcript-search.ts +56 -0
  27. package/dist/admin.d.ts +3 -1
  28. package/dist/admin.js +756 -127
  29. package/dist/admin.js.map +1 -1
  30. package/dist/assignments-CsuAjxGO.js +75 -0
  31. package/dist/assignments-CsuAjxGO.js.map +1 -0
  32. package/dist/astro.js +4 -0
  33. package/dist/astro.js.map +1 -1
  34. package/dist/{constants-C0kT94tc.js → constants-DyQbwNbP.js} +25 -3
  35. package/dist/constants-DyQbwNbP.js.map +1 -0
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/runtime.d.ts +129 -16
  39. package/dist/runtime.js +1201 -130
  40. package/dist/runtime.js.map +1 -1
  41. package/dist/schemas.d.ts +136 -3
  42. package/dist/schemas.js +80 -7
  43. package/dist/schemas.js.map +1 -1
  44. package/dist/server.d.ts +18 -1
  45. package/dist/server.js +17 -3
  46. package/dist/server.js.map +1 -1
  47. package/dist/types.d.ts +172 -4
  48. package/package.json +1 -1
  49. package/dist/constants-C0kT94tc.js.map +0 -1
  50. package/dist/errors-ChzJS9al.js +0 -16
  51. package/dist/errors-ChzJS9al.js.map +0 -1
package/dist/schemas.d.ts CHANGED
@@ -56,12 +56,29 @@ declare const quizSchema: z.ZodObject<{
56
56
  after_submit: "after_submit";
57
57
  }>>;
58
58
  }, z.core.$strip>;
59
+ declare const rubricCriterionSchema: z.ZodObject<{
60
+ id: z.ZodString;
61
+ title: z.ZodString;
62
+ description: z.ZodDefault<z.ZodString>;
63
+ maxPoints: z.ZodNumber;
64
+ }, z.core.$strip>;
65
+ declare const rubricScoreSchema: z.ZodObject<{
66
+ criterionId: z.ZodString;
67
+ points: z.ZodNumber;
68
+ feedback: z.ZodDefault<z.ZodString>;
69
+ }, z.core.$strip>;
59
70
  declare const assignmentSchema: z.ZodObject<{
60
71
  instructions: z.ZodString;
61
72
  maxPoints: z.ZodDefault<z.ZodNumber>;
62
73
  passingPoints: z.ZodDefault<z.ZodNumber>;
63
74
  dueAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
64
75
  allowResubmission: z.ZodDefault<z.ZodBoolean>;
76
+ rubric: z.ZodOptional<z.ZodArray<z.ZodObject<{
77
+ id: z.ZodString;
78
+ title: z.ZodString;
79
+ description: z.ZodDefault<z.ZodString>;
80
+ maxPoints: z.ZodNumber;
81
+ }, z.core.$strip>>>;
65
82
  }, z.core.$strip>;
66
83
  declare const lessonSchema: z.ZodObject<{
67
84
  id: z.ZodString;
@@ -83,6 +100,12 @@ declare const lessonSchema: z.ZodObject<{
83
100
  field: z.ZodDefault<z.ZodString>;
84
101
  }, z.core.$strip>>>;
85
102
  mediaUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
103
+ transcript: z.ZodDefault<z.ZodString>;
104
+ captions: z.ZodDefault<z.ZodArray<z.ZodObject<{
105
+ src: z.ZodString;
106
+ language: z.ZodString;
107
+ label: z.ZodString;
108
+ }, z.core.$strip>>>;
86
109
  liveStartsAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
87
110
  durationMinutes: z.ZodDefault<z.ZodNumber>;
88
111
  minStudySeconds: z.ZodDefault<z.ZodNumber>;
@@ -129,6 +152,12 @@ declare const lessonSchema: z.ZodObject<{
129
152
  passingPoints: z.ZodDefault<z.ZodNumber>;
130
153
  dueAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
131
154
  allowResubmission: z.ZodDefault<z.ZodBoolean>;
155
+ rubric: z.ZodOptional<z.ZodArray<z.ZodObject<{
156
+ id: z.ZodString;
157
+ title: z.ZodString;
158
+ description: z.ZodDefault<z.ZodString>;
159
+ maxPoints: z.ZodNumber;
160
+ }, z.core.$strip>>>;
132
161
  }, z.core.$strip>>>;
133
162
  }, z.core.$strip>;
134
163
  declare const moduleSchema: z.ZodObject<{
@@ -157,6 +186,12 @@ declare const moduleSchema: z.ZodObject<{
157
186
  field: z.ZodDefault<z.ZodString>;
158
187
  }, z.core.$strip>>>;
159
188
  mediaUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
189
+ transcript: z.ZodDefault<z.ZodString>;
190
+ captions: z.ZodDefault<z.ZodArray<z.ZodObject<{
191
+ src: z.ZodString;
192
+ language: z.ZodString;
193
+ label: z.ZodString;
194
+ }, z.core.$strip>>>;
160
195
  liveStartsAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
161
196
  durationMinutes: z.ZodDefault<z.ZodNumber>;
162
197
  minStudySeconds: z.ZodDefault<z.ZodNumber>;
@@ -203,6 +238,12 @@ declare const moduleSchema: z.ZodObject<{
203
238
  passingPoints: z.ZodDefault<z.ZodNumber>;
204
239
  dueAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
205
240
  allowResubmission: z.ZodDefault<z.ZodBoolean>;
241
+ rubric: z.ZodOptional<z.ZodArray<z.ZodObject<{
242
+ id: z.ZodString;
243
+ title: z.ZodString;
244
+ description: z.ZodDefault<z.ZodString>;
245
+ maxPoints: z.ZodNumber;
246
+ }, z.core.$strip>>>;
206
247
  }, z.core.$strip>>>;
207
248
  }, z.core.$strip>>>;
208
249
  }, z.core.$strip>;
@@ -279,6 +320,12 @@ declare const courseDataSchema: z.ZodObject<{
279
320
  field: z.ZodDefault<z.ZodString>;
280
321
  }, z.core.$strip>>>;
281
322
  mediaUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
323
+ transcript: z.ZodDefault<z.ZodString>;
324
+ captions: z.ZodDefault<z.ZodArray<z.ZodObject<{
325
+ src: z.ZodString;
326
+ language: z.ZodString;
327
+ label: z.ZodString;
328
+ }, z.core.$strip>>>;
282
329
  liveStartsAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
283
330
  durationMinutes: z.ZodDefault<z.ZodNumber>;
284
331
  minStudySeconds: z.ZodDefault<z.ZodNumber>;
@@ -325,6 +372,12 @@ declare const courseDataSchema: z.ZodObject<{
325
372
  passingPoints: z.ZodDefault<z.ZodNumber>;
326
373
  dueAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
327
374
  allowResubmission: z.ZodDefault<z.ZodBoolean>;
375
+ rubric: z.ZodOptional<z.ZodArray<z.ZodObject<{
376
+ id: z.ZodString;
377
+ title: z.ZodString;
378
+ description: z.ZodDefault<z.ZodString>;
379
+ maxPoints: z.ZodNumber;
380
+ }, z.core.$strip>>>;
328
381
  }, z.core.$strip>>>;
329
382
  }, z.core.$strip>>>;
330
383
  }, z.core.$strip>>>;
@@ -405,6 +458,12 @@ declare const courseSaveSchema: z.ZodObject<{
405
458
  field: z.ZodDefault<z.ZodString>;
406
459
  }, z.core.$strip>>>;
407
460
  mediaUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
461
+ transcript: z.ZodDefault<z.ZodString>;
462
+ captions: z.ZodDefault<z.ZodArray<z.ZodObject<{
463
+ src: z.ZodString;
464
+ language: z.ZodString;
465
+ label: z.ZodString;
466
+ }, z.core.$strip>>>;
408
467
  liveStartsAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
409
468
  durationMinutes: z.ZodDefault<z.ZodNumber>;
410
469
  minStudySeconds: z.ZodDefault<z.ZodNumber>;
@@ -451,6 +510,12 @@ declare const courseSaveSchema: z.ZodObject<{
451
510
  passingPoints: z.ZodDefault<z.ZodNumber>;
452
511
  dueAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
453
512
  allowResubmission: z.ZodDefault<z.ZodBoolean>;
513
+ rubric: z.ZodOptional<z.ZodArray<z.ZodObject<{
514
+ id: z.ZodString;
515
+ title: z.ZodString;
516
+ description: z.ZodDefault<z.ZodString>;
517
+ maxPoints: z.ZodNumber;
518
+ }, z.core.$strip>>>;
454
519
  }, z.core.$strip>>>;
455
520
  }, z.core.$strip>>>;
456
521
  }, z.core.$strip>>>;
@@ -486,12 +551,29 @@ declare const quizSubmitSchema: z.ZodObject<{
486
551
  lessonId: z.ZodString;
487
552
  attemptId: z.ZodString;
488
553
  answers: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
554
+ expectedDraftRevision: z.ZodOptional<z.ZodNumber>;
555
+ }, z.core.$strip>;
556
+ declare const quizDraftSchema: z.ZodObject<{
557
+ courseId: z.ZodString;
558
+ lessonId: z.ZodString;
559
+ attemptId: z.ZodString;
560
+ answers: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
561
+ expectedDraftRevision: z.ZodDefault<z.ZodNumber>;
489
562
  }, z.core.$strip>;
490
563
  declare const assignmentSubmitSchema: z.ZodObject<{
491
564
  courseId: z.ZodString;
492
565
  lessonId: z.ZodString;
493
566
  body: z.ZodString;
494
567
  attachmentUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
568
+ submissionId: z.ZodOptional<z.ZodString>;
569
+ expectedDraftRevision: z.ZodOptional<z.ZodNumber>;
570
+ }, z.core.$strip>;
571
+ declare const assignmentDraftSchema: z.ZodObject<{
572
+ courseId: z.ZodString;
573
+ lessonId: z.ZodString;
574
+ body: z.ZodDefault<z.ZodString>;
575
+ attachmentUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
576
+ expectedDraftRevision: z.ZodNumber;
495
577
  }, z.core.$strip>;
496
578
  declare const enrollmentRequestSchema: z.ZodObject<{
497
579
  courseId: z.ZodString;
@@ -501,9 +583,9 @@ declare const enrollmentAdminSchema: z.ZodObject<{
501
583
  courseId: z.ZodString;
502
584
  userId: z.ZodString;
503
585
  status: z.ZodEnum<{
586
+ suspended: "suspended";
504
587
  active: "active";
505
588
  rejected: "rejected";
506
- suspended: "suspended";
507
589
  cancelled: "cancelled";
508
590
  }>;
509
591
  reason: z.ZodDefault<z.ZodString>;
@@ -516,7 +598,12 @@ declare const gradeSchema: z.ZodObject<{
516
598
  lessonId: z.ZodString;
517
599
  userId: z.ZodString;
518
600
  submissionId: z.ZodString;
519
- points: z.ZodNumber;
601
+ points: z.ZodOptional<z.ZodNumber>;
602
+ rubricScores: z.ZodOptional<z.ZodArray<z.ZodObject<{
603
+ criterionId: z.ZodString;
604
+ points: z.ZodNumber;
605
+ feedback: z.ZodDefault<z.ZodString>;
606
+ }, z.core.$strip>>>;
520
607
  feedback: z.ZodDefault<z.ZodString>;
521
608
  }, z.core.$strip>;
522
609
  declare const discussionSchema: z.ZodObject<{
@@ -578,7 +665,53 @@ declare const noteSchema: z.ZodObject<{
578
665
  courseId: z.ZodString;
579
666
  lessonId: z.ZodString;
580
667
  note: z.ZodString;
668
+ expectedRevision: z.ZodDefault<z.ZodNumber>;
669
+ }, z.core.$strip>;
670
+ declare const studyNoteSchema: z.ZodObject<{
671
+ courseId: z.ZodString;
672
+ lessonId: z.ZodString;
673
+ id: z.ZodString;
674
+ body: z.ZodString;
675
+ positionSeconds: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
676
+ starred: z.ZodDefault<z.ZodBoolean>;
677
+ archived: z.ZodDefault<z.ZodBoolean>;
678
+ expectedRevision: z.ZodNumber;
679
+ }, z.core.$strip>;
680
+ declare const preferencesSchema: z.ZodObject<{
681
+ emailNotifications: z.ZodDefault<z.ZodBoolean>;
682
+ weeklyGoalLessons: z.ZodDefault<z.ZodNumber>;
683
+ }, z.core.$strip>;
684
+ declare const playbackSchema: z.ZodObject<{
685
+ courseId: z.ZodString;
686
+ lessonId: z.ZodString;
687
+ positionSeconds: z.ZodNumber;
688
+ playbackRate: z.ZodNumber;
689
+ expectedRevision: z.ZodNumber;
690
+ }, z.core.$strip>;
691
+ declare const pathDataSchema: z.ZodObject<{
692
+ title: z.ZodString;
693
+ description: z.ZodDefault<z.ZodString>;
694
+ courseIds: z.ZodArray<z.ZodString>;
695
+ status: z.ZodDefault<z.ZodEnum<{
696
+ draft: "draft";
697
+ published: "published";
698
+ archived: "archived";
699
+ }>>;
700
+ }, z.core.$strip>;
701
+ declare const pathSaveSchema: z.ZodObject<{
702
+ id: z.ZodOptional<z.ZodString>;
703
+ expectedRevision: z.ZodDefault<z.ZodNullable<z.ZodString>>;
704
+ data: z.ZodObject<{
705
+ title: z.ZodString;
706
+ description: z.ZodDefault<z.ZodString>;
707
+ courseIds: z.ZodArray<z.ZodString>;
708
+ status: z.ZodDefault<z.ZodEnum<{
709
+ draft: "draft";
710
+ published: "published";
711
+ archived: "archived";
712
+ }>>;
713
+ }, z.core.$strip>;
581
714
  }, z.core.$strip>;
582
715
  //#endregion
583
- export { answersSchema, assignmentSchema, assignmentSubmitSchema, catalogSchema, certificateActionSchema, certificateRevokeSchema, cohortDataSchema, cohortSaveSchema, courseDataSchema, courseIdSchema, courseSaveSchema, discussionSchema, enrollmentAdminSchema, enrollmentRequestSchema, gradeSchema, idSchema, keySchema, lessonIdSchema, lessonSchema, moderateSchema, moduleSchema, noteSchema, pageSchema, questionSchema, quizSchema, quizSubmitSchema, resourceSchema, reviewSchema, safeUrlSchema, settingsSchema };
716
+ export { answersSchema, assignmentDraftSchema, assignmentSchema, assignmentSubmitSchema, catalogSchema, certificateActionSchema, certificateRevokeSchema, cohortDataSchema, cohortSaveSchema, courseDataSchema, courseIdSchema, courseSaveSchema, discussionSchema, enrollmentAdminSchema, enrollmentRequestSchema, gradeSchema, idSchema, keySchema, lessonIdSchema, lessonSchema, moderateSchema, moduleSchema, noteSchema, pageSchema, pathDataSchema, pathSaveSchema, playbackSchema, preferencesSchema, questionSchema, quizDraftSchema, quizSchema, quizSubmitSchema, resourceSchema, reviewSchema, rubricCriterionSchema, rubricScoreSchema, safeUrlSchema, settingsSchema, studyNoteSchema };
584
717
  //# sourceMappingURL=schemas.d.ts.map
package/dist/schemas.js CHANGED
@@ -84,13 +84,35 @@ const quizSchema = z.object({
84
84
  "never"
85
85
  ]).default("after_pass")
86
86
  }).refine((quiz) => new Set(quiz.questions.map((question) => question.id)).size === quiz.questions.length, "Question IDs must be unique.");
87
+ const rubricCriterionSchema = z.object({
88
+ id: idSchema,
89
+ title,
90
+ description: z.string().max(2e3).default(""),
91
+ maxPoints: z.number().int().min(1).max(1e3)
92
+ });
93
+ const rubricScoreSchema = z.object({
94
+ criterionId: idSchema,
95
+ points: z.number().int().min(0).max(1e3),
96
+ feedback: z.string().max(2e3).default("")
97
+ });
87
98
  const assignmentSchema = z.object({
88
99
  instructions: z.string().trim().min(1).max(2e4),
89
100
  maxPoints: z.number().int().min(1).max(1e3).default(100),
90
101
  passingPoints: z.number().int().min(1).max(1e3).default(60),
91
102
  dueAt: timestamp.nullable().default(null),
92
- allowResubmission: z.boolean().default(true)
93
- }).refine((assignment) => assignment.passingPoints <= assignment.maxPoints, "Passing points cannot exceed maximum points.");
103
+ allowResubmission: z.boolean().default(true),
104
+ rubric: z.array(rubricCriterionSchema).max(20).optional()
105
+ }).refine((assignment) => assignment.passingPoints <= assignment.maxPoints, "Passing points cannot exceed maximum points.").superRefine((assignment, ctx) => {
106
+ const rubric = assignment.rubric ?? [];
107
+ if (new Set(rubric.map((item) => item.id)).size !== rubric.length) ctx.addIssue({
108
+ code: "custom",
109
+ message: "Rubric criterion IDs must be unique."
110
+ });
111
+ if (rubric.length && rubric.reduce((sum, item) => sum + item.maxPoints, 0) !== assignment.maxPoints) ctx.addIssue({
112
+ code: "custom",
113
+ message: "Rubric points must add up to the assignment maximum."
114
+ });
115
+ });
94
116
  const lessonSchema = z.object({
95
117
  id: idSchema,
96
118
  title,
@@ -111,6 +133,12 @@ const lessonSchema = z.object({
111
133
  field: idSchema.default("content")
112
134
  }).nullable().default(null),
113
135
  mediaUrl: safeUrlSchema.nullable().default(null),
136
+ transcript: text.default(""),
137
+ captions: z.array(z.object({
138
+ src: safeUrlSchema,
139
+ language: z.string().regex(/^[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,8})*$/).max(35),
140
+ label: title
141
+ })).max(20).default([]),
114
142
  liveStartsAt: timestamp.nullable().default(null),
115
143
  durationMinutes: z.number().int().min(0).max(1440).default(10),
116
144
  minStudySeconds: z.number().int().min(0).max(86400).default(0),
@@ -243,11 +271,20 @@ const lessonIdSchema = courseIdSchema.extend({ lessonId: idSchema });
243
271
  const answersSchema = z.record(idSchema, z.union([z.string().max(2e3), z.array(z.string().max(500)).max(10)]));
244
272
  const quizSubmitSchema = lessonIdSchema.extend({
245
273
  attemptId: idSchema,
246
- answers: answersSchema
274
+ answers: answersSchema,
275
+ expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
247
276
  });
277
+ const quizDraftSchema = quizSubmitSchema.extend({ expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).default(0) });
248
278
  const assignmentSubmitSchema = lessonIdSchema.extend({
249
279
  body: z.string().trim().min(1).max(2e4),
250
- attachmentUrl: safeUrlSchema.nullable().default(null)
280
+ attachmentUrl: safeUrlSchema.nullable().default(null),
281
+ submissionId: idSchema.optional(),
282
+ expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER - 1).optional()
283
+ });
284
+ const assignmentDraftSchema = lessonIdSchema.extend({
285
+ body: z.string().max(2e4).default(""),
286
+ attachmentUrl: safeUrlSchema.nullable().default(null),
287
+ expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER - 1)
251
288
  });
252
289
  const enrollmentRequestSchema = courseIdSchema.extend({ cohortId: idSchema.optional() });
253
290
  const enrollmentAdminSchema = courseIdSchema.extend({
@@ -266,7 +303,8 @@ const enrollmentAdminSchema = courseIdSchema.extend({
266
303
  const gradeSchema = lessonIdSchema.extend({
267
304
  userId: idSchema,
268
305
  submissionId: idSchema,
269
- points: z.number().int().min(0).max(1e3),
306
+ points: z.number().int().min(0).max(1e3).optional(),
307
+ rubricScores: z.array(rubricScoreSchema).max(20).optional(),
270
308
  feedback: z.string().max(1e4).default("")
271
309
  });
272
310
  const discussionSchema = lessonIdSchema.extend({
@@ -308,8 +346,43 @@ const certificateRevokeSchema = courseIdSchema.extend({
308
346
  userId: idSchema,
309
347
  reason: z.string().trim().min(1).max(1e3)
310
348
  });
311
- const noteSchema = lessonIdSchema.extend({ note: z.string().max(1e4) });
349
+ const noteSchema = lessonIdSchema.extend({
350
+ note: z.string().max(1e4),
351
+ expectedRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER - 1).default(0)
352
+ });
353
+ const studyNoteSchema = lessonIdSchema.extend({
354
+ id: idSchema,
355
+ body: z.string().max(5e3),
356
+ positionSeconds: z.number().min(0).max(86400).nullable().default(null),
357
+ starred: z.boolean().default(false),
358
+ archived: z.boolean().default(false),
359
+ expectedRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER - 1)
360
+ }).refine((note) => note.body.trim().length > 0 || note.positionSeconds !== null, "Write a note or choose a media timestamp.");
361
+ const preferencesSchema = z.object({
362
+ emailNotifications: z.boolean().default(true),
363
+ weeklyGoalLessons: z.number().int().min(0).max(100).default(3)
364
+ });
365
+ const playbackSchema = lessonIdSchema.extend({
366
+ positionSeconds: z.number().finite().min(0).max(86400),
367
+ playbackRate: z.number().min(.25).max(3),
368
+ expectedRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER)
369
+ });
370
+ const pathDataSchema = z.object({
371
+ title,
372
+ description: z.string().max(5e3).default(""),
373
+ courseIds: z.array(idSchema).min(1).max(30).refine((ids) => new Set(ids).size === ids.length, "Courses must be unique."),
374
+ status: z.enum([
375
+ "draft",
376
+ "published",
377
+ "archived"
378
+ ]).default("draft")
379
+ });
380
+ const pathSaveSchema = z.object({
381
+ id: idSchema.optional(),
382
+ expectedRevision: z.string().max(128).nullable().default(null),
383
+ data: pathDataSchema
384
+ });
312
385
 
313
386
  //#endregion
314
- export { answersSchema, assignmentSchema, assignmentSubmitSchema, catalogSchema, certificateActionSchema, certificateRevokeSchema, cohortDataSchema, cohortSaveSchema, courseDataSchema, courseIdSchema, courseSaveSchema, discussionSchema, enrollmentAdminSchema, enrollmentRequestSchema, gradeSchema, idSchema, keySchema, lessonIdSchema, lessonSchema, moderateSchema, moduleSchema, noteSchema, pageSchema, questionSchema, quizSchema, quizSubmitSchema, resourceSchema, reviewSchema, safeUrlSchema, settingsSchema };
387
+ export { answersSchema, assignmentDraftSchema, assignmentSchema, assignmentSubmitSchema, catalogSchema, certificateActionSchema, certificateRevokeSchema, cohortDataSchema, cohortSaveSchema, courseDataSchema, courseIdSchema, courseSaveSchema, discussionSchema, enrollmentAdminSchema, enrollmentRequestSchema, gradeSchema, idSchema, keySchema, lessonIdSchema, lessonSchema, moderateSchema, moduleSchema, noteSchema, pageSchema, pathDataSchema, pathSaveSchema, playbackSchema, preferencesSchema, questionSchema, quizDraftSchema, quizSchema, quizSubmitSchema, resourceSchema, reviewSchema, rubricCriterionSchema, rubricScoreSchema, safeUrlSchema, settingsSchema, studyNoteSchema };
315
388
  //# sourceMappingURL=schemas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const idSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-zA-Z0-9_-]+$/, \"Use letters, numbers, underscores or hyphens.\")\n .refine(\n (value) => ![\"__proto__\", \"constructor\", \"prototype\"].includes(value),\n \"This identifier is reserved. Choose another ID.\",\n );\nexport const keySchema = z\n .string()\n .min(1)\n .max(1024)\n .regex(/^[a-zA-Z0-9_:.-]+$/);\nconst title = z.string().trim().min(1).max(200);\nconst text = z.string().max(50_000);\nconst timestamp = z.iso.datetime({ offset: true });\nexport const safeUrlSchema = z\n .string()\n .max(2048)\n .refine((value) => {\n if (/^\\/(?!\\/)[^\\s\\\\]*$/.test(value)) return true;\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" && !url.username && !url.password;\n } catch {\n return false;\n }\n }, \"Use an HTTPS URL or a path on this site.\");\n\nexport const resourceSchema = z.object({\n id: idSchema,\n title,\n url: safeUrlSchema,\n description: z.string().max(1000).default(\"\"),\n});\nconst optionSchema = z.object({ id: idSchema, text: z.string().trim().min(1).max(2000) });\nexport const questionSchema = z\n .object({\n id: idSchema,\n type: z.enum([\"single\", \"multiple\", \"true_false\", \"short\"]),\n prompt: z.string().trim().min(1).max(5000),\n options: z.array(optionSchema).max(10).default([]),\n correctAnswers: z.array(z.string().trim().min(1).max(500)).min(1).max(10),\n points: z.number().int().min(1).max(100).default(1),\n explanation: z.string().max(5000).default(\"\"),\n })\n .superRefine((question, ctx) => {\n const optionIds = question.options.map((option) => option.id);\n if (new Set(optionIds).size !== optionIds.length)\n ctx.addIssue({ code: \"custom\", message: \"Option IDs must be unique.\" });\n if (new Set(question.correctAnswers).size !== question.correctAnswers.length)\n ctx.addIssue({ code: \"custom\", message: \"Correct answers must be unique.\" });\n if (question.type !== \"short\") {\n if (question.options.length < 2)\n ctx.addIssue({ code: \"custom\", message: \"Choice questions need at least two options.\" });\n if (question.correctAnswers.some((answer) => !optionIds.includes(answer)))\n ctx.addIssue({ code: \"custom\", message: \"Correct answers must refer to option IDs.\" });\n if (question.type !== \"multiple\" && question.correctAnswers.length !== 1)\n ctx.addIssue({ code: \"custom\", message: \"This question requires one correct answer.\" });\n if (\n question.type === \"true_false\" &&\n (question.options.length !== 2 ||\n !optionIds.includes(\"true\") ||\n !optionIds.includes(\"false\"))\n )\n ctx.addIssue({\n code: \"custom\",\n message: \"True/false options must have the IDs true and false.\",\n });\n }\n });\nexport const quizSchema = z\n .object({\n questions: z.array(questionSchema).min(1).max(50),\n passingPercent: z.number().int().min(1).max(100).default(70),\n maxAttempts: z.number().int().min(1).max(20).default(3),\n timeLimitMinutes: z.number().int().min(0).max(180).default(30),\n randomizeQuestions: z.boolean().default(true),\n randomizeOptions: z.boolean().default(false),\n showFeedback: z.enum([\"after_pass\", \"after_submit\", \"never\"]).default(\"after_pass\"),\n })\n .refine(\n (quiz) => new Set(quiz.questions.map((question) => question.id)).size === quiz.questions.length,\n \"Question IDs must be unique.\",\n );\n\nexport const assignmentSchema = z\n .object({\n instructions: z.string().trim().min(1).max(20_000),\n maxPoints: z.number().int().min(1).max(1000).default(100),\n passingPoints: z.number().int().min(1).max(1000).default(60),\n dueAt: timestamp.nullable().default(null),\n allowResubmission: z.boolean().default(true),\n })\n .refine(\n (assignment) => assignment.passingPoints <= assignment.maxPoints,\n \"Passing points cannot exceed maximum points.\",\n );\n\nexport const lessonSchema = z\n .object({\n id: idSchema,\n title,\n summary: z.string().max(2000).default(\"\"),\n kind: z.enum([\"text\", \"video\", \"audio\", \"quiz\", \"assignment\", \"live\"]).default(\"text\"),\n body: text.default(\"\"),\n portableText: z.array(z.record(z.string(), z.unknown())).max(1000).default([]),\n contentSource: z\n .object({ collection: idSchema, id: idSchema, field: idSchema.default(\"content\") })\n .nullable()\n .default(null),\n mediaUrl: safeUrlSchema.nullable().default(null),\n liveStartsAt: timestamp.nullable().default(null),\n durationMinutes: z.number().int().min(0).max(1440).default(10),\n minStudySeconds: z.number().int().min(0).max(86400).default(0),\n preview: z.boolean().default(false),\n required: z.boolean().default(true),\n resources: z.array(resourceSchema).max(30).default([]),\n quiz: quizSchema.nullable().default(null),\n assignment: assignmentSchema.nullable().default(null),\n })\n .superRefine((lesson, ctx) => {\n if (lesson.kind === \"quiz\" && !lesson.quiz)\n ctx.addIssue({ code: \"custom\", message: \"Quiz lessons need a quiz.\" });\n if (lesson.kind === \"assignment\" && !lesson.assignment)\n ctx.addIssue({ code: \"custom\", message: \"Assignment lessons need an assignment.\" });\n if ([\"video\", \"audio\", \"live\"].includes(lesson.kind) && !lesson.mediaUrl)\n ctx.addIssue({ code: \"custom\", message: \"Media and live lessons need a URL.\" });\n if (lesson.kind === \"live\" && !lesson.liveStartsAt)\n ctx.addIssue({ code: \"custom\", message: \"Live lessons need a start time.\" });\n if (new Set(lesson.resources.map((resource) => resource.id)).size !== lesson.resources.length)\n ctx.addIssue({ code: \"custom\", message: \"Resource IDs must be unique.\" });\n });\n\nexport const moduleSchema = z.object({\n id: idSchema,\n title,\n description: z.string().max(2000).default(\"\"),\n releaseDays: z.number().int().min(0).max(3650).default(0),\n unlockAt: timestamp.nullable().default(null),\n lessons: z.array(lessonSchema).max(100).default([]),\n});\n\nexport const courseDataSchema = z\n .object({\n slug: z\n .string()\n .trim()\n .min(1)\n .max(100)\n .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, \"Use lowercase words separated by hyphens.\"),\n title,\n summary: z.string().trim().max(1000).default(\"\"),\n description: text.default(\"\"),\n outcomes: z.array(z.string().trim().min(1).max(500)).max(30).default([]),\n requirements: z.array(z.string().trim().min(1).max(500)).max(30).default([]),\n category: z.string().trim().max(100).default(\"\"),\n tags: z.array(z.string().trim().min(1).max(60)).max(20).default([]),\n language: z.string().trim().min(2).max(35).default(\"en\"),\n level: z.enum([\"beginner\", \"intermediate\", \"advanced\", \"all\"]).default(\"all\"),\n featuredImage: z\n .object({\n id: z.string().max(128).default(\"\"),\n src: safeUrlSchema,\n alt: z.string().max(500).default(\"\"),\n })\n .nullable()\n .default(null),\n instructorName: z.string().trim().max(200).default(\"\"),\n instructorIds: z.array(idSchema).max(20).default([]),\n status: z.enum([\"draft\", \"published\", \"archived\"]).default(\"draft\"),\n enrollmentMode: z.enum([\"open\", \"approval\", \"invite\"]).default(\"open\"),\n commerce: z\n .object({\n accessModel: z.enum([\"free\", \"paid\"]).default(\"free\"),\n offerId: idSchema.nullable().default(null),\n priceMinor: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().default(null),\n currency: z\n .string()\n .regex(/^[A-Z]{3}$/)\n .default(\"INR\"),\n })\n .default({ accessModel: \"free\", offerId: null, priceMinor: null, currency: \"INR\" }),\n prerequisiteCourseIds: z.array(idSchema).max(20).default([]),\n sequential: z.boolean().default(true),\n enrollmentClosesAt: timestamp.nullable().default(null),\n accessDays: z.number().int().min(0).max(3650).default(0),\n certificateEnabled: z.boolean().default(true),\n modules: z.array(moduleSchema).max(50).default([]),\n })\n .superRefine((course, ctx) => {\n const allIds = course.modules.flatMap((module) => [\n module.id,\n ...module.lessons.map((lesson) => lesson.id),\n ]);\n if (new Set(allIds).size !== allIds.length)\n ctx.addIssue({\n code: \"custom\",\n message: \"Module and lesson IDs must be unique across the course.\",\n });\n if (course.modules.flatMap((module) => module.lessons).length > 150)\n ctx.addIssue({ code: \"custom\", message: \"A course supports up to 150 lessons.\" });\n if (\n course.status === \"published\" &&\n !course.modules.some((module) => module.lessons.some((lesson) => lesson.required))\n )\n ctx.addIssue({\n code: \"custom\",\n message: \"Publish a course with at least one required lesson.\",\n });\n });\n\nexport const courseSaveSchema = z.object({\n id: idSchema.optional(),\n expectedRevision: z.string().max(128).nullable().default(null),\n data: courseDataSchema,\n});\nexport const pageSchema = z.object({\n cursor: z.string().max(4000).optional(),\n limit: z.coerce.number().int().min(1).max(100).default(24),\n});\nexport const catalogSchema = pageSchema.extend({\n q: z.string().max(100).default(\"\"),\n category: z.string().max(100).default(\"\"),\n level: z.enum([\"beginner\", \"intermediate\", \"advanced\", \"all\"]).optional(),\n language: z.string().max(35).optional(),\n});\nexport const courseIdSchema = z.object({ courseId: idSchema });\nexport const lessonIdSchema = courseIdSchema.extend({ lessonId: idSchema });\nexport const answersSchema = z.record(\n idSchema,\n z.union([z.string().max(2000), z.array(z.string().max(500)).max(10)]),\n);\nexport const quizSubmitSchema = lessonIdSchema.extend({\n attemptId: idSchema,\n answers: answersSchema,\n});\nexport const assignmentSubmitSchema = lessonIdSchema.extend({\n body: z.string().trim().min(1).max(20_000),\n attachmentUrl: safeUrlSchema.nullable().default(null),\n});\nexport const enrollmentRequestSchema = courseIdSchema.extend({ cohortId: idSchema.optional() });\nexport const enrollmentAdminSchema = courseIdSchema.extend({\n userId: idSchema,\n status: z.enum([\"active\", \"rejected\", \"suspended\", \"cancelled\"]),\n reason: z.string().max(1000).default(\"\"),\n cohortId: idSchema.nullable().optional(),\n accessStartsAt: timestamp.nullable().optional(),\n accessExpiresAt: timestamp.nullable().optional(),\n});\nexport const gradeSchema = lessonIdSchema.extend({\n userId: idSchema,\n submissionId: idSchema,\n points: z.number().int().min(0).max(1000),\n feedback: z.string().max(10_000).default(\"\"),\n});\nexport const discussionSchema = lessonIdSchema.extend({\n body: z.string().trim().min(1).max(5000),\n parentId: idSchema.nullable().default(null),\n});\nexport const reviewSchema = courseIdSchema.extend({\n rating: z.number().int().min(1).max(5),\n body: z.string().trim().min(1).max(3000),\n});\nexport const moderateSchema = z.object({\n id: keySchema,\n status: z.enum([\"published\", \"hidden\"]),\n expectedRevision: z.string().min(1).max(128),\n});\nexport const cohortDataSchema = z\n .object({\n title,\n courseIds: z.array(idSchema).min(1).max(20),\n memberIds: z.array(idSchema).max(1000).default([]),\n startsAt: timestamp.nullable().default(null),\n endsAt: timestamp.nullable().default(null),\n })\n .refine(\n (cohort) =>\n !cohort.startsAt || !cohort.endsAt || Date.parse(cohort.endsAt) > Date.parse(cohort.startsAt),\n \"Cohort end must follow its start.\",\n )\n .refine(\n (cohort) => new Set(cohort.memberIds).size === cohort.memberIds.length,\n \"Cohort members must be unique.\",\n )\n .refine(\n (cohort) => new Set(cohort.courseIds).size === cohort.courseIds.length,\n \"Cohort courses must be unique.\",\n );\nexport const cohortSaveSchema = z.object({\n id: idSchema.optional(),\n expectedRevision: z.string().max(128).nullable().default(null),\n data: cohortDataSchema,\n});\nexport const settingsSchema = z.object({\n academyTitle: title.default(\"Ananta Gnanam Academy\"),\n academyDescription: z.string().max(2000).default(\"Build knowledge, one lesson at a time.\"),\n issuerName: title.default(\"Ananta Gnanam\"),\n moderateDiscussions: z.boolean().default(true),\n moderateReviews: z.boolean().default(true),\n emailNotifications: z.boolean().default(false),\n reminderDays: z.number().int().min(0).max(90).default(7),\n});\nexport const certificateActionSchema = courseIdSchema.extend({ shared: z.boolean() });\nexport const certificateRevokeSchema = courseIdSchema.extend({\n userId: idSchema,\n reason: z.string().trim().min(1).max(1000),\n});\nexport const noteSchema = lessonIdSchema.extend({ note: z.string().max(10_000) });\n"],"mappings":"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"}
1
+ {"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const idSchema = z\n .string()\n .min(1)\n .max(128)\n .regex(/^[a-zA-Z0-9_-]+$/, \"Use letters, numbers, underscores or hyphens.\")\n .refine(\n (value) => ![\"__proto__\", \"constructor\", \"prototype\"].includes(value),\n \"This identifier is reserved. Choose another ID.\",\n );\nexport const keySchema = z\n .string()\n .min(1)\n .max(1024)\n .regex(/^[a-zA-Z0-9_:.-]+$/);\nconst title = z.string().trim().min(1).max(200);\nconst text = z.string().max(50_000);\nconst timestamp = z.iso.datetime({ offset: true });\nexport const safeUrlSchema = z\n .string()\n .max(2048)\n .refine((value) => {\n if (/^\\/(?!\\/)[^\\s\\\\]*$/.test(value)) return true;\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" && !url.username && !url.password;\n } catch {\n return false;\n }\n }, \"Use an HTTPS URL or a path on this site.\");\n\nexport const resourceSchema = z.object({\n id: idSchema,\n title,\n url: safeUrlSchema,\n description: z.string().max(1000).default(\"\"),\n});\nconst optionSchema = z.object({ id: idSchema, text: z.string().trim().min(1).max(2000) });\nexport const questionSchema = z\n .object({\n id: idSchema,\n type: z.enum([\"single\", \"multiple\", \"true_false\", \"short\"]),\n prompt: z.string().trim().min(1).max(5000),\n options: z.array(optionSchema).max(10).default([]),\n correctAnswers: z.array(z.string().trim().min(1).max(500)).min(1).max(10),\n points: z.number().int().min(1).max(100).default(1),\n explanation: z.string().max(5000).default(\"\"),\n })\n .superRefine((question, ctx) => {\n const optionIds = question.options.map((option) => option.id);\n if (new Set(optionIds).size !== optionIds.length)\n ctx.addIssue({ code: \"custom\", message: \"Option IDs must be unique.\" });\n if (new Set(question.correctAnswers).size !== question.correctAnswers.length)\n ctx.addIssue({ code: \"custom\", message: \"Correct answers must be unique.\" });\n if (question.type !== \"short\") {\n if (question.options.length < 2)\n ctx.addIssue({ code: \"custom\", message: \"Choice questions need at least two options.\" });\n if (question.correctAnswers.some((answer) => !optionIds.includes(answer)))\n ctx.addIssue({ code: \"custom\", message: \"Correct answers must refer to option IDs.\" });\n if (question.type !== \"multiple\" && question.correctAnswers.length !== 1)\n ctx.addIssue({ code: \"custom\", message: \"This question requires one correct answer.\" });\n if (\n question.type === \"true_false\" &&\n (question.options.length !== 2 ||\n !optionIds.includes(\"true\") ||\n !optionIds.includes(\"false\"))\n )\n ctx.addIssue({\n code: \"custom\",\n message: \"True/false options must have the IDs true and false.\",\n });\n }\n });\nexport const quizSchema = z\n .object({\n questions: z.array(questionSchema).min(1).max(50),\n passingPercent: z.number().int().min(1).max(100).default(70),\n maxAttempts: z.number().int().min(1).max(20).default(3),\n timeLimitMinutes: z.number().int().min(0).max(180).default(30),\n randomizeQuestions: z.boolean().default(true),\n randomizeOptions: z.boolean().default(false),\n showFeedback: z.enum([\"after_pass\", \"after_submit\", \"never\"]).default(\"after_pass\"),\n })\n .refine(\n (quiz) => new Set(quiz.questions.map((question) => question.id)).size === quiz.questions.length,\n \"Question IDs must be unique.\",\n );\n\nexport const rubricCriterionSchema = z.object({\n id: idSchema,\n title,\n description: z.string().max(2000).default(\"\"),\n maxPoints: z.number().int().min(1).max(1000),\n});\nexport const rubricScoreSchema = z.object({\n criterionId: idSchema,\n points: z.number().int().min(0).max(1000),\n feedback: z.string().max(2000).default(\"\"),\n});\nexport const assignmentSchema = z\n .object({\n instructions: z.string().trim().min(1).max(20_000),\n maxPoints: z.number().int().min(1).max(1000).default(100),\n passingPoints: z.number().int().min(1).max(1000).default(60),\n dueAt: timestamp.nullable().default(null),\n allowResubmission: z.boolean().default(true),\n rubric: z.array(rubricCriterionSchema).max(20).optional(),\n })\n .refine(\n (assignment) => assignment.passingPoints <= assignment.maxPoints,\n \"Passing points cannot exceed maximum points.\",\n )\n .superRefine((assignment, ctx) => {\n const rubric = assignment.rubric ?? [];\n if (new Set(rubric.map((item) => item.id)).size !== rubric.length)\n ctx.addIssue({ code: \"custom\", message: \"Rubric criterion IDs must be unique.\" });\n if (\n rubric.length &&\n rubric.reduce((sum, item) => sum + item.maxPoints, 0) !== assignment.maxPoints\n )\n ctx.addIssue({\n code: \"custom\",\n message: \"Rubric points must add up to the assignment maximum.\",\n });\n });\n\nexport const lessonSchema = z\n .object({\n id: idSchema,\n title,\n summary: z.string().max(2000).default(\"\"),\n kind: z.enum([\"text\", \"video\", \"audio\", \"quiz\", \"assignment\", \"live\"]).default(\"text\"),\n body: text.default(\"\"),\n portableText: z.array(z.record(z.string(), z.unknown())).max(1000).default([]),\n contentSource: z\n .object({ collection: idSchema, id: idSchema, field: idSchema.default(\"content\") })\n .nullable()\n .default(null),\n mediaUrl: safeUrlSchema.nullable().default(null),\n transcript: text.default(\"\"),\n captions: z\n .array(\n z.object({\n src: safeUrlSchema,\n language: z\n .string()\n .regex(/^[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,8})*$/)\n .max(35),\n label: title,\n }),\n )\n .max(20)\n .default([]),\n liveStartsAt: timestamp.nullable().default(null),\n durationMinutes: z.number().int().min(0).max(1440).default(10),\n minStudySeconds: z.number().int().min(0).max(86400).default(0),\n preview: z.boolean().default(false),\n required: z.boolean().default(true),\n resources: z.array(resourceSchema).max(30).default([]),\n quiz: quizSchema.nullable().default(null),\n assignment: assignmentSchema.nullable().default(null),\n })\n .superRefine((lesson, ctx) => {\n if (lesson.kind === \"quiz\" && !lesson.quiz)\n ctx.addIssue({ code: \"custom\", message: \"Quiz lessons need a quiz.\" });\n if (lesson.kind === \"assignment\" && !lesson.assignment)\n ctx.addIssue({ code: \"custom\", message: \"Assignment lessons need an assignment.\" });\n if ([\"video\", \"audio\", \"live\"].includes(lesson.kind) && !lesson.mediaUrl)\n ctx.addIssue({ code: \"custom\", message: \"Media and live lessons need a URL.\" });\n if (lesson.kind === \"live\" && !lesson.liveStartsAt)\n ctx.addIssue({ code: \"custom\", message: \"Live lessons need a start time.\" });\n if (new Set(lesson.resources.map((resource) => resource.id)).size !== lesson.resources.length)\n ctx.addIssue({ code: \"custom\", message: \"Resource IDs must be unique.\" });\n });\n\nexport const moduleSchema = z.object({\n id: idSchema,\n title,\n description: z.string().max(2000).default(\"\"),\n releaseDays: z.number().int().min(0).max(3650).default(0),\n unlockAt: timestamp.nullable().default(null),\n lessons: z.array(lessonSchema).max(100).default([]),\n});\n\nexport const courseDataSchema = z\n .object({\n slug: z\n .string()\n .trim()\n .min(1)\n .max(100)\n .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, \"Use lowercase words separated by hyphens.\"),\n title,\n summary: z.string().trim().max(1000).default(\"\"),\n description: text.default(\"\"),\n outcomes: z.array(z.string().trim().min(1).max(500)).max(30).default([]),\n requirements: z.array(z.string().trim().min(1).max(500)).max(30).default([]),\n category: z.string().trim().max(100).default(\"\"),\n tags: z.array(z.string().trim().min(1).max(60)).max(20).default([]),\n language: z.string().trim().min(2).max(35).default(\"en\"),\n level: z.enum([\"beginner\", \"intermediate\", \"advanced\", \"all\"]).default(\"all\"),\n featuredImage: z\n .object({\n id: z.string().max(128).default(\"\"),\n src: safeUrlSchema,\n alt: z.string().max(500).default(\"\"),\n })\n .nullable()\n .default(null),\n instructorName: z.string().trim().max(200).default(\"\"),\n instructorIds: z.array(idSchema).max(20).default([]),\n status: z.enum([\"draft\", \"published\", \"archived\"]).default(\"draft\"),\n enrollmentMode: z.enum([\"open\", \"approval\", \"invite\"]).default(\"open\"),\n commerce: z\n .object({\n accessModel: z.enum([\"free\", \"paid\"]).default(\"free\"),\n offerId: idSchema.nullable().default(null),\n priceMinor: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().default(null),\n currency: z\n .string()\n .regex(/^[A-Z]{3}$/)\n .default(\"INR\"),\n })\n .default({ accessModel: \"free\", offerId: null, priceMinor: null, currency: \"INR\" }),\n prerequisiteCourseIds: z.array(idSchema).max(20).default([]),\n sequential: z.boolean().default(true),\n enrollmentClosesAt: timestamp.nullable().default(null),\n accessDays: z.number().int().min(0).max(3650).default(0),\n certificateEnabled: z.boolean().default(true),\n modules: z.array(moduleSchema).max(50).default([]),\n })\n .superRefine((course, ctx) => {\n const allIds = course.modules.flatMap((module) => [\n module.id,\n ...module.lessons.map((lesson) => lesson.id),\n ]);\n if (new Set(allIds).size !== allIds.length)\n ctx.addIssue({\n code: \"custom\",\n message: \"Module and lesson IDs must be unique across the course.\",\n });\n if (course.modules.flatMap((module) => module.lessons).length > 150)\n ctx.addIssue({ code: \"custom\", message: \"A course supports up to 150 lessons.\" });\n if (\n course.status === \"published\" &&\n !course.modules.some((module) => module.lessons.some((lesson) => lesson.required))\n )\n ctx.addIssue({\n code: \"custom\",\n message: \"Publish a course with at least one required lesson.\",\n });\n });\n\nexport const courseSaveSchema = z.object({\n id: idSchema.optional(),\n expectedRevision: z.string().max(128).nullable().default(null),\n data: courseDataSchema,\n});\nexport const pageSchema = z.object({\n cursor: z.string().max(4000).optional(),\n limit: z.coerce.number().int().min(1).max(100).default(24),\n});\nexport const catalogSchema = pageSchema.extend({\n q: z.string().max(100).default(\"\"),\n category: z.string().max(100).default(\"\"),\n level: z.enum([\"beginner\", \"intermediate\", \"advanced\", \"all\"]).optional(),\n language: z.string().max(35).optional(),\n});\nexport const courseIdSchema = z.object({ courseId: idSchema });\nexport const lessonIdSchema = courseIdSchema.extend({ lessonId: idSchema });\nexport const answersSchema = z.record(\n idSchema,\n z.union([z.string().max(2000), z.array(z.string().max(500)).max(10)]),\n);\nexport const quizSubmitSchema = lessonIdSchema.extend({\n attemptId: idSchema,\n answers: answersSchema,\n expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),\n});\nexport const quizDraftSchema = quizSubmitSchema.extend({\n expectedDraftRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).default(0),\n});\nexport const assignmentSubmitSchema = lessonIdSchema.extend({\n body: z.string().trim().min(1).max(20_000),\n attachmentUrl: safeUrlSchema.nullable().default(null),\n submissionId: idSchema.optional(),\n expectedDraftRevision: z\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER - 1)\n .optional(),\n});\nexport const assignmentDraftSchema = lessonIdSchema.extend({\n body: z.string().max(20_000).default(\"\"),\n attachmentUrl: safeUrlSchema.nullable().default(null),\n expectedDraftRevision: z\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER - 1),\n});\nexport const enrollmentRequestSchema = courseIdSchema.extend({ cohortId: idSchema.optional() });\nexport const enrollmentAdminSchema = courseIdSchema.extend({\n userId: idSchema,\n status: z.enum([\"active\", \"rejected\", \"suspended\", \"cancelled\"]),\n reason: z.string().max(1000).default(\"\"),\n cohortId: idSchema.nullable().optional(),\n accessStartsAt: timestamp.nullable().optional(),\n accessExpiresAt: timestamp.nullable().optional(),\n});\nexport const gradeSchema = lessonIdSchema.extend({\n userId: idSchema,\n submissionId: idSchema,\n points: z.number().int().min(0).max(1000).optional(),\n rubricScores: z.array(rubricScoreSchema).max(20).optional(),\n feedback: z.string().max(10_000).default(\"\"),\n});\nexport const discussionSchema = lessonIdSchema.extend({\n body: z.string().trim().min(1).max(5000),\n parentId: idSchema.nullable().default(null),\n});\nexport const reviewSchema = courseIdSchema.extend({\n rating: z.number().int().min(1).max(5),\n body: z.string().trim().min(1).max(3000),\n});\nexport const moderateSchema = z.object({\n id: keySchema,\n status: z.enum([\"published\", \"hidden\"]),\n expectedRevision: z.string().min(1).max(128),\n});\nexport const cohortDataSchema = z\n .object({\n title,\n courseIds: z.array(idSchema).min(1).max(20),\n memberIds: z.array(idSchema).max(1000).default([]),\n startsAt: timestamp.nullable().default(null),\n endsAt: timestamp.nullable().default(null),\n })\n .refine(\n (cohort) =>\n !cohort.startsAt || !cohort.endsAt || Date.parse(cohort.endsAt) > Date.parse(cohort.startsAt),\n \"Cohort end must follow its start.\",\n )\n .refine(\n (cohort) => new Set(cohort.memberIds).size === cohort.memberIds.length,\n \"Cohort members must be unique.\",\n )\n .refine(\n (cohort) => new Set(cohort.courseIds).size === cohort.courseIds.length,\n \"Cohort courses must be unique.\",\n );\nexport const cohortSaveSchema = z.object({\n id: idSchema.optional(),\n expectedRevision: z.string().max(128).nullable().default(null),\n data: cohortDataSchema,\n});\nexport const settingsSchema = z.object({\n academyTitle: title.default(\"Ananta Gnanam Academy\"),\n academyDescription: z.string().max(2000).default(\"Build knowledge, one lesson at a time.\"),\n issuerName: title.default(\"Ananta Gnanam\"),\n moderateDiscussions: z.boolean().default(true),\n moderateReviews: z.boolean().default(true),\n emailNotifications: z.boolean().default(false),\n reminderDays: z.number().int().min(0).max(90).default(7),\n});\nexport const certificateActionSchema = courseIdSchema.extend({ shared: z.boolean() });\nexport const certificateRevokeSchema = courseIdSchema.extend({\n userId: idSchema,\n reason: z.string().trim().min(1).max(1000),\n});\nexport const noteSchema = lessonIdSchema.extend({\n note: z.string().max(10_000),\n expectedRevision: z\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER - 1)\n .default(0),\n});\nexport const studyNoteSchema = lessonIdSchema\n .extend({\n id: idSchema,\n body: z.string().max(5000),\n positionSeconds: z.number().min(0).max(86_400).nullable().default(null),\n starred: z.boolean().default(false),\n archived: z.boolean().default(false),\n expectedRevision: z\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER - 1),\n })\n .refine(\n (note) => note.body.trim().length > 0 || note.positionSeconds !== null,\n \"Write a note or choose a media timestamp.\",\n );\n\nexport const preferencesSchema = z.object({\n emailNotifications: z.boolean().default(true),\n weeklyGoalLessons: z.number().int().min(0).max(100).default(3),\n});\nexport const playbackSchema = lessonIdSchema.extend({\n positionSeconds: z.number().finite().min(0).max(86_400),\n playbackRate: z.number().min(0.25).max(3),\n expectedRevision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),\n});\nexport const pathDataSchema = z.object({\n title,\n description: z.string().max(5000).default(\"\"),\n courseIds: z\n .array(idSchema)\n .min(1)\n .max(30)\n .refine((ids) => new Set(ids).size === ids.length, \"Courses must be unique.\"),\n status: z.enum([\"draft\", \"published\", \"archived\"]).default(\"draft\"),\n});\nexport const pathSaveSchema = z.object({\n id: idSchema.optional(),\n expectedRevision: z.string().max(128).nullable().default(null),\n data: pathDataSchema,\n});\n"],"mappings":";;;AAEA,MAAa,WAAW,EACrB,QAAQ,CACR,IAAI,EAAE,CACN,IAAI,IAAI,CACR,MAAM,oBAAoB,gDAAgD,CAC1E,QACE,UAAU,CAAC;CAAC;CAAa;CAAe;CAAY,CAAC,SAAS,MAAM,EACrE,kDACD;AACH,MAAa,YAAY,EACtB,QAAQ,CACR,IAAI,EAAE,CACN,IAAI,KAAK,CACT,MAAM,qBAAqB;AAC9B,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;AAC/C,MAAM,OAAO,EAAE,QAAQ,CAAC,IAAI,IAAO;AACnC,MAAM,YAAY,EAAE,IAAI,SAAS,EAAE,QAAQ,MAAM,CAAC;AAClD,MAAa,gBAAgB,EAC1B,QAAQ,CACR,IAAI,KAAK,CACT,QAAQ,UAAU;AACjB,KAAI,qBAAqB,KAAK,MAAM,CAAE,QAAO;AAC7C,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,SAAO,IAAI,aAAa,YAAY,CAAC,IAAI,YAAY,CAAC,IAAI;SACpD;AACN,SAAO;;GAER,2CAA2C;AAEhD,MAAa,iBAAiB,EAAE,OAAO;CACrC,IAAI;CACJ;CACA,KAAK;CACL,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC9C,CAAC;AACF,MAAM,eAAe,EAAE,OAAO;CAAE,IAAI;CAAU,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CAAE,CAAC;AACzF,MAAa,iBAAiB,EAC3B,OAAO;CACN,IAAI;CACJ,MAAM,EAAE,KAAK;EAAC;EAAU;EAAY;EAAc;EAAQ,CAAC;CAC3D,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CAC1C,SAAS,EAAE,MAAM,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CAClD,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;CACzE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;CACnD,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC9C,CAAC,CACD,aAAa,UAAU,QAAQ;CAC9B,MAAM,YAAY,SAAS,QAAQ,KAAK,WAAW,OAAO,GAAG;AAC7D,KAAI,IAAI,IAAI,UAAU,CAAC,SAAS,UAAU,OACxC,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAA8B,CAAC;AACzE,KAAI,IAAI,IAAI,SAAS,eAAe,CAAC,SAAS,SAAS,eAAe,OACpE,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAmC,CAAC;AAC9E,KAAI,SAAS,SAAS,SAAS;AAC7B,MAAI,SAAS,QAAQ,SAAS,EAC5B,KAAI,SAAS;GAAE,MAAM;GAAU,SAAS;GAA+C,CAAC;AAC1F,MAAI,SAAS,eAAe,MAAM,WAAW,CAAC,UAAU,SAAS,OAAO,CAAC,CACvE,KAAI,SAAS;GAAE,MAAM;GAAU,SAAS;GAA6C,CAAC;AACxF,MAAI,SAAS,SAAS,cAAc,SAAS,eAAe,WAAW,EACrE,KAAI,SAAS;GAAE,MAAM;GAAU,SAAS;GAA8C,CAAC;AACzF,MACE,SAAS,SAAS,iBACjB,SAAS,QAAQ,WAAW,KAC3B,CAAC,UAAU,SAAS,OAAO,IAC3B,CAAC,UAAU,SAAS,QAAQ,EAE9B,KAAI,SAAS;GACX,MAAM;GACN,SAAS;GACV,CAAC;;EAEN;AACJ,MAAa,aAAa,EACvB,OAAO;CACN,WAAW,EAAE,MAAM,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;CACjD,gBAAgB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CAC5D,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE;CACvD,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CAC9D,oBAAoB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC7C,kBAAkB,EAAE,SAAS,CAAC,QAAQ,MAAM;CAC5C,cAAc,EAAE,KAAK;EAAC;EAAc;EAAgB;EAAQ,CAAC,CAAC,QAAQ,aAAa;CACpF,CAAC,CACD,QACE,SAAS,IAAI,IAAI,KAAK,UAAU,KAAK,aAAa,SAAS,GAAG,CAAC,CAAC,SAAS,KAAK,UAAU,QACzF,+BACD;AAEH,MAAa,wBAAwB,EAAE,OAAO;CAC5C,IAAI;CACJ;CACA,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC7C,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CAC7C,CAAC;AACF,MAAa,oBAAoB,EAAE,OAAO;CACxC,aAAa;CACb,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CACzC,UAAU,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC3C,CAAC;AACF,MAAa,mBAAmB,EAC7B,OAAO;CACN,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAO;CAClD,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK,CAAC,QAAQ,IAAI;CACzD,eAAe,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC5D,OAAO,UAAU,UAAU,CAAC,QAAQ,KAAK;CACzC,mBAAmB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC5C,QAAQ,EAAE,MAAM,sBAAsB,CAAC,IAAI,GAAG,CAAC,UAAU;CAC1D,CAAC,CACD,QACE,eAAe,WAAW,iBAAiB,WAAW,WACvD,+CACD,CACA,aAAa,YAAY,QAAQ;CAChC,MAAM,SAAS,WAAW,UAAU,EAAE;AACtC,KAAI,IAAI,IAAI,OAAO,KAAK,SAAS,KAAK,GAAG,CAAC,CAAC,SAAS,OAAO,OACzD,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAwC,CAAC;AACnF,KACE,OAAO,UACP,OAAO,QAAQ,KAAK,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,WAAW,UAErE,KAAI,SAAS;EACX,MAAM;EACN,SAAS;EACV,CAAC;EACJ;AAEJ,MAAa,eAAe,EACzB,OAAO;CACN,IAAI;CACJ;CACA,SAAS,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CACzC,MAAM,EAAE,KAAK;EAAC;EAAQ;EAAS;EAAS;EAAQ;EAAc;EAAO,CAAC,CAAC,QAAQ,OAAO;CACtF,MAAM,KAAK,QAAQ,GAAG;CACtB,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,IAAK,CAAC,QAAQ,EAAE,CAAC;CAC9E,eAAe,EACZ,OAAO;EAAE,YAAY;EAAU,IAAI;EAAU,OAAO,SAAS,QAAQ,UAAU;EAAE,CAAC,CAClF,UAAU,CACV,QAAQ,KAAK;CAChB,UAAU,cAAc,UAAU,CAAC,QAAQ,KAAK;CAChD,YAAY,KAAK,QAAQ,GAAG;CAC5B,UAAU,EACP,MACC,EAAE,OAAO;EACP,KAAK;EACL,UAAU,EACP,QAAQ,CACR,MAAM,wCAAwC,CAC9C,IAAI,GAAG;EACV,OAAO;EACR,CAAC,CACH,CACA,IAAI,GAAG,CACP,QAAQ,EAAE,CAAC;CACd,cAAc,UAAU,UAAU,CAAC,QAAQ,KAAK;CAChD,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,QAAQ,GAAG;CAC9D,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE;CAC9D,SAAS,EAAE,SAAS,CAAC,QAAQ,MAAM;CACnC,UAAU,EAAE,SAAS,CAAC,QAAQ,KAAK;CACnC,WAAW,EAAE,MAAM,eAAe,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CACtD,MAAM,WAAW,UAAU,CAAC,QAAQ,KAAK;CACzC,YAAY,iBAAiB,UAAU,CAAC,QAAQ,KAAK;CACtD,CAAC,CACD,aAAa,QAAQ,QAAQ;AAC5B,KAAI,OAAO,SAAS,UAAU,CAAC,OAAO,KACpC,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAA6B,CAAC;AACxE,KAAI,OAAO,SAAS,gBAAgB,CAAC,OAAO,WAC1C,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAA0C,CAAC;AACrF,KAAI;EAAC;EAAS;EAAS;EAAO,CAAC,SAAS,OAAO,KAAK,IAAI,CAAC,OAAO,SAC9D,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAsC,CAAC;AACjF,KAAI,OAAO,SAAS,UAAU,CAAC,OAAO,aACpC,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAmC,CAAC;AAC9E,KAAI,IAAI,IAAI,OAAO,UAAU,KAAK,aAAa,SAAS,GAAG,CAAC,CAAC,SAAS,OAAO,UAAU,OACrF,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAgC,CAAC;EAC3E;AAEJ,MAAa,eAAe,EAAE,OAAO;CACnC,IAAI;CACJ;CACA,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC7C,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE;CACzD,UAAU,UAAU,UAAU,CAAC,QAAQ,KAAK;CAC5C,SAAS,EAAE,MAAM,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;CACpD,CAAC;AAEF,MAAa,mBAAmB,EAC7B,OAAO;CACN,MAAM,EACH,QAAQ,CACR,MAAM,CACN,IAAI,EAAE,CACN,IAAI,IAAI,CACR,MAAM,8BAA8B,4CAA4C;CACnF;CACA,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAChD,aAAa,KAAK,QAAQ,GAAG;CAC7B,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CACxE,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CAC5E,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CAChD,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CACnE,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK;CACxD,OAAO,EAAE,KAAK;EAAC;EAAY;EAAgB;EAAY;EAAM,CAAC,CAAC,QAAQ,MAAM;CAC7E,eAAe,EACZ,OAAO;EACN,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;EACnC,KAAK;EACL,KAAK,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;EACrC,CAAC,CACD,UAAU,CACV,QAAQ,KAAK;CAChB,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CACtD,eAAe,EAAE,MAAM,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CACpD,QAAQ,EAAE,KAAK;EAAC;EAAS;EAAa;EAAW,CAAC,CAAC,QAAQ,QAAQ;CACnE,gBAAgB,EAAE,KAAK;EAAC;EAAQ;EAAY;EAAS,CAAC,CAAC,QAAQ,OAAO;CACtE,UAAU,EACP,OAAO;EACN,aAAa,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,CAAC,QAAQ,OAAO;EACrD,SAAS,SAAS,UAAU,CAAC,QAAQ,KAAK;EAC1C,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB,CAAC,UAAU,CAAC,QAAQ,KAAK;EACzF,UAAU,EACP,QAAQ,CACR,MAAM,aAAa,CACnB,QAAQ,MAAM;EAClB,CAAC,CACD,QAAQ;EAAE,aAAa;EAAQ,SAAS;EAAM,YAAY;EAAM,UAAU;EAAO,CAAC;CACrF,uBAAuB,EAAE,MAAM,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CAC5D,YAAY,EAAE,SAAS,CAAC,QAAQ,KAAK;CACrC,oBAAoB,UAAU,UAAU,CAAC,QAAQ,KAAK;CACtD,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE;CACxD,oBAAoB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC7C,SAAS,EAAE,MAAM,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;CACnD,CAAC,CACD,aAAa,QAAQ,QAAQ;CAC5B,MAAM,SAAS,OAAO,QAAQ,SAAS,WAAW,CAChD,OAAO,IACP,GAAG,OAAO,QAAQ,KAAK,WAAW,OAAO,GAAG,CAC7C,CAAC;AACF,KAAI,IAAI,IAAI,OAAO,CAAC,SAAS,OAAO,OAClC,KAAI,SAAS;EACX,MAAM;EACN,SAAS;EACV,CAAC;AACJ,KAAI,OAAO,QAAQ,SAAS,WAAW,OAAO,QAAQ,CAAC,SAAS,IAC9D,KAAI,SAAS;EAAE,MAAM;EAAU,SAAS;EAAwC,CAAC;AACnF,KACE,OAAO,WAAW,eAClB,CAAC,OAAO,QAAQ,MAAM,WAAW,OAAO,QAAQ,MAAM,WAAW,OAAO,SAAS,CAAC,CAElF,KAAI,SAAS;EACX,MAAM;EACN,SAAS;EACV,CAAC;EACJ;AAEJ,MAAa,mBAAmB,EAAE,OAAO;CACvC,IAAI,SAAS,UAAU;CACvB,kBAAkB,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK;CAC9D,MAAM;CACP,CAAC;AACF,MAAa,aAAa,EAAE,OAAO;CACjC,QAAQ,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,UAAU;CACvC,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CAC3D,CAAC;AACF,MAAa,gBAAgB,WAAW,OAAO;CAC7C,GAAG,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CAClC,UAAU,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG;CACzC,OAAO,EAAE,KAAK;EAAC;EAAY;EAAgB;EAAY;EAAM,CAAC,CAAC,UAAU;CACzE,UAAU,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,UAAU;CACxC,CAAC;AACF,MAAa,iBAAiB,EAAE,OAAO,EAAE,UAAU,UAAU,CAAC;AAC9D,MAAa,iBAAiB,eAAe,OAAO,EAAE,UAAU,UAAU,CAAC;AAC3E,MAAa,gBAAgB,EAAE,OAC7B,UACA,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,IAAI,IAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CACtE;AACD,MAAa,mBAAmB,eAAe,OAAO;CACpD,WAAW;CACX,SAAS;CACT,uBAAuB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB,CAAC,UAAU;CACvF,CAAC;AACF,MAAa,kBAAkB,iBAAiB,OAAO,EACrD,uBAAuB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB,CAAC,QAAQ,EAAE,EACvF,CAAC;AACF,MAAa,yBAAyB,eAAe,OAAO;CAC1D,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAO;CAC1C,eAAe,cAAc,UAAU,CAAC,QAAQ,KAAK;CACrD,cAAc,SAAS,UAAU;CACjC,uBAAuB,EACpB,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,OAAO,mBAAmB,EAAE,CAChC,UAAU;CACd,CAAC;AACF,MAAa,wBAAwB,eAAe,OAAO;CACzD,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAO,CAAC,QAAQ,GAAG;CACxC,eAAe,cAAc,UAAU,CAAC,QAAQ,KAAK;CACrD,uBAAuB,EACpB,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,OAAO,mBAAmB,EAAE;CACpC,CAAC;AACF,MAAa,0BAA0B,eAAe,OAAO,EAAE,UAAU,SAAS,UAAU,EAAE,CAAC;AAC/F,MAAa,wBAAwB,eAAe,OAAO;CACzD,QAAQ;CACR,QAAQ,EAAE,KAAK;EAAC;EAAU;EAAY;EAAa;EAAY,CAAC;CAChE,QAAQ,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CACxC,UAAU,SAAS,UAAU,CAAC,UAAU;CACxC,gBAAgB,UAAU,UAAU,CAAC,UAAU;CAC/C,iBAAiB,UAAU,UAAU,CAAC,UAAU;CACjD,CAAC;AACF,MAAa,cAAc,eAAe,OAAO;CAC/C,QAAQ;CACR,cAAc;CACd,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK,CAAC,UAAU;CACpD,cAAc,EAAE,MAAM,kBAAkB,CAAC,IAAI,GAAG,CAAC,UAAU;CAC3D,UAAU,EAAE,QAAQ,CAAC,IAAI,IAAO,CAAC,QAAQ,GAAG;CAC7C,CAAC;AACF,MAAa,mBAAmB,eAAe,OAAO;CACpD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CACxC,UAAU,SAAS,UAAU,CAAC,QAAQ,KAAK;CAC5C,CAAC;AACF,MAAa,eAAe,eAAe,OAAO;CAChD,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;CACtC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CACzC,CAAC;AACF,MAAa,iBAAiB,EAAE,OAAO;CACrC,IAAI;CACJ,QAAQ,EAAE,KAAK,CAAC,aAAa,SAAS,CAAC;CACvC,kBAAkB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAC7C,CAAC;AACF,MAAa,mBAAmB,EAC7B,OAAO;CACN;CACA,WAAW,EAAE,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;CAC3C,WAAW,EAAE,MAAM,SAAS,CAAC,IAAI,IAAK,CAAC,QAAQ,EAAE,CAAC;CAClD,UAAU,UAAU,UAAU,CAAC,QAAQ,KAAK;CAC5C,QAAQ,UAAU,UAAU,CAAC,QAAQ,KAAK;CAC3C,CAAC,CACD,QACE,WACC,CAAC,OAAO,YAAY,CAAC,OAAO,UAAU,KAAK,MAAM,OAAO,OAAO,GAAG,KAAK,MAAM,OAAO,SAAS,EAC/F,oCACD,CACA,QACE,WAAW,IAAI,IAAI,OAAO,UAAU,CAAC,SAAS,OAAO,UAAU,QAChE,iCACD,CACA,QACE,WAAW,IAAI,IAAI,OAAO,UAAU,CAAC,SAAS,OAAO,UAAU,QAChE,iCACD;AACH,MAAa,mBAAmB,EAAE,OAAO;CACvC,IAAI,SAAS,UAAU;CACvB,kBAAkB,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK;CAC9D,MAAM;CACP,CAAC;AACF,MAAa,iBAAiB,EAAE,OAAO;CACrC,cAAc,MAAM,QAAQ,wBAAwB;CACpD,oBAAoB,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,yCAAyC;CAC1F,YAAY,MAAM,QAAQ,gBAAgB;CAC1C,qBAAqB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC9C,iBAAiB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC1C,oBAAoB,EAAE,SAAS,CAAC,QAAQ,MAAM;CAC9C,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE;CACzD,CAAC;AACF,MAAa,0BAA0B,eAAe,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACrF,MAAa,0BAA0B,eAAe,OAAO;CAC3D,QAAQ;CACR,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAK;CAC3C,CAAC;AACF,MAAa,aAAa,eAAe,OAAO;CAC9C,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAO;CAC5B,kBAAkB,EACf,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,OAAO,mBAAmB,EAAE,CAChC,QAAQ,EAAE;CACd,CAAC;AACF,MAAa,kBAAkB,eAC5B,OAAO;CACN,IAAI;CACJ,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAK;CAC1B,iBAAiB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,MAAO,CAAC,UAAU,CAAC,QAAQ,KAAK;CACvE,SAAS,EAAE,SAAS,CAAC,QAAQ,MAAM;CACnC,UAAU,EAAE,SAAS,CAAC,QAAQ,MAAM;CACpC,kBAAkB,EACf,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,OAAO,mBAAmB,EAAE;CACpC,CAAC,CACD,QACE,SAAS,KAAK,KAAK,MAAM,CAAC,SAAS,KAAK,KAAK,oBAAoB,MAClE,4CACD;AAEH,MAAa,oBAAoB,EAAE,OAAO;CACxC,oBAAoB,EAAE,SAAS,CAAC,QAAQ,KAAK;CAC7C,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE;CAC/D,CAAC;AACF,MAAa,iBAAiB,eAAe,OAAO;CAClD,iBAAiB,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,MAAO;CACvD,cAAc,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,IAAI,EAAE;CACzC,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB;CACvE,CAAC;AACF,MAAa,iBAAiB,EAAE,OAAO;CACrC;CACA,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAK,CAAC,QAAQ,GAAG;CAC7C,WAAW,EACR,MAAM,SAAS,CACf,IAAI,EAAE,CACN,IAAI,GAAG,CACP,QAAQ,QAAQ,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,QAAQ,0BAA0B;CAC/E,QAAQ,EAAE,KAAK;EAAC;EAAS;EAAa;EAAW,CAAC,CAAC,QAAQ,QAAQ;CACpE,CAAC;AACF,MAAa,iBAAiB,EAAE,OAAO;CACrC,IAAI,SAAS,UAAU;CACvB,kBAAkB,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK;CAC9D,MAAM;CACP,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ import { CourseDetail, Lesson, LessonProgress, PublicLesson } from "./types.js";
2
+
3
+ //#region src/assignments.d.ts
4
+ declare function assignmentBlock(assignment: NonNullable<Lesson["assignment"]>, progress: Pick<LessonProgress, "completedAt" | "assignments">, now: Date): {
5
+ code: string;
6
+ message: string;
7
+ status: number;
8
+ } | null;
9
+ //#endregion
1
10
  //#region src/errors.d.ts
2
11
  declare class LmsError extends Error {
3
12
  readonly code: string;
@@ -22,9 +31,17 @@ interface RuntimeLocals {
22
31
  declare function lmsPublic<T>(locals: RuntimeLocals, route: string, input: Record<string, unknown>, origin: string): Promise<T>;
23
32
  declare function lmsLearner<T>(locals: RuntimeLocals, route: string, input: Record<string, unknown>, origin: string): Promise<T>;
24
33
  declare function loginUrl(loginPath: string, returnTo: string): string;
34
+ /** A fixed private read route; authorization remains at the EmDash runtime boundary. */
35
+ declare function lmsAuthorLessonPreview(locals: RuntimeLocals, input: {
36
+ courseId: string;
37
+ lessonId: string;
38
+ }, origin: string): Promise<{
39
+ course: CourseDetail;
40
+ lesson: PublicLesson;
41
+ }>;
25
42
  declare function courseUrl(basePath: string, slug: string): string;
26
43
  declare function lessonUrl(basePath: string, slug: string, lessonId: string): string;
27
44
  declare function certificateUrl(basePath: string, id: string): string;
28
45
  //#endregion
29
- export { LmsError, certificateUrl, courseUrl, lessonUrl, lmsLearner, lmsPublic, loginUrl };
46
+ export { LmsError, assignmentBlock, certificateUrl, courseUrl, lessonUrl, lmsAuthorLessonPreview, lmsLearner, lmsPublic, loginUrl };
30
47
  //# sourceMappingURL=server.d.ts.map
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { r as PLUGIN_ID } from "./constants-C0kT94tc.js";
2
- import { t as LmsError } from "./errors-ChzJS9al.js";
1
+ import { r as PLUGIN_ID } from "./constants-DyQbwNbP.js";
2
+ import { i as LmsError, t as assignmentBlock } from "./assignments-CsuAjxGO.js";
3
3
 
4
4
  //#region src/server.ts
5
5
  function requestUrl(route, input, origin) {
@@ -18,6 +18,12 @@ async function lmsPublic(locals, route, input, origin) {
18
18
  return unwrap(await dispatch(PLUGIN_ID, "GET", route, new Request(requestUrl(route, input, origin))));
19
19
  }
20
20
  const READ_ROUTES = new Set([
21
+ "learner/study/courses",
22
+ "learner/notebook",
23
+ "learner/agenda",
24
+ "learner/paths",
25
+ "learner/saved",
26
+ "learner/preferences",
21
27
  "learner/dashboard",
22
28
  "learner/course",
23
29
  "learner/course-by-slug",
@@ -39,6 +45,14 @@ function loginUrl(loginPath, returnTo) {
39
45
  url.searchParams.set("redirect", returnTo);
40
46
  return `${url.pathname}${url.search}${url.hash}`;
41
47
  }
48
+ /** A fixed private read route; authorization remains at the EmDash runtime boundary. */
49
+ async function lmsAuthorLessonPreview(locals, input, origin) {
50
+ if (!locals.user) throw new LmsError("UNAUTHORIZED", "Sign in to preview this lesson.", 401);
51
+ const dispatch = locals.emdash?.handlePluginApiRoute;
52
+ if (!dispatch) throw new LmsError("LMS_UNAVAILABLE", "The learning service is unavailable.", 503);
53
+ const route = "admin/lesson/preview";
54
+ return unwrap(await dispatch(PLUGIN_ID, "GET", route, new Request(requestUrl(route, input, origin)), locals.user));
55
+ }
42
56
  function courseUrl(basePath, slug) {
43
57
  return `${basePath}/courses/${encodeURIComponent(slug)}`;
44
58
  }
@@ -50,5 +64,5 @@ function certificateUrl(basePath, id) {
50
64
  }
51
65
 
52
66
  //#endregion
53
- export { LmsError, certificateUrl, courseUrl, lessonUrl, lmsLearner, lmsPublic, loginUrl };
67
+ export { LmsError, assignmentBlock, certificateUrl, courseUrl, lessonUrl, lmsAuthorLessonPreview, lmsLearner, lmsPublic, loginUrl };
54
68
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["import { PLUGIN_ID } from \"./constants.js\";\nimport { LmsError } from \"./errors.js\";\nimport type { RouteEnvelope } from \"./types.js\";\n\ninterface RuntimeLocals {\n user?: { id: string; email: string; name: string | null; role: number; createdAt: Date | string };\n emdash?: {\n handlePublicPluginApiRoute?: (\n pluginId: string,\n method: string,\n path: string,\n request: Request,\n ) => Promise<unknown>;\n handlePluginApiRoute?: (\n pluginId: string,\n method: string,\n path: string,\n request: Request,\n user?: RuntimeLocals[\"user\"] | null,\n ) => Promise<unknown>;\n };\n}\n\nfunction requestUrl(route: string, input: Record<string, unknown>, origin: string): URL {\n const url = new URL(`/_emdash/api/plugins/${PLUGIN_ID}/${route}`, origin);\n for (const [key, value] of Object.entries(input))\n if (value !== undefined && value !== null && value !== \"\")\n url.searchParams.set(key, String(value));\n return url;\n}\nfunction unwrap<T>(input: unknown): T {\n const result = input as RouteEnvelope<T>;\n if (!result?.success)\n throw new LmsError(\n result?.error?.code ?? \"LMS_UNAVAILABLE\",\n result?.error?.message ?? \"The learning service is unavailable.\",\n result?.status ?? 503,\n );\n return result.data as T;\n}\nexport async function lmsPublic<T>(\n locals: RuntimeLocals,\n route: string,\n input: Record<string, unknown>,\n origin: string,\n): Promise<T> {\n const dispatch = locals.emdash?.handlePublicPluginApiRoute;\n if (!dispatch) throw new LmsError(\"LMS_UNAVAILABLE\", \"The learning service is unavailable.\", 503);\n return unwrap<T>(\n await dispatch(PLUGIN_ID, \"GET\", route, new Request(requestUrl(route, input, origin))),\n );\n}\nconst READ_ROUTES = new Set([\n \"learner/dashboard\",\n \"learner/course\",\n \"learner/course-by-slug\",\n \"learner/lesson\",\n \"learner/certificate\",\n \"learner/certificate-by-id\",\n \"learner/cohort\",\n \"learner/notifications\",\n]);\nexport async function lmsLearner<T>(\n locals: RuntimeLocals,\n route: string,\n input: Record<string, unknown>,\n origin: string,\n): Promise<T> {\n if (!locals.user || locals.user.role < 10)\n throw new LmsError(\"UNAUTHORIZED\", \"Sign in to continue.\", 401);\n if (!READ_ROUTES.has(route))\n throw new LmsError(\"FORBIDDEN\", \"This route is not available to the learner renderer.\", 403);\n const dispatch = locals.emdash?.handlePluginApiRoute;\n if (!dispatch) throw new LmsError(\"LMS_UNAVAILABLE\", \"The learning service is unavailable.\", 503);\n return unwrap<T>(\n await dispatch(\n PLUGIN_ID,\n \"GET\",\n route,\n new Request(requestUrl(route, input, origin)),\n locals.user,\n ),\n );\n}\nexport function loginUrl(loginPath: string, returnTo: string): string {\n const url = new URL(loginPath, \"https://lms.invalid\");\n url.searchParams.set(\"redirect\", returnTo);\n return `${url.pathname}${url.search}${url.hash}`;\n}\nexport function courseUrl(basePath: string, slug: string): string {\n return `${basePath}/courses/${encodeURIComponent(slug)}`;\n}\nexport function lessonUrl(basePath: string, slug: string, lessonId: string): string {\n return `${courseUrl(basePath, slug)}/lessons/${encodeURIComponent(lessonId)}`;\n}\nexport function certificateUrl(basePath: string, id: string): string {\n return `${basePath}/certificates/${encodeURIComponent(id)}`;\n}\nexport { LmsError } from \"./errors.js\";\n"],"mappings":";;;;AAuBA,SAAS,WAAW,OAAe,OAAgC,QAAqB;CACtF,MAAM,MAAM,IAAI,IAAI,wBAAwB,UAAU,GAAG,SAAS,OAAO;AACzE,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,KAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GACrD,KAAI,aAAa,IAAI,KAAK,OAAO,MAAM,CAAC;AAC5C,QAAO;;AAET,SAAS,OAAU,OAAmB;CACpC,MAAM,SAAS;AACf,KAAI,CAAC,QAAQ,QACX,OAAM,IAAI,SACR,QAAQ,OAAO,QAAQ,mBACvB,QAAQ,OAAO,WAAW,wCAC1B,QAAQ,UAAU,IACnB;AACH,QAAO,OAAO;;AAEhB,eAAsB,UACpB,QACA,OACA,OACA,QACY;CACZ,MAAM,WAAW,OAAO,QAAQ;AAChC,KAAI,CAAC,SAAU,OAAM,IAAI,SAAS,mBAAmB,wCAAwC,IAAI;AACjG,QAAO,OACL,MAAM,SAAS,WAAW,OAAO,OAAO,IAAI,QAAQ,WAAW,OAAO,OAAO,OAAO,CAAC,CAAC,CACvF;;AAEH,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AACF,eAAsB,WACpB,QACA,OACA,OACA,QACY;AACZ,KAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,OAAO,GACrC,OAAM,IAAI,SAAS,gBAAgB,wBAAwB,IAAI;AACjE,KAAI,CAAC,YAAY,IAAI,MAAM,CACzB,OAAM,IAAI,SAAS,aAAa,wDAAwD,IAAI;CAC9F,MAAM,WAAW,OAAO,QAAQ;AAChC,KAAI,CAAC,SAAU,OAAM,IAAI,SAAS,mBAAmB,wCAAwC,IAAI;AACjG,QAAO,OACL,MAAM,SACJ,WACA,OACA,OACA,IAAI,QAAQ,WAAW,OAAO,OAAO,OAAO,CAAC,EAC7C,OAAO,KACR,CACF;;AAEH,SAAgB,SAAS,WAAmB,UAA0B;CACpE,MAAM,MAAM,IAAI,IAAI,WAAW,sBAAsB;AACrD,KAAI,aAAa,IAAI,YAAY,SAAS;AAC1C,QAAO,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI;;AAE5C,SAAgB,UAAU,UAAkB,MAAsB;AAChE,QAAO,GAAG,SAAS,WAAW,mBAAmB,KAAK;;AAExD,SAAgB,UAAU,UAAkB,MAAc,UAA0B;AAClF,QAAO,GAAG,UAAU,UAAU,KAAK,CAAC,WAAW,mBAAmB,SAAS;;AAE7E,SAAgB,eAAe,UAAkB,IAAoB;AACnE,QAAO,GAAG,SAAS,gBAAgB,mBAAmB,GAAG"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["import { PLUGIN_ID } from \"./constants.js\";\nexport { assignmentBlock } from \"./assignments.js\";\nimport { LmsError } from \"./errors.js\";\nimport type { CourseDetail, PublicLesson, RouteEnvelope } from \"./types.js\";\n\ninterface RuntimeLocals {\n user?: { id: string; email: string; name: string | null; role: number; createdAt: Date | string };\n emdash?: {\n handlePublicPluginApiRoute?: (\n pluginId: string,\n method: string,\n path: string,\n request: Request,\n ) => Promise<unknown>;\n handlePluginApiRoute?: (\n pluginId: string,\n method: string,\n path: string,\n request: Request,\n user?: RuntimeLocals[\"user\"] | null,\n ) => Promise<unknown>;\n };\n}\n\nfunction requestUrl(route: string, input: Record<string, unknown>, origin: string): URL {\n const url = new URL(`/_emdash/api/plugins/${PLUGIN_ID}/${route}`, origin);\n for (const [key, value] of Object.entries(input))\n if (value !== undefined && value !== null && value !== \"\")\n url.searchParams.set(key, String(value));\n return url;\n}\nfunction unwrap<T>(input: unknown): T {\n const result = input as RouteEnvelope<T>;\n if (!result?.success)\n throw new LmsError(\n result?.error?.code ?? \"LMS_UNAVAILABLE\",\n result?.error?.message ?? \"The learning service is unavailable.\",\n result?.status ?? 503,\n );\n return result.data as T;\n}\nexport async function lmsPublic<T>(\n locals: RuntimeLocals,\n route: string,\n input: Record<string, unknown>,\n origin: string,\n): Promise<T> {\n const dispatch = locals.emdash?.handlePublicPluginApiRoute;\n if (!dispatch) throw new LmsError(\"LMS_UNAVAILABLE\", \"The learning service is unavailable.\", 503);\n return unwrap<T>(\n await dispatch(PLUGIN_ID, \"GET\", route, new Request(requestUrl(route, input, origin))),\n );\n}\nconst READ_ROUTES = new Set([\n \"learner/study/courses\",\n \"learner/notebook\",\n \"learner/agenda\",\n \"learner/paths\",\n \"learner/saved\",\n \"learner/preferences\",\n \"learner/dashboard\",\n \"learner/course\",\n \"learner/course-by-slug\",\n \"learner/lesson\",\n \"learner/certificate\",\n \"learner/certificate-by-id\",\n \"learner/cohort\",\n \"learner/notifications\",\n]);\nexport async function lmsLearner<T>(\n locals: RuntimeLocals,\n route: string,\n input: Record<string, unknown>,\n origin: string,\n): Promise<T> {\n if (!locals.user || locals.user.role < 10)\n throw new LmsError(\"UNAUTHORIZED\", \"Sign in to continue.\", 401);\n if (!READ_ROUTES.has(route))\n throw new LmsError(\"FORBIDDEN\", \"This route is not available to the learner renderer.\", 403);\n const dispatch = locals.emdash?.handlePluginApiRoute;\n if (!dispatch) throw new LmsError(\"LMS_UNAVAILABLE\", \"The learning service is unavailable.\", 503);\n return unwrap<T>(\n await dispatch(\n PLUGIN_ID,\n \"GET\",\n route,\n new Request(requestUrl(route, input, origin)),\n locals.user,\n ),\n );\n}\nexport function loginUrl(loginPath: string, returnTo: string): string {\n const url = new URL(loginPath, \"https://lms.invalid\");\n url.searchParams.set(\"redirect\", returnTo);\n return `${url.pathname}${url.search}${url.hash}`;\n}\n/** A fixed private read route; authorization remains at the EmDash runtime boundary. */\nexport async function lmsAuthorLessonPreview(\n locals: RuntimeLocals,\n input: { courseId: string; lessonId: string },\n origin: string,\n): Promise<{ course: CourseDetail; lesson: PublicLesson }> {\n if (!locals.user) throw new LmsError(\"UNAUTHORIZED\", \"Sign in to preview this lesson.\", 401);\n const dispatch = locals.emdash?.handlePluginApiRoute;\n if (!dispatch) throw new LmsError(\"LMS_UNAVAILABLE\", \"The learning service is unavailable.\", 503);\n const route = \"admin/lesson/preview\";\n return unwrap(\n await dispatch(\n PLUGIN_ID,\n \"GET\",\n route,\n new Request(requestUrl(route, input, origin)),\n locals.user,\n ),\n );\n}\nexport function courseUrl(basePath: string, slug: string): string {\n return `${basePath}/courses/${encodeURIComponent(slug)}`;\n}\nexport function lessonUrl(basePath: string, slug: string, lessonId: string): string {\n return `${courseUrl(basePath, slug)}/lessons/${encodeURIComponent(lessonId)}`;\n}\nexport function certificateUrl(basePath: string, id: string): string {\n return `${basePath}/certificates/${encodeURIComponent(id)}`;\n}\nexport { LmsError } from \"./errors.js\";\n"],"mappings":";;;;AAwBA,SAAS,WAAW,OAAe,OAAgC,QAAqB;CACtF,MAAM,MAAM,IAAI,IAAI,wBAAwB,UAAU,GAAG,SAAS,OAAO;AACzE,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,KAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GACrD,KAAI,aAAa,IAAI,KAAK,OAAO,MAAM,CAAC;AAC5C,QAAO;;AAET,SAAS,OAAU,OAAmB;CACpC,MAAM,SAAS;AACf,KAAI,CAAC,QAAQ,QACX,OAAM,IAAI,SACR,QAAQ,OAAO,QAAQ,mBACvB,QAAQ,OAAO,WAAW,wCAC1B,QAAQ,UAAU,IACnB;AACH,QAAO,OAAO;;AAEhB,eAAsB,UACpB,QACA,OACA,OACA,QACY;CACZ,MAAM,WAAW,OAAO,QAAQ;AAChC,KAAI,CAAC,SAAU,OAAM,IAAI,SAAS,mBAAmB,wCAAwC,IAAI;AACjG,QAAO,OACL,MAAM,SAAS,WAAW,OAAO,OAAO,IAAI,QAAQ,WAAW,OAAO,OAAO,OAAO,CAAC,CAAC,CACvF;;AAEH,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AACF,eAAsB,WACpB,QACA,OACA,OACA,QACY;AACZ,KAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,OAAO,GACrC,OAAM,IAAI,SAAS,gBAAgB,wBAAwB,IAAI;AACjE,KAAI,CAAC,YAAY,IAAI,MAAM,CACzB,OAAM,IAAI,SAAS,aAAa,wDAAwD,IAAI;CAC9F,MAAM,WAAW,OAAO,QAAQ;AAChC,KAAI,CAAC,SAAU,OAAM,IAAI,SAAS,mBAAmB,wCAAwC,IAAI;AACjG,QAAO,OACL,MAAM,SACJ,WACA,OACA,OACA,IAAI,QAAQ,WAAW,OAAO,OAAO,OAAO,CAAC,EAC7C,OAAO,KACR,CACF;;AAEH,SAAgB,SAAS,WAAmB,UAA0B;CACpE,MAAM,MAAM,IAAI,IAAI,WAAW,sBAAsB;AACrD,KAAI,aAAa,IAAI,YAAY,SAAS;AAC1C,QAAO,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI;;;AAG5C,eAAsB,uBACpB,QACA,OACA,QACyD;AACzD,KAAI,CAAC,OAAO,KAAM,OAAM,IAAI,SAAS,gBAAgB,mCAAmC,IAAI;CAC5F,MAAM,WAAW,OAAO,QAAQ;AAChC,KAAI,CAAC,SAAU,OAAM,IAAI,SAAS,mBAAmB,wCAAwC,IAAI;CACjG,MAAM,QAAQ;AACd,QAAO,OACL,MAAM,SACJ,WACA,OACA,OACA,IAAI,QAAQ,WAAW,OAAO,OAAO,OAAO,CAAC,EAC7C,OAAO,KACR,CACF;;AAEH,SAAgB,UAAU,UAAkB,MAAsB;AAChE,QAAO,GAAG,SAAS,WAAW,mBAAmB,KAAK;;AAExD,SAAgB,UAAU,UAAkB,MAAc,UAA0B;AAClF,QAAO,GAAG,UAAU,UAAU,KAAK,CAAC,WAAW,mBAAmB,SAAS;;AAE7E,SAAgB,eAAe,UAAkB,IAAoB;AACnE,QAAO,GAAG,SAAS,gBAAgB,mBAAmB,GAAG"}