@goscribe/server 1.3.3 → 1.5.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 (378) hide show
  1. package/.env.example +12 -0
  2. package/.vscode/settings.json +3 -0
  3. package/REFACTOR_NOTES.md +60 -0
  4. package/TESTING_PROMPT.md +225 -0
  5. package/dist/controllers/admin.controller.d.ts +715 -0
  6. package/dist/controllers/admin.controller.js +9 -0
  7. package/dist/controllers/annotations.controller.d.ts +439 -0
  8. package/dist/controllers/annotations.controller.js +9 -0
  9. package/dist/controllers/app-router.controller.d.ts +3011 -0
  10. package/dist/controllers/app-router.controller.js +38 -0
  11. package/dist/controllers/app-router.controller.test.d.ts +1 -0
  12. package/dist/controllers/app-router.controller.test.js +36 -0
  13. package/dist/controllers/auth.controller.d.ts +323 -0
  14. package/dist/controllers/auth.controller.js +9 -0
  15. package/dist/controllers/base.controller.d.ts +4 -0
  16. package/dist/controllers/base.controller.js +5 -0
  17. package/dist/controllers/chat.controller.d.ts +341 -0
  18. package/dist/controllers/chat.controller.js +9 -0
  19. package/dist/controllers/copilot.controller.d.ts +397 -0
  20. package/dist/controllers/copilot.controller.js +9 -0
  21. package/dist/controllers/flashcards.controller.d.ts +651 -0
  22. package/dist/controllers/flashcards.controller.js +9 -0
  23. package/dist/controllers/members.controller.d.ts +339 -0
  24. package/dist/controllers/members.controller.js +9 -0
  25. package/dist/controllers/notifications.controller.d.ts +199 -0
  26. package/dist/controllers/notifications.controller.js +9 -0
  27. package/dist/controllers/payment.controller.d.ts +181 -0
  28. package/dist/controllers/payment.controller.js +9 -0
  29. package/dist/controllers/podcast.controller.d.ts +575 -0
  30. package/dist/controllers/podcast.controller.js +9 -0
  31. package/dist/controllers/router-module.controller.d.ts +5 -0
  32. package/dist/controllers/router-module.controller.js +6 -0
  33. package/dist/controllers/studyguide.controller.d.ts +73 -0
  34. package/dist/controllers/studyguide.controller.js +9 -0
  35. package/dist/controllers/worksheets.controller.d.ts +829 -0
  36. package/dist/controllers/worksheets.controller.js +9 -0
  37. package/dist/controllers/workspace.controller.d.ts +1207 -0
  38. package/dist/controllers/workspace.controller.js +9 -0
  39. package/dist/lib/activity_human_description.test.js +16 -15
  40. package/dist/lib/activity_log_service.test.js +28 -23
  41. package/dist/lib/ai/config.d.ts +20 -0
  42. package/dist/lib/ai/config.js +31 -0
  43. package/dist/lib/ai/embedding-client.d.ts +8 -0
  44. package/dist/lib/ai/embedding-client.js +30 -0
  45. package/dist/lib/ai/index.d.ts +47 -0
  46. package/dist/lib/ai/index.js +28 -0
  47. package/dist/lib/ai/inference-backend/client.d.ts +28 -0
  48. package/dist/lib/ai/inference-backend/client.js +301 -0
  49. package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
  50. package/dist/lib/ai/inference-backend/mocks.js +133 -0
  51. package/dist/lib/ai/inference-backend/types.d.ts +44 -0
  52. package/dist/lib/ai/inference-backend/types.js +1 -0
  53. package/dist/lib/ai/json-parse.d.ts +2 -0
  54. package/dist/lib/ai/json-parse.js +34 -0
  55. package/dist/lib/ai/llm-client.d.ts +6 -0
  56. package/dist/lib/ai/llm-client.js +19 -0
  57. package/dist/lib/ai/mock.d.ts +2 -0
  58. package/dist/lib/ai/mock.js +10 -0
  59. package/dist/lib/ai/types.d.ts +9 -0
  60. package/dist/lib/ai/types.js +1 -0
  61. package/dist/lib/chunking.d.ts +19 -0
  62. package/dist/lib/chunking.js +47 -0
  63. package/dist/lib/curated-kb-seed.d.ts +12 -0
  64. package/dist/lib/curated-kb-seed.js +155 -0
  65. package/dist/lib/email.js +67 -108
  66. package/dist/lib/embeddings.d.ts +2 -0
  67. package/dist/lib/embeddings.js +1 -0
  68. package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
  69. package/dist/lib/ensure-curated-kb-catalog.js +53 -0
  70. package/dist/lib/env.d.ts +1 -5
  71. package/dist/lib/env.js +2 -7
  72. package/dist/lib/inference.d.ts +1 -8
  73. package/dist/lib/inference.js +1 -19
  74. package/dist/lib/kb-meta.d.ts +8 -0
  75. package/dist/lib/kb-meta.js +77 -0
  76. package/dist/lib/note-text.d.ts +1 -0
  77. package/dist/lib/note-text.js +47 -0
  78. package/dist/lib/notification-service.test.js +37 -36
  79. package/dist/lib/pdf.d.ts +11 -0
  80. package/dist/lib/pdf.js +11 -0
  81. package/dist/lib/usage_service.d.ts +2 -1
  82. package/dist/lib/usage_service.js +30 -12
  83. package/dist/lib/worksheet-generation.js +4 -4
  84. package/dist/lib/worksheet-generation.test.js +32 -17
  85. package/dist/lib/workspace-kb.d.ts +5 -0
  86. package/dist/lib/workspace-kb.js +7 -0
  87. package/dist/models/controller-context.model.d.ts +8 -0
  88. package/dist/models/controller-context.model.js +1 -0
  89. package/dist/repositories/artifact.repository.d.ts +60 -0
  90. package/dist/repositories/artifact.repository.js +40 -0
  91. package/dist/repositories/base.repository.d.ts +14 -0
  92. package/dist/repositories/base.repository.js +14 -0
  93. package/dist/repositories/invitation.repository.d.ts +94 -0
  94. package/dist/repositories/invitation.repository.js +44 -0
  95. package/dist/repositories/notification.repository.d.ts +72 -0
  96. package/dist/repositories/notification.repository.js +44 -0
  97. package/dist/repositories/router-module.repository.d.ts +10 -0
  98. package/dist/repositories/router-module.repository.js +14 -0
  99. package/dist/repositories/user.repository.d.ts +74 -0
  100. package/dist/repositories/user.repository.js +37 -0
  101. package/dist/repositories/workspace-member.repository.d.ts +31 -0
  102. package/dist/repositories/workspace-member.repository.js +31 -0
  103. package/dist/repositories/workspace.repository.d.ts +97 -0
  104. package/dist/repositories/workspace.repository.js +79 -0
  105. package/dist/routers/_app.d.ts +528 -33
  106. package/dist/routers/_app.js +4 -0
  107. package/dist/routers/admin.d.ts +0 -4
  108. package/dist/routers/admin.js +21 -549
  109. package/dist/routers/annotations.js +12 -170
  110. package/dist/routers/artifactVersions.d.ts +65 -0
  111. package/dist/routers/artifactVersions.js +14 -0
  112. package/dist/routers/auth.d.ts +0 -6
  113. package/dist/routers/auth.js +36 -421
  114. package/dist/routers/chat.js +15 -229
  115. package/dist/routers/copilot.d.ts +14 -13
  116. package/dist/routers/copilot.js +13 -532
  117. package/dist/routers/flashcards.d.ts +5 -5
  118. package/dist/routers/flashcards.js +23 -349
  119. package/dist/routers/knowledgeBase.d.ts +421 -0
  120. package/dist/routers/knowledgeBase.js +118 -0
  121. package/dist/routers/members.d.ts +0 -41
  122. package/dist/routers/members.js +22 -710
  123. package/dist/routers/notes.d.ts +94 -0
  124. package/dist/routers/notes.js +37 -0
  125. package/dist/routers/notifications.js +7 -109
  126. package/dist/routers/payment.d.ts +3 -2
  127. package/dist/routers/payment.js +11 -393
  128. package/dist/routers/podcast.d.ts +1 -1
  129. package/dist/routers/podcast.js +11 -784
  130. package/dist/routers/studyguide.js +3 -129
  131. package/dist/routers/worksheets.d.ts +29 -14
  132. package/dist/routers/worksheets.js +49 -628
  133. package/dist/routers/workspace.d.ts +0 -4
  134. package/dist/routers/workspace.js +28 -922
  135. package/dist/scripts/purge-deleted-users.js +2 -2
  136. package/dist/server.js +10 -3
  137. package/dist/services/activity/activity-human-description.service.d.ts +13 -0
  138. package/dist/services/activity/activity-human-description.service.js +221 -0
  139. package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
  140. package/dist/services/activity/activity-human-description.service.test.js +16 -0
  141. package/dist/services/activity/activity-log.service.d.ts +87 -0
  142. package/dist/services/activity/activity-log.service.js +276 -0
  143. package/dist/services/activity/activity-log.service.test.d.ts +1 -0
  144. package/dist/services/activity/activity-log.service.test.js +27 -0
  145. package/dist/services/activity-human-description.service.d.ts +13 -0
  146. package/dist/services/activity-human-description.service.js +221 -0
  147. package/dist/services/activity-human-description.service.test.d.ts +1 -0
  148. package/dist/services/activity-human-description.service.test.js +16 -0
  149. package/dist/services/activity-log.service.d.ts +87 -0
  150. package/dist/services/activity-log.service.js +276 -0
  151. package/dist/services/activity-log.service.test.d.ts +1 -0
  152. package/dist/services/activity-log.service.test.js +27 -0
  153. package/dist/services/admin/admin.service.d.ts +270 -0
  154. package/dist/services/admin/admin.service.js +476 -0
  155. package/dist/services/admin.service.d.ts +270 -0
  156. package/dist/services/admin.service.js +476 -0
  157. package/dist/services/ai/ai-session.service.d.ts +5 -0
  158. package/dist/services/ai/ai-session.service.js +4 -0
  159. package/dist/services/ai-session.service.d.ts +60 -0
  160. package/dist/services/ai-session.service.js +561 -0
  161. package/dist/services/annotation.service.d.ts +177 -0
  162. package/dist/services/annotation.service.js +154 -0
  163. package/dist/services/artifact-notification.service.d.ts +14 -0
  164. package/dist/services/artifact-notification.service.js +20 -0
  165. package/dist/services/artifact-version.service.d.ts +38 -0
  166. package/dist/services/artifact-version.service.js +129 -0
  167. package/dist/services/artifacts/annotation.service.d.ts +177 -0
  168. package/dist/services/artifacts/annotation.service.js +154 -0
  169. package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
  170. package/dist/services/artifacts/artifact-version.service.js +129 -0
  171. package/dist/services/artifacts/chat.service.d.ts +127 -0
  172. package/dist/services/artifacts/chat.service.js +182 -0
  173. package/dist/services/artifacts/study-guide.service.d.ts +18 -0
  174. package/dist/services/artifacts/study-guide.service.js +65 -0
  175. package/dist/services/auth/auth.service.d.ts +94 -0
  176. package/dist/services/auth/auth.service.js +368 -0
  177. package/dist/services/auth.service.d.ts +94 -0
  178. package/dist/services/auth.service.js +368 -0
  179. package/dist/services/base.service.d.ts +14 -0
  180. package/dist/services/base.service.js +14 -0
  181. package/dist/services/billing/payment.service.d.ts +55 -0
  182. package/dist/services/billing/payment.service.js +368 -0
  183. package/dist/services/billing/subscription.service.d.ts +37 -0
  184. package/dist/services/billing/subscription.service.js +654 -0
  185. package/dist/services/billing/usage.service.d.ts +27 -0
  186. package/dist/services/billing/usage.service.js +77 -0
  187. package/dist/services/chat.service.d.ts +127 -0
  188. package/dist/services/chat.service.js +182 -0
  189. package/dist/services/content/copilot.service.d.ts +113 -0
  190. package/dist/services/content/copilot.service.js +453 -0
  191. package/dist/services/content/flashcard-progress.service.d.ts +159 -0
  192. package/dist/services/content/flashcard-progress.service.js +432 -0
  193. package/dist/services/content/flashcard.service.d.ts +140 -0
  194. package/dist/services/content/flashcard.service.js +326 -0
  195. package/dist/services/content/media-analysis.service.d.ts +23 -0
  196. package/dist/services/content/media-analysis.service.js +404 -0
  197. package/dist/services/content/podcast.service.d.ts +267 -0
  198. package/dist/services/content/podcast.service.js +653 -0
  199. package/dist/services/content/worksheet-content.service.d.ts +37 -0
  200. package/dist/services/content/worksheet-content.service.js +84 -0
  201. package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
  202. package/dist/services/content/worksheet-content.service.test.js +69 -0
  203. package/dist/services/content/worksheet-generation.service.d.ts +91 -0
  204. package/dist/services/content/worksheet-generation.service.js +95 -0
  205. package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
  206. package/dist/services/content/worksheet-generation.service.test.js +20 -0
  207. package/dist/services/content/worksheet.service.d.ts +347 -0
  208. package/dist/services/content/worksheet.service.js +599 -0
  209. package/dist/services/copilot.service.d.ts +116 -0
  210. package/dist/services/copilot.service.js +447 -0
  211. package/dist/services/flashcard-progress.service.d.ts +2 -2
  212. package/dist/services/flashcard-progress.service.js +3 -2
  213. package/dist/services/flashcard.service.d.ts +140 -0
  214. package/dist/services/flashcard.service.js +325 -0
  215. package/dist/services/invitation.service.d.ts +66 -0
  216. package/dist/services/invitation.service.js +348 -0
  217. package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
  218. package/dist/services/knowledge/knowledge-base.service.js +544 -0
  219. package/dist/services/knowledge-base.service.d.ts +316 -0
  220. package/dist/services/knowledge-base.service.js +536 -0
  221. package/dist/services/media-analysis.service.d.ts +23 -0
  222. package/dist/services/media-analysis.service.js +384 -0
  223. package/dist/services/member.service.d.ts +36 -0
  224. package/dist/services/member.service.js +193 -0
  225. package/dist/services/members/invitation.service.d.ts +66 -0
  226. package/dist/services/members/invitation.service.js +348 -0
  227. package/dist/services/members/member.service.d.ts +36 -0
  228. package/dist/services/members/member.service.js +193 -0
  229. package/dist/services/note.service.d.ts +55 -0
  230. package/dist/services/note.service.js +111 -0
  231. package/dist/services/notification.service.d.ts +214 -0
  232. package/dist/services/notification.service.js +550 -0
  233. package/dist/services/notification.service.test.d.ts +1 -0
  234. package/dist/services/notification.service.test.js +87 -0
  235. package/dist/services/notifications/notification.service.d.ts +214 -0
  236. package/dist/services/notifications/notification.service.js +550 -0
  237. package/dist/services/notifications/notification.service.test.d.ts +1 -0
  238. package/dist/services/notifications/notification.service.test.js +87 -0
  239. package/dist/services/payment.service.d.ts +55 -0
  240. package/dist/services/payment.service.js +368 -0
  241. package/dist/services/podcast.service.d.ts +267 -0
  242. package/dist/services/podcast.service.js +654 -0
  243. package/dist/services/router-module.service.d.ts +7 -0
  244. package/dist/services/router-module.service.js +10 -0
  245. package/dist/services/study-guide.service.d.ts +18 -0
  246. package/dist/services/study-guide.service.js +65 -0
  247. package/dist/services/subscription.service.d.ts +37 -0
  248. package/dist/services/subscription.service.js +654 -0
  249. package/dist/services/usage-limit-policy.service.d.ts +12 -0
  250. package/dist/services/usage-limit-policy.service.js +22 -0
  251. package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
  252. package/dist/services/usage-limit-policy.service.test.js +46 -0
  253. package/dist/services/usage.service.d.ts +27 -0
  254. package/dist/services/usage.service.js +77 -0
  255. package/dist/services/worksheet-content.service.d.ts +42 -0
  256. package/dist/services/worksheet-content.service.js +84 -0
  257. package/dist/services/worksheet-content.service.test.d.ts +1 -0
  258. package/dist/services/worksheet-content.service.test.js +69 -0
  259. package/dist/services/worksheet-generation.service.d.ts +91 -0
  260. package/dist/services/worksheet-generation.service.js +95 -0
  261. package/dist/services/worksheet-generation.service.test.d.ts +1 -0
  262. package/dist/services/worksheet-generation.service.test.js +20 -0
  263. package/dist/services/worksheet.service.d.ts +385 -0
  264. package/dist/services/worksheet.service.js +596 -0
  265. package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
  266. package/dist/services/workspace/workspace-analytics.service.js +95 -0
  267. package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
  268. package/dist/services/workspace/workspace-kb.service.js +184 -0
  269. package/dist/services/workspace/workspace.service.d.ts +307 -0
  270. package/dist/services/workspace/workspace.service.js +394 -0
  271. package/dist/services/workspace-analytics.service.d.ts +24 -0
  272. package/dist/services/workspace-analytics.service.js +95 -0
  273. package/dist/services/workspace-kb.service.d.ts +40 -0
  274. package/dist/services/workspace-kb.service.js +184 -0
  275. package/dist/services/workspace-progress.service.d.ts +27 -0
  276. package/dist/services/workspace-progress.service.js +56 -0
  277. package/dist/services/workspace-progress.service.test.d.ts +1 -0
  278. package/dist/services/workspace-progress.service.test.js +49 -0
  279. package/dist/services/workspace.service.d.ts +307 -0
  280. package/dist/services/workspace.service.js +390 -0
  281. package/dist/trpc.js +2 -2
  282. package/package.json +5 -6
  283. package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
  284. package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
  285. package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
  286. package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
  287. package/prisma/schema.prisma +150 -48
  288. package/prisma/seed.mjs +67 -0
  289. package/scripts/debug/README.md +4 -0
  290. package/src/README.md +63 -0
  291. package/src/lib/ai/config.ts +34 -0
  292. package/src/lib/ai/embedding-client.ts +47 -0
  293. package/src/lib/ai/index.ts +62 -0
  294. package/src/lib/ai/inference-backend/client.ts +479 -0
  295. package/src/lib/ai/inference-backend/mocks.ts +171 -0
  296. package/src/lib/ai/inference-backend/types.ts +50 -0
  297. package/src/lib/ai/json-parse.ts +35 -0
  298. package/src/lib/ai/llm-client.ts +31 -0
  299. package/src/lib/ai/mock.ts +12 -0
  300. package/src/lib/ai/types.ts +11 -0
  301. package/src/lib/chunking.ts +81 -0
  302. package/src/lib/curated-kb-seed.ts +164 -0
  303. package/src/lib/email.ts +77 -115
  304. package/src/lib/embeddings.ts +9 -0
  305. package/src/lib/ensure-curated-kb-catalog.ts +60 -0
  306. package/src/lib/env.ts +2 -7
  307. package/src/lib/inference.ts +1 -21
  308. package/src/lib/kb-meta.ts +81 -0
  309. package/src/lib/pdf.ts +23 -0
  310. package/src/lib/workspace-kb.ts +7 -0
  311. package/src/repositories/artifact.repository.ts +55 -0
  312. package/src/repositories/base.repository.ts +19 -0
  313. package/src/repositories/invitation.repository.ts +53 -0
  314. package/src/repositories/notification.repository.ts +53 -0
  315. package/src/repositories/user.repository.ts +44 -0
  316. package/src/repositories/workspace-member.repository.ts +38 -0
  317. package/src/repositories/workspace.repository.ts +89 -0
  318. package/src/routers/_app.ts +4 -0
  319. package/src/routers/admin.ts +124 -692
  320. package/src/routers/annotations.ts +25 -203
  321. package/src/routers/artifactVersions.ts +32 -0
  322. package/src/routers/auth.ts +81 -519
  323. package/src/routers/chat.ts +42 -245
  324. package/src/routers/copilot.ts +41 -666
  325. package/src/routers/flashcards.ts +108 -404
  326. package/src/routers/knowledgeBase.ts +216 -0
  327. package/src/routers/members.ts +60 -782
  328. package/src/routers/notifications.ts +15 -117
  329. package/src/routers/payment.ts +37 -446
  330. package/src/routers/podcast.ts +36 -898
  331. package/src/routers/studyguide.ts +5 -144
  332. package/src/routers/worksheets.ts +171 -735
  333. package/src/routers/workspace.ts +138 -1109
  334. package/src/scripts/purge-deleted-users.ts +2 -2
  335. package/src/server.ts +10 -3
  336. package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
  337. package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
  338. package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
  339. package/src/services/admin/admin.service.ts +612 -0
  340. package/src/services/ai/ai-session.service.ts +5 -0
  341. package/src/services/artifacts/annotation.service.ts +189 -0
  342. package/src/services/artifacts/artifact-version.service.ts +151 -0
  343. package/src/services/artifacts/chat.service.ts +197 -0
  344. package/src/services/artifacts/study-guide.service.ts +72 -0
  345. package/src/services/auth/auth.service.ts +473 -0
  346. package/src/services/base.service.ts +19 -0
  347. package/src/services/billing/payment.service.ts +436 -0
  348. package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
  349. package/src/{lib/usage_service.ts → services/billing/usage.service.ts} +32 -12
  350. package/src/services/content/copilot.service.ts +596 -0
  351. package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +6 -3
  352. package/src/services/content/flashcard.service.ts +394 -0
  353. package/src/services/content/media-analysis.service.ts +556 -0
  354. package/src/services/content/podcast.service.ts +777 -0
  355. package/src/services/content/worksheet-content.service.test.ts +83 -0
  356. package/src/services/content/worksheet-content.service.ts +117 -0
  357. package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +1 -1
  358. package/src/services/content/worksheet.service.ts +751 -0
  359. package/src/services/knowledge/knowledge-base.service.ts +705 -0
  360. package/src/services/members/invitation.service.ts +427 -0
  361. package/src/services/members/member.service.ts +241 -0
  362. package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
  363. package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
  364. package/src/services/workspace/workspace-analytics.service.ts +107 -0
  365. package/src/services/workspace/workspace-kb.service.ts +273 -0
  366. package/src/services/workspace/workspace.service.ts +481 -0
  367. package/src/trpc.ts +2 -2
  368. package/src/lib/ai-session.ts +0 -704
  369. package/src/lib/workspace-access.ts +0 -13
  370. /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
  371. /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
  372. /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
  373. /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
  374. /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
  375. /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
  376. /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
  377. /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
  378. /package/src/{lib/worksheet-generation.ts → services/content/worksheet-generation.service.ts} +0 -0
