@studious-lms/server 1.4.2 → 1.4.4

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 (152) hide show
  1. package/.coderabbit.yaml +4 -1
  2. package/.vscode/settings.json +3 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +68 -29
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/fileUpload.d.ts +10 -2
  7. package/dist/lib/fileUpload.d.ts.map +1 -1
  8. package/dist/lib/fileUpload.js +38 -6
  9. package/dist/lib/fileUpload.js.map +1 -1
  10. package/dist/middleware/auth.d.ts.map +1 -1
  11. package/dist/middleware/auth.js +18 -5
  12. package/dist/middleware/auth.js.map +1 -1
  13. package/dist/models/auth.d.ts +19 -14
  14. package/dist/models/auth.d.ts.map +1 -1
  15. package/dist/models/auth.js +53 -30
  16. package/dist/models/auth.js.map +1 -1
  17. package/dist/models/class.d.ts +3 -1
  18. package/dist/models/class.d.ts.map +1 -1
  19. package/dist/models/class.js +16 -4
  20. package/dist/models/class.js.map +1 -1
  21. package/dist/models/notification.d.ts +11 -10
  22. package/dist/models/notification.d.ts.map +1 -1
  23. package/dist/models/notification.js +13 -9
  24. package/dist/models/notification.js.map +1 -1
  25. package/dist/models/worksheet.d.ts +379 -7
  26. package/dist/models/worksheet.d.ts.map +1 -1
  27. package/dist/models/worksheet.js +168 -2
  28. package/dist/models/worksheet.js.map +1 -1
  29. package/dist/pipelines/aiLabChat.d.ts.map +1 -1
  30. package/dist/pipelines/aiLabChat.js +11 -3
  31. package/dist/pipelines/aiLabChat.js.map +1 -1
  32. package/dist/pipelines/aiLabChatContract.d.ts +3 -3
  33. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
  34. package/dist/pipelines/aiNewtonChat.js +25 -14
  35. package/dist/pipelines/aiNewtonChat.js.map +1 -1
  36. package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
  37. package/dist/pipelines/gradeWorksheet.js +10 -3
  38. package/dist/pipelines/gradeWorksheet.js.map +1 -1
  39. package/dist/pipelines/pdfToWorksheet.d.ts +12 -0
  40. package/dist/pipelines/pdfToWorksheet.d.ts.map +1 -0
  41. package/dist/pipelines/pdfToWorksheet.js +155 -0
  42. package/dist/pipelines/pdfToWorksheet.js.map +1 -0
  43. package/dist/routers/_app.d.ts +264 -16
  44. package/dist/routers/_app.d.ts.map +1 -1
  45. package/dist/routers/class.d.ts +2 -1
  46. package/dist/routers/class.d.ts.map +1 -1
  47. package/dist/routers/class.js +3 -3
  48. package/dist/routers/class.js.map +1 -1
  49. package/dist/routers/labChat.d.ts +6 -0
  50. package/dist/routers/labChat.d.ts.map +1 -1
  51. package/dist/routers/labChat.js +5 -3
  52. package/dist/routers/labChat.js.map +1 -1
  53. package/dist/routers/message.d.ts +31 -0
  54. package/dist/routers/message.d.ts.map +1 -1
  55. package/dist/routers/message.js +27 -4
  56. package/dist/routers/message.js.map +1 -1
  57. package/dist/routers/newtonChat.d.ts +6 -0
  58. package/dist/routers/newtonChat.d.ts.map +1 -1
  59. package/dist/routers/newtonChat.js +5 -4
  60. package/dist/routers/newtonChat.js.map +1 -1
  61. package/dist/routers/notifications.d.ts +9 -2
  62. package/dist/routers/notifications.d.ts.map +1 -1
  63. package/dist/routers/notifications.js +4 -4
  64. package/dist/routers/notifications.js.map +1 -1
  65. package/dist/routers/worksheet.d.ts +78 -5
  66. package/dist/routers/worksheet.d.ts.map +1 -1
  67. package/dist/routers/worksheet.js +126 -17
  68. package/dist/routers/worksheet.js.map +1 -1
  69. package/dist/services/auth.d.ts +1 -1
  70. package/dist/services/auth.d.ts.map +1 -1
  71. package/dist/services/auth.js +19 -12
  72. package/dist/services/auth.js.map +1 -1
  73. package/dist/services/class.d.ts +1 -1
  74. package/dist/services/class.d.ts.map +1 -1
  75. package/dist/services/class.js +6 -3
  76. package/dist/services/class.js.map +1 -1
  77. package/dist/services/file.d.ts.map +1 -1
  78. package/dist/services/file.js +7 -2
  79. package/dist/services/file.js.map +1 -1
  80. package/dist/services/labChat.d.ts +6 -0
  81. package/dist/services/labChat.d.ts.map +1 -1
  82. package/dist/services/labChat.js +30 -18
  83. package/dist/services/labChat.js.map +1 -1
  84. package/dist/services/message.d.ts +30 -0
  85. package/dist/services/message.d.ts.map +1 -1
  86. package/dist/services/message.js +97 -21
  87. package/dist/services/message.js.map +1 -1
  88. package/dist/services/newtonChat.d.ts +6 -1
  89. package/dist/services/newtonChat.d.ts.map +1 -1
  90. package/dist/services/newtonChat.js +36 -18
  91. package/dist/services/newtonChat.js.map +1 -1
  92. package/dist/services/notification.d.ts +12 -5
  93. package/dist/services/notification.d.ts.map +1 -1
  94. package/dist/services/notification.js +24 -9
  95. package/dist/services/notification.js.map +1 -1
  96. package/dist/services/studentProgress.d.ts.map +1 -1
  97. package/dist/services/studentProgress.js +6 -3
  98. package/dist/services/studentProgress.js.map +1 -1
  99. package/dist/services/worksheet.d.ts +36 -15
  100. package/dist/services/worksheet.d.ts.map +1 -1
  101. package/dist/services/worksheet.js +186 -54
  102. package/dist/services/worksheet.js.map +1 -1
  103. package/dist/trpc.d.ts.map +1 -1
  104. package/dist/trpc.js +11 -17
  105. package/dist/trpc.js.map +1 -1
  106. package/dist/utils/inference.d.ts +10 -1
  107. package/dist/utils/inference.d.ts.map +1 -1
  108. package/dist/utils/inference.js +186 -50
  109. package/dist/utils/inference.js.map +1 -1
  110. package/package.json +1 -1
  111. package/prisma/migrations/20260415103500_add_session_type/migration.sql +33 -0
  112. package/prisma/migrations/20260415133000_add_ai_usage_logs/migration.sql +19 -0
  113. package/prisma/schema.prisma +27 -1
  114. package/scripts/test-pre-push.ts +6 -2
  115. package/src/index.ts +83 -30
  116. package/src/lib/fileUpload.ts +55 -5
  117. package/src/middleware/auth.ts +19 -4
  118. package/src/models/auth.ts +59 -29
  119. package/src/models/class.ts +15 -4
  120. package/src/models/notification.ts +13 -7
  121. package/src/models/worksheet.ts +203 -0
  122. package/src/pipelines/aiLabChat.ts +9 -1
  123. package/src/pipelines/aiNewtonChat.ts +24 -14
  124. package/src/pipelines/gradeWorksheet.ts +8 -0
  125. package/src/pipelines/pdfToWorksheet.ts +177 -0
  126. package/src/routers/class.ts +2 -2
  127. package/src/routers/labChat.ts +3 -1
  128. package/src/routers/message.ts +38 -1
  129. package/src/routers/newtonChat.ts +4 -2
  130. package/src/routers/notifications.ts +2 -2
  131. package/src/routers/worksheet.ts +174 -19
  132. package/src/services/auth.ts +26 -12
  133. package/src/services/class.ts +4 -1
  134. package/src/services/file.ts +6 -0
  135. package/src/services/labChat.ts +42 -18
  136. package/src/services/message.ts +163 -18
  137. package/src/services/newtonChat.ts +49 -18
  138. package/src/services/notification.ts +27 -8
  139. package/src/services/studentProgress.ts +4 -1
  140. package/src/services/worksheet.ts +252 -51
  141. package/src/trpc.ts +12 -18
  142. package/src/utils/inference.ts +280 -56
  143. package/tests/globalSetup.ts +13 -4
  144. package/tests/pipelines/pdfToWorksheet.test.ts +176 -0
  145. package/tests/routers/auth.test.ts +120 -17
  146. package/tests/routers/class.test.ts +7 -1
  147. package/tests/routers/message.test.ts +236 -9
  148. package/tests/routers/newtonChat.test.ts +81 -0
  149. package/tests/routers/notification.test.ts +12 -0
  150. package/tests/routers/worksheet.test.ts +194 -0
  151. package/tests/setup.ts +22 -5
  152. package/tests/utils/inference.test.ts +255 -0
