@studious-lms/server 1.4.9 → 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 (237) 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 +2 -3
  5. package/dist/lib/config/cors.js.map +1 -1
  6. package/dist/lib/fileUpload.d.ts.map +1 -1
  7. package/dist/lib/fileUpload.js +4 -5
  8. package/dist/lib/fileUpload.js.map +1 -1
  9. package/dist/lib/pusher.d.ts +7 -1
  10. package/dist/lib/pusher.d.ts.map +1 -1
  11. package/dist/lib/pusher.js +9 -3
  12. package/dist/lib/pusher.js.map +1 -1
  13. package/dist/models/attendance.d.ts +16 -7
  14. package/dist/models/attendance.d.ts.map +1 -1
  15. package/dist/models/attendance.js +17 -2
  16. package/dist/models/attendance.js.map +1 -1
  17. package/dist/models/auth.d.ts +1 -0
  18. package/dist/models/auth.d.ts.map +1 -1
  19. package/dist/models/auth.js +3 -2
  20. package/dist/models/auth.js.map +1 -1
  21. package/dist/models/comment.d.ts +0 -5
  22. package/dist/models/comment.d.ts.map +1 -1
  23. package/dist/models/conversation.d.ts +17 -16
  24. package/dist/models/conversation.d.ts.map +1 -1
  25. package/dist/models/labChat.d.ts +2 -1
  26. package/dist/models/labChat.d.ts.map +1 -1
  27. package/dist/models/message.d.ts +6 -3
  28. package/dist/models/message.d.ts.map +1 -1
  29. package/dist/models/school.d.ts +0 -22
  30. package/dist/models/school.d.ts.map +1 -1
  31. package/dist/models/school.js +2 -14
  32. package/dist/models/school.js.map +1 -1
  33. package/dist/models/worksheet.d.ts +76 -19
  34. package/dist/models/worksheet.d.ts.map +1 -1
  35. package/dist/models/worksheet.js +2 -2
  36. package/dist/models/worksheet.js.map +1 -1
  37. package/dist/pipelines/aiLabChat.d.ts +20 -9
  38. package/dist/pipelines/aiLabChat.d.ts.map +1 -1
  39. package/dist/pipelines/aiLabChat.js +63 -75
  40. package/dist/pipelines/aiLabChat.js.map +1 -1
  41. package/dist/pipelines/aiNewtonChat.d.ts +13 -4
  42. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
  43. package/dist/pipelines/aiNewtonChat.js +39 -27
  44. package/dist/pipelines/aiNewtonChat.js.map +1 -1
  45. package/dist/pipelines/gradeWorksheet.d.ts +5 -3
  46. package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
  47. package/dist/pipelines/gradeWorksheet.js +60 -24
  48. package/dist/pipelines/gradeWorksheet.js.map +1 -1
  49. package/dist/pipelines/pdfToWorksheet.d.ts +34 -2
  50. package/dist/pipelines/pdfToWorksheet.d.ts.map +1 -1
  51. package/dist/pipelines/pdfToWorksheet.js +205 -32
  52. package/dist/pipelines/pdfToWorksheet.js.map +1 -1
  53. package/dist/routers/_app.d.ts +106 -48
  54. package/dist/routers/_app.d.ts.map +1 -1
  55. package/dist/routers/announcement.d.ts +0 -4
  56. package/dist/routers/announcement.d.ts.map +1 -1
  57. package/dist/routers/assignment.d.ts +0 -8
  58. package/dist/routers/assignment.d.ts.map +1 -1
  59. package/dist/routers/assignment.js +64 -4
  60. package/dist/routers/assignment.js.map +1 -1
  61. package/dist/routers/auth.d.ts +1 -0
  62. package/dist/routers/auth.d.ts.map +1 -1
  63. package/dist/routers/comment.d.ts +0 -3
  64. package/dist/routers/comment.d.ts.map +1 -1
  65. package/dist/routers/conversation.d.ts +2 -1
  66. package/dist/routers/conversation.d.ts.map +1 -1
  67. package/dist/routers/labChat.d.ts +3 -1
  68. package/dist/routers/labChat.d.ts.map +1 -1
  69. package/dist/routers/message.d.ts +3 -0
  70. package/dist/routers/message.d.ts.map +1 -1
  71. package/dist/routers/newtonChat.d.ts +1 -0
  72. package/dist/routers/newtonChat.d.ts.map +1 -1
  73. package/dist/routers/school.d.ts +6 -0
  74. package/dist/routers/school.d.ts.map +1 -1
  75. package/dist/routers/school.js +7 -2
  76. package/dist/routers/school.js.map +1 -1
  77. package/dist/routers/worksheet.d.ts +37 -7
  78. package/dist/routers/worksheet.d.ts.map +1 -1
  79. package/dist/routers/worksheet.js +16 -6
  80. package/dist/routers/worksheet.js.map +1 -1
  81. package/dist/services/announcement.js +4 -4
  82. package/dist/services/announcement.js.map +1 -1
  83. package/dist/services/assignment.d.ts.map +1 -1
  84. package/dist/services/assignment.js +16 -6
  85. package/dist/services/assignment.js.map +1 -1
  86. package/dist/services/attendance.d.ts.map +1 -1
  87. package/dist/services/attendance.js +68 -4
  88. package/dist/services/attendance.js.map +1 -1
  89. package/dist/services/auth.d.ts +1 -0
  90. package/dist/services/auth.d.ts.map +1 -1
  91. package/dist/services/comment.d.ts +0 -3
  92. package/dist/services/comment.d.ts.map +1 -1
  93. package/dist/services/conversation.d.ts +2 -1
  94. package/dist/services/conversation.d.ts.map +1 -1
  95. package/dist/services/labChat.d.ts +10 -2
  96. package/dist/services/labChat.d.ts.map +1 -1
  97. package/dist/services/labChat.js +103 -44
  98. package/dist/services/labChat.js.map +1 -1
  99. package/dist/services/message.d.ts +3 -0
  100. package/dist/services/message.d.ts.map +1 -1
  101. package/dist/services/message.js +20 -2
  102. package/dist/services/message.js.map +1 -1
  103. package/dist/services/newtonChat.d.ts +1 -0
  104. package/dist/services/newtonChat.d.ts.map +1 -1
  105. package/dist/services/newtonChat.js +40 -17
  106. package/dist/services/newtonChat.js.map +1 -1
  107. package/dist/services/school.d.ts +6 -0
  108. package/dist/services/school.d.ts.map +1 -1
  109. package/dist/services/school.js +71 -6
  110. package/dist/services/school.js.map +1 -1
  111. package/dist/services/worksheet.d.ts +48 -11
  112. package/dist/services/worksheet.d.ts.map +1 -1
  113. package/dist/services/worksheet.js +73 -29
  114. package/dist/services/worksheet.js.map +1 -1
  115. package/dist/utils/generateUsername.d.ts +8 -0
  116. package/dist/utils/generateUsername.d.ts.map +1 -0
  117. package/dist/utils/generateUsername.js +103 -0
  118. package/dist/utils/generateUsername.js.map +1 -0
  119. package/dist/utils/inference.d.ts +50 -1
  120. package/dist/utils/inference.d.ts.map +1 -1
  121. package/dist/utils/inference.js +167 -2
  122. package/dist/utils/inference.js.map +1 -1
  123. package/dist/workers/connection.d.ts +3 -0
  124. package/dist/workers/connection.d.ts.map +1 -0
  125. package/dist/workers/connection.js +33 -0
  126. package/dist/workers/connection.js.map +1 -0
  127. package/dist/workers/index.d.ts +10 -0
  128. package/dist/workers/index.d.ts.map +1 -0
  129. package/dist/workers/index.js +63 -0
  130. package/dist/workers/index.js.map +1 -0
  131. package/dist/workers/processors/aiLabChat.d.ts +7 -0
  132. package/dist/workers/processors/aiLabChat.d.ts.map +1 -0
  133. package/dist/workers/processors/aiLabChat.js +52 -0
  134. package/dist/workers/processors/aiLabChat.js.map +1 -0
  135. package/dist/workers/processors/aiNewtonChat.d.ts +7 -0
  136. package/dist/workers/processors/aiNewtonChat.d.ts.map +1 -0
  137. package/dist/workers/processors/aiNewtonChat.js +57 -0
  138. package/dist/workers/processors/aiNewtonChat.js.map +1 -0
  139. package/dist/workers/processors/createRunJobWorker.d.ts +46 -0
  140. package/dist/workers/processors/createRunJobWorker.d.ts.map +1 -0
  141. package/dist/workers/processors/createRunJobWorker.js +118 -0
  142. package/dist/workers/processors/createRunJobWorker.js.map +1 -0
  143. package/dist/workers/processors/gradeWorksheet.d.ts +6 -0
  144. package/dist/workers/processors/gradeWorksheet.d.ts.map +1 -0
  145. package/dist/workers/processors/gradeWorksheet.js +19 -0
  146. package/dist/workers/processors/gradeWorksheet.js.map +1 -0
  147. package/dist/workers/processors/pdfToWorksheet.d.ts +8 -0
  148. package/dist/workers/processors/pdfToWorksheet.d.ts.map +1 -0
  149. package/dist/workers/processors/pdfToWorksheet.js +20 -0
  150. package/dist/workers/processors/pdfToWorksheet.js.map +1 -0
  151. package/dist/workers/processors/studentProgressChat.d.ts +8 -0
  152. package/dist/workers/processors/studentProgressChat.d.ts.map +1 -0
  153. package/dist/workers/processors/studentProgressChat.js +27 -0
  154. package/dist/workers/processors/studentProgressChat.js.map +1 -0
  155. package/dist/workers/queues.d.ts +85 -0
  156. package/dist/workers/queues.d.ts.map +1 -0
  157. package/dist/workers/queues.js +119 -0
  158. package/dist/workers/queues.js.map +1 -0
  159. package/package.json +6 -3
  160. package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +166 -0
  161. package/prisma/schema.prisma +465 -387
  162. package/src/index.ts +12 -1
  163. package/src/lib/config/cors.ts +0 -1
  164. package/src/lib/fileUpload.ts +2 -4
  165. package/src/lib/pusher.ts +7 -1
  166. package/src/models/attendance.ts +15 -0
  167. package/src/models/auth.ts +1 -0
  168. package/src/models/school.ts +0 -14
  169. package/src/models/worksheet.ts +2 -2
  170. package/src/pipelines/aiLabChat.ts +71 -79
  171. package/src/pipelines/aiNewtonChat.ts +47 -31
  172. package/src/pipelines/gradeWorksheet.ts +63 -25
  173. package/src/pipelines/pdfToWorksheet.ts +272 -34
  174. package/src/routers/assignment.ts +74 -3
  175. package/src/routers/school.ts +5 -0
  176. package/src/routers/worksheet.ts +25 -4
  177. package/src/services/announcement.ts +2 -2
  178. package/src/services/assignment.ts +18 -4
  179. package/src/services/attendance.ts +87 -2
  180. package/src/services/labChat.ts +108 -48
  181. package/src/services/message.ts +19 -0
  182. package/src/services/newtonChat.ts +46 -25
  183. package/src/services/school.ts +89 -6
  184. package/src/services/worksheet.ts +87 -28
  185. package/src/utils/generateUsername.ts +108 -0
  186. package/src/utils/inference.ts +209 -1
  187. package/src/workers/connection.ts +37 -0
  188. package/src/workers/index.ts +71 -0
  189. package/src/workers/processors/aiLabChat.ts +65 -0
  190. package/src/workers/processors/aiNewtonChat.ts +75 -0
  191. package/src/workers/processors/createRunJobWorker.ts +164 -0
  192. package/src/workers/processors/gradeWorksheet.ts +16 -0
  193. package/src/workers/processors/pdfToWorksheet.ts +17 -0
  194. package/src/workers/processors/studentProgressChat.ts +28 -0
  195. package/src/workers/queues.ts +174 -0
  196. package/tests/{globalSetup.ts → integration/globalSetup.ts} +4 -4
  197. package/tests/{helpers.ts → integration/helpers.ts} +2 -2
  198. package/tests/{pipelines → integration/pipelines}/pdfToWorksheet.test.ts +55 -43
  199. package/tests/{routers → integration/routers}/attendance.test.ts +61 -2
  200. package/tests/{routers → integration/routers}/auth.test.ts +3 -3
  201. package/tests/{routers → integration/routers}/class.test.ts +3 -17
  202. package/tests/{routers → integration/routers}/conversation.test.ts +1 -1
  203. package/tests/{routers → integration/routers}/event.test.ts +1 -1
  204. package/tests/{routers → integration/routers}/message.test.ts +1 -1
  205. package/tests/{routers → integration/routers}/newtonChat.test.ts +1 -1
  206. package/tests/{routers → integration/routers}/studentProgress.test.ts +1 -1
  207. package/tests/{user.test.ts → integration/routers/user.test.ts} +2 -2
  208. package/tests/integration/routers/worksheet.test.ts +448 -0
  209. package/tests/{setup.ts → integration/setup.ts} +4 -4
  210. package/tests/{lib → unit/lib}/cors.test.ts +1 -1
  211. package/tests/{middleware → unit/middleware}/security.test.ts +1 -1
  212. package/tests/{pipelines → unit/pipelines}/aiLabChat.test.ts +1 -1
  213. package/tests/{lib → unit/pipelines}/aiLabChatContract.test.ts +1 -1
  214. package/tests/{utils/aiLabChatPrompt.test.ts → unit/pipelines/labChatPrompt.test.ts} +2 -2
  215. package/tests/{utils → unit/services}/studentProgress.test.ts +5 -5
  216. package/tests/{utils → unit/utils}/aiUser.test.ts +1 -1
  217. package/tests/{utils → unit/utils}/generateInviteCode.test.ts +1 -1
  218. package/tests/{utils → unit/utils}/inference.test.ts +6 -6
  219. package/tests/{utils → unit/utils}/logger.test.ts +1 -1
  220. package/tests/{utils → unit/utils}/prismaErrorHandler.test.ts +1 -1
  221. package/tests/{utils → unit/utils}/prismaWrapper.test.ts +1 -1
  222. package/vitest.config.ts +11 -3
  223. package/vitest.unit.config.ts +10 -10
  224. package/tests/routers/worksheet.test.ts +0 -194
  225. package/tests/startup.test.ts +0 -5
  226. package/tests/worksheet.test.ts +0 -181
  227. /package/tests/{routers → integration/routers}/agenda.test.ts +0 -0
  228. /package/tests/{routers → integration/routers}/announcement.test.ts +0 -0
  229. /package/tests/{routers → integration/routers}/assignment.test.ts +0 -0
  230. /package/tests/{routers → integration/routers}/comment.test.ts +0 -0
  231. /package/tests/{routers → integration/routers}/folder.test.ts +0 -0
  232. /package/tests/{routers → integration/routers}/labChat.test.ts +0 -0
  233. /package/tests/{routers → integration/routers}/marketing.test.ts +0 -0
  234. /package/tests/{routers → integration/routers}/notification.test.ts +0 -0
  235. /package/tests/{routers → integration/routers}/search.test.ts +0 -0
  236. /package/tests/{routers → integration/routers}/section.test.ts +0 -0
  237. /package/tests/{server → unit/middleware}/rateLimit.test.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"attendance.js","sources":["services/attendance.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Attendance service – get and update class attendance records.\n * Auto-creates attendance records for events that don't have them yet.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findClassWithStudents,\n findClassWithTeacher,\n findEventsByClassId,\n findAttendanceByEventId,\n findAttendanceByClassAndEvent,\n findManyAttendance,\n createAttendance,\n createAttendanceForEvent,\n updateAttendance,\n} from \"../models/attendance.js\";\n\n/** Get attendance for a class (optionally filtered by event). Creates missing records. */\nexport async function getAttendance(classId: string, eventId?: string) {\n const classData = await findClassWithStudents(classId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this class's attendance\",\n });\n }\n\n const events = await findEventsByClassId(classId);\n const studentIds = classData.students.map((s) => s.id);\n\n for (const event of events) {\n const existing = await findAttendanceByEventId(event.id);\n if (!existing) {\n await createAttendanceForEvent({\n classId,\n eventId: event.id,\n presentIds: studentIds,\n });\n }\n }\n\n return findManyAttendance(classId, eventId);\n}\n\n/** Update attendance record (present/late/absent). Teacher-only. */\nexport async function updateAttendanceRecord(\n userId: string,\n classId: string,\n eventId: string | null | undefined,\n attendance: {\n present: { id: string; username: string }[];\n late: { id: string; username: string }[];\n absent: { id: string; username: string }[];\n }\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this class's attendance\",\n });\n }\n\n const existing = await findAttendanceByClassAndEvent(classId, eventId ?? null);\n\n const presentIds = attendance.present.map((s) => s.id);\n const lateIds = attendance.late.map((s) => s.id);\n const absentIds = attendance.absent.map((s) => s.id);\n\n if (!existing) {\n return createAttendance({\n classId,\n eventId: eventId ?? null,\n presentIds,\n lateIds,\n absentIds,\n });\n }\n\n return updateAttendance(existing.id, {\n presentIds,\n lateIds,\n absentIds,\n });\n}\n"],"names":[],"mappings":"AAAA;;;GAGG;;;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,6BAA6B,EAC7B,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,OAAgB;IACnE,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,SAAS,CAAC;YAClB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,wDAAwD;SAClE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,wBAAwB,CAAC;gBAC7B,OAAO;gBACP,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,UAAU,EAAE,UAAU;aACvB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAc,EACd,OAAe,EACf,OAAkC,EAClC,UAIC;IAED,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,SAAS,CAAC;YAClB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,0DAA0D;SACpE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,6BAA6B,CAAC,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC;IAE/E,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAErD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,gBAAgB,CAAC;YACtB,OAAO;YACP,OAAO,EAAE,OAAO,IAAI,IAAI;YACxB,UAAU;YACV,OAAO;YACP,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,OAAO,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE;QACnC,UAAU;QACV,OAAO;QACP,SAAS;KACV,CAAC,CAAC;AACL,CAAC","debug_id":"55bfbcca-f33b-598a-a729-a6202fde1f7e"}