@@ -1,94 +1,17 @@
1
1
  import { z } from 'zod';
2
- import { TRPCError } from '@trpc/server';
3
2
  import { router, authedProcedure, limitedProcedure } from '../trpc.js';
4
- import { aiSessionService } from '../lib/ai-session.js';
5
- import PusherService from '../lib/pusher.js';
6
- import { notifyArtifactFailed, notifyArtifactReady } from '../lib/notification-service.js';
7
- import { createFlashcardProgressService } from '../services/flashcard-progress.service.js';
8
- import { ArtifactType } from '../lib/constants.js';
9
- import { workspaceAccessFilter } from '../lib/workspace-access.js';
10
- import inference from '../lib/inference.js';
11
- const typedAnswerGradeSchema = z.object({
12
- isCorrect: z.boolean(),
13
- confidence: z.number().min(0).max(1),
14
- reason: z.string().min(1),
15
- matchedAnswer: z.string().nullable(),
16
- });
17
- function normalizeAcceptedAnswers(answers) {
18
- if (!answers || answers.length === 0)
19
- return [];
20
- const seen = new Set();
21
- const normalized = [];
22
- for (const answer of answers) {
23
- const trimmed = answer.trim();
24
- if (!trimmed)
25
- continue;
26
- const key = trimmed.toLowerCase();
27
- if (seen.has(key))
28
- continue;
29
- seen.add(key);
30
- normalized.push(trimmed);
31
- }
32
- return normalized;
33
- }
34
- function extractFirstJsonObject(text) {
35
- const start = text.indexOf('{');
36
- const end = text.lastIndexOf('}');
37
- if (start === -1 || end === -1 || end <= start)
38
- return null;
39
- return text.slice(start, end + 1);
40
- }
3
+ import { FlashcardService } from '../services/content/flashcard.service.js';
4
+ import { createFlashcardProgressService } from '../services/content/flashcard-progress.service.js';
41
5
  export const flashcards = router({
42
6
  listSets: authedProcedure
43
7
  .input(z.object({ workspaceId: z.string() }))
44
- .query(async ({ ctx, input }) => {
45
- const workspace = await ctx.db.workspace.findFirst({
46
- where: { id: input.workspaceId, ownerId: ctx.session.user.id },
47
- });
48
- if (!workspace)
49
- throw new TRPCError({ code: 'NOT_FOUND' });
50
- return ctx.db.artifact.findMany({
51
- where: { workspaceId: input.workspaceId, type: ArtifactType.FLASHCARD_SET },
52
- include: {
53
- versions: {
54
- orderBy: { version: 'desc' },
55
- take: 1, // Get only the latest version
56
- },
57
- },
58
- orderBy: { updatedAt: 'desc' },
59
- });
60
- }),
8
+ .query(({ ctx, input }) => new FlashcardService(ctx.db).listSets(ctx.session.user.id, input.workspaceId)),
61
9
  listCards: authedProcedure
62
10
  .input(z.object({ workspaceId: z.string() }))
63
- .query(async ({ ctx, input }) => {
64
- const set = await ctx.db.artifact.findFirst({
65
- where: { workspaceId: input.workspaceId, type: ArtifactType.FLASHCARD_SET, workspace: workspaceAccessFilter(ctx.session.user.id) },
66
- include: {
67
- flashcards: {
68
- include: {
69
- progress: {
70
- where: {
71
- userId: ctx.session.user.id,
72
- },
73
- },
74
- }
75
- },
76
- },
77
- orderBy: { createdAt: 'desc' },
78
- });
79
- if (!set)
80
- throw new TRPCError({ code: 'NOT_FOUND' });
81
- return set.flashcards;
82
- }),
11
+ .query(({ ctx, input }) => new FlashcardService(ctx.db).listCards(ctx.session.user.id, input.workspaceId)),
83
12
  isGenerating: authedProcedure
84
13
  .input(z.object({ workspaceId: z.string() }))
85
- .query(async ({ ctx, input }) => {
86
- const artifact = await ctx.db.artifact.findFirst({
87
- where: { workspaceId: input.workspaceId, type: ArtifactType.FLASHCARD_SET, workspace: workspaceAccessFilter(ctx.session.user.id) },
88
- orderBy: { createdAt: 'desc' },
89
- });
90
- return artifact?.generating;
91
- }),
14
+ .query(({ ctx, input }) => new FlashcardService(ctx.db).isGenerating(ctx.session.user.id, input.workspaceId)),
92
15
  createCard: limitedProcedure
93
16
  .input(z.object({
94
17
  workspaceId: z.string(),
@@ -98,31 +21,7 @@ export const flashcards = router({
98
21
  tags: z.array(z.string()).optional(),
99
22
  order: z.number().int().optional(),
100
23
  }))
101
- .mutation(async ({ ctx, input }) => {
102
- const set = await ctx.db.artifact.findFirst({
103
- where: {
104
- type: ArtifactType.FLASHCARD_SET, workspace: {
105
- id: input.workspaceId,
106
- }
107
- },
108
- include: {
109
- flashcards: true,
110
- },
111
- orderBy: { updatedAt: 'desc' },
112
- });
113
- if (!set)
114
- throw new TRPCError({ code: 'NOT_FOUND' });
115
- return ctx.db.flashcard.create({
116
- data: {
117
- artifactId: set.id,
118
- front: input.front,
119
- back: input.back,
120
- acceptedAnswers: normalizeAcceptedAnswers(input.acceptedAnswers),
121
- tags: input.tags ?? [],
122
- order: input.order ?? 0,
123
- },
124
- });
125
- }),
24
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).createCard(ctx.session.user.id, input)),
126
25
  updateCard: authedProcedure
127
26
  .input(z.object({
128
27
  cardId: z.string(),
@@ -132,109 +31,19 @@ export const flashcards = router({
132
31
  tags: z.array(z.string()).optional(),
133
32
  order: z.number().int().optional(),
134
33
  }))
135
- .mutation(async ({ ctx, input }) => {
136
- const card = await ctx.db.flashcard.findFirst({
137
- where: { id: input.cardId, artifact: { type: ArtifactType.FLASHCARD_SET, workspace: workspaceAccessFilter(ctx.session.user.id) } },
138
- });
139
- if (!card)
140
- throw new TRPCError({ code: 'NOT_FOUND' });
141
- return ctx.db.flashcard.update({
142
- where: { id: input.cardId },
143
- data: {
144
- front: input.front ?? card.front,
145
- back: input.back ?? card.back,
146
- acceptedAnswers: input.acceptedAnswers ? normalizeAcceptedAnswers(input.acceptedAnswers) : card.acceptedAnswers,
147
- tags: input.tags ?? card.tags,
148
- order: input.order ?? card.order,
149
- },
150
- });
151
- }),
34
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).updateCard(ctx.session.user.id, input)),
152
35
  gradeTypedAnswer: authedProcedure
153
36
  .input(z.object({
154
37
  flashcardId: z.string().cuid(),
155
38
  userAnswer: z.string().min(1),
156
39
  }))
157
- .mutation(async ({ ctx, input }) => {
158
- const flashcard = await ctx.db.flashcard.findFirst({
159
- where: {
160
- id: input.flashcardId,
161
- artifact: {
162
- type: ArtifactType.FLASHCARD_SET,
163
- workspace: workspaceAccessFilter(ctx.session.user.id),
164
- },
165
- },
166
- select: {
167
- id: true,
168
- front: true,
169
- back: true,
170
- acceptedAnswers: true,
171
- },
172
- });
173
- if (!flashcard) {
174
- throw new TRPCError({ code: 'NOT_FOUND', message: 'Flashcard not found' });
175
- }
176
- const acceptedAnswers = [
177
- flashcard.back,
178
- ...normalizeAcceptedAnswers(flashcard.acceptedAnswers),
179
- ];
180
- const prompt = [
181
- 'Grade whether the student answer is semantically correct for the flashcard.',
182
- '',
183
- 'Return ONLY valid JSON with this exact shape:',
184
- '{"isCorrect": boolean, "confidence": number, "reason": string, "matchedAnswer": string | null}',
185
- '',
186
- 'Rules:',
187
- '- Accept synonyms, short paraphrases, and equivalent wording.',
188
- '- Reject answers that are contradictory, unrelated, or materially incomplete.',
189
- '- confidence must be from 0 to 1.',
190
- '- reason must be under 160 characters.',
191
- '- matchedAnswer must be the matched canonical/alias answer, or null if incorrect.',
192
- '',
193
- `Question: ${flashcard.front}`,
194
- `Canonical answer: ${flashcard.back}`,
195
- `Accepted aliases: ${JSON.stringify(acceptedAnswers)}`,
196
- `Student answer: ${input.userAnswer}`,
197
- ].join('\n');
198
- try {
199
- const response = await inference([{ role: 'user', content: prompt }]);
200
- const content = response.choices?.[0]?.message?.content ?? '';
201
- const jsonCandidate = extractFirstJsonObject(content);
202
- if (!jsonCandidate) {
203
- throw new Error('No JSON object found in grading response');
204
- }
205
- const parsed = JSON.parse(jsonCandidate);
206
- return typedAnswerGradeSchema.parse(parsed);
207
- }
208
- catch (error) {
209
- throw new TRPCError({
210
- code: 'INTERNAL_SERVER_ERROR',
211
- message: 'Failed to grade typed answer. Please retry.',
212
- cause: error,
213
- });
214
- }
215
- }),
40
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).gradeTypedAnswer(ctx.session.user.id, input)),
216
41
  deleteCard: authedProcedure
