@studious-lms/server 1.1.26 → 1.2.6

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 (486) hide show
  1. package/.coderabbit.yaml +9 -0
  2. package/.env.example +53 -0
  3. package/.env.test.example +37 -0
  4. package/README.md +34 -7
  5. package/dist/exportType.d.ts.map +1 -1
  6. package/dist/exportType.js +4 -0
  7. package/dist/exportType.js.map +1 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +212 -51
  11. package/dist/index.js.map +1 -0
  12. package/dist/instrument.d.ts +2 -0
  13. package/dist/instrument.d.ts.map +1 -0
  14. package/dist/instrument.js +18 -0
  15. package/dist/instrument.js.map +1 -0
  16. package/dist/lib/config/env.d.ts +190 -0
  17. package/dist/lib/config/env.d.ts.map +1 -0
  18. package/dist/lib/config/env.js +121 -0
  19. package/dist/lib/config/env.js.map +1 -0
  20. package/dist/lib/fileUpload.d.ts +2 -2
  21. package/dist/lib/fileUpload.d.ts.map +1 -1
  22. package/dist/lib/fileUpload.js +15 -5
  23. package/dist/lib/fileUpload.js.map +1 -0
  24. package/dist/lib/googleCloudStorage.d.ts +6 -0
  25. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  26. package/dist/lib/googleCloudStorage.js +26 -6
  27. package/dist/lib/googleCloudStorage.js.map +1 -0
  28. package/dist/lib/jsonConversion.d.ts.map +1 -1
  29. package/dist/lib/jsonConversion.js +16 -14
  30. package/dist/lib/jsonConversion.js.map +1 -0
  31. package/dist/lib/jsonStyles.d.ts.map +1 -1
  32. package/dist/lib/jsonStyles.js +4 -0
  33. package/dist/lib/jsonStyles.js.map +1 -0
  34. package/dist/lib/notificationHandler.d.ts +2 -2
  35. package/dist/lib/notificationHandler.d.ts.map +1 -1
  36. package/dist/lib/notificationHandler.js +4 -0
  37. package/dist/lib/notificationHandler.js.map +1 -0
  38. package/dist/lib/prisma.d.ts +2 -2
  39. package/dist/lib/prisma.d.ts.map +1 -1
  40. package/dist/lib/prisma.js +24 -1
  41. package/dist/lib/prisma.js.map +1 -0
  42. package/dist/lib/pusher.d.ts +4 -1
  43. package/dist/lib/pusher.d.ts.map +1 -1
  44. package/dist/lib/pusher.js +14 -6
  45. package/dist/lib/pusher.js.map +1 -0
  46. package/dist/lib/redis.d.ts +5 -0
  47. package/dist/lib/redis.d.ts.map +1 -0
  48. package/dist/lib/redis.js +53 -0
  49. package/dist/lib/redis.js.map +1 -0
  50. package/dist/lib/thumbnailGenerator.d.ts +0 -21
  51. package/dist/lib/thumbnailGenerator.d.ts.map +1 -1
  52. package/dist/lib/thumbnailGenerator.js +159 -158
  53. package/dist/lib/thumbnailGenerator.js.map +1 -0
  54. package/dist/middleware/auth.d.ts.map +1 -1
  55. package/dist/middleware/auth.js +41 -93
  56. package/dist/middleware/auth.js.map +1 -0
  57. package/dist/middleware/logging.d.ts.map +1 -1
  58. package/dist/middleware/logging.js +4 -0
  59. package/dist/middleware/logging.js.map +1 -0
  60. package/dist/middleware/security.d.ts +5 -0
  61. package/dist/middleware/security.d.ts.map +1 -0
  62. package/dist/middleware/security.js +77 -0
  63. package/dist/middleware/security.js.map +1 -0
  64. package/dist/models/agenda.d.ts +97 -0
  65. package/dist/models/agenda.d.ts.map +1 -0
  66. package/dist/models/agenda.js +40 -0
  67. package/dist/models/agenda.js.map +1 -0
  68. package/dist/models/announcement.d.ts +223 -0
  69. package/dist/models/announcement.d.ts.map +1 -0
  70. package/dist/models/announcement.js +120 -0
  71. package/dist/models/announcement.js.map +1 -0
  72. package/dist/models/assignment.d.ts +1292 -0
  73. package/dist/models/assignment.d.ts.map +1 -0
  74. package/dist/models/assignment.js +309 -0
  75. package/dist/models/assignment.js.map +1 -0
  76. package/dist/models/attendance.d.ts +180 -0
  77. package/dist/models/attendance.d.ts.map +1 -0
  78. package/dist/models/attendance.js +188 -0
  79. package/dist/models/attendance.js.map +1 -0
  80. package/dist/models/auth.d.ts +153 -0
  81. package/dist/models/auth.d.ts.map +1 -0
  82. package/dist/models/auth.js +217 -0
  83. package/dist/models/auth.js.map +1 -0
  84. package/dist/models/class.d.ts +439 -0
  85. package/dist/models/class.d.ts.map +1 -0
  86. package/dist/models/class.js +546 -0
  87. package/dist/models/class.js.map +1 -0
  88. package/dist/models/comment.d.ts +171 -0
  89. package/dist/models/comment.d.ts.map +1 -0
  90. package/dist/models/comment.js +138 -0
  91. package/dist/models/comment.js.map +1 -0
  92. package/dist/models/conversation.d.ts +164 -0
  93. package/dist/models/conversation.d.ts.map +1 -0
  94. package/dist/models/conversation.js +175 -0
  95. package/dist/models/conversation.js.map +1 -0
  96. package/dist/models/event.d.ts +295 -0
  97. package/dist/models/event.d.ts.map +1 -0
  98. package/dist/models/event.js +145 -0
  99. package/dist/models/event.js.map +1 -0
  100. package/dist/models/file.d.ts +536 -0
  101. package/dist/models/file.d.ts.map +1 -0
  102. package/dist/models/file.js +126 -0
  103. package/dist/models/file.js.map +1 -0
  104. package/dist/models/folder.d.ts +295 -0
  105. package/dist/models/folder.d.ts.map +1 -0
  106. package/dist/models/folder.js +202 -0
  107. package/dist/models/folder.js.map +1 -0
  108. package/dist/models/labChat.d.ts +243 -0
  109. package/dist/models/labChat.d.ts.map +1 -0
  110. package/dist/models/labChat.js +204 -0
  111. package/dist/models/labChat.js.map +1 -0
  112. package/dist/models/marketing.d.ts +72 -0
  113. package/dist/models/marketing.d.ts.map +1 -0
  114. package/dist/models/marketing.js +26 -0
  115. package/dist/models/marketing.js.map +1 -0
  116. package/dist/models/message.d.ts +100 -0
  117. package/dist/models/message.d.ts.map +1 -0
  118. package/dist/models/message.js +131 -0
  119. package/dist/models/message.js.map +1 -0
  120. package/dist/models/newtonChat.d.ts +72 -0
  121. package/dist/models/newtonChat.d.ts.map +1 -0
  122. package/dist/models/newtonChat.js +61 -0
  123. package/dist/models/newtonChat.js.map +1 -0
  124. package/dist/models/notification.d.ts +65 -0
  125. package/dist/models/notification.d.ts.map +1 -0
  126. package/dist/models/notification.js +46 -0
  127. package/dist/models/notification.js.map +1 -0
  128. package/dist/models/section.d.ts +102 -0
  129. package/dist/models/section.d.ts.map +1 -0
  130. package/dist/models/section.js +83 -0
  131. package/dist/models/section.js.map +1 -0
  132. package/dist/models/user.d.ts +39 -0
  133. package/dist/models/user.d.ts.map +1 -0
  134. package/dist/models/user.js +38 -0
  135. package/dist/models/user.js.map +1 -0
  136. package/dist/models/worksheet.d.ts +460 -0
  137. package/dist/models/worksheet.d.ts.map +1 -0
  138. package/dist/models/worksheet.js +200 -0
  139. package/dist/models/worksheet.js.map +1 -0
  140. package/dist/pipelines/aiLabChat.d.ts +21 -0
  141. package/dist/pipelines/aiLabChat.d.ts.map +1 -0
  142. package/dist/pipelines/aiLabChat.js +460 -0
  143. package/dist/pipelines/aiLabChat.js.map +1 -0
  144. package/dist/pipelines/aiNewtonChat.d.ts +30 -0
  145. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -0
  146. package/dist/pipelines/aiNewtonChat.js +289 -0
  147. package/dist/pipelines/aiNewtonChat.js.map +1 -0
  148. package/dist/pipelines/gradeWorksheet.d.ts +30 -0
  149. package/dist/pipelines/gradeWorksheet.d.ts.map +1 -0
  150. package/dist/pipelines/gradeWorksheet.js +252 -0
  151. package/dist/pipelines/gradeWorksheet.js.map +1 -0
  152. package/dist/routers/_app.d.ts +6438 -3910
  153. package/dist/routers/_app.d.ts.map +1 -1
  154. package/dist/routers/_app.js +10 -0
  155. package/dist/routers/_app.js.map +1 -0
  156. package/dist/routers/agenda.d.ts +58 -6
  157. package/dist/routers/agenda.d.ts.map +1 -1
  158. package/dist/routers/agenda.js +6 -58
  159. package/dist/routers/agenda.js.map +1 -0
  160. package/dist/routers/announcement.d.ts +325 -6
  161. package/dist/routers/announcement.d.ts.map +1 -1
  162. package/dist/routers/announcement.js +543 -77
  163. package/dist/routers/announcement.js.map +1 -0
  164. package/dist/routers/assignment.d.ts +419 -357
  165. package/dist/routers/assignment.d.ts.map +1 -1
  166. package/dist/routers/assignment.js +100 -1689
  167. package/dist/routers/assignment.js.map +1 -0
  168. package/dist/routers/attendance.d.ts +20 -9
  169. package/dist/routers/attendance.d.ts.map +1 -1
  170. package/dist/routers/attendance.js +10 -263
  171. package/dist/routers/attendance.js.map +1 -0
  172. package/dist/routers/auth.d.ts +21 -1
  173. package/dist/routers/auth.d.ts.map +1 -1
  174. package/dist/routers/auth.js +37 -241
  175. package/dist/routers/auth.js.map +1 -0
  176. package/dist/routers/class.d.ts +198 -68
  177. package/dist/routers/class.d.ts.map +1 -1
  178. package/dist/routers/class.js +88 -909
  179. package/dist/routers/class.js.map +1 -0
  180. package/dist/routers/comment.d.ts +153 -0
  181. package/dist/routers/comment.d.ts.map +1 -0
  182. package/dist/routers/comment.js +58 -0
  183. package/dist/routers/comment.js.map +1 -0
  184. package/dist/routers/conversation.d.ts +73 -3
  185. package/dist/routers/conversation.d.ts.map +1 -1
  186. package/dist/routers/conversation.js +23 -265
  187. package/dist/routers/conversation.js.map +1 -0
  188. package/dist/routers/event.d.ts +46 -37
  189. package/dist/routers/event.d.ts.map +1 -1
  190. package/dist/routers/event.js +15 -431
  191. package/dist/routers/event.js.map +1 -0
  192. package/dist/routers/file.d.ts +4 -2
  193. package/dist/routers/file.d.ts.map +1 -1
  194. package/dist/routers/file.js +11 -298
  195. package/dist/routers/file.js.map +1 -0
  196. package/dist/routers/folder.d.ts +21 -14
  197. package/dist/routers/folder.d.ts.map +1 -1
  198. package/dist/routers/folder.js +36 -743
  199. package/dist/routers/folder.js.map +1 -0
  200. package/dist/routers/labChat.d.ts +12 -9
  201. package/dist/routers/labChat.d.ts.map +1 -1
  202. package/dist/routers/labChat.js +21 -885
  203. package/dist/routers/labChat.js.map +1 -0
  204. package/dist/routers/marketing.d.ts +2 -2
  205. package/dist/routers/marketing.d.ts.map +1 -1
  206. package/dist/routers/marketing.js +9 -54
  207. package/dist/routers/marketing.js.map +1 -0
  208. package/dist/routers/message.d.ts +2 -1
  209. package/dist/routers/message.d.ts.map +1 -1
  210. package/dist/routers/message.js +29 -519
  211. package/dist/routers/message.js.map +1 -0
  212. package/dist/routers/newtonChat.d.ts +55 -0
  213. package/dist/routers/newtonChat.d.ts.map +1 -0
  214. package/dist/routers/newtonChat.js +22 -0
  215. package/dist/routers/newtonChat.js.map +1 -0
  216. package/dist/routers/notifications.d.ts +8 -8
  217. package/dist/routers/notifications.d.ts.map +1 -1
  218. package/dist/routers/notifications.js +20 -81
  219. package/dist/routers/notifications.js.map +1 -0
  220. package/dist/routers/section.d.ts +23 -8
  221. package/dist/routers/section.d.ts.map +1 -1
  222. package/dist/routers/section.js +23 -273
  223. package/dist/routers/section.js.map +1 -0
  224. package/dist/routers/user.d.ts +1 -1
  225. package/dist/routers/user.d.ts.map +1 -1
  226. package/dist/routers/user.js +34 -204
  227. package/dist/routers/user.js.map +1 -0
  228. package/dist/routers/worksheet.d.ts +362 -0
  229. package/dist/routers/worksheet.d.ts.map +1 -0
  230. package/dist/routers/worksheet.js +153 -0
  231. package/dist/routers/worksheet.js.map +1 -0
  232. package/dist/seedDatabase.d.ts +2 -3
  233. package/dist/seedDatabase.d.ts.map +1 -1
  234. package/dist/seedDatabase.js +309 -288
  235. package/dist/seedDatabase.js.map +1 -0
  236. package/dist/server/pipelines/aiLabChat.d.ts +21 -0
  237. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  238. package/dist/server/pipelines/aiLabChat.js +456 -0
  239. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  240. package/dist/server/pipelines/aiNewtonChat.d.ts +30 -0
  241. package/dist/server/pipelines/aiNewtonChat.d.ts.map +1 -0
  242. package/dist/server/pipelines/aiNewtonChat.js +285 -0
  243. package/dist/server/pipelines/aiNewtonChat.js.map +1 -0
  244. package/dist/server/pipelines/gradeWorksheet.d.ts +30 -0
  245. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  246. package/dist/server/pipelines/gradeWorksheet.js +248 -0
  247. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  248. package/dist/services/agenda.d.ts +100 -0
  249. package/dist/services/agenda.d.ts.map +1 -0
  250. package/dist/services/agenda.js +21 -0
  251. package/dist/services/agenda.js.map +1 -0
  252. package/dist/services/announcement.d.ts +135 -0
  253. package/dist/services/announcement.d.ts.map +1 -0
  254. package/dist/services/announcement.js +223 -0
  255. package/dist/services/announcement.js.map +1 -0
  256. package/dist/services/assignment.d.ts +1462 -0
  257. package/dist/services/assignment.d.ts.map +1 -0
  258. package/dist/services/assignment.js +898 -0
  259. package/dist/services/assignment.js.map +1 -0
  260. package/dist/services/attendance.d.ts +93 -0
  261. package/dist/services/attendance.d.ts.map +1 -0
  262. package/dist/services/attendance.js +61 -0
  263. package/dist/services/attendance.js.map +1 -0
  264. package/dist/services/auth.d.ts +68 -0
  265. package/dist/services/auth.d.ts.map +1 -0
  266. package/dist/services/auth.js +218 -0
  267. package/dist/services/auth.js.map +1 -0
  268. package/dist/services/class.d.ts +621 -0
  269. package/dist/services/class.d.ts.map +1 -0
  270. package/dist/services/class.js +474 -0
  271. package/dist/services/class.js.map +1 -0
  272. package/dist/services/comment.d.ts +100 -0
  273. package/dist/services/comment.d.ts.map +1 -0
  274. package/dist/services/comment.js +83 -0
  275. package/dist/services/comment.js.map +1 -0
  276. package/dist/services/conversation.d.ts +159 -0
  277. package/dist/services/conversation.d.ts.map +1 -0
  278. package/dist/services/conversation.js +138 -0
  279. package/dist/services/conversation.js.map +1 -0
  280. package/dist/services/event.d.ts +216 -0
  281. package/dist/services/event.d.ts.map +1 -0
  282. package/dist/services/event.js +168 -0
  283. package/dist/services/event.js.map +1 -0
  284. package/dist/services/file.d.ts +74 -0
  285. package/dist/services/file.d.ts.map +1 -0
  286. package/dist/services/file.js +133 -0
  287. package/dist/services/file.js.map +1 -0
  288. package/dist/services/folder.d.ts +239 -0
  289. package/dist/services/folder.d.ts.map +1 -0
  290. package/dist/services/folder.js +248 -0
  291. package/dist/services/folder.js.map +1 -0
  292. package/dist/services/labChat.d.ts +165 -0
  293. package/dist/services/labChat.d.ts.map +1 -0
  294. package/dist/services/labChat.js +289 -0
  295. package/dist/services/labChat.js.map +1 -0
  296. package/dist/services/marketing.d.ts +50 -0
  297. package/dist/services/marketing.d.ts.map +1 -0
  298. package/dist/services/marketing.js +32 -0
  299. package/dist/services/marketing.js.map +1 -0
  300. package/dist/services/message.d.ts +95 -0
  301. package/dist/services/message.d.ts.map +1 -0
  302. package/dist/services/message.js +350 -0
  303. package/dist/services/message.js.map +1 -0
  304. package/dist/services/newtonChat.d.ts +22 -0
  305. package/dist/services/newtonChat.d.ts.map +1 -0
  306. package/dist/services/newtonChat.js +174 -0
  307. package/dist/services/newtonChat.js.map +1 -0
  308. package/dist/services/notification.d.ts +65 -0
  309. package/dist/services/notification.d.ts.map +1 -0
  310. package/dist/services/notification.js +33 -0
  311. package/dist/services/notification.js.map +1 -0
  312. package/dist/services/section.d.ts +53 -0
  313. package/dist/services/section.d.ts.map +1 -0
  314. package/dist/services/section.js +199 -0
  315. package/dist/services/section.js.map +1 -0
  316. package/dist/services/user.d.ts +48 -0
  317. package/dist/services/user.d.ts.map +1 -0
  318. package/dist/services/user.js +141 -0
  319. package/dist/services/user.js.map +1 -0
  320. package/dist/services/worksheet.d.ts +239 -0
  321. package/dist/services/worksheet.d.ts.map +1 -0
  322. package/dist/services/worksheet.js +235 -0
  323. package/dist/services/worksheet.js.map +1 -0
  324. package/dist/socket/handlers.d.ts.map +1 -1
  325. package/dist/socket/handlers.js +4 -0
  326. package/dist/socket/handlers.js.map +1 -0
  327. package/dist/trpc.d.ts.map +1 -1
  328. package/dist/trpc.js +4 -0
  329. package/dist/trpc.js.map +1 -0
  330. package/dist/types/trpc.d.ts.map +1 -1
  331. package/dist/types/trpc.js +4 -0
  332. package/dist/types/trpc.js.map +1 -0
  333. package/dist/utils/aiUser.d.ts +1 -3
  334. package/dist/utils/aiUser.d.ts.map +1 -1
  335. package/dist/utils/aiUser.js +8 -3
  336. package/dist/utils/aiUser.js.map +1 -0
  337. package/dist/utils/email.d.ts +12 -1
  338. package/dist/utils/email.d.ts.map +1 -1
  339. package/dist/utils/email.js +26 -4
  340. package/dist/utils/email.js.map +1 -0
  341. package/dist/utils/generateInviteCode.d.ts +1 -2
  342. package/dist/utils/generateInviteCode.d.ts.map +1 -1
  343. package/dist/utils/generateInviteCode.js +5 -2
  344. package/dist/utils/generateInviteCode.js.map +1 -0
  345. package/dist/utils/inference.d.ts +8 -0
  346. package/dist/utils/inference.d.ts.map +1 -1
  347. package/dist/utils/inference.js +78 -10
  348. package/dist/utils/inference.js.map +1 -0
  349. package/dist/utils/logger.d.ts +3 -0
  350. package/dist/utils/logger.d.ts.map +1 -1
  351. package/dist/utils/logger.js +8 -1
  352. package/dist/utils/logger.js.map +1 -0
  353. package/dist/utils/prismaErrorHandler.d.ts.map +1 -1
  354. package/dist/utils/prismaErrorHandler.js +7 -0
  355. package/dist/utils/prismaErrorHandler.js.map +1 -0
  356. package/dist/utils/prismaWrapper.d.ts +1 -0
  357. package/dist/utils/prismaWrapper.d.ts.map +1 -1
  358. package/dist/utils/prismaWrapper.js +8 -0
  359. package/dist/utils/prismaWrapper.js.map +1 -0
  360. package/docker-compose.yml +19 -0
  361. package/package.json +21 -4
  362. package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +30 -0
  363. package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +35 -0
  364. package/prisma/schema.prisma +180 -12
  365. package/scripts/test-pre-push.ts +14 -0
  366. package/src/index.ts +247 -52
  367. package/src/instrument.ts +15 -0
  368. package/src/lib/config/env.ts +132 -0
  369. package/src/lib/fileUpload.ts +13 -6
  370. package/src/lib/googleCloudStorage.ts +23 -6
  371. package/src/lib/jsonConversion.ts +12 -14
  372. package/src/lib/prisma.ts +23 -2
  373. package/src/lib/pusher.ts +11 -6
  374. package/src/lib/redis.ts +56 -0
  375. package/src/lib/thumbnailGenerator.ts +170 -168
  376. package/src/middleware/auth.ts +86 -137
  377. package/src/middleware/security.ts +80 -0
  378. package/src/models/agenda.ts +46 -0
  379. package/src/models/announcement.ts +134 -0
  380. package/src/models/assignment.ts +322 -0
  381. package/src/models/attendance.ts +208 -0
  382. package/src/models/auth.ts +247 -0
  383. package/src/models/class.ts +598 -0
  384. package/src/models/comment.ts +152 -0
  385. package/src/models/conversation.ts +200 -0
  386. package/src/models/event.ts +177 -0
  387. package/src/models/file.ts +129 -0
  388. package/src/models/folder.ts +225 -0
  389. package/src/models/labChat.ts +213 -0
  390. package/src/models/marketing.ts +45 -0
  391. package/src/models/message.ts +153 -0
  392. package/src/models/newtonChat.ts +70 -0
  393. package/src/models/notification.ts +54 -0
  394. package/src/models/section.ts +98 -0
  395. package/src/models/user.ts +47 -0
  396. package/src/models/worksheet.ts +294 -0
  397. package/src/pipelines/aiLabChat.ts +511 -0
  398. package/src/pipelines/aiNewtonChat.ts +347 -0
  399. package/src/pipelines/gradeWorksheet.ts +286 -0
  400. package/src/routers/_app.ts +6 -0
  401. package/src/routers/agenda.ts +3 -61
  402. package/src/routers/announcement.ts +616 -79
  403. package/src/routers/assignment.ts +148 -1827
  404. package/src/routers/attendance.ts +16 -277
  405. package/src/routers/auth.ts +79 -313
  406. package/src/routers/class.ts +265 -1038
  407. package/src/routers/comment.ts +76 -0
  408. package/src/routers/conversation.ts +53 -284
  409. package/src/routers/event.ts +50 -481
  410. package/src/routers/file.ts +45 -344
  411. package/src/routers/folder.ts +107 -836
  412. package/src/routers/labChat.ts +29 -969
  413. package/src/routers/marketing.ts +35 -77
  414. package/src/routers/message.ts +45 -571
  415. package/src/routers/newtonChat.ts +36 -0
  416. package/src/routers/notifications.ts +32 -82
  417. package/src/routers/section.ts +58 -322
  418. package/src/routers/user.ts +49 -226
  419. package/src/routers/worksheet.ts +252 -0
  420. package/src/seedDatabase.ts +328 -289
  421. package/src/services/agenda.ts +21 -0
  422. package/src/services/announcement.ts +290 -0
  423. package/src/services/assignment.ts +1198 -0
  424. package/src/services/attendance.ts +85 -0
  425. package/src/services/auth.ts +277 -0
  426. package/src/services/class.ts +622 -0
  427. package/src/services/comment.ts +106 -0
  428. package/src/services/conversation.ts +213 -0
  429. package/src/services/event.ts +231 -0
  430. package/src/services/file.ts +167 -0
  431. package/src/services/folder.ts +316 -0
  432. package/src/services/labChat.ts +352 -0
  433. package/src/services/marketing.ts +57 -0
  434. package/src/services/message.ts +461 -0
  435. package/src/services/newtonChat.ts +222 -0
  436. package/src/services/notification.ts +50 -0
  437. package/src/services/section.ts +283 -0
  438. package/src/services/user.ts +172 -0
  439. package/src/services/worksheet.ts +358 -0
  440. package/src/trpc.ts +4 -0
  441. package/src/utils/aiUser.ts +4 -3
  442. package/src/utils/email.ts +33 -4
  443. package/src/utils/generateInviteCode.ts +1 -3
  444. package/src/utils/inference.ts +89 -10
  445. package/src/utils/logger.ts +4 -1
  446. package/src/utils/prismaErrorHandler.ts +3 -0
  447. package/src/utils/prismaWrapper.ts +4 -0
  448. package/tests/globalSetup.ts +62 -0
  449. package/tests/helpers.ts +22 -0
  450. package/tests/middleware/security.test.ts +42 -0
  451. package/tests/routers/agenda.test.ts +138 -0
  452. package/tests/routers/announcement.test.ts +490 -0
  453. package/tests/routers/assignment.test.ts +837 -0
  454. package/tests/routers/attendance.test.ts +160 -0
  455. package/tests/routers/auth.test.ts +171 -0
  456. package/tests/{class.test.ts → routers/class.test.ts} +163 -92
  457. package/tests/routers/comment.test.ts +126 -0
  458. package/tests/routers/conversation.test.ts +145 -0
  459. package/tests/routers/event.test.ts +289 -0
  460. package/tests/routers/folder.test.ts +178 -0
  461. package/tests/routers/labChat.test.ts +115 -0
  462. package/tests/routers/marketing.test.ts +59 -0
  463. package/tests/routers/message.test.ts +123 -0
  464. package/tests/routers/notification.test.ts +69 -0
  465. package/tests/routers/section.test.ts +208 -0
  466. package/tests/server/rateLimit.test.ts +73 -0
  467. package/tests/setup.ts +39 -59
  468. package/tests/user.test.ts +136 -0
  469. package/tests/utils/aiUser.test.ts +22 -0
  470. package/tests/utils/generateInviteCode.test.ts +24 -0
  471. package/tests/utils/logger.test.ts +74 -0
  472. package/tests/utils/prismaErrorHandler.test.ts +101 -0
  473. package/tests/utils/prismaWrapper.test.ts +82 -0
  474. package/tests/worksheet.test.ts +181 -0
  475. package/tsconfig.json +9 -2
  476. package/vitest.config.ts +30 -1
  477. package/vitest.unit.config.ts +21 -0
  478. package/API_SPECIFICATION.md +0 -1597
  479. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  480. package/CHAT_API_SPEC.md +0 -579
  481. package/LAB_CHAT_API_SPEC.md +0 -518
  482. package/dist/routers/school.d.ts +0 -208
  483. package/dist/routers/school.d.ts.map +0 -1
  484. package/dist/routers/school.js +0 -481
  485. package/src/lib/notificationHandler.ts +0 -36
  486. package/tests/auth.test.ts +0 -25
