@studious-lms/server 1.5.0 → 1.6.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 (126) hide show
  1. package/dist/index.js +15 -3
  2. package/dist/index.js.map +1 -1
  3. package/dist/lib/config/cors.d.ts.map +1 -1
  4. package/dist/lib/config/cors.js +3 -2
  5. package/dist/lib/config/cors.js.map +1 -1
  6. package/dist/lib/pusher.d.ts +7 -1
  7. package/dist/lib/pusher.d.ts.map +1 -1
  8. package/dist/lib/pusher.js +9 -3
  9. package/dist/lib/pusher.js.map +1 -1
  10. package/dist/models/attendance.d.ts +16 -7
  11. package/dist/models/attendance.d.ts.map +1 -1
  12. package/dist/models/attendance.js +17 -2
  13. package/dist/models/attendance.js.map +1 -1
  14. package/dist/models/conversation.d.ts +17 -17
  15. package/dist/pipelines/aiLabChat.d.ts +20 -9
  16. package/dist/pipelines/aiLabChat.d.ts.map +1 -1
  17. package/dist/pipelines/aiLabChat.js +62 -74
  18. package/dist/pipelines/aiLabChat.js.map +1 -1
  19. package/dist/pipelines/aiNewtonChat.d.ts +13 -4
  20. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
  21. package/dist/pipelines/aiNewtonChat.js +39 -27
  22. package/dist/pipelines/aiNewtonChat.js.map +1 -1
  23. package/dist/pipelines/pdfToWorksheet.d.ts +31 -2
  24. package/dist/pipelines/pdfToWorksheet.d.ts.map +1 -1
  25. package/dist/pipelines/pdfToWorksheet.js +160 -28
  26. package/dist/pipelines/pdfToWorksheet.js.map +1 -1
  27. package/dist/routers/_app.d.ts +18 -4
  28. package/dist/routers/_app.d.ts.map +1 -1
  29. package/dist/routers/assignment.d.ts.map +1 -1
  30. package/dist/routers/assignment.js +64 -4
  31. package/dist/routers/assignment.js.map +1 -1
  32. package/dist/routers/labChat.d.ts +1 -0
  33. package/dist/routers/labChat.d.ts.map +1 -1
  34. package/dist/routers/message.d.ts +3 -0
  35. package/dist/routers/message.d.ts.map +1 -1
  36. package/dist/routers/newtonChat.d.ts +1 -0
  37. package/dist/routers/newtonChat.d.ts.map +1 -1
  38. package/dist/routers/worksheet.d.ts +4 -2
  39. package/dist/routers/worksheet.d.ts.map +1 -1
  40. package/dist/routers/worksheet.js +16 -6
  41. package/dist/routers/worksheet.js.map +1 -1
  42. package/dist/services/announcement.js +4 -4
  43. package/dist/services/announcement.js.map +1 -1
  44. package/dist/services/assignment.d.ts.map +1 -1
  45. package/dist/services/assignment.js +16 -6
  46. package/dist/services/assignment.js.map +1 -1
  47. package/dist/services/attendance.d.ts.map +1 -1
  48. package/dist/services/attendance.js +68 -4
  49. package/dist/services/attendance.js.map +1 -1
  50. package/dist/services/labChat.d.ts +8 -1
  51. package/dist/services/labChat.d.ts.map +1 -1
  52. package/dist/services/labChat.js +101 -42
  53. package/dist/services/labChat.js.map +1 -1
  54. package/dist/services/message.d.ts +3 -0
  55. package/dist/services/message.d.ts.map +1 -1
  56. package/dist/services/message.js +8 -2
  57. package/dist/services/message.js.map +1 -1
  58. package/dist/services/newtonChat.d.ts +1 -0
  59. package/dist/services/newtonChat.d.ts.map +1 -1
  60. package/dist/services/newtonChat.js +40 -17
  61. package/dist/services/newtonChat.js.map +1 -1
  62. package/dist/services/worksheet.d.ts +15 -6
  63. package/dist/services/worksheet.d.ts.map +1 -1
  64. package/dist/services/worksheet.js +58 -12
  65. package/dist/services/worksheet.js.map +1 -1
  66. package/dist/utils/inference.d.ts +50 -1
  67. package/dist/utils/inference.d.ts.map +1 -1
  68. package/dist/utils/inference.js +167 -2
  69. package/dist/utils/inference.js.map +1 -1
  70. package/dist/workers/index.js +13 -3
  71. package/dist/workers/index.js.map +1 -1
  72. package/dist/workers/processors/aiLabChat.d.ts +7 -0
  73. package/dist/workers/processors/aiLabChat.d.ts.map +1 -0
  74. package/dist/workers/processors/aiLabChat.js +52 -0
  75. package/dist/workers/processors/aiLabChat.js.map +1 -0
  76. package/dist/workers/processors/aiNewtonChat.d.ts +7 -0
  77. package/dist/workers/processors/aiNewtonChat.d.ts.map +1 -0
  78. package/dist/workers/processors/aiNewtonChat.js +57 -0
  79. package/dist/workers/processors/aiNewtonChat.js.map +1 -0
  80. package/dist/workers/processors/createRunJobWorker.d.ts +46 -0
  81. package/dist/workers/processors/createRunJobWorker.d.ts.map +1 -0
  82. package/dist/workers/processors/createRunJobWorker.js +118 -0
  83. package/dist/workers/processors/createRunJobWorker.js.map +1 -0
  84. package/dist/workers/processors/gradeWorksheet.d.ts +6 -0
  85. package/dist/workers/processors/gradeWorksheet.d.ts.map +1 -0
  86. package/dist/workers/processors/gradeWorksheet.js +19 -0
  87. package/dist/workers/processors/gradeWorksheet.js.map +1 -0
  88. package/dist/workers/processors/pdfToWorksheet.d.ts +5 -6
  89. package/dist/workers/processors/pdfToWorksheet.d.ts.map +1 -1
  90. package/dist/workers/processors/pdfToWorksheet.js +15 -95
  91. package/dist/workers/processors/pdfToWorksheet.js.map +1 -1
  92. package/dist/workers/processors/studentProgressChat.d.ts +8 -0
  93. package/dist/workers/processors/studentProgressChat.d.ts.map +1 -0
  94. package/dist/workers/processors/studentProgressChat.js +27 -0
  95. package/dist/workers/processors/studentProgressChat.js.map +1 -0
  96. package/dist/workers/queues.d.ts +20 -4
  97. package/dist/workers/queues.d.ts.map +1 -1
  98. package/dist/workers/queues.js +3 -3
  99. package/dist/workers/queues.js.map +1 -1
  100. package/package.json +3 -3
  101. package/src/index.ts +12 -1
  102. package/src/lib/config/cors.ts +1 -0
  103. package/src/lib/pusher.ts +7 -1
  104. package/src/models/attendance.ts +15 -0
  105. package/src/pipelines/aiLabChat.ts +70 -78
  106. package/src/pipelines/aiNewtonChat.ts +47 -31
  107. package/src/pipelines/pdfToWorksheet.ts +224 -32
  108. package/src/routers/assignment.ts +74 -3
  109. package/src/routers/worksheet.ts +25 -4
  110. package/src/services/announcement.ts +2 -2
  111. package/src/services/assignment.ts +18 -4
  112. package/src/services/attendance.ts +87 -2
  113. package/src/services/labChat.ts +107 -47
  114. package/src/services/message.ts +6 -0
  115. package/src/services/newtonChat.ts +46 -25
  116. package/src/services/worksheet.ts +71 -10
  117. package/src/utils/inference.ts +209 -1
  118. package/src/workers/index.ts +11 -1
  119. package/src/workers/processors/aiLabChat.ts +65 -0
  120. package/src/workers/processors/aiNewtonChat.ts +75 -0
  121. package/src/workers/processors/createRunJobWorker.ts +164 -0
  122. package/src/workers/processors/gradeWorksheet.ts +16 -0
  123. package/src/workers/processors/pdfToWorksheet.ts +12 -114
  124. package/src/workers/processors/studentProgressChat.ts +28 -0
  125. package/src/workers/queues.ts +20 -5
  126. package/tests/integration/routers/attendance.test.ts +60 -1