217
42
  .input(z.object({ cardId: z.string() }))
218
- .mutation(async ({ ctx, input }) => {
219
- const card = await ctx.db.flashcard.findFirst({
220
- where: { id: input.cardId, artifact: { workspace: workspaceAccessFilter(ctx.session.user.id) } },
221
- });
222
- if (!card)
223
- throw new TRPCError({ code: 'NOT_FOUND' });
224
- await ctx.db.flashcard.delete({ where: { id: input.cardId } });
225
- return true;
226
- }),
43
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).deleteCard(ctx.session.user.id, input.cardId)),
227
44
  deleteSet: authedProcedure
228
45
  .input(z.object({ setId: z.string().uuid() }))
229
- .mutation(async ({ ctx, input }) => {
230
- const deleted = await ctx.db.artifact.deleteMany({
231
- where: { id: input.setId, type: ArtifactType.FLASHCARD_SET, workspace: workspaceAccessFilter(ctx.session.user.id) },
232
- });
233
- if (deleted.count === 0)
234
- throw new TRPCError({ code: 'NOT_FOUND' });
235
- return true;
236
- }),
237
- // Generate a flashcard set from a user prompt
46
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).deleteSet(ctx.session.user.id, input.setId)),
238
47
  generateFromPrompt: limitedProcedure