@@ -4,12 +4,13 @@ import { readFileSync } from 'fs'
4
4
  import { join } from 'path'
5
5
  import { writeFile } from 'fs'
6
6
  import { DocumentBlock, FormatTypes, Fonts } from './jsonStyles.js'
7
+ import { logger } from '../utils/logger.js'
7
8
 
8
9
  export async function createPdf(blocks: DocumentBlock[]) {
9
- console.log('createPdf: Starting PDF creation with', blocks.length, 'blocks');
10
+ logger.info(`createPdf: Starting PDF creation with ${blocks.length} blocks`);
10
11
  try {
11
12
  const pdfDoc = await PDFDocument.create()
12
- console.log('createPdf: PDFDocument created successfully');
13
+ logger.info('createPdf: PDFDocument created successfully');
13
14
 
14
15
  // Register fontkit to enable custom font embedding
15
16
  pdfDoc.registerFontkit(fontkit)
@@ -33,9 +34,9 @@ export async function createPdf(blocks: DocumentBlock[]) {
33
34
  notoSansItalic = await pdfDoc.embedFont(italicFontBytes)
34
35
  courierFont = await pdfDoc.embedFont(StandardFonts.Courier) // Keep Courier for code blocks
35
36
 
36
- console.log('createPdf: Unicode fonts loaded successfully');
37
+ logger.info('createPdf: Unicode fonts loaded successfully');
37
38
  } catch (fontError) {
38
- console.warn('createPdf: Failed to load custom fonts, falling back to standard fonts:', fontError);
39
+ logger.warn(`createPdf: Failed to load custom fonts, falling back to standard fonts: ${fontError}`);
39
40
  // Fallback to standard fonts if custom fonts fail
40
41
  notoSansRegular = await pdfDoc.embedFont(StandardFonts.Helvetica)
41
42
  notoSansBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold)
@@ -342,10 +343,10 @@ export async function createPdf(blocks: DocumentBlock[]) {
342
343
 
343
344
  let y = height - marginTop
344
345
  let lastLineHeight = -1
345
- console.log('createPdf: Starting to process', blocks.length, 'blocks');
346
+ logger.info(`createPdf: Starting to process ${blocks.length} blocks`);
346
347
  for (let i = 0; i < blocks.length; i++) {
347
348
  const block = blocks[i];
348
- console.log(`createPdf: Processing block ${i + 1}/${blocks.length}, format: ${block.format}, content type: ${typeof block.content}`);
349
+ logger.info(`createPdf: Processing block ${i + 1}/${blocks.length}, format: ${block.format}, content type: ${typeof block.content}`);
349
350
  try {
350
351
  const preset = STYLE_PRESETS[block.format] || { fontSize: defaultFontSize, lineHeight: defaultLineHeight }
351
352
 
@@ -725,24 +726,21 @@ export async function createPdf(blocks: DocumentBlock[]) {
725
726
  }
726
727
  }
727
728
  }
728
- console.log(`createPdf: Successfully processed block ${i + 1}`);
729
+ logger.info(`createPdf: Successfully processed block ${i + 1}`);
729
730
  y -= paragraphSpacing
730
731
  lastLineHeight = lineHeight
731
732
  } catch (blockError) {
732
- console.error(`createPdf: Error processing block ${i + 1}:`, blockError);
733
+ logger.error(`createPdf: Error processing block ${i + 1}: ${blockError}`);
733
734
  throw blockError;
734
735
  }
735
736
  }
736
737
 
737
- console.log('createPdf: About to save PDF document');
738
+ logger.info('createPdf: About to save PDF document');
738
739
  const pdfBytes = await pdfDoc.save()
739
- console.log('createPdf: PDF saved successfully, bytes length:', pdfBytes.length);
740
- // writeFile('output.pdf', pdfBytes, () => {
741
- // console.log('PDF created successfully') // Still only saves file, no API yet
742
- // })
740
+ logger.info(`createPdf: PDF saved successfully, bytes length: ${pdfBytes.length}`);
743
741
  return pdfBytes
744
742
  } catch (error) {
745
- console.error('createPdf: Error during PDF creation:', error);
743
+ logger.error(`createPdf: Error during PDF creation: ${error}`);
746
744
  throw error;
747
745
  }