@@ -3,22 +3,47 @@
3
3
  * Integrates with gradeWorksheet pipeline for auto-grading.
4
4
  */
5
5
 
6
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cffbcf20-cef6-5fd4-979f-670d50592d0a")}catch(e){}}();
6
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2fcbad58-5215-5f4a-a912-82db38a85645")}catch(e){}}();
7
7
  import { TRPCError } from "@trpc/server";
8
8
  import { GenerationStatus } from "@prisma/client";
9
9
  import { prisma } from "../lib/prisma.js";
10
+ import { getFileUrl } from "../lib/fileUpload.js";
10
11
  import { cancelGradePipeline, regradeWorksheetPipeline } from "../pipelines/gradeWorksheet.js";
11
- import { findWorksheetById, findWorksheetByIdMinimal, findWorksheetsByClassId, createWorksheet, updateWorksheet, deleteWorksheet, findQuestionsByWorksheetId, createWorksheetQuestion, updateWorksheetQuestion, deleteWorksheetQuestion, findSubmissionById, findOrCreateWorksheetResponse, findWorksheetResponseWithResponses, findWorksheetQuestionById, updateStudentQuestionProgress, createStudentQuestionProgress, findStudentQuestionProgress, updateStudentQuestionProgressForGrading, createStudentQuestionProgressForGrading, createComment, } from "../models/worksheet.js";
12
+ import { pdfToWorksheet } from "../pipelines/pdfToWorksheet.js";
13
+ import { findWorksheetByIdMinimal, findWorksheetByIdForClassMember, findWorksheetByIdForTeacher, findWorksheetsByClassId, createWorksheet, updateWorksheet, deleteWorksheet, findQuestionsByWorksheetId, createWorksheetQuestion, updateWorksheetQuestion, deleteWorksheetQuestion, findSubmissionByIdForWorksheetAccess, findOrCreateWorksheetResponse, findWorksheetResponseByIdForTeacher, findWorksheetResponseWithResponsesForStudent, findWorksheetQuestionByIdForTeacher, findWorksheetQuestionByIdInWorksheet, updateStudentQuestionProgress, createStudentQuestionProgress, findStudentQuestionProgress, updateStudentQuestionProgressForGrading, createStudentQuestionProgressForGrading, createComment, findStudentQuestionProgressByIdForTeacher, findStudentQuestionProgressByIdForTeacherAndResponse, } from "../models/worksheet.js";
14
+ const sanitizeQuestionOptionsForStudent = (options) => {
15
+ if (!Array.isArray(options))
16
+ return options;
17
+ return options.map((option) => {
18
+ if (!option || typeof option !== "object")
19
+ return option;
20
+ const { isCorrect: _isCorrect, ...rest } = option;
21
+ return rest;
22
+ });
23
+ };
24
+ const sanitizeWorksheetForStudent = (worksheet) => ({
25
+ ...worksheet,
26
+ questions: worksheet.questions.map((question) => ({
27
+ ...question,
28
+ answer: "",
29
+ markScheme: null,
30
+ options: sanitizeQuestionOptionsForStudent(question.options),
31
+ })),
32
+ });
12
33
  /** Get worksheet with questions and mark schemes. */
13
- export async function getWorksheet(worksheetId) {
14
- const worksheet = await findWorksheetById(worksheetId);
15
- if (!worksheet) {
34
+ export async function getWorksheet(worksheetId, userId) {
35
+ const teacherWorksheet = await findWorksheetByIdForTeacher(worksheetId, userId);
36
+ if (teacherWorksheet) {
37
+ return teacherWorksheet;
38
+ }
39
+ const studentWorksheet = await findWorksheetByIdForClassMember(worksheetId, userId);
40
+ if (!studentWorksheet) {
16
41
  throw new TRPCError({
17
- code: "NOT_FOUND",
18
- message: "Worksheet not found",
42
+ code: "FORBIDDEN",
43
+ message: "You do not have access to this worksheet",
19
44
  });
20
45
  }
21
- return worksheet;
46
+ return sanitizeWorksheetForStudent(studentWorksheet);
22
47
  }
23
48
  /** Check if worksheet exists. */
24
49
  export async function worksheetExists(id) {
@@ -32,21 +57,81 @@ export async function listWorksheets(classId) {
32
57
  questionCount: w.questions.length,
33
58
  }));
34
59
  }
35
- export async function updateWorksheetRecord(worksheetId, data) {
60
+ export async function updateWorksheetRecord(worksheetId, userId, data) {
61
+ const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);
62
+ if (!worksheet) {
63
+ throw new TRPCError({
64
+ code: "FORBIDDEN",
65
+ message: "Only class teachers can update worksheets",
66
+ });
67
+ }
36
68
  return updateWorksheet(worksheetId, data);
37
69
  }
38
- export async function deleteWorksheetRecord(worksheetId) {
70
+ export async function deleteWorksheetRecord(worksheetId, userId) {
71
+ const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);
72
+ if (!worksheet) {
73
+ throw new TRPCError({
74
+ code: "FORBIDDEN",
75
+ message: "Only class teachers can delete worksheets",
76
+ });
77
+ }
39
78
  return deleteWorksheet(worksheetId);
40
79
  }
41
80
  export async function createWorksheetRecord(classId, name) {
42
81
  return createWorksheet({ classId, name });
43
82
  }