@@ -0,0 +1,28 @@
1
+ import { chatAboutStudentProgress } from '../../services/studentProgress.js';
2
+ import { createRunJobWorker } from './createRunJobWorker.js';
3
+
4
+ export const studentProgressChatWorker = createRunJobWorker({
5
+ type: 'STUDENT_PROGRESS_CHAT',
6
+ workerOptions: {
7
+ concurrency: 4,
8
+ limiter: { max: 20, duration: 60_000 },
9
+ },
10
+ run: async ({ classId, studentId, message }, ctx) => {
11
+ // `chatAboutStudentProgress` runs an authorization check using the viewer
12
+ // id, so callers MUST pass `userId` via `enqueueRunJob` options for the
13
+ // service to receive it here.
14
+ if (!ctx.userId) {
15
+ throw new Error(
16
+ 'STUDENT_PROGRESS_CHAT requires `userId` on the RunJob (set via enqueueRunJob options)',
17
+ );
18
+ }
19
+
20
+ const response = await chatAboutStudentProgress(ctx.userId, {
21
+ classId,
22
+ studentId,
23
+ message,
24
+ });
25
+
26
+ return response;
27
+ },
28
+ });
@@ -26,15 +26,30 @@ const DEFAULT_JOB_OPTIONS: JobsOptions = {
26
26
  * The queue name string must match what the corresponding processor passes
27
27
  * to `new Worker(<name>, ...)`.
28
28
  */
29
- type JobInputs = {
30
- PDF_TO_WORKSHEET: { gcsUrl: string; classId: string };
29
+ export type JobInputs = {
30
+ /**
31
+ * `worksheetId` is the placeholder Worksheet row created synchronously by
32
+ * the producer (so the client has an id to navigate to). The pipeline fills
33
+ * that row in asynchronously and broadcasts progress on the per-worksheet
34
+ * job channel.
35
+ */
36
+ PDF_TO_WORKSHEET: { gcsUrl: string; classId: string; worksheetId: string };
31
37
  GRADE_WORKSHEET: { worksheetResponseId: string };
32
- AI_LAB_CHAT: { conversationId: string; messageId: string };
33
- AI_NEWTON_CHAT: { conversationId: string; messageId: string };
38
+ /**
39
+ * `aiMessageId` is the placeholder AI Message row created synchronously by
40
+ * the producer before enqueue (so the client renders a PENDING bubble in
41
+ * the timeline). The pipeline fills in the content and flips the row to
42
+ * COMPLETED / FAILED. Used for both intros and replies — single shape.
43
+ */
44
+ AI_LAB_CHAT: { conversationId: string; aiMessageId: string };
45
+ /**
46
+ * `aiMessageId` placeholder pattern, same as AI_LAB_CHAT — see above.
47
+ */
48
+ AI_NEWTON_CHAT: { conversationId: string; aiMessageId: string };
34
49
  STUDENT_PROGRESS_CHAT: { classId: string; studentId: string; message: string };
35
50
  };
36
51
 
37
- const QUEUE_NAMES: Record<RunJobType, string> = {
52
+ export const QUEUE_NAMES: Record<RunJobType, string> = {
38
53
  PDF_TO_WORKSHEET: 'pdfToWorksheet',
39
54
  GRADE_WORKSHEET: 'gradeWorksheet',
40
55
  AI_LAB_CHAT: 'aiLabChat',
@@ -117,6 +117,66 @@ describe('Attendance Router', () => {
117
117
  expect(updatedRecord?.late.some((l: any) => l.id === student2.id)).toBe(true);
118
118
  });
119
119
 
120
+ test('should notify students newly marked late or absent', async () => {
121
+ await prisma.notification.deleteMany({
122
+ where: { receiverId: student2.id },
123
+ });
124
+
125
+ await user1Caller.attendance.update({
126
+ classId: testClass.id,
127
+ eventId: testEvent.event.id,
128
+ attendance: {
129
+ present: [{ id: student1.id, username: student1.username }],
130
+ late: [{ id: student2.id, username: student2.username }],
131
+ absent: [],
132
+ },
133
+ });
134
+
135
+ let notifications = await user2Caller.notification.list();
136
+ expect(
137
+ notifications.some(
138
+ (notification: any) =>
139
+ notification.title === `Marked late in ${testClass.name}` &&
140
+ notification.content.includes(testEvent.event.name) &&
141
+ notification.content.includes(`/class/${testClass.id}/attendance/${testEvent.event.id}`)
142
+ )
143
+ ).toBe(true);
144
+
145
+ await user1Caller.attendance.update({
146
+ classId: testClass.id,
147
+ eventId: testEvent.event.id,
148
+ attendance: {
149
+ present: [{ id: student1.id, username: student1.username }],
150
+ late: [{ id: student2.id, username: student2.username }],
151
+ absent: [],
152
+ },
153
+ });
154
+
155
+ notifications = await user2Caller.notification.list();
156
+ expect(
157
+ notifications.filter(
158
+ (notification: any) => notification.title === `Marked late in ${testClass.name}`
159
+ )
160
+ ).toHaveLength(1);
161
+
162
+ await user1Caller.attendance.update({
163
+ classId: testClass.id,
164
+ eventId: testEvent.event.id,
165
+ attendance: {
166
+ present: [{ id: student1.id, username: student1.username }],
167
+ late: [],
168
+ absent: [{ id: student2.id, username: student2.username }],
169
+ },
170
+ });
171
+
172
+ notifications = await user2Caller.notification.list();
173
+ expect(
174
+ notifications.some(
175
+ (notification: any) => notification.title === `Marked absent in ${testClass.name}`
176
+ )
177
+ ).toBe(true);
178
+ });
179
+
120
180
  test('should update attendance without event', async () => {
121
181
  const result = await user1Caller.attendance.update({
122
182
  classId: testClass.id,
@@ -157,4 +217,3 @@ describe('Attendance Router', () => {
157
217
  })));
158
218
  });
159
219
  });
160
-