1
+ {"version":3,"file":"attendance.js","sources":["services/attendance.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Attendance service – get and update class attendance records.\n * Auto-creates attendance records for events that don't have them yet.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findClassWithStudents,\n findClassWithTeacher,\n findEventsByClassId,\n findAttendanceByEventId,\n findAttendanceByClassAndEvent,\n findManyAttendance,\n createAttendance,\n createAttendanceForEvent,\n updateAttendance,\n} from \"../models/attendance.js\";\nimport { sendToMultiple } from \"./notification.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/** Get attendance for a class (optionally filtered by event). Creates missing records. */\nexport async function getAttendance(classId: string, eventId?: string) {\n const classData = await findClassWithStudents(classId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this class's attendance\",\n });\n }\n\n const events = await findEventsByClassId(classId);\n const studentIds = classData.students.map((s) => s.id);\n\n for (const event of events) {\n const existing = await findAttendanceByEventId(event.id);\n if (!existing) {\n await createAttendanceForEvent({\n classId,\n eventId: event.id,\n presentIds: studentIds,\n });\n }\n }\n\n return findManyAttendance(classId, eventId);\n}\n\n/** Update attendance record (present/late/absent). Teacher-only. */\nexport async function updateAttendanceRecord(\n userId: string,\n classId: string,\n eventId: string | null | undefined,\n attendance: {\n present: { id: string; username: string }[];\n late: { id: string; username: string }[];\n absent: { id: string; username: string }[];\n }\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this class's attendance\",\n });\n }\n\n const existing = await findAttendanceByClassAndEvent(classId, eventId ?? null);\n\n const presentIds = attendance.present.map((s) => s.id);\n const lateIds = attendance.late.map((s) => s.id);\n const absentIds = attendance.absent.map((s) => s.id);\n const previousLateIds = new Set(existing?.late.map((student) => student.id) ?? []);\n const previousAbsentIds = new Set(existing?.absent.map((student) => student.id) ?? []);\n const classStudentIds = new Set(classData.students.map((student) => student.id));\n\n if (!existing) {\n const created = await createAttendance({\n classId,\n eventId: eventId ?? null,\n presentIds,\n lateIds,\n absentIds,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: created.event?.name ?? null,\n classStudentIds,\n lateIds,\n absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return created;\n }\n\n const updated = await updateAttendance(existing.id, {\n presentIds,\n lateIds,\n absentIds,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: existing.event?.name ?? null,\n classStudentIds,\n lateIds,\n absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return updated;\n}\n\n/** Notify only students whose late or absent status is newly added. */\nasync function notifyMarkedLateOrAbsent(input: {\n classId: string;\n className: string;\n eventId: string | null;\n eventName: string | null;\n classStudentIds: Set<string>;\n lateIds: string[];\n absentIds: string[];\n previousLateIds: Set<string>;\n previousAbsentIds: Set<string>;\n}) {\n const lateReceiverIds = [...new Set(input.lateIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousLateIds.has(id)\n );\n const absentReceiverIds = [...new Set(input.absentIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousAbsentIds.has(id)\n );\n const link = input.eventId\n ? `/class/${input.classId}/attendance/${input.eventId}`\n : `/class/${input.classId}/attendance`;\n const attendanceLabel = input.eventName\n ? `\"${input.eventName}\" in ${input.className}`\n : input.className;\n\n await Promise.all([\n sendAttendanceNotification({\n receiverIds: lateReceiverIds,\n title: `Marked late in ${input.className}`,\n content: `You were marked late for ${attendanceLabel}.\\n[View attendance](${link})`,\n }),\n sendAttendanceNotification({\n receiverIds: absentReceiverIds,\n title: `Marked absent in ${input.className}`,\n content: `You were marked absent for ${attendanceLabel}.\\n[View attendance](${link})`,\n }),\n ]);\n}\n\n/** Send attendance notifications without failing the attendance update itself. */\nasync function sendAttendanceNotification(input: {\n receiverIds: string[];\n title: string;\n content: string;\n}) {\n if (input.receiverIds.length === 0) {\n return;\n }\n\n try {\n await sendToMultiple(input);\n } catch (error) {\n logger.error(\"Failed to send attendance notifications:\", { error });\n }\n}\n"],"names":[],"mappings":"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","debug_id":"234d526b-a633-54ce-87f8-d4e6af5df483"}
@@ -39,6 +39,7 @@ export declare function check(userId: string): Promise<{
39
39
  user: {
40
40
  id: string;
41
41
  username: string;
42
+ email: string;
42
43
  profile: {
43
44
  location: string | null;
44
45
  displayName: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["services/auth.ts"],"names":[],"mappings":"AA6BA,qFAAqF;AACrF,wBAAsB,QAAQ,CAAC,KAAK,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;;;;;GAqEA;AAED,8DAA8D;AAC9D,wBAAsB,KAAK,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;GAoCxE;AAED,iEAAiE;AACjE,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM;;GAG1C;AAED,0EAA0E;AAC1E,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;GASzC;AAED,gFAAgF;AAChF,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,MAAM;;GAiC1D;AAED,8EAA8E;AAC9E,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM;;GA+BzC;AAED,kFAAkF;AAClF,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM;;GA+BvD;AAED,mFAAmF;AACnF,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;GAuBlE"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["services/auth.ts"],"names":[],"mappings":"AA6BA,qFAAqF;AACrF,wBAAsB,QAAQ,CAAC,KAAK,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;;;;;GAqEA;AAED,8DAA8D;AAC9D,wBAAsB,KAAK,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;GAoCxE;AAED,iEAAiE;AACjE,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM;;GAG1C;AAED,0EAA0E;AAC1E,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;GASzC;AAED,gFAAgF;AAChF,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,MAAM;;GAiC1D;AAED,8EAA8E;AAC9E,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM;;GA+BzC;AAED,kFAAkF;AAClF,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM;;GA+BvD;AAED,mFAAmF;AACnF,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;GAuBlE"}
@@ -42,7 +42,6 @@ export declare function getReplies(userId: string, commentId: string): Promise<(
42
42
  } | null;
43
43
  };
44
44
  } & {
45
- status: import(".prisma/client").$Enums.GenerationStatus | null;
46
45
  id: string;
47
46
  createdAt: Date;
48
47
  assignmentId: string | null;
@@ -56,7 +55,6 @@ export declare function getReplies(userId: string, commentId: string): Promise<(
56
55
  })[]>;