44
- export async function addQuestionToWorksheet(worksheetId, data) {
45
- const worksheet = await findWorksheetByIdMinimal(worksheetId);
46
- if (!worksheet) {
83
+ /**
84
+ * Create a worksheet by converting a PDF (URL) into structured questions.
85
+ * Uses the `pdfToWorksheet` pipeline to do inference + persistence.
86
+ */
87
+ export async function createWorksheetFromPdf(classId, url) {
88
+ const created = await pdfToWorksheet(url, classId);
89
+ if (!created) {
90
+ throw new TRPCError({
91
+ code: "INTERNAL_SERVER_ERROR",
92
+ message: "Failed to create worksheet from PDF",
93
+ });
94
+ }
95
+ return created;
96
+ }
97
+ /**
98
+ * Create a worksheet from a PDF that was uploaded through the direct-upload flow.
99
+ */
100
+ export async function createWorksheetFromUploadedPdf(classId, fileId, userId) {
101
+ const file = await prisma.file.findFirst({
102
+ where: {
103
+ id: fileId,
104
+ userId,
105
+ uploadStatus: "COMPLETED",
106
+ },
107
+ select: {
108
+ id: true,
109
+ path: true,
110
+ type: true,
111
+ },
112
+ });
113
+ if (!file) {
47
114
  throw new TRPCError({
48
115
  code: "NOT_FOUND",
49
- message: "Worksheet not found",
116
+ message: "Uploaded file not found or not ready",
117
+ });
118
+ }
119
+ const isPdf = file.type === "application/pdf" || file.path.toLowerCase().endsWith(".pdf");
120
+ if (!isPdf) {
121
+ throw new TRPCError({
122
+ code: "BAD_REQUEST",
123
+ message: "Only PDF files can be converted into worksheets",
124
+ });
125
+ }
126
+ const signedUrl = await getFileUrl(file.path);
127
+ return createWorksheetFromPdf(classId, signedUrl);
128
+ }
129
+ export async function addQuestionToWorksheet(worksheetId, userId, data) {
130
+ const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);
131
+ if (!worksheet) {
132
+ throw new TRPCError({
133
+ code: "FORBIDDEN",
134
+ message: "Only class teachers can modify worksheet questions",
50
135
  });
51
136
  }
52
137
  return createWorksheetQuestion({
@@ -54,12 +139,12 @@ export async function addQuestionToWorksheet(worksheetId, data) {
54
139
  ...data,
55
140
  });
56
141
  }
57
- export async function reorderWorksheetQuestions(worksheetId, movedId, position, targetId) {
58
- const worksheet = await findWorksheetByIdMinimal(worksheetId);
142
+ export async function reorderWorksheetQuestions(worksheetId, userId, movedId, position, targetId) {
143
+ const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);
59
144
  if (!worksheet) {
60
145
  throw new TRPCError({
61
- code: "NOT_FOUND",
62
- message: "Worksheet not found",
146
+ code: "FORBIDDEN",
147
+ message: "Only class teachers can reorder worksheet questions",
63
148
  });
64
149
  }
65
150
  const questions = await findQuestionsByWorksheetId(worksheetId);
@@ -99,51 +184,64 @@ export async function reorderWorksheetQuestions(worksheetId, movedId, position,
99
184
  })));
100
185
  return next;
101
186
  }