748
746
  }
package/src/lib/prisma.ts CHANGED
@@ -1,6 +1,23 @@
1
1
  import { PrismaClient } from '@prisma/client';
2
+ import { env } from './config/env.js';
3
+
4
+ const getLogLevel = () => {
5
+ switch (env.NODE_ENV) {
6
+ case 'development':
7
+ return ['query', 'error', 'warn'];
8
+ case 'production':
9
+ return ['error'];
10
+ default:
11
+ return ['error'];
12
+ }
13
+ }
2
14
 
3
15
  const prismaClientSingleton = () => {
16
+ // return new PrismaClient({
17
+ // log: env.NODE_ENV === 'development'
18
+ // ? ['query', 'error', 'warn']
19
+ // : ['error'],
20
+ // });
4
21
  return new PrismaClient();
5
22
  };
6
23
 
@@ -11,6 +28,10 @@ declare global {
11
28
 
12
29
  export const prisma = globalThis.prisma ?? prismaClientSingleton();
13
30
 
14
- if (process.env.NODE_ENV !== 'production') {
31
+ if (env.NODE_ENV !== 'production') {
15
32
  globalThis.prisma = prisma;
16
- }
33
+ }
34
+
35
+ process.on('beforeExit', async () => {
36
+ await prisma.$disconnect();
37
+ });
package/src/lib/pusher.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import Pusher from 'pusher';
2
+ import { env } from './config/env.js';
2
3
 
3
4
  const pusher = new Pusher({
4
- appId: process.env.PUSHER_APP_ID!,
5
- key: process.env.PUSHER_KEY!,
6
- secret: process.env.PUSHER_SECRET!,
7
- cluster: process.env.PUSHER_CLUSTER!,
8
- useTLS: true,
5
+ appId: env.PUSHER_APP_ID,
6
+ key: env.PUSHER_KEY,
7
+ secret: env.PUSHER_SECRET,
8
+ cluster: env.PUSHER_CLUSTER,
9
+ useTLS: env.NODE_ENV !== 'development',
9
10
  });
10
11
 
11
- export { pusher };
12
+ const chatChannel = (conversationId: string) => `private-conversation-${conversationId}`;
13
+ const worksheetChannel = (worksheetResponseId: string) => `private-worksheet-${worksheetResponseId}`;
14
+ const teacherChannel = (classId: string) => `private-teacher-${classId}`;
15
+
16
+ export { pusher, chatChannel, worksheetChannel, teacherChannel };
@@ -0,0 +1,56 @@
1
+ import Redis from 'ioredis';
2
+ import { env } from './config/env.js';
3
+ import { logger } from '../utils/logger.js';
4
+
5
+ let redis: Redis | null = null;
6
+
7
+ export function getRedis(): Redis | null {
8
+ return redis;
9
+ }
10
+
11
+ export async function connectRedis(): Promise<Redis | null> {
12
+ const url = env.REDIS_URL;
13
+ if (!url) {
14
+ logger.info('Redis not configured (REDIS_URL not set), skipping');
15
+ return null;
16
+ }
17
+
18
+ if (redis) {
19
+ return redis;
20
+ }
21
+
22
+ redis = new Redis(url, {
23
+ maxRetriesPerRequest: 3,
24
+ retryStrategy(times) {
25
+ if (times > 3) return null;
26
+ return Math.min(times * 200, 2000);
27
+ },
28
+ });
29
+
30
+ redis.on('error', (err) => {
31
+ logger.error('Redis connection error', { error: err.message });
32
+ });
33
+
34
+ redis.on('connect', () => {
35
+ logger.info('Redis connected');
36
+ });
37
+
38
+ try {
39
+ await redis.ping();
40
+ logger.info('Redis ready');
41
+ return redis;
42
+ } catch (error) {
43
+ logger.error('Redis ping failed', { error });
44
+ redis.disconnect();
45
+ redis = null;
46
+ return null;
47
+ }
48
+ }
49
+
50
+ export async function disconnectRedis(): Promise<void> {
51
+ if (redis) {
52
+ await redis.quit();
53
+ redis = null;
54
+ logger.info('Redis disconnected');
55
+ }
56
+ }
@@ -1,170 +1,172 @@
1
- import sharp from 'sharp';
2
- import { prisma } from './prisma.js';
3
- import { deleteFile, getSignedUrl } from './googleCloudStorage.js';
4
-
5
- // Thumbnail size configuration
6
- const THUMBNAIL_WIDTH = 200;
7
- const THUMBNAIL_HEIGHT = 200;
8
-
9
- // File type configurations
10
- const SUPPORTED_IMAGE_TYPES = [
11
- 'image/jpeg',
12
- 'image/png',
13
- 'image/gif',
14
- 'image/webp',
15
- 'image/tiff',
16
- 'image/bmp',
17
- 'image/avif'
18
- ];
19
-
20
- const DOCUMENT_TYPES = [
21
- 'application/pdf',
22
- 'application/msword',
23
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
24
- 'application/vnd.ms-excel',
25
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
26
- 'application/vnd.ms-powerpoint',
27
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
28
- 'text/plain',
29
- 'text/csv',
30
- 'application/json',
31
- 'text/html',
32
- 'text/javascript',
33
- 'text/css'
34
- ];
35
-
36
- const VIDEO_TYPES = [
37
- 'video/mp4',
38
- 'video/webm',
39
- 'video/ogg',
40
- 'video/quicktime'
41
- ];
42
-
43
- const AUDIO_TYPES = [
44
- 'audio/mpeg',
45
- 'audio/ogg',
46
- 'audio/wav',
47
- 'audio/webm'
48
- ];
49
-
50
- /**
51
- * Generates a thumbnail for an image or PDF file
52
- * @param fileBuffer The file buffer
53
- * @param fileType The MIME type of the file
54
- * @returns Thumbnail buffer
55
- */
56
- export async function generateMediaThumbnail(fileBuffer: Buffer, fileType: string): Promise<Buffer> {
57
- if (fileType === 'application/pdf') {
58
- // For PDFs, we need to use a different approach
59
- try {
60
- return await sharp(fileBuffer, {
61
- density: 300, // Higher density for better quality
62
- page: 0 // First page only
63
- })
64
- .resize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, {
65
- fit: 'inside',
66
- withoutEnlargement: true,
67
- })
68
- .jpeg({ quality: 80 })
69
- .toBuffer();
70
- } catch (error) {
71
- console.warn('Failed to generate PDF thumbnail:', error);
72
- return generateGenericThumbnail(fileType);
73
- }
74
- }
1
+ // @deprecated: this is not used anymore
2
+
3
+ // import sharp from 'sharp';
4
+ // import { prisma } from './prisma.js';
5
+ // import { deleteFile, getSignedUrl } from './googleCloudStorage.js';
6
+
7
+ // // Thumbnail size configuration
8
+ // const THUMBNAIL_WIDTH = 200;
9
+ // const THUMBNAIL_HEIGHT = 200;
10
+
11
+ // // File type configurations
12
+ // const SUPPORTED_IMAGE_TYPES = [
13
+ // 'image/jpeg',
14
+ // 'image/png',
15
+ // 'image/gif',
16
+ // 'image/webp',
17
+ // 'image/tiff',
18
+ // 'image/bmp',
19
+ // 'image/avif'
20
+ // ];
21
+
22
+ // const DOCUMENT_TYPES = [
23
+ // 'application/pdf',
24
+ // 'application/msword',
25
+ // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
26
+ // 'application/vnd.ms-excel',
27
+ // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
28
+ // 'application/vnd.ms-powerpoint',
29
+ // 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
30
+ // 'text/plain',
31
+ // 'text/csv',
32
+ // 'application/json',
33
+ // 'text/html',
34
+ // 'text/javascript',
35
+ // 'text/css'
36
+ // ];
37
+
38
+ // const VIDEO_TYPES = [
39
+ // 'video/mp4',
40
+ // 'video/webm',
41
+ // 'video/ogg',
42
+ // 'video/quicktime'
43
+ // ];
44
+
45
+ // const AUDIO_TYPES = [
46
+ // 'audio/mpeg',
47
+ // 'audio/ogg',
48
+ // 'audio/wav',
49
+ // 'audio/webm'
50
+ // ];
51
+
52
+ // /**
53
+ // * Generates a thumbnail for an image or PDF file
54
+ // * @param fileBuffer The file buffer
55
+ // * @param fileType The MIME type of the file
56
+ // * @returns Thumbnail buffer
57
+ // */
58
+ // export async function generateMediaThumbnail(fileBuffer: Buffer, fileType: string): Promise<Buffer> {
59
+ // if (fileType === 'application/pdf') {
60
+ // // For PDFs, we need to use a different approach
61
+ // try {
62
+ // return await sharp(fileBuffer, {
63
+ // density: 300, // Higher density for better quality
64
+ // page: 0 // First page only
65
+ // })
66
+ // .resize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, {
67
+ // fit: 'inside',
68
+ // withoutEnlargement: true,
69
+ // })
70
+ // .jpeg({ quality: 80 })
71
+ // .toBuffer();
72
+ // } catch (error) {
73
+ // console.warn('Failed to generate PDF thumbnail:', error);
74
+ // return generateGenericThumbnail(fileType);
75
+ // }
76
+ // }
75
77
 
76
- // For regular images
77
- return sharp(fileBuffer)
78
- .resize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, {
79
- fit: 'inside',
80
- withoutEnlargement: true,
81
- })
82
- .jpeg({ quality: 80 })
83
- .toBuffer();
84
- }
85
-
86
- /**
87
- * Generates a generic icon-based thumbnail for a file type
88
- * @param fileType The MIME type of the file
89
- * @returns Thumbnail buffer
90
- */
91
- async function generateGenericThumbnail(fileType: string): Promise<Buffer> {
92
- // Create a blank canvas with a colored background based on file type
93
- const canvas = sharp({
94
- create: {
95
- width: THUMBNAIL_WIDTH,
96
- height: THUMBNAIL_HEIGHT,
97
- channels: 4,
98
- background: { r: 245, g: 245, b: 245, alpha: 1 }
99
- }
100
- });
101
-
102
- // Add a colored overlay based on file type
103
- let color = { r: 200, g: 200, b: 200, alpha: 0.5 }; // Default gray
104
-
105
- if (DOCUMENT_TYPES.includes(fileType)) {
106
- color = { r: 52, g: 152, b: 219, alpha: 0.5 }; // Blue for documents
107
- } else if (VIDEO_TYPES.includes(fileType)) {
108
- color = { r: 231, g: 76, b: 60, alpha: 0.5 }; // Red for videos
109
- } else if (AUDIO_TYPES.includes(fileType)) {
110
- color = { r: 46, g: 204, b: 113, alpha: 0.5 }; // Green for audio
111
- }
112
-
113
- return canvas
114
- .composite([{
115
- input: Buffer.from([color.r, color.g, color.b, Math.floor(color.alpha * 255)]),
116
- raw: {
117
- width: 1,
118
- height: 1,
119
- channels: 4
120
- },
121
- tile: true,
122
- blend: 'overlay'
123
- }])
124
- .jpeg({ quality: 80 })
125
- .toBuffer();
126
- }
127
-
128
- /**
129
- * Generates a thumbnail for a file
130
- * @param fileName The name of the file in Google Cloud Storage
131
- * @param fileType The MIME type of the file
132
- * @returns The thumbnail buffer or null if thumbnail generation is not supported
133
- */
134
- export async function generateThumbnail(fileName: string, fileType: string): Promise<Buffer | null> {
135
- try {
136
- const signedUrl = await getSignedUrl(fileName);
137
- const response = await fetch(signedUrl);
78
+ // // For regular images
79
+ // return sharp(fileBuffer)
80
+ // .resize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, {
81
+ // fit: 'inside',
82
+ // withoutEnlargement: true,
83
+ // })
84
+ // .jpeg({ quality: 80 })
85
+ // .toBuffer();
86
+ // }
87
+
88
+ // /**
89
+ // * Generates a generic icon-based thumbnail for a file type
90
+ // * @param fileType The MIME type of the file
91
+ // * @returns Thumbnail buffer
92
+ // */
93
+ // async function generateGenericThumbnail(fileType: string): Promise<Buffer> {
94
+ // // Create a blank canvas with a colored background based on file type
95
+ // const canvas = sharp({
96
+ // create: {
97
+ // width: THUMBNAIL_WIDTH,
98
+ // height: THUMBNAIL_HEIGHT,
99
+ // channels: 4,
100
+ // background: { r: 245, g: 245, b: 245, alpha: 1 }
101
+ // }
102
+ // });
103
+
104
+ // // Add a colored overlay based on file type
105
+ // let color = { r: 200, g: 200, b: 200, alpha: 0.5 }; // Default gray
106
+
107
+ // if (DOCUMENT_TYPES.includes(fileType)) {
108
+ // color = { r: 52, g: 152, b: 219, alpha: 0.5 }; // Blue for documents
109
+ // } else if (VIDEO_TYPES.includes(fileType)) {
110
+ // color = { r: 231, g: 76, b: 60, alpha: 0.5 }; // Red for videos
111
+ // } else if (AUDIO_TYPES.includes(fileType)) {
112
+ // color = { r: 46, g: 204, b: 113, alpha: 0.5 }; // Green for audio
113
+ // }
114
+
115
+ // return canvas
116
+ // .composite([{
117
+ // input: Buffer.from([color.r, color.g, color.b, Math.floor(color.alpha * 255)]),
118
+ // raw: {
119
+ // width: 1,
120
+ // height: 1,
121
+ // channels: 4
122
+ // },
123
+ // tile: true,
124
+ // blend: 'overlay'
125
+ // }])
126
+ // .jpeg({ quality: 80 })
127
+ // .toBuffer();
128
+ // }
129
+
130
+ // /**
131
+ // * Generates a thumbnail for a file
132
+ // * @param fileName The name of the file in Google Cloud Storage
133
+ // * @param fileType The MIME type of the file
134
+ // * @returns The thumbnail buffer or null if thumbnail generation is not supported
135
+ // */
136
+ // export async function generateThumbnail(fileName: string, fileType: string): Promise<Buffer | null> {
137
+ // try {
138
+ // const signedUrl = await getSignedUrl(fileName);
139
+ // const response = await fetch(signedUrl);
138
140
 
139
- if (!response.ok) {
140
- throw new Error(`Failed to download file from storage: ${response.status} ${response.statusText}`);
141
- }
142
-
143
- const fileBuffer = await response.arrayBuffer();
144
-
145
- if (SUPPORTED_IMAGE_TYPES.includes(fileType) || fileType === 'application/pdf') {
146
- try {
147
- const thumbnail = await generateMediaThumbnail(Buffer.from(fileBuffer), fileType);
148
- return thumbnail;
149
- } catch (error) {
150
- return generateGenericThumbnail(fileType);
151
- }
152
- } else if ([...DOCUMENT_TYPES, ...VIDEO_TYPES, ...AUDIO_TYPES].includes(fileType)) {
153
- return generateGenericThumbnail(fileType);
154
- }
155
-
156
- return null; // Unsupported file type
157
- } catch (error) {
158
- return null;
159
- }
160
- }
161
-
162
- /**
163
- * Stores a thumbnail in Google Cloud Storage and creates a File entry
164
- * @param thumbnailBuffer The thumbnail buffer to store
165
- * @param originalFileName The original file name
166
- * @param userId The user ID who owns the file
167
- * @returns The ID of the created thumbnail File
168
- */
169
- // DEPRECATED: This function is no longer used - thumbnails are generated during direct uploads
170
- // Thumbnail generation is now handled in the direct upload flow
141
+ // if (!response.ok) {
142
+ // throw new Error(`Failed to download file from storage: ${response.status} ${response.statusText}`);
143
+ // }
144
+
145
+ // const fileBuffer = await response.arrayBuffer();
146
+
147
+ // if (SUPPORTED_IMAGE_TYPES.includes(fileType) || fileType === 'application/pdf') {
148
+ // try {
149
+ // const thumbnail = await generateMediaThumbnail(Buffer.from(fileBuffer), fileType);
150
+ // return thumbnail;
151
+ // } catch (error) {
152
+ // return generateGenericThumbnail(fileType);
153
+ // }
154
+ // } else if ([...DOCUMENT_TYPES, ...VIDEO_TYPES, ...AUDIO_TYPES].includes(fileType)) {
155
+ // return generateGenericThumbnail(fileType);
156
+ // }
157
+
158
+ // return null; // Unsupported file type
159
+ // } catch (error) {
160
+ // return null;
161
+ // }
162
+ // }
163
+
164
+ // /**
165
+ // * Stores a thumbnail in Google Cloud Storage and creates a File entry
166
+ // * @param thumbnailBuffer The thumbnail buffer to store
167
+ // * @param originalFileName The original file name
168
+ // * @param userId The user ID who owns the file
169
+ // * @returns The ID of the created thumbnail File
170
+ // */
171
+ // // DEPRECATED: This function is no longer used - thumbnails are generated during direct uploads
172
+ // // Thumbnail generation is now handled in the direct upload flow