57
56
  /** Create a reply to an existing comment. */
58
57
  export declare function replyToComment(userId: string, parentCommentId: string, content: string): Promise<{
59
- status: import(".prisma/client").$Enums.GenerationStatus | null;
60
58
  id: string;
61
59
  createdAt: Date;
62
60
  assignmentId: string | null;
@@ -70,7 +68,6 @@ export declare function replyToComment(userId: string, parentCommentId: string,
70
68
  }>;
71
69
  /** Update a comment authored by the user. */
72
70
  export declare function updateComment(userId: string, id: string, content: string): Promise<{
73
- status: import(".prisma/client").$Enums.GenerationStatus | null;
74
71
  id: string;
75
72
  createdAt: Date;
76
73
  assignmentId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"comment.d.ts","sourceRoot":"/","sources":["services/comment.ts"],"names":[],"mappings":"AA6FA,2BAA2B;AAC3B,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAU1D;AAED,oCAAoC;AACpC,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;MAGjE;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;;;;;;;;;;;;GAYhB;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;GAa9E;AAED,6EAA6E;AAC7E,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;GAW7D;AAED,qDAAqD;AACrD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAMb;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAWrE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;GAuBnE"}
1
+ {"version":3,"file":"comment.d.ts","sourceRoot":"/","sources":["services/comment.ts"],"names":[],"mappings":"AA6FA,2BAA2B;AAC3B,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAU1D;AAED,oCAAoC;AACpC,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;MAGjE;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;;;;;;;;;;;GAYhB;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;GAa9E;AAED,6EAA6E;AAC7E,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;GAW7D;AAED,qDAAqD;AACrD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAMb;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAWrE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;GAuBnE"}
@@ -37,13 +37,14 @@ export declare function listConversations(userId: string): Promise<{
37
37
  } | null;
38
38
  };