102
- export async function updateWorksheetQuestionRecord(worksheetId, questionId, data) {
103
- const worksheet = await findWorksheetByIdMinimal(worksheetId);
104
- if (!worksheet) {
187
+ export async function updateWorksheetQuestionRecord(worksheetId, questionId, userId, data) {
188
+ const question = await findWorksheetQuestionByIdForTeacher(questionId, userId);
189
+ if (!question || question.worksheetId !== worksheetId) {
105
190
  throw new TRPCError({
106
- code: "NOT_FOUND",
107
- message: "Worksheet not found",
191
+ code: "FORBIDDEN",
192
+ message: "Only class teachers can update worksheet questions",
108
193
  });
109
194
  }
110
195
  return updateWorksheetQuestion(questionId, data);
111
196
  }
112
- export async function deleteWorksheetQuestionRecord(worksheetId, questionId) {
113
- const worksheet = await findWorksheetByIdMinimal(worksheetId);
114
- if (!worksheet) {
197
+ export async function deleteWorksheetQuestionRecord(worksheetId, questionId, userId) {
198
+ const question = await findWorksheetQuestionByIdForTeacher(questionId, userId);
199
+ if (!question || question.worksheetId !== worksheetId) {
115
200
  throw new TRPCError({
116
- code: "NOT_FOUND",
117
- message: "Worksheet not found",
201
+ code: "FORBIDDEN",
202
+ message: "Only class teachers can delete worksheet questions",
118
203
  });
119
204
  }
120
205
  return deleteWorksheetQuestion(questionId);
121
206
  }
122
- export async function getWorksheetSubmission(worksheetId, submissionId) {
123
- const submission = await findSubmissionById(submissionId);
207
+ export async function getWorksheetSubmission(worksheetId, submissionId, userId) {
208
+ const worksheet = await findWorksheetByIdForClassMember(worksheetId, userId);
209
+ if (!worksheet) {
210
+ throw new TRPCError({
211
+ code: "FORBIDDEN",
212
+ message: "You do not have access to this worksheet",
213
+ });
214
+ }
215
+ const submission = await findSubmissionByIdForWorksheetAccess(submissionId, worksheetId, worksheet.classId, userId);
124
216
  if (!submission) {
125
217
  throw new TRPCError({
126
- code: "NOT_FOUND",
127
- message: "Submission not found",
218
+ code: "FORBIDDEN",
219
+ message: "You do not have access to this worksheet submission",
128
220
  });
129
221
  }
130
222
  return findOrCreateWorksheetResponse(submissionId, worksheetId, submission.studentId);
131
223
  }
132
224
  export async function answerWorksheetQuestion(worksheetResponseId, questionId, response, userId) {
133
- const worksheetResponse = await findWorksheetResponseWithResponses(worksheetResponseId, questionId);
225
+ const worksheetResponse = await findWorksheetResponseWithResponsesForStudent(worksheetResponseId, userId, questionId);
134
226
  if (!worksheetResponse) {
227
+ throw new TRPCError({
228
+ code: "FORBIDDEN",
229
+ message: "You can only answer your own worksheet responses",
230
+ });
231
+ }
232
+ const question = await findWorksheetQuestionByIdInWorksheet(questionId, worksheetResponse.worksheetId);
233
+ if (!question) {
135
234
  throw new TRPCError({
136
235
  code: "NOT_FOUND",
137
- message: "Worksheet response not found",
236
+ message: "Worksheet question not found",
138
237
  });
139
238
  }
140
- const question = await findWorksheetQuestionById(questionId);
141
- const isMarkableByAlgo = question?.type === "MULTIPLE_CHOICE" || question?.type === "TRUE_FALSE";
142
- const marksAwardedIfCorrect = question?.points || 0;
239
+ const isMarkableByAlgo = question.type === "MULTIPLE_CHOICE" || question.type === "TRUE_FALSE";
240
+ const marksAwardedIfCorrect = question.points || 0;
143
241
  const correctAnswer = isMarkableByAlgo
144
- ? question?.type === "MULTIPLE_CHOICE"
145
- ? question?.options?.find((o) => o.isCorrect)?.id
146
- : question?.answer?.toString()
242
+ ? question.type === "MULTIPLE_CHOICE"
243
+ ? question.options?.find((o) => o.isCorrect)?.id
244
+ : question.answer?.toString()
147
245
  : null;
148
246
  const existingResponse = worksheetResponse.responses[0];
149
247
  if (existingResponse) {
@@ -178,14 +276,51 @@ export async function answerWorksheetQuestion(worksheetResponseId, questionId, r
178
276
  });
179
277
  return updated;
180
278
  }
181
- export async function cancelGrading(worksheetResponseId, progressId) {
279
+ export async function cancelGrading(worksheetResponseId, progressId, userId) {
280
+ const progress = await findStudentQuestionProgressByIdForTeacherAndResponse(progressId, worksheetResponseId, userId);
281
+ if (!progress) {
282
+ throw new TRPCError({
283
+ code: "FORBIDDEN",
284
+ message: "Only class teachers can cancel worksheet grading",
285
+ });
286
+ }
182
287
  return cancelGradePipeline(worksheetResponseId, progressId);
183
288
  }
184
- export async function regradeQuestion(worksheetResponseId, progressId) {
289
+ export async function regradeQuestion(worksheetResponseId, progressId, userId) {
290
+ const progress = await findStudentQuestionProgressByIdForTeacherAndResponse(progressId, worksheetResponseId, userId);
291
+ if (!progress) {
292
+ throw new TRPCError({
293
+ code: "FORBIDDEN",
294
+ message: "Only class teachers can regrade worksheet answers",
295
+ });
296
+ }
185
297
  return regradeWorksheetPipeline(worksheetResponseId, progressId);
186
298
  }
187
- export async function gradeAnswer(questionId, studentWorksheetResponseId, data) {
299
+ export async function gradeAnswer(questionId, studentWorksheetResponseId, userId, data) {
300
+ const worksheetResponse = await findWorksheetResponseByIdForTeacher(studentWorksheetResponseId, userId);
301
+ if (!worksheetResponse) {
302
+ throw new TRPCError({
303
+ code: "FORBIDDEN",
304
+ message: "Only class teachers can grade worksheet answers",
305
+ });
306
+ }
307
+ const question = await findWorksheetQuestionByIdInWorksheet(questionId, worksheetResponse.worksheetId);
308
+ if (!question) {
309
+ throw new TRPCError({
310
+ code: "NOT_FOUND",
311
+ message: "Worksheet question not found",
312
+ });
313
+ }
188
314
  if (data.responseId) {
315
+ const existingProgress = await findStudentQuestionProgressByIdForTeacher(data.responseId, userId);
316
+ if (!existingProgress ||
317
+ existingProgress.studentWorksheetResponseId !== studentWorksheetResponseId ||
318
+ existingProgress.questionId !== questionId) {
319
+ throw new TRPCError({
320
+ code: "FORBIDDEN",
321
+ message: "Only class teachers can grade worksheet answers",
322
+ });
323
+ }
189
324
  return updateStudentQuestionProgressForGrading(data.responseId, {
190
325
  isCorrect: data.isCorrect,
191
326
  feedback: data.feedback,
@@ -193,16 +328,6 @@ export async function gradeAnswer(questionId, studentWorksheetResponseId, data)
193
328
  points: data.points,
194
329
  });
195
330
  }
196
- const worksheetResponse = await prisma.studentWorksheetResponse.findUnique({
197
- where: { id: studentWorksheetResponseId },
198
- select: { studentId: true },
199
- });
200
- if (!worksheetResponse) {
201
- throw new TRPCError({
202
- code: "NOT_FOUND",
203
- message: "Student worksheet response not found",
204
- });
205
- }
206
331
  const existing = await findStudentQuestionProgress(worksheetResponse.studentId, questionId, studentWorksheetResponseId);
207
332
  if (existing) {
208
333
  return updateStudentQuestionProgressForGrading(existing.id, {
@@ -225,6 +350,13 @@ export async function gradeAnswer(questionId, studentWorksheetResponseId, data)
225
350
  });
226
351
  }
227
352
  export async function addCommentToResponse(responseId, comment, authorId) {
353
+ const progress = await findStudentQuestionProgressByIdForTeacher(responseId, authorId);
354
+ if (!progress) {
355
+ throw new TRPCError({
356
+ code: "FORBIDDEN",
357
+ message: "Only class teachers can comment on worksheet responses",
358
+ });
359
+ }
228
360
  return createComment({
229
361
  studentQuestionProgressId: responseId,
230
362
  content: comment,
@@ -232,4 +364,4 @@ export async function addCommentToResponse(responseId, comment, authorId) {
232
364
  });
233
365
  }
234
366
  //# sourceMappingURL=worksheet.js.map
235
- //# debugId=cffbcf20-cef6-5fd4-979f-670d50592d0a
367
+ //# debugId=2fcbad58-5215-5f4a-a912-82db38a85645
@@ -1 +1 @@
1
- {"version":3,"file":"worksheet.js","sources":["services/worksheet.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Worksheet service – CRUD for worksheets, questions, submissions, and AI grading.\n * Integrates with gradeWorksheet pipeline for auto-grading.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { GenerationStatus, type WorksheetQuestionType } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { cancelGradePipeline, regradeWorksheetPipeline } from \"../pipelines/gradeWorksheet.js\";\nimport {\n findWorksheetById,\n findWorksheetByIdMinimal,\n findWorksheetsByClassId,\n createWorksheet,\n updateWorksheet,\n deleteWorksheet,\n findQuestionsByWorksheetId,\n createWorksheetQuestion,\n updateWorksheetQuestion,\n deleteWorksheetQuestion,\n findSubmissionById,\n findOrCreateWorksheetResponse,\n findWorksheetResponseWithResponses,\n findWorksheetQuestionById,\n updateStudentQuestionProgress,\n createStudentQuestionProgress,\n findStudentQuestionProgress,\n updateStudentQuestionProgressForGrading,\n createStudentQuestionProgressForGrading,\n createComment,\n} from \"../models/worksheet.js\";\n\ntype MCQOptions = { id: string; text: string; isCorrect: boolean }[];\n\n/** Get worksheet with questions and mark schemes. */\nexport async function getWorksheet(worksheetId: string) {\n const worksheet = await findWorksheetById(worksheetId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet not found\",\n });\n }\n return worksheet;\n}\n\n/** Check if worksheet exists. */\nexport async function worksheetExists(id: string) {\n const worksheet = await findWorksheetByIdMinimal(id);\n return !!worksheet;\n}\n\nexport async function listWorksheets(classId: string) {\n const worksheets = await findWorksheetsByClassId(classId);\n return worksheets.map((w) => ({\n ...w,\n questionCount: w.questions.length,\n }));\n}\n\nexport async function updateWorksheetRecord(\n worksheetId: string,\n data: { name?: string }\n) {\n return updateWorksheet(worksheetId, data);\n}\n\nexport async function deleteWorksheetRecord(worksheetId: string) {\n return deleteWorksheet(worksheetId);\n}\n\nexport async function createWorksheetRecord(classId: string, name: string) {\n return createWorksheet({ classId, name });\n}\n\nexport async function addQuestionToWorksheet(\n worksheetId: string,\n data: {\n question: string;\n answer: string;\n points?: number;\n options?: object;\n markScheme?: object;\n type: WorksheetQuestionType;\n }\n) {\n const worksheet = await findWorksheetByIdMinimal(worksheetId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet not found\",\n });\n }\n return createWorksheetQuestion({\n worksheetId,\n ...data,\n });\n}\n\nexport async function reorderWorksheetQuestions(\n worksheetId: string,\n movedId: string,\n position: \"before\" | \"after\",\n targetId: string\n) {\n const worksheet = await findWorksheetByIdMinimal(worksheetId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet not found\",\n });\n }\n\n const questions = await findQuestionsByWorksheetId(worksheetId);\n const movedIdx = questions.findIndex((q) => q.id === movedId);\n if (movedIdx === -1) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Moved question not found\",\n });\n }\n const targetIdx = questions.findIndex((q) => q.id === targetId);\n if (targetIdx === -1) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Target question not found\",\n });\n }\n\n const withoutMoved = questions.filter((q) => q.id !== movedId);\n const next =\n position === \"before\"\n ? [\n ...withoutMoved.slice(0, targetIdx).map((item) => ({ id: item.id })),\n { id: movedId },\n ...withoutMoved.slice(targetIdx).map((item) => ({ id: item.id })),\n ]\n : [\n ...withoutMoved\n .slice(0, targetIdx + 1)\n .map((item) => ({ id: item.id })),\n { id: movedId },\n ...withoutMoved\n .slice(targetIdx + 1)\n .map((item) => ({ id: item.id })),\n ];\n\n await prisma.$transaction(\n next.map((item, index) =>\n prisma.worksheetQuestion.update({\n where: { id: item.id },\n data: { order: index },\n })\n )\n );\n return next;\n}\n\nexport async function updateWorksheetQuestionRecord(\n worksheetId: string,\n questionId: string,\n data: {\n question?: string;\n answer?: string;\n points?: number;\n options?: object;\n markScheme?: object;\n type?: WorksheetQuestionType;\n }\n) {\n const worksheet = await findWorksheetByIdMinimal(worksheetId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet not found\",\n });\n }\n return updateWorksheetQuestion(questionId, data);\n}\n\nexport async function deleteWorksheetQuestionRecord(\n worksheetId: string,\n questionId: string\n) {\n const worksheet = await findWorksheetByIdMinimal(worksheetId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet not found\",\n });\n }\n return deleteWorksheetQuestion(questionId);\n}\n\nexport async function getWorksheetSubmission(\n worksheetId: string,\n submissionId: string\n) {\n const submission = await findSubmissionById(submissionId);\n if (!submission) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Submission not found\",\n });\n }\n return findOrCreateWorksheetResponse(\n submissionId,\n worksheetId,\n submission.studentId\n );\n}\n\nexport async function answerWorksheetQuestion(\n worksheetResponseId: string,\n questionId: string,\n response: string,\n userId: string\n) {\n const worksheetResponse = await findWorksheetResponseWithResponses(\n worksheetResponseId,\n questionId\n );\n if (!worksheetResponse) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet response not found\",\n });\n }\n\n const question = await findWorksheetQuestionById(questionId);\n const isMarkableByAlgo =\n question?.type === \"MULTIPLE_CHOICE\" || question?.type === \"TRUE_FALSE\";\n const marksAwardedIfCorrect = question?.points || 0;\n const correctAnswer = isMarkableByAlgo\n ? question?.type === \"MULTIPLE_CHOICE\"\n ? (question?.options as MCQOptions)?.find((o) => o.isCorrect)?.id\n : question?.answer?.toString()\n : null;\n\n const existingResponse = worksheetResponse.responses[0];\n\n if (existingResponse) {\n await updateStudentQuestionProgress(existingResponse.id, {\n response,\n ...(isMarkableByAlgo && {\n isCorrect: response === correctAnswer,\n }),\n ...(isMarkableByAlgo && {\n points: response === correctAnswer ? marksAwardedIfCorrect : 0,\n }),\n status: GenerationStatus.NOT_STARTED,\n });\n } else {\n await createStudentQuestionProgress({\n studentId: worksheetResponse.studentId,\n questionId,\n response,\n studentWorksheetResponseId: worksheetResponseId,\n ...(isMarkableByAlgo && {\n isCorrect: response === correctAnswer,\n }),\n ...(isMarkableByAlgo && {\n points: response === correctAnswer ? marksAwardedIfCorrect : 0,\n }),\n });\n }\n\n const updated = await prisma.studentWorksheetResponse.findUnique({\n where: { id: worksheetResponseId },\n include: { responses: true },\n });\n return updated!;\n}\n\nexport async function cancelGrading(\n worksheetResponseId: string,\n progressId: string\n) {\n return cancelGradePipeline(worksheetResponseId, progressId);\n}\n\nexport async function regradeQuestion(\n worksheetResponseId: string,\n progressId: string\n) {\n return regradeWorksheetPipeline(worksheetResponseId, progressId);\n}\n\nexport async function gradeAnswer(\n questionId: string,\n studentWorksheetResponseId: string,\n data: {\n responseId?: string;\n response?: string;\n isCorrect: boolean;\n feedback?: string;\n markschemeState?: object;\n points?: number;\n }\n) {\n if (data.responseId) {\n return updateStudentQuestionProgressForGrading(data.responseId, {\n isCorrect: data.isCorrect,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points,\n });\n }\n\n const worksheetResponse = await prisma.studentWorksheetResponse.findUnique({\n where: { id: studentWorksheetResponseId },\n select: { studentId: true },\n });\n if (!worksheetResponse) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Student worksheet response not found\",\n });\n }\n\n const existing = await findStudentQuestionProgress(\n worksheetResponse.studentId,\n questionId,\n studentWorksheetResponseId\n );\n\n if (existing) {\n return updateStudentQuestionProgressForGrading(existing.id, {\n isCorrect: data.isCorrect,\n response: data.response,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points,\n });\n }\n\n return createStudentQuestionProgressForGrading({\n studentId: worksheetResponse.studentId,\n questionId,\n studentWorksheetResponseId,\n response: data.response || \"\",\n isCorrect: data.isCorrect,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points || 0,\n });\n}\n\nexport async function addCommentToResponse(\n responseId: string,\n comment: string,\n authorId: string\n) {\n return createComment({\n studentQuestionProgressId: responseId,\n content: comment,\n authorId,\n });\n}\n"],"names":[],"mappings":"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","debug_id":"cffbcf20-cef6-5fd4-979f-670d50592d0a"}
1
+ {"version":3,"file":"worksheet.js","sources":["services/worksheet.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Worksheet service – CRUD for worksheets, questions, submissions, and AI grading.\n * Integrates with gradeWorksheet pipeline for auto-grading.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { GenerationStatus, type WorksheetQuestionType } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { getFileUrl } from \"../lib/fileUpload.js\";\nimport { cancelGradePipeline, regradeWorksheetPipeline } from \"../pipelines/gradeWorksheet.js\";\nimport { pdfToWorksheet } from \"../pipelines/pdfToWorksheet.js\";\nimport {\n findWorksheetByIdMinimal,\n findWorksheetByIdForClassMember,\n findWorksheetByIdForTeacher,\n findWorksheetsByClassId,\n createWorksheet,\n updateWorksheet,\n deleteWorksheet,\n findQuestionsByWorksheetId,\n createWorksheetQuestion,\n updateWorksheetQuestion,\n deleteWorksheetQuestion,\n findSubmissionByIdForWorksheetAccess,\n findOrCreateWorksheetResponse,\n findWorksheetResponseByIdForTeacher,\n findWorksheetResponseWithResponsesForStudent,\n findWorksheetQuestionByIdForTeacher,\n findWorksheetQuestionByIdInWorksheet,\n updateStudentQuestionProgress,\n createStudentQuestionProgress,\n findStudentQuestionProgress,\n updateStudentQuestionProgressForGrading,\n createStudentQuestionProgressForGrading,\n createComment,\n findStudentQuestionProgressByIdForTeacher,\n findStudentQuestionProgressByIdForTeacherAndResponse,\n} from \"../models/worksheet.js\";\n\ntype MCQOptions = { id: string; text: string; isCorrect: boolean }[];\n\nconst sanitizeQuestionOptionsForStudent = (options: unknown) => {\n if (!Array.isArray(options)) return options;\n\n return options.map((option) => {\n if (!option || typeof option !== \"object\") return option;\n\n const { isCorrect: _isCorrect, ...rest } = option as Record<string, unknown>;\n return rest;\n });\n};\n\nconst sanitizeWorksheetForStudent = <T extends {\n questions: Array<Record<string, unknown>>;\n}>(worksheet: T) => ({\n ...worksheet,\n questions: worksheet.questions.map((question) => ({\n ...question,\n answer: \"\",\n markScheme: null,\n options: sanitizeQuestionOptionsForStudent(question.options),\n })),\n});\n\n/** Get worksheet with questions and mark schemes. */\nexport async function getWorksheet(worksheetId: string, userId: string) {\n const teacherWorksheet = await findWorksheetByIdForTeacher(worksheetId, userId);\n if (teacherWorksheet) {\n return teacherWorksheet;\n }\n\n const studentWorksheet = await findWorksheetByIdForClassMember(worksheetId, userId);\n if (!studentWorksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this worksheet\",\n });\n }\n\n return sanitizeWorksheetForStudent(studentWorksheet);\n}\n\n/** Check if worksheet exists. */\nexport async function worksheetExists(id: string) {\n const worksheet = await findWorksheetByIdMinimal(id);\n return !!worksheet;\n}\n\nexport async function listWorksheets(classId: string) {\n const worksheets = await findWorksheetsByClassId(classId);\n return worksheets.map((w) => ({\n ...w,\n questionCount: w.questions.length,\n }));\n}\n\nexport async function updateWorksheetRecord(\n worksheetId: string,\n userId: string,\n data: { name?: string }\n) {\n const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can update worksheets\",\n });\n }\n return updateWorksheet(worksheetId, data);\n}\n\nexport async function deleteWorksheetRecord(worksheetId: string, userId: string) {\n const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can delete worksheets\",\n });\n }\n return deleteWorksheet(worksheetId);\n}\n\nexport async function createWorksheetRecord(classId: string, name: string) {\n return createWorksheet({ classId, name });\n}\n\n/**\n * Create a worksheet by converting a PDF (URL) into structured questions.\n * Uses the `pdfToWorksheet` pipeline to do inference + persistence.\n */\nexport async function createWorksheetFromPdf(\n classId: string,\n url: string\n) {\n const created = await pdfToWorksheet(url, classId);\n if (!created) {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Failed to create worksheet from PDF\",\n });\n }\n return created;\n}\n\n/**\n * Create a worksheet from a PDF that was uploaded through the direct-upload flow.\n */\nexport async function createWorksheetFromUploadedPdf(\n classId: string,\n fileId: string,\n userId: string\n) {\n const file = await prisma.file.findFirst({\n where: {\n id: fileId,\n userId,\n uploadStatus: \"COMPLETED\",\n },\n select: {\n id: true,\n path: true,\n type: true,\n },\n });\n\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Uploaded file not found or not ready\",\n });\n }\n\n const isPdf =\n file.type === \"application/pdf\" || file.path.toLowerCase().endsWith(\".pdf\");\n if (!isPdf) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Only PDF files can be converted into worksheets\",\n });\n }\n\n const signedUrl = await getFileUrl(file.path);\n return createWorksheetFromPdf(classId, signedUrl);\n}\n\nexport async function addQuestionToWorksheet(\n worksheetId: string,\n userId: string,\n data: {\n question: string;\n answer: string;\n points?: number;\n options?: object;\n markScheme?: object;\n type: WorksheetQuestionType;\n }\n) {\n const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can modify worksheet questions\",\n });\n }\n return createWorksheetQuestion({\n worksheetId,\n ...data,\n });\n}\n\nexport async function reorderWorksheetQuestions(\n worksheetId: string,\n userId: string,\n movedId: string,\n position: \"before\" | \"after\",\n targetId: string\n) {\n const worksheet = await findWorksheetByIdForTeacher(worksheetId, userId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can reorder worksheet questions\",\n });\n }\n\n const questions = await findQuestionsByWorksheetId(worksheetId);\n const movedIdx = questions.findIndex((q) => q.id === movedId);\n if (movedIdx === -1) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Moved question not found\",\n });\n }\n const targetIdx = questions.findIndex((q) => q.id === targetId);\n if (targetIdx === -1) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Target question not found\",\n });\n }\n\n const withoutMoved = questions.filter((q) => q.id !== movedId);\n const next =\n position === \"before\"\n ? [\n ...withoutMoved.slice(0, targetIdx).map((item) => ({ id: item.id })),\n { id: movedId },\n ...withoutMoved.slice(targetIdx).map((item) => ({ id: item.id })),\n ]\n : [\n ...withoutMoved\n .slice(0, targetIdx + 1)\n .map((item) => ({ id: item.id })),\n { id: movedId },\n ...withoutMoved\n .slice(targetIdx + 1)\n .map((item) => ({ id: item.id })),\n ];\n\n await prisma.$transaction(\n next.map((item, index) =>\n prisma.worksheetQuestion.update({\n where: { id: item.id },\n data: { order: index },\n })\n )\n );\n return next;\n}\n\nexport async function updateWorksheetQuestionRecord(\n worksheetId: string,\n questionId: string,\n userId: string,\n data: {\n question?: string;\n answer?: string;\n points?: number;\n options?: object;\n markScheme?: object;\n type?: WorksheetQuestionType;\n }\n) {\n const question = await findWorksheetQuestionByIdForTeacher(questionId, userId);\n if (!question || question.worksheetId !== worksheetId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can update worksheet questions\",\n });\n }\n return updateWorksheetQuestion(questionId, data);\n}\n\nexport async function deleteWorksheetQuestionRecord(\n worksheetId: string,\n questionId: string,\n userId: string\n) {\n const question = await findWorksheetQuestionByIdForTeacher(questionId, userId);\n if (!question || question.worksheetId !== worksheetId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can delete worksheet questions\",\n });\n }\n return deleteWorksheetQuestion(questionId);\n}\n\nexport async function getWorksheetSubmission(\n worksheetId: string,\n submissionId: string,\n userId: string\n) {\n const worksheet = await findWorksheetByIdForClassMember(worksheetId, userId);\n if (!worksheet) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this worksheet\",\n });\n }\n\n const submission = await findSubmissionByIdForWorksheetAccess(\n submissionId,\n worksheetId,\n worksheet.classId,\n userId\n );\n if (!submission) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this worksheet submission\",\n });\n }\n return findOrCreateWorksheetResponse(\n submissionId,\n worksheetId,\n submission.studentId\n );\n}\n\nexport async function answerWorksheetQuestion(\n worksheetResponseId: string,\n questionId: string,\n response: string,\n userId: string\n) {\n const worksheetResponse = await findWorksheetResponseWithResponsesForStudent(\n worksheetResponseId,\n userId,\n questionId\n );\n if (!worksheetResponse) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You can only answer your own worksheet responses\",\n });\n }\n\n const question = await findWorksheetQuestionByIdInWorksheet(\n questionId,\n worksheetResponse.worksheetId\n );\n if (!question) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet question not found\",\n });\n }\n\n const isMarkableByAlgo =\n question.type === \"MULTIPLE_CHOICE\" || question.type === \"TRUE_FALSE\";\n const marksAwardedIfCorrect = question.points || 0;\n const correctAnswer = isMarkableByAlgo\n ? question.type === \"MULTIPLE_CHOICE\"\n ? (question.options as MCQOptions)?.find((o) => o.isCorrect)?.id\n : question.answer?.toString()\n : null;\n\n const existingResponse = worksheetResponse.responses[0];\n\n if (existingResponse) {\n await updateStudentQuestionProgress(existingResponse.id, {\n response,\n ...(isMarkableByAlgo && {\n isCorrect: response === correctAnswer,\n }),\n ...(isMarkableByAlgo && {\n points: response === correctAnswer ? marksAwardedIfCorrect : 0,\n }),\n status: GenerationStatus.NOT_STARTED,\n });\n } else {\n await createStudentQuestionProgress({\n studentId: worksheetResponse.studentId,\n questionId,\n response,\n studentWorksheetResponseId: worksheetResponseId,\n ...(isMarkableByAlgo && {\n isCorrect: response === correctAnswer,\n }),\n ...(isMarkableByAlgo && {\n points: response === correctAnswer ? marksAwardedIfCorrect : 0,\n }),\n });\n }\n\n const updated = await prisma.studentWorksheetResponse.findUnique({\n where: { id: worksheetResponseId },\n include: { responses: true },\n });\n return updated!;\n}\n\nexport async function cancelGrading(\n worksheetResponseId: string,\n progressId: string,\n userId: string\n) {\n const progress = await findStudentQuestionProgressByIdForTeacherAndResponse(\n progressId,\n worksheetResponseId,\n userId\n );\n if (!progress) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can cancel worksheet grading\",\n });\n }\n return cancelGradePipeline(worksheetResponseId, progressId);\n}\n\nexport async function regradeQuestion(\n worksheetResponseId: string,\n progressId: string,\n userId: string\n) {\n const progress = await findStudentQuestionProgressByIdForTeacherAndResponse(\n progressId,\n worksheetResponseId,\n userId\n );\n if (!progress) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can regrade worksheet answers\",\n });\n }\n return regradeWorksheetPipeline(worksheetResponseId, progressId);\n}\n\nexport async function gradeAnswer(\n questionId: string,\n studentWorksheetResponseId: string,\n userId: string,\n data: {\n responseId?: string;\n response?: string;\n isCorrect: boolean;\n feedback?: string;\n markschemeState?: object;\n points?: number;\n }\n) {\n const worksheetResponse = await findWorksheetResponseByIdForTeacher(\n studentWorksheetResponseId,\n userId\n );\n if (!worksheetResponse) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can grade worksheet answers\",\n });\n }\n\n const question = await findWorksheetQuestionByIdInWorksheet(\n questionId,\n worksheetResponse.worksheetId\n );\n if (!question) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Worksheet question not found\",\n });\n }\n\n if (data.responseId) {\n const existingProgress = await findStudentQuestionProgressByIdForTeacher(\n data.responseId,\n userId\n );\n if (\n !existingProgress ||\n existingProgress.studentWorksheetResponseId !== studentWorksheetResponseId ||\n existingProgress.questionId !== questionId\n ) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can grade worksheet answers\",\n });\n }\n\n return updateStudentQuestionProgressForGrading(data.responseId, {\n isCorrect: data.isCorrect,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points,\n });\n }\n\n const existing = await findStudentQuestionProgress(\n worksheetResponse.studentId,\n questionId,\n studentWorksheetResponseId\n );\n\n if (existing) {\n return updateStudentQuestionProgressForGrading(existing.id, {\n isCorrect: data.isCorrect,\n response: data.response,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points,\n });\n }\n\n return createStudentQuestionProgressForGrading({\n studentId: worksheetResponse.studentId,\n questionId,\n studentWorksheetResponseId,\n response: data.response || \"\",\n isCorrect: data.isCorrect,\n feedback: data.feedback,\n markschemeState: data.markschemeState,\n points: data.points || 0,\n });\n}\n\nexport async function addCommentToResponse(\n responseId: string,\n comment: string,\n authorId: string\n) {\n const progress = await findStudentQuestionProgressByIdForTeacher(\n responseId,\n authorId\n );\n if (!progress) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can comment on worksheet responses\",\n });\n }\n\n return createComment({\n studentQuestionProgressId: responseId,\n content: comment,\n authorId,\n });\n}\n"],"names":[],"mappings":"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","debug_id":"2fcbad58-5215-5f4a-a912-82db38a85645"}
@@ -1 +1 @@
1
- {"version":3,"file":"trpc.d.ts","sourceRoot":"/","sources":["trpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,SAAS,EAAE,MAAM,cAAc,CAAC;AAMnD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAqB,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGnF,UAAU,oBAAoB;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,MAAM,oBAAoB,KAAG,OAAO,CAAC,OAAO,CAwBnF,CAAC;AAEF,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BZ,CAAC;AAOH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;EAAW,CAAC;AACzC,eAAO,MAAM,eAAe,yOAAqC,CAAC;AAIlE,eAAO,MAAM,kBAAkB,yOAAgC,CAAC;AAEhE,eAAO,MAAM,6BAA6B;;;;uHAEnB,CAAC;AAExB,eAAO,MAAM,yBAAyB;;;;uHAEd,CAAC;AAIzB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;EAAwB,CAAC"}
1
+ {"version":3,"file":"trpc.d.ts","sourceRoot":"/","sources":["trpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,SAAS,EAAE,MAAM,cAAc,CAAC;AAKnD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAqB,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGnF,UAAU,oBAAoB;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,MAAM,oBAAoB,KAAG,OAAO,CAAC,OAAO,CAmBnF,CAAC;AAEF,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BZ,CAAC;AAOH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;EAAW,CAAC;AACzC,eAAO,MAAM,eAAe,yOAAqC,CAAC;AAIlE,eAAO,MAAM,kBAAkB,yOAAgC,CAAC;AAEhE,eAAO,MAAM,6BAA6B;;;;uHAEnB,CAAC;AAExB,eAAO,MAAM,yBAAyB;;;;uHAEd,CAAC;AAIzB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;EAAwB,CAAC"}
package/dist/trpc.js CHANGED
@@ -1,29 +1,23 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fe8afe09-5435-5257-8a3f-ef011f89e860")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6b11f8e8-b33f-5cae-aab3-08d27c3e81e9")}catch(e){}}();
3
3
  import { initTRPC } from '@trpc/server';
4
4
  import { ZodError } from 'zod';
5
5
  import { logger } from './utils/logger.js';
6
- import { prisma } from './lib/prisma.js';
7
6
  import { createLoggingMiddleware } from './middleware/logging.js';
8
7
  import { createAuthMiddleware } from './middleware/auth.js';
9
8
  import { z } from 'zod';
10
9
  import { handlePrismaError } from './utils/prismaErrorHandler.js';
10
+ import { findUserBySessionToken } from './models/auth.js';
11
11
  export const createTRPCContext = async (opts) => {
12
12
  const { req, res } = opts;
13
- // Get user from session/token
14
- const token = req.headers.authorization?.split(' ')[1];
15
- const user = token ? await prisma.user.findFirst({
16
- where: {
17
- sessions: {
18
- some: {
19
- id: token
20
- }
21
- },
22
- },
23
- select: {
24
- id: true,
25
- }
26
- }) : null;
13
+ const userHeader = req.headers["x-user"];
14
+ const tokenFromUserHeader = typeof userHeader === "string" ? userHeader : userHeader?.[0];
15
+ const authorizationHeader = req.headers.authorization;
16
+ const tokenFromAuthorization = typeof authorizationHeader === "string" && authorizationHeader.startsWith("Bearer ")
17
+ ? authorizationHeader.slice(7)
18
+ : null;
19
+ const token = tokenFromUserHeader ?? tokenFromAuthorization;
20
+ const user = token ? await findUserBySessionToken(token) : null;
27
21
  return {
28
22
  req,
29
23
  res,
@@ -77,4 +71,4 @@ export const protectedTeacherProcedure = protectedProcedure
77
71
  // Create caller factory
78
72
  export const createCallerFactory = t.createCallerFactory;
79
73
  //# sourceMappingURL=trpc.js.map
80
- //# debugId=fe8afe09-5435-5257-8a3f-ef011f89e860
74
+ //# debugId=6b11f8e8-b33f-5cae-aab3-08d27c3e81e9
package/dist/trpc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"trpc.js","sources":["trpc.ts"],"sourceRoot":"/","sourcesContent":["import { initTRPC, TRPCError } from '@trpc/server';\nimport { ZodError } from 'zod';\nimport { logger } from './utils/logger.js';\nimport { prisma } from './lib/prisma.js';\nimport { createLoggingMiddleware } from './middleware/logging.js';\nimport { createAuthMiddleware } from './middleware/auth.js';\nimport { Request, Response } from 'express';\nimport { z } from 'zod';\nimport { handlePrismaError, PrismaErrorInfo } from './utils/prismaErrorHandler.js';\nimport { generalLimiter } from './middleware/security.js';\n\ninterface CreateContextOptions {\n req: Request;\n res: Response;\n}\n\nexport type Context = {\n req: Request;\n res: Response;\n user: { id: string } | null;\n meta?: {\n classId?: string;\n institutionId?: string;\n };\n};\n\nexport const createTRPCContext = async (opts: CreateContextOptions): Promise<Context> => {\n const { req, res } = opts;\n \n // Get user from session/token\n const token = req.headers.authorization?.split(' ')[1];\n const user = token ? await prisma.user.findFirst({\n where: {\n sessions: {\n some: {\n id: token\n }\n },\n },\n select: {\n id: true,\n }\n }) : null;\n \n return {\n req,\n res,\n user,\n meta: {},\n };\n};\n\nexport const t = initTRPC.context<Context>().create({\n errorFormatter({ shape, error }) {\n // Handle Prisma errors specifically\n let prismaErrorInfo: PrismaErrorInfo | null = null;\n if (error.cause) {\n try {\n prismaErrorInfo = handlePrismaError(error.cause);\n } catch (e) {\n // If Prisma error handling fails, continue with normal error handling\n }\n }\n\n logger.error('tRPC Error', {\n code: shape.code,\n message: error.message,\n cause: error.cause,\n stack: error.stack,\n prismaError: prismaErrorInfo,\n });\n\n return {\n ...shape,\n data: {\n ...shape.data,\n zodError:\n error.cause instanceof ZodError ? error.cause.flatten() : null,\n prismaError: prismaErrorInfo,\n },\n };\n },\n});\n\n// Create middleware\nconst loggingMiddleware = createLoggingMiddleware(t);\nconst { isAuthed, isMemberInClass, isTeacherInClass } = createAuthMiddleware(t);\n\n// Base procedures\nexport const createTRPCRouter = t.router;\nexport const publicProcedure = t.procedure.use(loggingMiddleware);\n\n\n// Protected procedures\nexport const protectedProcedure = publicProcedure.use(isAuthed);\n\nexport const protectedClassMemberProcedure = protectedProcedure\n .input(z.object({ classId: z.string() }).passthrough())\n .use(isMemberInClass);\n\nexport const protectedTeacherProcedure = protectedProcedure\n .input(z.object({ classId: z.string() }).passthrough())\n .use(isTeacherInClass);\n\n\n// Create caller factory\nexport const createCallerFactory = t.createCallerFactory; "],"names":[],"mappings":"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","debug_id":"fe8afe09-5435-5257-8a3f-ef011f89e860"}
1
+ {"version":3,"file":"trpc.js","sources":["trpc.ts"],"sourceRoot":"/","sourcesContent":["import { initTRPC, TRPCError } from '@trpc/server';\nimport { ZodError } from 'zod';\nimport { logger } from './utils/logger.js';\nimport { createLoggingMiddleware } from './middleware/logging.js';\nimport { createAuthMiddleware } from './middleware/auth.js';\nimport { Request, Response } from 'express';\nimport { z } from 'zod';\nimport { handlePrismaError, PrismaErrorInfo } from './utils/prismaErrorHandler.js';\nimport { findUserBySessionToken } from './models/auth.js';\n\ninterface CreateContextOptions {\n req: Request;\n res: Response;\n}\n\nexport type Context = {\n req: Request;\n res: Response;\n user: { id: string } | null;\n meta?: {\n classId?: string;\n institutionId?: string;\n };\n};\n\nexport const createTRPCContext = async (opts: CreateContextOptions): Promise<Context> => {\n const { req, res } = opts;\n\n const userHeader = req.headers[\"x-user\"];\n const tokenFromUserHeader = typeof userHeader === \"string\" ? userHeader : userHeader?.[0];\n const authorizationHeader = req.headers.authorization;\n const tokenFromAuthorization =\n typeof authorizationHeader === \"string\" && authorizationHeader.startsWith(\"Bearer \")\n ? authorizationHeader.slice(7)\n : null;\n const token = tokenFromUserHeader ?? tokenFromAuthorization;\n const user = token ? await findUserBySessionToken(token) : null;\n\n return {\n req,\n res,\n user,\n meta: {},\n };\n};\n\nexport const t = initTRPC.context<Context>().create({\n errorFormatter({ shape, error }) {\n // Handle Prisma errors specifically\n let prismaErrorInfo: PrismaErrorInfo | null = null;\n if (error.cause) {\n try {\n prismaErrorInfo = handlePrismaError(error.cause);\n } catch (e) {\n // If Prisma error handling fails, continue with normal error handling\n }\n }\n\n logger.error('tRPC Error', {\n code: shape.code,\n message: error.message,\n cause: error.cause,\n stack: error.stack,\n prismaError: prismaErrorInfo,\n });\n\n return {\n ...shape,\n data: {\n ...shape.data,\n zodError:\n error.cause instanceof ZodError ? error.cause.flatten() : null,\n prismaError: prismaErrorInfo,\n },\n };\n },\n});\n\n// Create middleware\nconst loggingMiddleware = createLoggingMiddleware(t);\nconst { isAuthed, isMemberInClass, isTeacherInClass } = createAuthMiddleware(t);\n\n// Base procedures\nexport const createTRPCRouter = t.router;\nexport const publicProcedure = t.procedure.use(loggingMiddleware);\n\n\n// Protected procedures\nexport const protectedProcedure = publicProcedure.use(isAuthed);\n\nexport const protectedClassMemberProcedure = protectedProcedure\n .input(z.object({ classId: z.string() }).passthrough())\n .use(isMemberInClass);\n\nexport const protectedTeacherProcedure = protectedProcedure\n .input(z.object({ classId: z.string() }).passthrough())\n .use(isTeacherInClass);\n\n\n// Create caller factory\nexport const createCallerFactory = t.createCallerFactory; "],"names":[],"mappings":"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","debug_id":"6b11f8e8-b33f-5cae-aab3-08d27c3e81e9"}
@@ -2,9 +2,18 @@
2
2
  * Inference util – OpenAI client, inference() for structured output, sendAIMessage for chat.
3
3
  */
4
4
  import OpenAI from 'openai';
5
+ import type { ResponseInput } from "openai/resources/responses/responses.js";
6
+ import { Prisma } from '@prisma/client';
5
7
  import { ZodSchema } from 'zod';
6
8
  export declare const inferenceClient: OpenAI;
7
9
  export declare const openAIClient: OpenAI;
10
+ export interface InferenceOptions {
11
+ reason?: string;
12
+ metadata?: Prisma.InputJsonValue;
13
+ model?: string;
14
+ temperature?: number;
15
+ maxTokens?: number;
16
+ }
8
17
  export interface LabChatContext {
9
18
  subject: string;
10
19
  topic: string;
@@ -46,7 +55,7 @@ export declare function sendAIMessage(content: string, conversationId: string, o
46
55
  createdAt: Date;
47
56
  meta?: Record<string, any>;
48
57
  }>;
49
- export declare function inference<T>(content: string | OpenAI.Chat.Completions.ChatCompletionMessageParam[], format?: ZodSchema): Promise<T>;
58
+ export declare function inference<T>(content: string | OpenAI.Chat.Completions.ChatCompletionMessageParam[] | ResponseInput, format?: ZodSchema, options?: InferenceOptions): Promise<T>;
50
59
  /**
51
60
  * Get available inference models (for admin/config purposes)
52
61
  */
@@ -1 +1 @@
1
- {"version":3,"file":"inference.d.ts","sourceRoot":"/","sources":["utils/inference.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAM5B,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAKhC,eAAO,MAAM,eAAe,QAG1B,CAAC;AAEH,eAAO,MAAM,YAAY,QAAe,CAAC;AAGzC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;IACrD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC3B,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC,CAAC;CACE,GACL,OAAO,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B,CAAC,CAwED;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,EACtE,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CA8DZ;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAW5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD"}
1
+ {"version":3,"file":"inference.d.ts","sourceRoot":"/","sources":["utils/inference.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAM7E,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAGhC,eAAO,MAAM,eAAe,QAG1B,CAAC;AAEH,eAAO,MAAM,YAAY,QAAe,CAAC;AASzC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoBD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;IACrD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAgHD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC3B,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC,CAAC;CACE,GACL,OAAO,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B,CAAC,CAoED;AAsCD,wBAAsB,SAAS,CAAC,CAAC,EAC/B,OAAO,EACH,MAAM,GACN,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,GACpD,aAAa,EACjB,MAAM,CAAC,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,CAAC,CAAC,CA6GZ;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAW5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD"}