239
48
  .input(z.object({
240
49
  workspaceId: z.string(),
@@ -244,119 +53,7 @@ export const flashcards = router({
244
53
  title: z.string().optional(),
245
54
  tags: z.array(z.string()).optional(),
246
55
  }))
247
- .mutation(async ({ ctx, input }) => {
248
- // Verify workspace ownership
249
- const workspace = await ctx.db.workspace.findFirst({
250
- where: { id: input.workspaceId, ownerId: ctx.session.user.id },
251
- });
252
- if (!workspace)
253
- throw new TRPCError({ code: 'NOT_FOUND' });
254
- const flashcardCurrent = await ctx.db.artifact.findFirst({
255
- where: {
256
- workspaceId: input.workspaceId,
257
- type: ArtifactType.FLASHCARD_SET,
258
- },
259
- select: {
260
- id: true,
261
- flashcards: true,
262
- },
263
- orderBy: {
264
- updatedAt: 'desc',
265
- },
266
- });
267
- try {
268
- await PusherService.emitTaskComplete(input.workspaceId, 'flash_card_info', { status: 'generating', numCards: input.numCards, difficulty: input.difficulty });
269
- const artifact = await ctx.db.artifact.create({
270
- data: {
271
- workspaceId: input.workspaceId,
272
- type: ArtifactType.FLASHCARD_SET,
273
- title: input.title || `Flashcards - ${new Date().toLocaleString()}`,
274
- createdById: ctx.session.user.id,
275
- generating: true,
276
- generatingMetadata: { quantity: input.numCards, difficulty: input.difficulty.toLowerCase() },
277
- flashcards: {
278
- create: flashcardCurrent?.flashcards.map((card) => ({
279
- front: card.front,
280
- back: card.back,
281
- })),
282
- },
283
- },
284
- });
285
- const currentCards = flashcardCurrent?.flashcards.length || 0;
286
- const newCards = input.numCards - currentCards;
287
- // Generate
288
- const content = await aiSessionService.generateFlashcardQuestions(input.workspaceId, ctx.session.user.id, input.numCards, input.difficulty, input.prompt);
289
- let createdCards = 0;
290
- try {
291
- const parsed = typeof content === 'string' ? JSON.parse(content) : content;
292
- const flashcardData = Array.isArray(parsed) ? parsed : (parsed.flashcards || []);
293
- for (let i = 0; i < Math.min(flashcardData.length, input.numCards); i++) {
294
- const card = flashcardData[i];
295
- const front = card.term || card.front || card.question || card.prompt || `Question ${i + 1}`;
296
- const back = card.definition || card.back || card.answer || card.solution || `Answer ${i + 1}`;
297
- await ctx.db.flashcard.create({
298
- data: {
299
- artifactId: artifact.id,
300
- front,
301
- back,
302
- order: i,
303
- tags: input.tags ?? ['ai-generated', input.difficulty],
304
- },
305
- });
306
- createdCards++;
307
- }
308
- }
309
- catch (error) {
310
- console.error("Failed to parse flashcard JSON or create cards:", error);
311
- // Fallback to text parsing if JSON fails
312
- const lines = content.split('\n').filter(line => line.trim());
313
- for (let i = 0; i < Math.min(lines.length, input.numCards); i++) {
314
- const line = lines[i];
315
- if (line.includes(' - ')) {
316
- const [front, back] = line.split(' - ');
317
- await ctx.db.flashcard.create({
318
- data: {
319
- artifactId: artifact.id,
320
- front: front.trim(),
321
- back: back.trim(),
322
- order: i,
323
- tags: input.tags ?? ['ai-generated', input.difficulty],
324
- },
325
- });
326
- createdCards++;
327
- }
328
- }
329
- }
330
- // Pusher complete
331
- await PusherService.emitFlashcardComplete(input.workspaceId, artifact);
332
- // Set generating to false on the artifact
333
- await ctx.db.artifact.update({ where: { id: artifact.id }, data: { generating: false } });
334
- await notifyArtifactReady(ctx.db, {
335
- userId: ctx.session.user.id,
336
- workspaceId: input.workspaceId,
337
- artifactId: artifact.id,
338
- artifactType: ArtifactType.FLASHCARD_SET,
339
- title: artifact.title,
340
- }).catch(() => { });
341
- return { artifact, createdCards };
342
- }
343
- catch (error) {
344
- if (flashcardCurrent?.id) {
345
- await ctx.db.artifact.update({ where: { id: flashcardCurrent.id }, data: { generating: false } });
346
- }
347
- await PusherService.emitError(input.workspaceId, `Failed to generate flashcards: ${error}`, 'flash_card_generation');
348
- await notifyArtifactFailed(ctx.db, {
349
- userId: ctx.session.user.id,
350
- workspaceId: input.workspaceId,
351
- artifactType: ArtifactType.FLASHCARD_SET,
352
- message: error instanceof Error
353
- ? error.message
354
- : 'Flashcard generation failed.',
355
- }).catch(() => { });
356
- throw error;
357
- }
358
- }),
359
- // Record study attempt
56
+ .mutation(({ ctx, input }) => new FlashcardService(ctx.db).generateFromPrompt(ctx.session.user.id, input)),
360
57
  recordStudyAttempt: authedProcedure
361
58
  .input(z.object({
362
59
  flashcardId: z.string().cuid(),
@@ -364,42 +61,22 @@ export const flashcards = router({
364
61
  confidence: z.enum(['easy', 'medium', 'hard']).optional(),
365
62
  timeSpentMs: z.number().optional(),
366
63
  }))
367
- .mutation(async ({ ctx, input }) => {
368
- const service = createFlashcardProgressService(ctx.db);
369
- return service.recordStudyAttempt({
370
- userId: ctx.userId,
371
- ...input,
372
- });
373
- }),
374
- // Get progress for a flashcard set
64
+ .mutation(({ ctx, input }) => createFlashcardProgressService(ctx.db).recordStudyAttempt({
65
+ userId: ctx.userId,
66
+ ...input,
67
+ })),
375
68
  getSetProgress: authedProcedure
376
69
  .input(z.object({ artifactId: z.string().cuid() }))
377
- .query(async ({ ctx, input }) => {
378
- const service = createFlashcardProgressService(ctx.db);
379
- return service.getSetProgress(ctx.userId, input.artifactId);
380
- }),
381
- // Get flashcards due for review
70
+ .query(({ ctx, input }) => createFlashcardProgressService(ctx.db).getSetProgress(ctx.userId, input.artifactId)),
382
71
  getDueFlashcards: authedProcedure
383
72
  .input(z.object({ workspaceId: z.string() }))
384
- .query(async ({ ctx, input }) => {
385
- const service = createFlashcardProgressService(ctx.db);
386
- return service.getDueFlashcards(ctx.userId, input.workspaceId);
387
- }),
388
- // Get statistics for a flashcard set
73
+ .query(({ ctx, input }) => createFlashcardProgressService(ctx.db).getDueFlashcards(ctx.userId, input.workspaceId)),
389
74
  getSetStatistics: authedProcedure
390
75
  .input(z.object({ artifactId: z.string().cuid() }))
391
- .query(async ({ ctx, input }) => {
392
- const service = createFlashcardProgressService(ctx.db);
393
- return service.getSetStatistics(ctx.userId, input.artifactId);
394
- }),
395
- // Reset progress for a flashcard
76
+ .query(({ ctx, input }) => createFlashcardProgressService(ctx.db).getSetStatistics(ctx.userId, input.artifactId)),
396
77
  resetProgress: authedProcedure
397
78
  .input(z.object({ flashcardId: z.string().cuid() }))
398
- .mutation(async ({ ctx, input }) => {
399
- const service = createFlashcardProgressService(ctx.db);
400
- return service.resetProgress(ctx.userId, input.flashcardId);
401
- }),
402
- // Bulk record study session
79
+ .mutation(({ ctx, input }) => createFlashcardProgressService(ctx.db).resetProgress(ctx.userId, input.flashcardId)),
403
80
  recordStudySession: authedProcedure
404
81
  .input(z.object({
405
82
  attempts: z.array(z.object({
@@ -409,11 +86,8 @@ export const flashcards = router({
409
86
  timeSpentMs: z.number().optional(),
410
87
  })),
411
88
  }))
412
- .mutation(async ({ ctx, input }) => {
413
- const service = createFlashcardProgressService(ctx.db);
414
- return service.recordStudySession({
415
- userId: ctx.userId,
416
- ...input,
417
- });
418
- }),
89
+ .mutation(({ ctx, input }) => createFlashcardProgressService(ctx.db).recordStudySession({
90
+ userId: ctx.userId,
91
+ ...input,
92
+ })),
419
93
  });