39
39
  } & {
40
- status: import(".prisma/client").$Enums.GenerationStatus | null;
40
+ status: import(".prisma/client").$Enums.JobStatus | null;
41
41
  meta: import("@prisma/client/runtime/library.js").JsonValue | null;
42
42
  id: string;
43
43
  createdAt: Date;
44
44
  conversationId: string;
45
45
  content: string;
46
46
  senderId: string;
47
+ runJobId: string | null;
47
48
  };
48
49
  unreadCount: number;
49
50
  unreadMentionCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"/","sources":["services/conversation.ts"],"names":[],"mappings":"AAmBA,gEAAgE;AAChE,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuDrD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GAY5E;AAED,gEAAgE;AAChE,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,GAAG,OAAO,EACpB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEpB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAavB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BvB;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAejB"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"/","sources":["services/conversation.ts"],"names":[],"mappings":"AAmBA,gEAAgE;AAChE,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuDrD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GAY5E;AAED,gEAAgE;AAChE,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,GAAG,OAAO,EACpB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEpB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAavB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BvB;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAejB"}
@@ -131,13 +131,14 @@ export declare function listLabChats(userId: string, classId: string): Promise<{
131
131
  } | null;
132
132
  };
133
133
  } & {
134
- status: import(".prisma/client").$Enums.GenerationStatus | null;
134
+ status: import(".prisma/client").$Enums.JobStatus | null;
135
135
  meta: import("@prisma/client/runtime/library.js").JsonValue | null;
136
136
  id: string;
137
137
  createdAt: Date;
138
138
  conversationId: string;
139
139
  content: string;
140
140
  senderId: string;
141
+ runJobId: string | null;
141
142
  };
142
143
  messageCount: number;
143
144
  }[]>;
@@ -151,6 +152,7 @@ export declare function postToLabChat(userId: string, input: {
151
152
  content: string;
152
153
  senderId: string;
153
154
  conversationId: string;
155
+ status: import(".prisma/client").$Enums.JobStatus | null;
154
156
  createdAt: Date;
155
157
  sender: {
156
158
  id: string;
@@ -170,7 +172,13 @@ export declare function postToLabChat(userId: string, input: {
170
172
  export declare function deleteLabChat(userId: string, labChatId: string): Promise<{
171
173
  success: boolean;
172
174
  }>;
173
- /** Rerun the last AI response for a lab chat. Deletes the last AI message and regenerates. */
175
+ /**
176
+ * Rerun the last AI response in a lab chat.
177
+ *
178
+ * The AI message bubble is reused (not deleted): we flip it back to
179
+ * PENDING and clear its content so the existing message id stays stable
180
+ * for the client. The pipeline then refills it.
181
+ */
174
182
  export declare function rerunLastResponse(userId: string, labChatId: string): Promise<{
175
183
  success: boolean;
176
184
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"AA2BA,sFAAsF;AACtF,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsH3D;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCjE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqBjE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;GAuIF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiDpE;AAED,8FAA8F;AAC9F,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiFxE"}
1
+ {"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"AA4BA,sFAAsF;AACtF,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiI3D;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCjE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqBjE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;;GA+JF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiDpE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiGxE"}
@@ -3,15 +3,16 @@
3
3
  * trigger AI responses, and broadcast via Pusher.
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]="a2cfffda-ee2d-53e3-a8f9-ea08a785e468")}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]="ca593f36-e2e1-5f0c-b82a-d2d4fe00b23b")}catch(e){}}();
7
7
  import { TRPCError } from "@trpc/server";
8
- import { GenerationStatus } from "@prisma/client";
8
+ import { JobStatus } from "@prisma/client";
9
9
  import { prisma } from "../lib/prisma.js";
10
10
  import { chatChannel, teacherChannel, pusher } from "../lib/pusher.js";
11
11
  import { findClassWithTeachersForLab, findLabChatByMember, findLabChatByTeacher, findLabChatById, findClassMembership, findLabChatsByClass, findLabChatForPost, findLabChatForDelete, findMentionedMemberships, } from "../models/labChat.js";
12
- import { generateAndSendLabIntroduction, generateAndSendLabResponse } from "../pipelines/aiLabChat.js";
13
- import { isAIUser } from "../utils/aiUser.js";
12
+ import { getAIUserId, isAIUser } from "../utils/aiUser.js";
13
+ import { createPendingAIMessage } from "../utils/inference.js";
14
14
  import { logger } from "../utils/logger.js";
15
+ import { enqueueRunJob, QUEUE_NAMES } from "../workers/queues.js";
15
16
  import { claimMessageAttachments, ensureMessageHasContentOrAttachments, } from "./message.js";
16
17
  /** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */
17
18
  export async function createLabChat(userId, input) {
@@ -103,7 +104,20 @@ export async function createLabChat(userId, input) {
103
104
  });
104
105
  return labChat;
105
106
  });
106
- generateAndSendLabIntroduction(result.id, result.conversationId, context, classWithTeachers.subject || "Lab");
107
+ // Create the AI introduction placeholder *outside* the transaction (the
108
+ // helper triggers Pusher and we don't want a tx rollback to leave a
109
+ // dangling broadcast). The pipeline will fill this row in.
110
+ try {
111
+ const aiPlaceholder = await createPendingAIMessage(result.conversationId);
112
+ await enqueueRunJob(QUEUE_NAMES.AI_LAB_CHAT, { conversationId: result.conversationId, aiMessageId: aiPlaceholder.id }, { classId, userId });
113
+ }
114
+ catch (error) {
115
+ logger.error("Failed to enqueue lab chat introduction", {
116
+ error,
117
+ labChatId: result.id,
118
+ conversationId: result.conversationId,
119
+ });
120
+ }
107
121
  try {
108
122
  await pusher.trigger(teacherChannel(classId), "lab-chat-created", {
109
123
  id: result.id,
@@ -140,11 +154,13 @@ export async function getLabChat(userId, labChatId) {
140
154
  message: "Lab chat not found or access denied",
141
155
  });
142
156
  }
157
+ // The AI placeholder row IS the pending generation marker now — its
158
+ // status flips PENDING → COMPLETED / FAILED as the pipeline runs.
143
159
  const pendingMessage = await prisma.message.findFirst({
144
160
  where: {
145
161
  conversationId: labChat.conversationId,
146
- status: GenerationStatus.PENDING,
147
- senderId: { not: "AI_ASSISTANT" },
162
+ status: JobStatus.PENDING,
163
+ senderId: getAIUserId(),
148
164
  },
149
165
  orderBy: { createdAt: "desc" },
150
166
  select: { id: true },
@@ -201,7 +217,6 @@ export async function postToLabChat(userId, input) {
201
217
  content: normalizedContent,
202
218
  senderId: userId,
203
219
  conversationId: labChat.conversationId,
204
- ...(isAIUser(userId) ? {} : { status: GenerationStatus.PENDING }),
205
220
  },
206
221
  });
207
222
  await claimMessageAttachments(tx, userId, labChat.conversationId, message.id, fileIds);
@@ -244,6 +259,7 @@ export async function postToLabChat(userId, input) {
244
259
  content: result.content,
245
260
  senderId: result.senderId,
246
261
  conversationId: result.conversationId,
262
+ status: result.status,
247
263
  createdAt: result.createdAt,
248
264
  sender: result.sender,
249
265
  attachments: result.attachments ?? [],
@@ -255,31 +271,53 @@ export async function postToLabChat(userId, input) {
255
271
  console.error("Failed to broadcast lab chat message:", error);
256
272
  }
257
273
  if (!isAIUser(userId)) {
274
+ // Create the AI placeholder post-tx so a transaction rollback can never
275
+ // leave a dangling PENDING bubble. The placeholder broadcast IS the
276
+ // "AI is thinking..." indicator inline in the chat; the teacher-channel
277
+ // event below drives the lab list "AI busy in this lab" pill.
278
+ let aiPlaceholderId = null;
279
+ try {
280
+ const aiPlaceholder = await createPendingAIMessage(labChat.conversationId);
281
+ aiPlaceholderId = aiPlaceholder.id;
282
+ }
283
+ catch (error) {
284
+ logger.error("Failed to create AI placeholder for lab response", {
285
+ error,
286
+ labChatId,
287
+ teacherMessageId: result.id,
288
+ conversationId: labChat.conversationId,
289
+ });
290
+ }
258
291
  try {
259
292
  await pusher.trigger(teacherChannel(labChat.classId), "lab-response-pending", {
260
293
  labChatId,
261
- messageId: result.id,
294
+ messageId: aiPlaceholderId ?? result.id,
262
295
  conversationId: labChat.conversationId,
263
296
  });
264
297
  }
265
298
  catch (error) {
266
299
  console.error("Failed to broadcast lab response pending:", error);
267
300
  }
268
- generateAndSendLabResponse(labChatId, normalizedContent, {
269
- classId: labChat.classId,
270
- messageId: result.id,
271
- }).catch((error) => logger.error("Failed to generate lab response", {
272
- error,
273
- labChatId,
274
- messageId: result.id,
275
- conversationId: labChat.conversationId,
276
- }));
301
+ if (aiPlaceholderId) {
302
+ try {
303
+ await enqueueRunJob(QUEUE_NAMES.AI_LAB_CHAT, { conversationId: labChat.conversationId, aiMessageId: aiPlaceholderId }, { classId: labChat.classId, userId });
304
+ }
305
+ catch (error) {
306
+ logger.error("Failed to enqueue lab response", {
307
+ error,
308
+ labChatId,
309
+ aiMessageId: aiPlaceholderId,
310
+ conversationId: labChat.conversationId,
311
+ });
312
+ }
313
+ }
277
314
  }
278
315
  return {
279
316
  id: result.id,
280
317
  content: result.content,
281
318
  senderId: result.senderId,
282
319
  conversationId: result.conversationId,
320
+ status: result.status,
283
321
  createdAt: result.createdAt,
284
322
  sender: result.sender,
285
323
  attachments: result.attachments ?? [],
@@ -330,7 +368,13 @@ export async function deleteLabChat(userId, labChatId) {
330
368
  }
331
369
  return { success: true };
332
370
  }
333
- /** Rerun the last AI response for a lab chat. Deletes the last AI message and regenerates. */
371
+ /**
372
+ * Rerun the last AI response in a lab chat.
373
+ *
374
+ * The AI message bubble is reused (not deleted): we flip it back to
375
+ * PENDING and clear its content so the existing message id stays stable
376
+ * for the client. The pipeline then refills it.
377
+ */
334
378
  export async function rerunLastResponse(userId, labChatId) {
335
379
  const labChat = await findLabChatForPost(labChatId, userId);
336
380
  if (!labChat) {
@@ -365,45 +409,60 @@ export async function rerunLastResponse(userId, labChatId) {
365
409
  message: "No teacher message found to rerun from",
366
410
  });
367
411
  }
368
- await prisma.$transaction([
369
- prisma.message.delete({
370
- where: { id: lastMessage.id },
371
- }),
372
- prisma.message.update({
373
- where: { id: teacherMessage.id },
374
- data: { status: GenerationStatus.PENDING },
375
- }),
376
- ]);
412
+ const reusedAiMessage = await prisma.message.update({
413
+ where: { id: lastMessage.id },
414
+ data: {
415
+ content: "",
416
+ status: JobStatus.PENDING,
417
+ meta: {},
418
+ },
419
+ select: { id: true, conversationId: true, status: true, content: true, senderId: true, createdAt: true },
420
+ });
421
+ // Tell the chat UI the existing AI bubble is regenerating — content
422
+ // cleared, status flipped back to PENDING, same id.
377
423
  try {
378
- await pusher.trigger(chatChannel(labChat.conversationId), "message-deleted", {
379
- messageId: lastMessage.id,
380
- conversationId: labChat.conversationId,
381
- senderId: lastMessage.senderId,
424
+ await pusher.trigger(chatChannel(labChat.conversationId), "message-updated", {
425
+ id: reusedAiMessage.id,
426
+ content: reusedAiMessage.content,
427
+ senderId: reusedAiMessage.senderId,
428
+ conversationId: reusedAiMessage.conversationId,
429
+ status: reusedAiMessage.status,
430
+ createdAt: reusedAiMessage.createdAt,
431
+ sender: {
432
+ id: reusedAiMessage.senderId,
433
+ username: 'Newton_AI',
434
+ profile: { displayName: 'Newton AI', profilePicture: null },
435
+ },
436
+ mentionedUserIds: [],
437
+ meta: {},
438
+ attachments: [],
382
439
  });
383
440
  }
384
441
  catch (error) {
385
- console.error("Failed to broadcast message deletion:", error);
442
+ console.error("Failed to broadcast AI message rerun reset:", error);
386
443
  }
387
444
  try {
388
445
  await pusher.trigger(teacherChannel(labChat.classId), "lab-response-pending", {
389
446
  labChatId,
390
- messageId: teacherMessage.id,
447
+ messageId: reusedAiMessage.id,
391
448
  conversationId: labChat.conversationId,
392
449
  });
393
450
  }
394
451
  catch (error) {
395
452
  console.error("Failed to broadcast lab response pending:", error);
396
453
  }
397
- generateAndSendLabResponse(labChatId, teacherMessage.content, {
398
- classId: labChat.classId,
399
- messageId: teacherMessage.id,
400
- }).catch((error) => logger.error("Failed to generate lab response", {
401
- error,
402
- labChatId,
403
- messageId: teacherMessage.id,
404
- conversationId: labChat.conversationId,
405
- }));
454
+ try {
455
+ await enqueueRunJob(QUEUE_NAMES.AI_LAB_CHAT, { conversationId: labChat.conversationId, aiMessageId: reusedAiMessage.id }, { classId: labChat.classId, userId });
456
+ }
457
+ catch (error) {
458
+ logger.error("Failed to enqueue lab response rerun", {
459
+ error,
460
+ labChatId,
461
+ aiMessageId: reusedAiMessage.id,
462
+ conversationId: labChat.conversationId,
463
+ });
464
+ }
406
465
  return { success: true };
407
466
  }
408
467
  //# sourceMappingURL=labChat.js.map
409
- //# debugId=a2cfffda-ee2d-53e3-a8f9-ea08a785e468
468
+ //# debugId=ca593f36-e2e1-5f0c-b82a-d2d4fe00b23b
@@ -1 +1 @@
1
- {"version":3,"file":"labChat.js","sources":["services/labChat.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab chat service – AI-powered lab conversations. Create lab chats, post messages,\n * trigger AI responses, and broadcast via Pusher.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { GenerationStatus } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { chatChannel, teacherChannel, pusher } from \"../lib/pusher.js\";\nimport {\n findClassWithTeachersForLab,\n findLabChatByMember,\n findLabChatByTeacher,\n findLabChatById,\n findClassMembership,\n findLabChatsByClass,\n findLabChatForPost,\n findLabChatForDelete,\n findMentionedMemberships,\n} from \"../models/labChat.js\";\nimport { generateAndSendLabIntroduction, generateAndSendLabResponse } from \"../pipelines/aiLabChat.js\";\nimport { isAIUser } from \"../utils/aiUser.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n claimMessageAttachments,\n ensureMessageHasContentOrAttachments,\n} from \"./message.js\";\n\n/** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */\nexport async function createLabChat(\n userId: string,\n input: { classId: string; title: string; context: string }\n) {\n const { classId, title, context } = input;\n\n const classWithTeachers = await findClassWithTeachersForLab(classId, userId);\n if (!classWithTeachers) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a teacher in this class\",\n });\n }\n\n try {\n JSON.parse(context);\n } catch {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Context must be valid JSON\",\n });\n }\n\n const result = await prisma.$transaction(async (tx) => {\n const conversation = await tx.conversation.create({\n data: {\n type: \"GROUP\",\n name: `Lab: ${title}`,\n displayInChat: false,\n },\n });\n\n const teacherMembers = classWithTeachers.teachers.map((t) => ({\n userId: t.id,\n role: \"ADMIN\" as const,\n }));\n\n await tx.conversationMember.createMany({\n data: teacherMembers.map((member) => ({\n userId: member.userId,\n conversationId: conversation.id,\n role: member.role,\n })),\n });\n\n const labChat = await tx.labChat.create({\n data: {\n title,\n context,\n classId,\n conversationId: conversation.id,\n createdById: userId,\n },\n include: {\n conversation: {\n include: {\n members: {\n include: {\n user: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n },\n },\n },\n },\n createdBy: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n },\n },\n },\n },\n class: {\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n },\n },\n },\n });\n\n return labChat;\n });\n\n generateAndSendLabIntroduction(\n result.id,\n result.conversationId,\n context,\n classWithTeachers.subject || \"Lab\"\n );\n\n try {\n await pusher.trigger(teacherChannel(classId), \"lab-chat-created\", {\n id: result.id,\n title: result.title,\n classId: result.classId,\n conversationId: result.conversationId,\n createdBy: result.createdBy,\n createdAt: result.createdAt,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat creation:\", error);\n }\n\n return result;\n}\n\nexport async function getLabChat(userId: string, labChatId: string) {\n let labChat = await findLabChatByMember(labChatId, userId);\n\n if (!labChat) {\n const labChatForTeacher = await findLabChatByTeacher(labChatId, userId);\n if (labChatForTeacher) {\n await prisma.conversationMember.create({\n data: {\n userId,\n conversationId: labChatForTeacher.conversation.id,\n role: \"ADMIN\",\n },\n });\n labChat = await findLabChatById(labChatId);\n }\n }\n\n if (!labChat) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n const pendingMessage = await prisma.message.findFirst({\n where: {\n conversationId: labChat.conversationId,\n status: GenerationStatus.PENDING,\n senderId: { not: \"AI_ASSISTANT\" },\n },\n orderBy: { createdAt: \"desc\" },\n select: { id: true },\n });\n\n return {\n ...labChat,\n pendingGenerationMessageId: pendingMessage?.id ?? null,\n };\n}\n\nexport async function listLabChats(userId: string, classId: string) {\n const classMembership = await findClassMembership(classId, userId);\n if (!classMembership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member of this class\",\n });\n }\n\n const labChats = await findLabChatsByClass(classId);\n return labChats.map((labChat) => ({\n id: labChat.id,\n title: labChat.title,\n classId: labChat.classId,\n conversationId: labChat.conversationId,\n createdBy: labChat.createdBy,\n createdAt: labChat.createdAt,\n updatedAt: labChat.updatedAt,\n lastMessage: labChat.conversation.messages[0] || null,\n messageCount: labChat.conversation._count.messages,\n }));\n}\n\nexport async function postToLabChat(\n userId: string,\n input: {\n labChatId: string;\n content: string;\n mentionedUserIds?: string[];\n fileIds?: string[];\n }\n) {\n const { labChatId, content, mentionedUserIds = [], fileIds = [] } = input;\n\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n if (mentionedUserIds.length > 0) {\n const mentionedMemberships = await findMentionedMemberships(\n labChat.conversationId,\n mentionedUserIds\n );\n if (mentionedMemberships.length !== mentionedUserIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Some mentioned users are not members of this lab chat\",\n });\n }\n }\n\n ensureMessageHasContentOrAttachments(content, fileIds);\n const normalizedContent = content.trim();\n\n const result = await prisma.$transaction(async (tx) => {\n const message = await tx.message.create({\n data: {\n content: normalizedContent,\n senderId: userId,\n conversationId: labChat.conversationId,\n ...(isAIUser(userId) ? {} : { status: GenerationStatus.PENDING }),\n },\n });\n\n await claimMessageAttachments(\n tx,\n userId,\n labChat.conversationId,\n message.id,\n fileIds\n );\n\n if (mentionedUserIds.length > 0) {\n await tx.mention.createMany({\n data: mentionedUserIds.map((mentionedUserId) => ({\n messageId: message.id,\n userId: mentionedUserId,\n })),\n });\n }\n\n await tx.labChat.update({\n where: { id: labChatId },\n data: { updatedAt: new Date() },\n });\n\n return tx.message.findUniqueOrThrow({\n where: { id: message.id },\n include: {\n sender: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n attachments: {\n select: { id: true, name: true, type: true },\n },\n },\n });\n });\n\n try {\n await pusher.trigger(\n chatChannel(labChat.conversationId),\n \"new-message\",\n {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n meta: {},\n }\n );\n } catch (error) {\n console.error(\"Failed to broadcast lab chat message:\", error);\n }\n\n if (!isAIUser(userId)) {\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: result.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n generateAndSendLabResponse(labChatId, normalizedContent, {\n classId: labChat.classId,\n messageId: result.id,\n }).catch((error) =>\n logger.error(\"Failed to generate lab response\", {\n error,\n labChatId,\n messageId: result.id,\n conversationId: labChat.conversationId,\n })\n );\n }\n\n return {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n };\n}\n\nexport async function deleteLabChat(userId: string, labChatId: string) {\n const labChat = await findLabChatForDelete(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or not the creator\",\n });\n }\n\n await prisma.$transaction(async (tx) => {\n await tx.mention.deleteMany({\n where: {\n message: {\n conversationId: labChat.conversationId,\n },\n },\n });\n\n await tx.message.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.conversationMember.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.labChat.delete({\n where: { id: labChatId },\n });\n\n await tx.conversation.delete({\n where: { id: labChat.conversationId },\n });\n });\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-chat-deleted\", {\n labChatId,\n classId: labChat.classId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat deletion:\", error);\n }\n\n return { success: true };\n}\n\n/** Rerun the last AI response for a lab chat. Deletes the last AI message and regenerates. */\nexport async function rerunLastResponse(userId: string, labChatId: string) {\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n const messages = await prisma.message.findMany({\n where: { conversationId: labChat.conversationId },\n orderBy: { createdAt: \"desc\" },\n take: 10,\n select: { id: true, content: true, senderId: true, createdAt: true },\n });\n\n const lastMessage = messages[0];\n if (!lastMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No messages to rerun\",\n });\n }\n\n if (!isAIUser(lastMessage.senderId)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Last message is not from AI – nothing to rerun\",\n });\n }\n\n const teacherMessage = messages.find((m) => !isAIUser(m.senderId));\n if (!teacherMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No teacher message found to rerun from\",\n });\n }\n\n await prisma.$transaction([\n prisma.message.delete({\n where: { id: lastMessage.id },\n }),\n prisma.message.update({\n where: { id: teacherMessage.id },\n data: { status: GenerationStatus.PENDING },\n }),\n ]);\n\n try {\n await pusher.trigger(chatChannel(labChat.conversationId), \"message-deleted\", {\n messageId: lastMessage.id,\n conversationId: labChat.conversationId,\n senderId: lastMessage.senderId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast message deletion:\", error);\n }\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: teacherMessage.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n generateAndSendLabResponse(labChatId, teacherMessage.content, {\n classId: labChat.classId,\n messageId: teacherMessage.id,\n }).catch((error) =>\n logger.error(\"Failed to generate lab response\", {\n error,\n labChatId,\n messageId: teacherMessage.id,\n conversationId: labChat.conversationId,\n })\n );\n\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"a2cfffda-ee2d-53e3-a8f9-ea08a785e468"}
1
+ {"version":3,"file":"labChat.js","sources":["services/labChat.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab chat service – AI-powered lab conversations. Create lab chats, post messages,\n * trigger AI responses, and broadcast via Pusher.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { JobStatus, RunJobType } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { chatChannel, teacherChannel, pusher } from \"../lib/pusher.js\";\nimport {\n findClassWithTeachersForLab,\n findLabChatByMember,\n findLabChatByTeacher,\n findLabChatById,\n findClassMembership,\n findLabChatsByClass,\n findLabChatForPost,\n findLabChatForDelete,\n findMentionedMemberships,\n} from \"../models/labChat.js\";\nimport { getAIUserId, isAIUser } from \"../utils/aiUser.js\";\nimport { createPendingAIMessage } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { enqueueRunJob, QUEUE_NAMES } from \"../workers/queues.js\";\nimport {\n claimMessageAttachments,\n ensureMessageHasContentOrAttachments,\n} from \"./message.js\";\n\n/** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */\nexport async function createLabChat(\n userId: string,\n input: { classId: string; title: string; context: string }\n) {\n const { classId, title, context } = input;\n\n const classWithTeachers = await findClassWithTeachersForLab(classId, userId);\n if (!classWithTeachers) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a teacher in this class\",\n });\n }\n\n try {\n JSON.parse(context);\n } catch {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Context must be valid JSON\",\n });\n }\n\n const result = await prisma.$transaction(async (tx) => {\n const conversation = await tx.conversation.create({\n data: {\n type: \"GROUP\",\n name: `Lab: ${title}`,\n displayInChat: false,\n },\n });\n\n const teacherMembers = classWithTeachers.teachers.map((t) => ({\n userId: t.id,\n role: \"ADMIN\" as const,\n }));\n\n await tx.conversationMember.createMany({\n data: teacherMembers.map((member) => ({\n userId: member.userId,\n conversationId: conversation.id,\n role: member.role,\n })),\n });\n\n const labChat = await tx.labChat.create({\n data: {\n title,\n context,\n classId,\n conversationId: conversation.id,\n createdById: userId,\n },\n include: {\n conversation: {\n include: {\n members: {\n include: {\n user: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n },\n },\n },\n },\n createdBy: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n },\n },\n },\n },\n class: {\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n },\n },\n },\n });\n\n return labChat;\n });\n\n // Create the AI introduction placeholder *outside* the transaction (the\n // helper triggers Pusher and we don't want a tx rollback to leave a\n // dangling broadcast). The pipeline will fill this row in.\n try {\n const aiPlaceholder = await createPendingAIMessage(result.conversationId);\n await enqueueRunJob(\n QUEUE_NAMES.AI_LAB_CHAT as RunJobType,\n { conversationId: result.conversationId, aiMessageId: aiPlaceholder.id },\n { classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab chat introduction\", {\n error,\n labChatId: result.id,\n conversationId: result.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(classId), \"lab-chat-created\", {\n id: result.id,\n title: result.title,\n classId: result.classId,\n conversationId: result.conversationId,\n createdBy: result.createdBy,\n createdAt: result.createdAt,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat creation:\", error);\n }\n\n return result;\n}\n\nexport async function getLabChat(userId: string, labChatId: string) {\n let labChat = await findLabChatByMember(labChatId, userId);\n\n if (!labChat) {\n const labChatForTeacher = await findLabChatByTeacher(labChatId, userId);\n if (labChatForTeacher) {\n await prisma.conversationMember.create({\n data: {\n userId,\n conversationId: labChatForTeacher.conversation.id,\n role: \"ADMIN\",\n },\n });\n labChat = await findLabChatById(labChatId);\n }\n }\n\n if (!labChat) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n // The AI placeholder row IS the pending generation marker now — its\n // status flips PENDING → COMPLETED / FAILED as the pipeline runs.\n const pendingMessage = await prisma.message.findFirst({\n where: {\n conversationId: labChat.conversationId,\n status: JobStatus.PENDING,\n senderId: getAIUserId(),\n },\n orderBy: { createdAt: \"desc\" },\n select: { id: true },\n });\n\n return {\n ...labChat,\n pendingGenerationMessageId: pendingMessage?.id ?? null,\n };\n}\n\nexport async function listLabChats(userId: string, classId: string) {\n const classMembership = await findClassMembership(classId, userId);\n if (!classMembership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member of this class\",\n });\n }\n\n const labChats = await findLabChatsByClass(classId);\n return labChats.map((labChat) => ({\n id: labChat.id,\n title: labChat.title,\n classId: labChat.classId,\n conversationId: labChat.conversationId,\n createdBy: labChat.createdBy,\n createdAt: labChat.createdAt,\n updatedAt: labChat.updatedAt,\n lastMessage: labChat.conversation.messages[0] || null,\n messageCount: labChat.conversation._count.messages,\n }));\n}\n\nexport async function postToLabChat(\n userId: string,\n input: {\n labChatId: string;\n content: string;\n mentionedUserIds?: string[];\n fileIds?: string[];\n }\n) {\n const { labChatId, content, mentionedUserIds = [], fileIds = [] } = input;\n\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n if (mentionedUserIds.length > 0) {\n const mentionedMemberships = await findMentionedMemberships(\n labChat.conversationId,\n mentionedUserIds\n );\n if (mentionedMemberships.length !== mentionedUserIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Some mentioned users are not members of this lab chat\",\n });\n }\n }\n\n ensureMessageHasContentOrAttachments(content, fileIds);\n const normalizedContent = content.trim();\n\n const result = await prisma.$transaction(async (tx) => {\n const message = await tx.message.create({\n data: {\n content: normalizedContent,\n senderId: userId,\n conversationId: labChat.conversationId,\n },\n });\n\n await claimMessageAttachments(\n tx,\n userId,\n labChat.conversationId,\n message.id,\n fileIds\n );\n\n if (mentionedUserIds.length > 0) {\n await tx.mention.createMany({\n data: mentionedUserIds.map((mentionedUserId) => ({\n messageId: message.id,\n userId: mentionedUserId,\n })),\n });\n }\n\n await tx.labChat.update({\n where: { id: labChatId },\n data: { updatedAt: new Date() },\n });\n\n return tx.message.findUniqueOrThrow({\n where: { id: message.id },\n include: {\n sender: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n attachments: {\n select: { id: true, name: true, type: true },\n },\n },\n });\n });\n\n try {\n await pusher.trigger(\n chatChannel(labChat.conversationId),\n \"new-message\",\n {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n meta: {},\n }\n );\n } catch (error) {\n console.error(\"Failed to broadcast lab chat message:\", error);\n }\n\n if (!isAIUser(userId)) {\n // Create the AI placeholder post-tx so a transaction rollback can never\n // leave a dangling PENDING bubble. The placeholder broadcast IS the\n // \"AI is thinking...\" indicator inline in the chat; the teacher-channel\n // event below drives the lab list \"AI busy in this lab\" pill.\n let aiPlaceholderId: string | null = null;\n try {\n const aiPlaceholder = await createPendingAIMessage(labChat.conversationId);\n aiPlaceholderId = aiPlaceholder.id;\n } catch (error) {\n logger.error(\"Failed to create AI placeholder for lab response\", {\n error,\n labChatId,\n teacherMessageId: result.id,\n conversationId: labChat.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: aiPlaceholderId ?? result.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n if (aiPlaceholderId) {\n try {\n await enqueueRunJob(\n QUEUE_NAMES.AI_LAB_CHAT as RunJobType,\n { conversationId: labChat.conversationId, aiMessageId: aiPlaceholderId },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response\", {\n error,\n labChatId,\n aiMessageId: aiPlaceholderId,\n conversationId: labChat.conversationId,\n });\n }\n }\n }\n\n return {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n };\n}\n\nexport async function deleteLabChat(userId: string, labChatId: string) {\n const labChat = await findLabChatForDelete(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or not the creator\",\n });\n }\n\n await prisma.$transaction(async (tx) => {\n await tx.mention.deleteMany({\n where: {\n message: {\n conversationId: labChat.conversationId,\n },\n },\n });\n\n await tx.message.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.conversationMember.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.labChat.delete({\n where: { id: labChatId },\n });\n\n await tx.conversation.delete({\n where: { id: labChat.conversationId },\n });\n });\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-chat-deleted\", {\n labChatId,\n classId: labChat.classId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat deletion:\", error);\n }\n\n return { success: true };\n}\n\n/**\n * Rerun the last AI response in a lab chat.\n *\n * The AI message bubble is reused (not deleted): we flip it back to\n * PENDING and clear its content so the existing message id stays stable\n * for the client. The pipeline then refills it.\n */\nexport async function rerunLastResponse(userId: string, labChatId: string) {\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n const messages = await prisma.message.findMany({\n where: { conversationId: labChat.conversationId },\n orderBy: { createdAt: \"desc\" },\n take: 10,\n select: { id: true, content: true, senderId: true, createdAt: true },\n });\n\n const lastMessage = messages[0];\n if (!lastMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No messages to rerun\",\n });\n }\n\n if (!isAIUser(lastMessage.senderId)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Last message is not from AI – nothing to rerun\",\n });\n }\n\n const teacherMessage = messages.find((m) => !isAIUser(m.senderId));\n if (!teacherMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No teacher message found to rerun from\",\n });\n }\n\n const reusedAiMessage = await prisma.message.update({\n where: { id: lastMessage.id },\n data: {\n content: \"\",\n status: JobStatus.PENDING,\n meta: {},\n },\n select: { id: true, conversationId: true, status: true, content: true, senderId: true, createdAt: true },\n });\n\n // Tell the chat UI the existing AI bubble is regenerating — content\n // cleared, status flipped back to PENDING, same id.\n try {\n await pusher.trigger(chatChannel(labChat.conversationId), \"message-updated\", {\n id: reusedAiMessage.id,\n content: reusedAiMessage.content,\n senderId: reusedAiMessage.senderId,\n conversationId: reusedAiMessage.conversationId,\n status: reusedAiMessage.status,\n createdAt: reusedAiMessage.createdAt,\n sender: {\n id: reusedAiMessage.senderId,\n username: 'Newton_AI',\n profile: { displayName: 'Newton AI', profilePicture: null },\n },\n mentionedUserIds: [],\n meta: {},\n attachments: [],\n });\n } catch (error) {\n console.error(\"Failed to broadcast AI message rerun reset:\", error);\n }\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n try {\n await enqueueRunJob(\n QUEUE_NAMES.AI_LAB_CHAT as RunJobType,\n { conversationId: labChat.conversationId, aiMessageId: reusedAiMessage.id },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response rerun\", {\n error,\n labChatId,\n aiMessageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n }\n\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"ca593f36-e2e1-5f0c-b82a-d2d4fe00b23b"}
@@ -42,6 +42,7 @@ export declare function listMessages(userId: string, input: {
42
42
  profilePicture: string | null;
43
43
  } | null;
44
44
  };
45
+ status: import(".prisma/client").$Enums.JobStatus | null;
45
46
  attachments: {
46
47
  id: string;
47
48
  name: string;
@@ -72,6 +73,7 @@ export declare function sendMessage(userId: string, input: {
72
73
  content: string;
73
74
  senderId: string;
74
75
  conversationId: string;
76
+ status: import(".prisma/client").$Enums.JobStatus | null;
75
77
  createdAt: Date;
76
78
  sender: {
77
79
  id: string;
@@ -97,6 +99,7 @@ export declare function updateMessage(userId: string, input: {
97
99
  content: string;
98
100
  senderId: string;
99
101
  conversationId: string;
102
+ status: import(".prisma/client").$Enums.JobStatus | null;
100
103
  createdAt: Date;
101
104
  sender: {
102
105
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["services/message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAmB7C,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,EAAO,QAQvB;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,CAAC,iBAAiB,EAC5B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAM,EAAO,iBA2BvB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD,8DAmBF;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;;;GAuCF;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;;;;;;;;;;;;;;;;;;;;cAoCyB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;GAMlD;AAED,oFAAoF;AACpF,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;GAgIF;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;;;;;;;;;;;;;;;GAmHF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;GAuDpE;AAUD,mFAAmF;AACnF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;;GA6HF;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GA+BtE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;GAgCvB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;GA8BvB"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["services/message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAmB7C,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,EAAO,QAQvB;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,CAAC,iBAAiB,EAC5B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAM,EAAO,iBA2BvB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD,8DAmBF;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;;;GAoDF;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;;;;;;;;;;;;;;;;;;;;;cAqCyB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;GAMlD;AAED,oFAAoF;AACpF,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;;GAkIF;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;;;;;;;;;;;;;;;;GAqHF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;GAuDpE;AAUD,mFAAmF;AACnF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;;GA8HF;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GA+BtE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;GAgCvB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;GA8BvB"}