@studious-lms/server 1.2.44 → 1.2.46

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 (234) hide show
  1. package/.env.example +45 -0
  2. package/.env.test.example +37 -0
  3. package/README.md +34 -7
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/clover.xml +12110 -0
  7. package/coverage/coverage-final.json +44 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +221 -0
  10. package/coverage/prettify.css +1 -0
  11. package/coverage/prettify.js +2 -0
  12. package/coverage/server/index.html +116 -0
  13. package/coverage/server/src/exportType.ts.html +109 -0
  14. package/coverage/server/src/index.html +161 -0
  15. package/coverage/server/src/index.ts.html +1702 -0
  16. package/coverage/server/src/instrument.ts.html +130 -0
  17. package/coverage/server/src/lib/config/env.ts.html +448 -0
  18. package/coverage/server/src/lib/config/index.html +116 -0
  19. package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
  20. package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
  21. package/coverage/server/src/lib/index.html +206 -0
  22. package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
  23. package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
  24. package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
  25. package/coverage/server/src/lib/pusher.ts.html +121 -0
  26. package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
  27. package/coverage/server/src/middleware/auth.ts.html +646 -0
  28. package/coverage/server/src/middleware/index.html +146 -0
  29. package/coverage/server/src/middleware/logging.ts.html +244 -0
  30. package/coverage/server/src/middleware/security.ts.html +271 -0
  31. package/coverage/server/src/routers/_app.ts.html +232 -0
  32. package/coverage/server/src/routers/agenda.ts.html +319 -0
  33. package/coverage/server/src/routers/announcement.ts.html +3481 -0
  34. package/coverage/server/src/routers/assignment.ts.html +7633 -0
  35. package/coverage/server/src/routers/attendance.ts.html +1030 -0
  36. package/coverage/server/src/routers/auth.ts.html +1081 -0
  37. package/coverage/server/src/routers/class.ts.html +3535 -0
  38. package/coverage/server/src/routers/comment.ts.html +991 -0
  39. package/coverage/server/src/routers/conversation.ts.html +982 -0
  40. package/coverage/server/src/routers/event.ts.html +1609 -0
  41. package/coverage/server/src/routers/file.ts.html +1144 -0
  42. package/coverage/server/src/routers/folder.ts.html +2797 -0
  43. package/coverage/server/src/routers/index.html +386 -0
  44. package/coverage/server/src/routers/labChat.ts.html +3073 -0
  45. package/coverage/server/src/routers/marketing.ts.html +340 -0
  46. package/coverage/server/src/routers/message.ts.html +1912 -0
  47. package/coverage/server/src/routers/notifications.ts.html +364 -0
  48. package/coverage/server/src/routers/section.ts.html +1120 -0
  49. package/coverage/server/src/routers/user.ts.html +862 -0
  50. package/coverage/server/src/routers/worksheet.ts.html +1729 -0
  51. package/coverage/server/src/trpc.ts.html +397 -0
  52. package/coverage/server/src/types/index.html +116 -0
  53. package/coverage/server/src/types/trpc.ts.html +127 -0
  54. package/coverage/server/src/utils/aiUser.ts.html +280 -0
  55. package/coverage/server/src/utils/email.ts.html +121 -0
  56. package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
  57. package/coverage/server/src/utils/index.html +206 -0
  58. package/coverage/server/src/utils/inference.ts.html +709 -0
  59. package/coverage/server/src/utils/logger.ts.html +664 -0
  60. package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
  61. package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
  62. package/coverage/server/vitest.config.ts.html +196 -0
  63. package/coverage/sort-arrow-sprite.png +0 -0
  64. package/coverage/sorter.js +210 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +83 -52
  67. package/dist/index.js.map +1 -1
  68. package/dist/instrument.js +15 -8
  69. package/dist/instrument.js.map +1 -1
  70. package/dist/lib/config/env.d.ts +169 -0
  71. package/dist/lib/config/env.d.ts.map +1 -0
  72. package/dist/lib/config/env.js +115 -0
  73. package/dist/lib/config/env.js.map +1 -0
  74. package/dist/lib/fileUpload.d.ts.map +1 -1
  75. package/dist/lib/fileUpload.js +5 -4
  76. package/dist/lib/fileUpload.js.map +1 -1
  77. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  78. package/dist/lib/googleCloudStorage.js +7 -8
  79. package/dist/lib/googleCloudStorage.js.map +1 -1
  80. package/dist/lib/jsonConversion.d.ts.map +1 -1
  81. package/dist/lib/jsonConversion.js +14 -16
  82. package/dist/lib/jsonConversion.js.map +1 -1
  83. package/dist/lib/notificationHandler.d.ts +2 -2
  84. package/dist/lib/prisma.d.ts +2 -2
  85. package/dist/lib/prisma.d.ts.map +1 -1
  86. package/dist/lib/prisma.js +22 -3
  87. package/dist/lib/prisma.js.map +1 -1
  88. package/dist/lib/pusher.d.ts.map +1 -1
  89. package/dist/lib/pusher.js +8 -7
  90. package/dist/lib/pusher.js.map +1 -1
  91. package/dist/middleware/auth.d.ts.map +1 -1
  92. package/dist/middleware/auth.js +6 -5
  93. package/dist/middleware/auth.js.map +1 -1
  94. package/dist/middleware/security.d.ts +5 -0
  95. package/dist/middleware/security.d.ts.map +1 -0
  96. package/dist/middleware/security.js +77 -0
  97. package/dist/middleware/security.js.map +1 -0
  98. package/dist/routers/_app.d.ts +304 -98
  99. package/dist/routers/_app.d.ts.map +1 -1
  100. package/dist/routers/_app.js +4 -2
  101. package/dist/routers/_app.js.map +1 -1
  102. package/dist/routers/agenda.d.ts.map +1 -1
  103. package/dist/routers/agenda.js +12 -9
  104. package/dist/routers/agenda.js.map +1 -1
  105. package/dist/routers/announcement.d.ts +8 -0
  106. package/dist/routers/announcement.d.ts.map +1 -1
  107. package/dist/routers/announcement.js +6 -4
  108. package/dist/routers/announcement.js.map +1 -1
  109. package/dist/routers/assignment.d.ts +7 -4
  110. package/dist/routers/assignment.d.ts.map +1 -1
  111. package/dist/routers/assignment.js +35 -18
  112. package/dist/routers/assignment.js.map +1 -1
  113. package/dist/routers/attendance.d.ts +1 -0
  114. package/dist/routers/attendance.d.ts.map +1 -1
  115. package/dist/routers/attendance.js +4 -4
  116. package/dist/routers/attendance.js.map +1 -1
  117. package/dist/routers/auth.d.ts +20 -0
  118. package/dist/routers/auth.d.ts.map +1 -1
  119. package/dist/routers/auth.js +132 -15
  120. package/dist/routers/auth.js.map +1 -1
  121. package/dist/routers/class.d.ts +10 -0
  122. package/dist/routers/class.d.ts.map +1 -1
  123. package/dist/routers/class.js +49 -5
  124. package/dist/routers/class.js.map +1 -1
  125. package/dist/routers/comment.d.ts +7 -0
  126. package/dist/routers/comment.d.ts.map +1 -1
  127. package/dist/routers/comment.js +9 -2
  128. package/dist/routers/comment.js.map +1 -1
  129. package/dist/routers/conversation.d.ts +1 -0
  130. package/dist/routers/conversation.d.ts.map +1 -1
  131. package/dist/routers/conversation.js +46 -31
  132. package/dist/routers/conversation.js.map +1 -1
  133. package/dist/routers/file.d.ts.map +1 -1
  134. package/dist/routers/file.js +30 -7
  135. package/dist/routers/file.js.map +1 -1
  136. package/dist/routers/labChat.d.ts +1 -0
  137. package/dist/routers/labChat.d.ts.map +1 -1
  138. package/dist/routers/labChat.js +2 -3
  139. package/dist/routers/labChat.js.map +1 -1
  140. package/dist/routers/marketing.d.ts +1 -1
  141. package/dist/routers/newtonChat.d.ts +55 -0
  142. package/dist/routers/newtonChat.d.ts.map +1 -0
  143. package/dist/routers/newtonChat.js +438 -0
  144. package/dist/routers/newtonChat.js.map +1 -0
  145. package/dist/routers/notifications.d.ts +4 -4
  146. package/dist/routers/section.d.ts +9 -4
  147. package/dist/routers/section.d.ts.map +1 -1
  148. package/dist/routers/section.js +8 -8
  149. package/dist/routers/section.js.map +1 -1
  150. package/dist/routers/user.d.ts.map +1 -1
  151. package/dist/routers/user.js +5 -4
  152. package/dist/routers/user.js.map +1 -1
  153. package/dist/routers/worksheet.d.ts +30 -36
  154. package/dist/routers/worksheet.d.ts.map +1 -1
  155. package/dist/routers/worksheet.js +11 -33
  156. package/dist/routers/worksheet.js.map +1 -1
  157. package/dist/seedDatabase.d.ts +1 -1
  158. package/dist/seedDatabase.js +275 -284
  159. package/dist/seedDatabase.js.map +1 -1
  160. package/dist/server/pipelines/aiLabChat.d.ts +10 -0
  161. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  162. package/dist/server/pipelines/aiLabChat.js +83 -0
  163. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  164. package/dist/server/pipelines/gradeWorksheet.d.ts +2 -0
  165. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  166. package/dist/server/pipelines/gradeWorksheet.js +138 -0
  167. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  168. package/dist/trpc.d.ts.map +1 -1
  169. package/dist/trpc.js +2 -2
  170. package/dist/trpc.js.map +1 -1
  171. package/dist/utils/email.d.ts +9 -1
  172. package/dist/utils/email.d.ts.map +1 -1
  173. package/dist/utils/email.js +20 -5
  174. package/dist/utils/email.js.map +1 -1
  175. package/dist/utils/inference.d.ts +3 -0
  176. package/dist/utils/inference.d.ts.map +1 -1
  177. package/dist/utils/inference.js +41 -7
  178. package/dist/utils/inference.js.map +1 -1
  179. package/dist/utils/logger.d.ts.map +1 -1
  180. package/dist/utils/logger.js +3 -3
  181. package/dist/utils/logger.js.map +1 -1
  182. package/docker-compose.yml +14 -0
  183. package/package.json +13 -4
  184. package/prisma/schema.prisma +32 -5
  185. package/scripts/test-pre-push.ts +14 -0
  186. package/src/index.ts +98 -54
  187. package/src/instrument.ts +13 -6
  188. package/src/lib/config/env.ts +126 -0
  189. package/src/lib/fileUpload.ts +3 -2
  190. package/src/lib/googleCloudStorage.ts +6 -6
  191. package/src/lib/jsonConversion.ts +12 -14
  192. package/src/lib/prisma.ts +23 -2
  193. package/src/lib/pusher.ts +6 -5
  194. package/src/middleware/auth.ts +4 -3
  195. package/src/middleware/security.ts +80 -0
  196. package/src/routers/_app.ts +2 -0
  197. package/src/routers/agenda.ts +10 -7
  198. package/src/routers/announcement.ts +4 -2
  199. package/src/routers/assignment.ts +58 -40
  200. package/src/routers/attendance.ts +2 -2
  201. package/src/routers/auth.ts +143 -14
  202. package/src/routers/class.ts +52 -3
  203. package/src/routers/comment.ts +7 -0
  204. package/src/routers/conversation.ts +49 -29
  205. package/src/routers/file.ts +29 -5
  206. package/src/routers/labChat.ts +0 -1
  207. package/src/routers/newtonChat.ts +520 -0
  208. package/src/routers/section.ts +6 -6
  209. package/src/routers/user.ts +3 -2
  210. package/src/routers/worksheet.ts +9 -37
  211. package/src/seedDatabase.ts +290 -283
  212. package/src/server/pipelines/aiLabChat.ts +92 -0
  213. package/src/server/pipelines/gradeWorksheet.ts +152 -0
  214. package/src/trpc.ts +2 -0
  215. package/src/utils/email.ts +30 -3
  216. package/src/utils/inference.ts +50 -5
  217. package/src/utils/logger.ts +2 -1
  218. package/tests/announcement.test.ts +164 -0
  219. package/tests/assignment.test.ts +296 -0
  220. package/tests/attendance.test.ts +168 -0
  221. package/tests/auth.test.ts +33 -10
  222. package/tests/class.test.ts +34 -9
  223. package/tests/event.test.ts +228 -0
  224. package/tests/section.test.ts +216 -0
  225. package/tests/setup.ts +70 -16
  226. package/tests/user.test.ts +158 -0
  227. package/vitest.config.ts +26 -0
  228. package/API_SPECIFICATION.md +0 -1597
  229. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  230. package/CHAT_API_SPEC.md +0 -579
  231. package/LAB_CHAT_API_SPEC.md +0 -518
  232. package/dist/routers/school.d.ts +0 -208
  233. package/dist/routers/school.d.ts.map +0 -1
  234. package/dist/routers/school.js +0 -483
@@ -0,0 +1,982 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for server/src/routers/conversation.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../../prettify.css" />
9
+ <link rel="stylesheet" href="../../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../../index.html">All files</a> / <a href="index.html">server/src/routers</a> conversation.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">8.17% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>22/269</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>0/0</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>0/0</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">8.17% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>22/269</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line low'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
366
+ <span class="cline-any cline-yes">1x</span>
367
+ <span class="cline-any cline-yes">1x</span>
368
+ <span class="cline-any cline-yes">1x</span>
369
+ <span class="cline-any cline-neutral">&nbsp;</span>
370
+ <span class="cline-any cline-yes">1x</span>
371
+ <span class="cline-any cline-yes">1x</span>
372
+ <span class="cline-any cline-no">&nbsp;</span>
373
+ <span class="cline-any cline-neutral">&nbsp;</span>
374
+ <span class="cline-any cline-no">&nbsp;</span>
375
+ <span class="cline-any cline-no">&nbsp;</span>
376
+ <span class="cline-any cline-no">&nbsp;</span>
377
+ <span class="cline-any cline-no">&nbsp;</span>
378
+ <span class="cline-any cline-no">&nbsp;</span>
379
+ <span class="cline-any cline-no">&nbsp;</span>
380
+ <span class="cline-any cline-no">&nbsp;</span>
381
+ <span class="cline-any cline-no">&nbsp;</span>
382
+ <span class="cline-any cline-no">&nbsp;</span>
383
+ <span class="cline-any cline-no">&nbsp;</span>
384
+ <span class="cline-any cline-no">&nbsp;</span>
385
+ <span class="cline-any cline-no">&nbsp;</span>
386
+ <span class="cline-any cline-no">&nbsp;</span>
387
+ <span class="cline-any cline-no">&nbsp;</span>
388
+ <span class="cline-any cline-no">&nbsp;</span>
389
+ <span class="cline-any cline-no">&nbsp;</span>
390
+ <span class="cline-any cline-no">&nbsp;</span>
391
+ <span class="cline-any cline-no">&nbsp;</span>
392
+ <span class="cline-any cline-no">&nbsp;</span>
393
+ <span class="cline-any cline-no">&nbsp;</span>
394
+ <span class="cline-any cline-no">&nbsp;</span>
395
+ <span class="cline-any cline-no">&nbsp;</span>
396
+ <span class="cline-any cline-no">&nbsp;</span>
397
+ <span class="cline-any cline-no">&nbsp;</span>
398
+ <span class="cline-any cline-no">&nbsp;</span>
399
+ <span class="cline-any cline-no">&nbsp;</span>
400
+ <span class="cline-any cline-no">&nbsp;</span>
401
+ <span class="cline-any cline-no">&nbsp;</span>
402
+ <span class="cline-any cline-no">&nbsp;</span>
403
+ <span class="cline-any cline-no">&nbsp;</span>
404
+ <span class="cline-any cline-no">&nbsp;</span>
405
+ <span class="cline-any cline-no">&nbsp;</span>
406
+ <span class="cline-any cline-no">&nbsp;</span>
407
+ <span class="cline-any cline-no">&nbsp;</span>
408
+ <span class="cline-any cline-no">&nbsp;</span>
409
+ <span class="cline-any cline-no">&nbsp;</span>
410
+ <span class="cline-any cline-no">&nbsp;</span>
411
+ <span class="cline-any cline-no">&nbsp;</span>
412
+ <span class="cline-any cline-no">&nbsp;</span>
413
+ <span class="cline-any cline-no">&nbsp;</span>
414
+ <span class="cline-any cline-no">&nbsp;</span>
415
+ <span class="cline-any cline-no">&nbsp;</span>
416
+ <span class="cline-any cline-no">&nbsp;</span>
417
+ <span class="cline-any cline-no">&nbsp;</span>
418
+ <span class="cline-any cline-no">&nbsp;</span>
419
+ <span class="cline-any cline-no">&nbsp;</span>
420
+ <span class="cline-any cline-no">&nbsp;</span>
421
+ <span class="cline-any cline-no">&nbsp;</span>
422
+ <span class="cline-any cline-no">&nbsp;</span>
423
+ <span class="cline-any cline-no">&nbsp;</span>
424
+ <span class="cline-any cline-no">&nbsp;</span>
425
+ <span class="cline-any cline-no">&nbsp;</span>
426
+ <span class="cline-any cline-no">&nbsp;</span>
427
+ <span class="cline-any cline-no">&nbsp;</span>
428
+ <span class="cline-any cline-no">&nbsp;</span>
429
+ <span class="cline-any cline-neutral">&nbsp;</span>
430
+ <span class="cline-any cline-neutral">&nbsp;</span>
431
+ <span class="cline-any cline-no">&nbsp;</span>
432
+ <span class="cline-any cline-no">&nbsp;</span>
433
+ <span class="cline-any cline-no">&nbsp;</span>
434
+ <span class="cline-any cline-no">&nbsp;</span>
435
+ <span class="cline-any cline-no">&nbsp;</span>
436
+ <span class="cline-any cline-neutral">&nbsp;</span>
437
+ <span class="cline-any cline-neutral">&nbsp;</span>
438
+ <span class="cline-any cline-no">&nbsp;</span>
439
+ <span class="cline-any cline-no">&nbsp;</span>
440
+ <span class="cline-any cline-no">&nbsp;</span>
441
+ <span class="cline-any cline-no">&nbsp;</span>
442
+ <span class="cline-any cline-no">&nbsp;</span>
443
+ <span class="cline-any cline-no">&nbsp;</span>
444
+ <span class="cline-any cline-no">&nbsp;</span>
445
+ <span class="cline-any cline-no">&nbsp;</span>
446
+ <span class="cline-any cline-no">&nbsp;</span>
447
+ <span class="cline-any cline-neutral">&nbsp;</span>
448
+ <span class="cline-any cline-neutral">&nbsp;</span>
449
+ <span class="cline-any cline-neutral">&nbsp;</span>
450
+ <span class="cline-any cline-neutral">&nbsp;</span>
451
+ <span class="cline-any cline-no">&nbsp;</span>
452
+ <span class="cline-any cline-no">&nbsp;</span>
453
+ <span class="cline-any cline-no">&nbsp;</span>
454
+ <span class="cline-any cline-neutral">&nbsp;</span>
455
+ <span class="cline-any cline-no">&nbsp;</span>
456
+ <span class="cline-any cline-no">&nbsp;</span>
457
+ <span class="cline-any cline-no">&nbsp;</span>
458
+ <span class="cline-any cline-no">&nbsp;</span>
459
+ <span class="cline-any cline-no">&nbsp;</span>
460
+ <span class="cline-any cline-no">&nbsp;</span>
461
+ <span class="cline-any cline-no">&nbsp;</span>
462
+ <span class="cline-any cline-no">&nbsp;</span>
463
+ <span class="cline-any cline-no">&nbsp;</span>
464
+ <span class="cline-any cline-no">&nbsp;</span>
465
+ <span class="cline-any cline-no">&nbsp;</span>
466
+ <span class="cline-any cline-no">&nbsp;</span>
467
+ <span class="cline-any cline-neutral">&nbsp;</span>
468
+ <span class="cline-any cline-no">&nbsp;</span>
469
+ <span class="cline-any cline-no">&nbsp;</span>
470
+ <span class="cline-any cline-no">&nbsp;</span>
471
+ <span class="cline-any cline-no">&nbsp;</span>
472
+ <span class="cline-any cline-no">&nbsp;</span>
473
+ <span class="cline-any cline-no">&nbsp;</span>
474
+ <span class="cline-any cline-no">&nbsp;</span>
475
+ <span class="cline-any cline-no">&nbsp;</span>
476
+ <span class="cline-any cline-no">&nbsp;</span>
477
+ <span class="cline-any cline-no">&nbsp;</span>
478
+ <span class="cline-any cline-no">&nbsp;</span>
479
+ <span class="cline-any cline-no">&nbsp;</span>
480
+ <span class="cline-any cline-no">&nbsp;</span>
481
+ <span class="cline-any cline-no">&nbsp;</span>
482
+ <span class="cline-any cline-neutral">&nbsp;</span>
483
+ <span class="cline-any cline-no">&nbsp;</span>
484
+ <span class="cline-any cline-yes">1x</span>
485
+ <span class="cline-any cline-neutral">&nbsp;</span>
486
+ <span class="cline-any cline-yes">1x</span>
487
+ <span class="cline-any cline-yes">1x</span>
488
+ <span class="cline-any cline-yes">1x</span>
489
+ <span class="cline-any cline-yes">1x</span>
490
+ <span class="cline-any cline-yes">1x</span>
491
+ <span class="cline-any cline-yes">1x</span>
492
+ <span class="cline-any cline-yes">1x</span>
493
+ <span class="cline-any cline-yes">1x</span>
494
+ <span class="cline-any cline-yes">1x</span>
495
+ <span class="cline-any cline-no">&nbsp;</span>
496
+ <span class="cline-any cline-no">&nbsp;</span>
497
+ <span class="cline-any cline-neutral">&nbsp;</span>
498
+ <span class="cline-any cline-neutral">&nbsp;</span>
499
+ <span class="cline-any cline-no">&nbsp;</span>
500
+ <span class="cline-any cline-no">&nbsp;</span>
501
+ <span class="cline-any cline-no">&nbsp;</span>
502
+ <span class="cline-any cline-no">&nbsp;</span>
503
+ <span class="cline-any cline-no">&nbsp;</span>
504
+ <span class="cline-any cline-no">&nbsp;</span>
505
+ <span class="cline-any cline-neutral">&nbsp;</span>
506
+ <span class="cline-any cline-no">&nbsp;</span>
507
+ <span class="cline-any cline-no">&nbsp;</span>
508
+ <span class="cline-any cline-no">&nbsp;</span>
509
+ <span class="cline-any cline-no">&nbsp;</span>
510
+ <span class="cline-any cline-no">&nbsp;</span>
511
+ <span class="cline-any cline-no">&nbsp;</span>
512
+ <span class="cline-any cline-neutral">&nbsp;</span>
513
+ <span class="cline-any cline-neutral">&nbsp;</span>
514
+ <span class="cline-any cline-no">&nbsp;</span>
515
+ <span class="cline-any cline-no">&nbsp;</span>
516
+ <span class="cline-any cline-no">&nbsp;</span>
517
+ <span class="cline-any cline-no">&nbsp;</span>
518
+ <span class="cline-any cline-no">&nbsp;</span>
519
+ <span class="cline-any cline-no">&nbsp;</span>
520
+ <span class="cline-any cline-no">&nbsp;</span>
521
+ <span class="cline-any cline-no">&nbsp;</span>
522
+ <span class="cline-any cline-no">&nbsp;</span>
523
+ <span class="cline-any cline-no">&nbsp;</span>
524
+ <span class="cline-any cline-no">&nbsp;</span>
525
+ <span class="cline-any cline-no">&nbsp;</span>
526
+ <span class="cline-any cline-no">&nbsp;</span>
527
+ <span class="cline-any cline-no">&nbsp;</span>
528
+ <span class="cline-any cline-no">&nbsp;</span>
529
+ <span class="cline-any cline-no">&nbsp;</span>
530
+ <span class="cline-any cline-no">&nbsp;</span>
531
+ <span class="cline-any cline-no">&nbsp;</span>
532
+ <span class="cline-any cline-no">&nbsp;</span>
533
+ <span class="cline-any cline-no">&nbsp;</span>
534
+ <span class="cline-any cline-no">&nbsp;</span>
535
+ <span class="cline-any cline-no">&nbsp;</span>
536
+ <span class="cline-any cline-no">&nbsp;</span>
537
+ <span class="cline-any cline-no">&nbsp;</span>
538
+ <span class="cline-any cline-no">&nbsp;</span>
539
+ <span class="cline-any cline-no">&nbsp;</span>
540
+ <span class="cline-any cline-no">&nbsp;</span>
541
+ <span class="cline-any cline-no">&nbsp;</span>
542
+ <span class="cline-any cline-no">&nbsp;</span>
543
+ <span class="cline-any cline-no">&nbsp;</span>
544
+ <span class="cline-any cline-no">&nbsp;</span>
545
+ <span class="cline-any cline-no">&nbsp;</span>
546
+ <span class="cline-any cline-no">&nbsp;</span>
547
+ <span class="cline-any cline-no">&nbsp;</span>
548
+ <span class="cline-any cline-no">&nbsp;</span>
549
+ <span class="cline-any cline-no">&nbsp;</span>
550
+ <span class="cline-any cline-no">&nbsp;</span>
551
+ <span class="cline-any cline-no">&nbsp;</span>
552
+ <span class="cline-any cline-neutral">&nbsp;</span>
553
+ <span class="cline-any cline-no">&nbsp;</span>
554
+ <span class="cline-any cline-no">&nbsp;</span>
555
+ <span class="cline-any cline-no">&nbsp;</span>
556
+ <span class="cline-any cline-no">&nbsp;</span>
557
+ <span class="cline-any cline-neutral">&nbsp;</span>
558
+ <span class="cline-any cline-neutral">&nbsp;</span>
559
+ <span class="cline-any cline-no">&nbsp;</span>
560
+ <span class="cline-any cline-no">&nbsp;</span>
561
+ <span class="cline-any cline-no">&nbsp;</span>
562
+ <span class="cline-any cline-no">&nbsp;</span>
563
+ <span class="cline-any cline-no">&nbsp;</span>
564
+ <span class="cline-any cline-no">&nbsp;</span>
565
+ <span class="cline-any cline-no">&nbsp;</span>
566
+ <span class="cline-any cline-no">&nbsp;</span>
567
+ <span class="cline-any cline-no">&nbsp;</span>
568
+ <span class="cline-any cline-no">&nbsp;</span>
569
+ <span class="cline-any cline-no">&nbsp;</span>
570
+ <span class="cline-any cline-neutral">&nbsp;</span>
571
+ <span class="cline-any cline-no">&nbsp;</span>
572
+ <span class="cline-any cline-no">&nbsp;</span>
573
+ <span class="cline-any cline-no">&nbsp;</span>
574
+ <span class="cline-any cline-no">&nbsp;</span>
575
+ <span class="cline-any cline-no">&nbsp;</span>
576
+ <span class="cline-any cline-no">&nbsp;</span>
577
+ <span class="cline-any cline-neutral">&nbsp;</span>
578
+ <span class="cline-any cline-neutral">&nbsp;</span>
579
+ <span class="cline-any cline-no">&nbsp;</span>
580
+ <span class="cline-any cline-no">&nbsp;</span>
581
+ <span class="cline-any cline-no">&nbsp;</span>
582
+ <span class="cline-any cline-no">&nbsp;</span>
583
+ <span class="cline-any cline-no">&nbsp;</span>
584
+ <span class="cline-any cline-no">&nbsp;</span>
585
+ <span class="cline-any cline-no">&nbsp;</span>
586
+ <span class="cline-any cline-no">&nbsp;</span>
587
+ <span class="cline-any cline-no">&nbsp;</span>
588
+ <span class="cline-any cline-no">&nbsp;</span>
589
+ <span class="cline-any cline-no">&nbsp;</span>
590
+ <span class="cline-any cline-no">&nbsp;</span>
591
+ <span class="cline-any cline-no">&nbsp;</span>
592
+ <span class="cline-any cline-no">&nbsp;</span>
593
+ <span class="cline-any cline-no">&nbsp;</span>
594
+ <span class="cline-any cline-no">&nbsp;</span>
595
+ <span class="cline-any cline-no">&nbsp;</span>
596
+ <span class="cline-any cline-no">&nbsp;</span>
597
+ <span class="cline-any cline-no">&nbsp;</span>
598
+ <span class="cline-any cline-no">&nbsp;</span>
599
+ <span class="cline-any cline-no">&nbsp;</span>
600
+ <span class="cline-any cline-no">&nbsp;</span>
601
+ <span class="cline-any cline-no">&nbsp;</span>
602
+ <span class="cline-any cline-no">&nbsp;</span>
603
+ <span class="cline-any cline-no">&nbsp;</span>
604
+ <span class="cline-any cline-no">&nbsp;</span>
605
+ <span class="cline-any cline-no">&nbsp;</span>
606
+ <span class="cline-any cline-no">&nbsp;</span>
607
+ <span class="cline-any cline-no">&nbsp;</span>
608
+ <span class="cline-any cline-no">&nbsp;</span>
609
+ <span class="cline-any cline-no">&nbsp;</span>
610
+ <span class="cline-any cline-no">&nbsp;</span>
611
+ <span class="cline-any cline-no">&nbsp;</span>
612
+ <span class="cline-any cline-no">&nbsp;</span>
613
+ <span class="cline-any cline-no">&nbsp;</span>
614
+ <span class="cline-any cline-no">&nbsp;</span>
615
+ <span class="cline-any cline-neutral">&nbsp;</span>
616
+ <span class="cline-any cline-no">&nbsp;</span>
617
+ <span class="cline-any cline-yes">1x</span>
618
+ <span class="cline-any cline-neutral">&nbsp;</span>
619
+ <span class="cline-any cline-yes">1x</span>
620
+ <span class="cline-any cline-yes">1x</span>
621
+ <span class="cline-any cline-yes">1x</span>
622
+ <span class="cline-any cline-no">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-neutral">&nbsp;</span>
625
+ <span class="cline-any cline-no">&nbsp;</span>
626
+ <span class="cline-any cline-no">&nbsp;</span>
627
+ <span class="cline-any cline-no">&nbsp;</span>
628
+ <span class="cline-any cline-no">&nbsp;</span>
629
+ <span class="cline-any cline-no">&nbsp;</span>
630
+ <span class="cline-any cline-no">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-no">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-no">&nbsp;</span>
640
+ <span class="cline-any cline-no">&nbsp;</span>
641
+ <span class="cline-any cline-no">&nbsp;</span>
642
+ <span class="cline-any cline-no">&nbsp;</span>
643
+ <span class="cline-any cline-no">&nbsp;</span>
644
+ <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-no">&nbsp;</span>
646
+ <span class="cline-any cline-no">&nbsp;</span>
647
+ <span class="cline-any cline-no">&nbsp;</span>
648
+ <span class="cline-any cline-no">&nbsp;</span>
649
+ <span class="cline-any cline-no">&nbsp;</span>
650
+ <span class="cline-any cline-no">&nbsp;</span>
651
+ <span class="cline-any cline-no">&nbsp;</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
653
+ <span class="cline-any cline-neutral">&nbsp;</span>
654
+ <span class="cline-any cline-no">&nbsp;</span>
655
+ <span class="cline-any cline-no">&nbsp;</span>
656
+ <span class="cline-any cline-no">&nbsp;</span>
657
+ <span class="cline-any cline-no">&nbsp;</span>
658
+ <span class="cline-any cline-no">&nbsp;</span>
659
+ <span class="cline-any cline-no">&nbsp;</span>
660
+ <span class="cline-any cline-neutral">&nbsp;</span>
661
+ <span class="cline-any cline-no">&nbsp;</span>
662
+ <span class="cline-any cline-yes">1x</span>
663
+ <span class="cline-any cline-yes">1x</span>
664
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { z } from 'zod';
665
+ import { createTRPCRouter, protectedProcedure } from '../trpc.js';
666
+ import { prisma } from '../lib/prisma.js';
667
+ import { TRPCError } from '@trpc/server';
668
+ &nbsp;
669
+ export const conversationRouter = createTRPCRouter({
670
+ list: protectedProcedure.query(async ({ ctx }) =&gt; {
671
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
672
+ &nbsp;
673
+ <span class="cstat-no" title="statement not covered" > const conversations = await prisma.conversation.findMany({</span>
674
+ <span class="cstat-no" title="statement not covered" > where: {</span>
675
+ <span class="cstat-no" title="statement not covered" > members: {</span>
676
+ <span class="cstat-no" title="statement not covered" > some: {</span>
677
+ <span class="cstat-no" title="statement not covered" > userId,</span>
678
+ <span class="cstat-no" title="statement not covered" > },</span>
679
+ <span class="cstat-no" title="statement not covered" > },</span>
680
+ <span class="cstat-no" title="statement not covered" > },</span>
681
+ <span class="cstat-no" title="statement not covered" > include: {</span>
682
+ <span class="cstat-no" title="statement not covered" > labChat: {</span>
683
+ <span class="cstat-no" title="statement not covered" > select: {</span>
684
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
685
+ <span class="cstat-no" title="statement not covered" > title: true,</span>
686
+ <span class="cstat-no" title="statement not covered" > },</span>
687
+ <span class="cstat-no" title="statement not covered" > },</span>
688
+ <span class="cstat-no" title="statement not covered" > members: {</span>
689
+ <span class="cstat-no" title="statement not covered" > include: {</span>
690
+ <span class="cstat-no" title="statement not covered" > user: {</span>
691
+ <span class="cstat-no" title="statement not covered" > select: {</span>
692
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
693
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
694
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
695
+ <span class="cstat-no" title="statement not covered" > select: {</span>
696
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
697
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
698
+ <span class="cstat-no" title="statement not covered" > },</span>
699
+ <span class="cstat-no" title="statement not covered" > },</span>
700
+ <span class="cstat-no" title="statement not covered" > },</span>
701
+ <span class="cstat-no" title="statement not covered" > },</span>
702
+ <span class="cstat-no" title="statement not covered" > },</span>
703
+ <span class="cstat-no" title="statement not covered" > },</span>
704
+ <span class="cstat-no" title="statement not covered" > messages: {</span>
705
+ <span class="cstat-no" title="statement not covered" > orderBy: {</span>
706
+ <span class="cstat-no" title="statement not covered" > createdAt: 'desc',</span>
707
+ <span class="cstat-no" title="statement not covered" > },</span>
708
+ <span class="cstat-no" title="statement not covered" > take: 1,</span>
709
+ <span class="cstat-no" title="statement not covered" > include: {</span>
710
+ <span class="cstat-no" title="statement not covered" > sender: {</span>
711
+ <span class="cstat-no" title="statement not covered" > select: {</span>
712
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
713
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
714
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
715
+ <span class="cstat-no" title="statement not covered" > select: {</span>
716
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
717
+ <span class="cstat-no" title="statement not covered" > },</span>
718
+ <span class="cstat-no" title="statement not covered" > },</span>
719
+ <span class="cstat-no" title="statement not covered" > },</span>
720
+ <span class="cstat-no" title="statement not covered" > },</span>
721
+ <span class="cstat-no" title="statement not covered" > },</span>
722
+ <span class="cstat-no" title="statement not covered" > },</span>
723
+ <span class="cstat-no" title="statement not covered" > },</span>
724
+ <span class="cstat-no" title="statement not covered" > orderBy: {</span>
725
+ <span class="cstat-no" title="statement not covered" > updatedAt: 'desc',</span>
726
+ <span class="cstat-no" title="statement not covered" > },</span>
727
+ <span class="cstat-no" title="statement not covered" > });</span>
728
+ &nbsp;
729
+ // Calculate unread counts for each conversation
730
+ <span class="cstat-no" title="statement not covered" > const conversationsWithUnread = await Promise.all(</span>
731
+ <span class="cstat-no" title="statement not covered" > conversations.map(async (conversation) =&gt; {</span>
732
+ <span class="cstat-no" title="statement not covered" > const userMembership = conversation.members.find(m =&gt; m.userId === userId);</span>
733
+ <span class="cstat-no" title="statement not covered" > const lastViewedAt = userMembership?.lastViewedAt;</span>
734
+ <span class="cstat-no" title="statement not covered" > const lastViewedMentionAt = userMembership?.lastViewedMentionAt;</span>
735
+
736
+ // Count regular unread messages
737
+ <span class="cstat-no" title="statement not covered" > const unreadCount = await prisma.message.count({</span>
738
+ <span class="cstat-no" title="statement not covered" > where: {</span>
739
+ <span class="cstat-no" title="statement not covered" > conversationId: conversation.id,</span>
740
+ <span class="cstat-no" title="statement not covered" > senderId: { not: userId },</span>
741
+ <span class="cstat-no" title="statement not covered" > ...(lastViewedAt &amp;&amp; {</span>
742
+ <span class="cstat-no" title="statement not covered" > createdAt: { gt: lastViewedAt }</span>
743
+ <span class="cstat-no" title="statement not covered" > }),</span>
744
+ <span class="cstat-no" title="statement not covered" > },</span>
745
+ <span class="cstat-no" title="statement not covered" > });</span>
746
+ &nbsp;
747
+ // Count unread mentions
748
+ // Use the later of lastViewedAt or lastViewedMentionAt
749
+ // This means if user viewed conversation after mention, mention is considered read
750
+ <span class="cstat-no" title="statement not covered" > const mentionCutoffTime = lastViewedMentionAt &amp;&amp; lastViewedAt </span>
751
+ <span class="cstat-no" title="statement not covered" > ? (lastViewedMentionAt &gt; lastViewedAt ? lastViewedMentionAt : lastViewedAt)</span>
752
+ <span class="cstat-no" title="statement not covered" > : (lastViewedMentionAt || lastViewedAt);</span>
753
+
754
+ <span class="cstat-no" title="statement not covered" > const unreadMentionCount = await prisma.mention.count({</span>
755
+ <span class="cstat-no" title="statement not covered" > where: {</span>
756
+ <span class="cstat-no" title="statement not covered" > userId,</span>
757
+ <span class="cstat-no" title="statement not covered" > message: {</span>
758
+ <span class="cstat-no" title="statement not covered" > conversationId: conversation.id,</span>
759
+ <span class="cstat-no" title="statement not covered" > senderId: { not: userId },</span>
760
+ <span class="cstat-no" title="statement not covered" > ...(mentionCutoffTime &amp;&amp; {</span>
761
+ <span class="cstat-no" title="statement not covered" > createdAt: { gt: mentionCutoffTime }</span>
762
+ <span class="cstat-no" title="statement not covered" > }),</span>
763
+ <span class="cstat-no" title="statement not covered" > },</span>
764
+ <span class="cstat-no" title="statement not covered" > },</span>
765
+ <span class="cstat-no" title="statement not covered" > });</span>
766
+ &nbsp;
767
+ <span class="cstat-no" title="statement not covered" > return {</span>
768
+ <span class="cstat-no" title="statement not covered" > id: conversation.id,</span>
769
+ <span class="cstat-no" title="statement not covered" > type: conversation.type,</span>
770
+ <span class="cstat-no" title="statement not covered" > name: conversation.name,</span>
771
+ <span class="cstat-no" title="statement not covered" > createdAt: conversation.createdAt,</span>
772
+ <span class="cstat-no" title="statement not covered" > updatedAt: conversation.updatedAt,</span>
773
+ <span class="cstat-no" title="statement not covered" > labChat: conversation.labChat,</span>
774
+ <span class="cstat-no" title="statement not covered" > members: conversation.members,</span>
775
+ <span class="cstat-no" title="statement not covered" > lastMessage: conversation.messages[0] || null,</span>
776
+ <span class="cstat-no" title="statement not covered" > unreadCount,</span>
777
+ <span class="cstat-no" title="statement not covered" > unreadMentionCount,</span>
778
+ <span class="cstat-no" title="statement not covered" > };</span>
779
+ <span class="cstat-no" title="statement not covered" > })</span>
780
+ <span class="cstat-no" title="statement not covered" > );</span>
781
+ &nbsp;
782
+ <span class="cstat-no" title="statement not covered" > return conversationsWithUnread;</span>
783
+ }),
784
+ &nbsp;
785
+ create: protectedProcedure
786
+ .input(
787
+ z.object({
788
+ type: z.enum(['DM', 'GROUP']),
789
+ name: z.string().optional(),
790
+ memberIds: z.array(z.string()),
791
+ })
792
+ )
793
+ .mutation(async ({ input, ctx }) =&gt; {
794
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
795
+ <span class="cstat-no" title="statement not covered" > const { type, name, memberIds } = input;</span>
796
+ &nbsp;
797
+ // Validate input
798
+ <span class="cstat-no" title="statement not covered" > if (type === 'GROUP' &amp;&amp; !name) {</span>
799
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
800
+ <span class="cstat-no" title="statement not covered" > code: 'BAD_REQUEST',</span>
801
+ <span class="cstat-no" title="statement not covered" > message: 'Group conversations must have a name',</span>
802
+ <span class="cstat-no" title="statement not covered" > });</span>
803
+ <span class="cstat-no" title="statement not covered" > }</span>
804
+ &nbsp;
805
+ <span class="cstat-no" title="statement not covered" > if (type === 'DM' &amp;&amp; memberIds.length !== 1) {</span>
806
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
807
+ <span class="cstat-no" title="statement not covered" > code: 'BAD_REQUEST',</span>
808
+ <span class="cstat-no" title="statement not covered" > message: 'DM conversations must have exactly one other member',</span>
809
+ <span class="cstat-no" title="statement not covered" > });</span>
810
+ <span class="cstat-no" title="statement not covered" > }</span>
811
+ &nbsp;
812
+ // For DMs, check if conversation already exists
813
+ <span class="cstat-no" title="statement not covered" > if (type === 'DM') {</span>
814
+ <span class="cstat-no" title="statement not covered" > const existingDM = await prisma.conversation.findFirst({</span>
815
+ <span class="cstat-no" title="statement not covered" > where: {</span>
816
+ <span class="cstat-no" title="statement not covered" > type: 'DM',</span>
817
+ <span class="cstat-no" title="statement not covered" > members: {</span>
818
+ <span class="cstat-no" title="statement not covered" > every: {</span>
819
+ <span class="cstat-no" title="statement not covered" > userId: {</span>
820
+ <span class="cstat-no" title="statement not covered" > in: [userId, memberIds[0]],</span>
821
+ <span class="cstat-no" title="statement not covered" > },</span>
822
+ <span class="cstat-no" title="statement not covered" > },</span>
823
+ <span class="cstat-no" title="statement not covered" > },</span>
824
+ <span class="cstat-no" title="statement not covered" > AND: {</span>
825
+ <span class="cstat-no" title="statement not covered" > members: {</span>
826
+ <span class="cstat-no" title="statement not covered" > some: {</span>
827
+ <span class="cstat-no" title="statement not covered" > userId,</span>
828
+ <span class="cstat-no" title="statement not covered" > },</span>
829
+ <span class="cstat-no" title="statement not covered" > },</span>
830
+ <span class="cstat-no" title="statement not covered" > },</span>
831
+ <span class="cstat-no" title="statement not covered" > },</span>
832
+ <span class="cstat-no" title="statement not covered" > include: {</span>
833
+ <span class="cstat-no" title="statement not covered" > members: {</span>
834
+ <span class="cstat-no" title="statement not covered" > include: {</span>
835
+ <span class="cstat-no" title="statement not covered" > user: {</span>
836
+ <span class="cstat-no" title="statement not covered" > select: {</span>
837
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
838
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
839
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
840
+ <span class="cstat-no" title="statement not covered" > select: {</span>
841
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
842
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
843
+ <span class="cstat-no" title="statement not covered" > },</span>
844
+ <span class="cstat-no" title="statement not covered" > },</span>
845
+ <span class="cstat-no" title="statement not covered" > },</span>
846
+ <span class="cstat-no" title="statement not covered" > },</span>
847
+ <span class="cstat-no" title="statement not covered" > },</span>
848
+ <span class="cstat-no" title="statement not covered" > },</span>
849
+ <span class="cstat-no" title="statement not covered" > },</span>
850
+ <span class="cstat-no" title="statement not covered" > });</span>
851
+ &nbsp;
852
+ <span class="cstat-no" title="statement not covered" > if (existingDM) {</span>
853
+ <span class="cstat-no" title="statement not covered" > return existingDM;</span>
854
+ <span class="cstat-no" title="statement not covered" > }</span>
855
+ <span class="cstat-no" title="statement not covered" > }</span>
856
+ &nbsp;
857
+ // Verify all members exist
858
+ <span class="cstat-no" title="statement not covered" > const members = await prisma.user.findMany({</span>
859
+ <span class="cstat-no" title="statement not covered" > where: {</span>
860
+ <span class="cstat-no" title="statement not covered" > username: {</span>
861
+ <span class="cstat-no" title="statement not covered" > in: memberIds,</span>
862
+ <span class="cstat-no" title="statement not covered" > },</span>
863
+ <span class="cstat-no" title="statement not covered" > },</span>
864
+ <span class="cstat-no" title="statement not covered" > select: {</span>
865
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
866
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
867
+ <span class="cstat-no" title="statement not covered" > },</span>
868
+ <span class="cstat-no" title="statement not covered" > });</span>
869
+ &nbsp;
870
+ <span class="cstat-no" title="statement not covered" > if (members.length !== memberIds.length) {</span>
871
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
872
+ <span class="cstat-no" title="statement not covered" > code: 'BAD_REQUEST',</span>
873
+ <span class="cstat-no" title="statement not covered" > message: 'One or more members not found',</span>
874
+ <span class="cstat-no" title="statement not covered" > });</span>
875
+ <span class="cstat-no" title="statement not covered" > }</span>
876
+ &nbsp;
877
+ // Create conversation with members
878
+ <span class="cstat-no" title="statement not covered" > const conversation = await prisma.conversation.create({</span>
879
+ <span class="cstat-no" title="statement not covered" > data: {</span>
880
+ <span class="cstat-no" title="statement not covered" > type,</span>
881
+ <span class="cstat-no" title="statement not covered" > name,</span>
882
+ <span class="cstat-no" title="statement not covered" > members: {</span>
883
+ <span class="cstat-no" title="statement not covered" > create: [</span>
884
+ <span class="cstat-no" title="statement not covered" > {</span>
885
+ <span class="cstat-no" title="statement not covered" > userId,</span>
886
+ <span class="cstat-no" title="statement not covered" > role: type === 'GROUP' ? 'ADMIN' : 'MEMBER',</span>
887
+ <span class="cstat-no" title="statement not covered" > },</span>
888
+ <span class="cstat-no" title="statement not covered" > ...memberIds.map((memberId) =&gt; ({</span>
889
+ <span class="cstat-no" title="statement not covered" > userId: members.find((member) =&gt; member.username === memberId)!.id,</span>
890
+ <span class="cstat-no" title="statement not covered" > role: 'MEMBER' as const,</span>
891
+ <span class="cstat-no" title="statement not covered" > })),</span>
892
+ <span class="cstat-no" title="statement not covered" > ],</span>
893
+ <span class="cstat-no" title="statement not covered" > },</span>
894
+ <span class="cstat-no" title="statement not covered" > },</span>
895
+ <span class="cstat-no" title="statement not covered" > include: {</span>
896
+ <span class="cstat-no" title="statement not covered" > members: {</span>
897
+ <span class="cstat-no" title="statement not covered" > include: {</span>
898
+ <span class="cstat-no" title="statement not covered" > user: {</span>
899
+ <span class="cstat-no" title="statement not covered" > select: {</span>
900
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
901
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
902
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
903
+ <span class="cstat-no" title="statement not covered" > select: {</span>
904
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
905
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
906
+ <span class="cstat-no" title="statement not covered" > },</span>
907
+ <span class="cstat-no" title="statement not covered" > },</span>
908
+ <span class="cstat-no" title="statement not covered" > },</span>
909
+ <span class="cstat-no" title="statement not covered" > },</span>
910
+ <span class="cstat-no" title="statement not covered" > },</span>
911
+ <span class="cstat-no" title="statement not covered" > },</span>
912
+ <span class="cstat-no" title="statement not covered" > },</span>
913
+ <span class="cstat-no" title="statement not covered" > });</span>
914
+ &nbsp;
915
+ <span class="cstat-no" title="statement not covered" > return conversation;</span>
916
+ }),
917
+ &nbsp;
918
+ get: protectedProcedure
919
+ .input(z.object({ conversationId: z.string() }))
920
+ .query(async ({ input, ctx }) =&gt; {
921
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
922
+ <span class="cstat-no" title="statement not covered" > const { conversationId } = input;</span>
923
+ &nbsp;
924
+ <span class="cstat-no" title="statement not covered" > const conversation = await prisma.conversation.findFirst({</span>
925
+ <span class="cstat-no" title="statement not covered" > where: {</span>
926
+ <span class="cstat-no" title="statement not covered" > id: conversationId,</span>
927
+ <span class="cstat-no" title="statement not covered" > members: {</span>
928
+ <span class="cstat-no" title="statement not covered" > some: {</span>
929
+ <span class="cstat-no" title="statement not covered" > userId,</span>
930
+ <span class="cstat-no" title="statement not covered" > },</span>
931
+ <span class="cstat-no" title="statement not covered" > },</span>
932
+ <span class="cstat-no" title="statement not covered" > },</span>
933
+ <span class="cstat-no" title="statement not covered" > include: {</span>
934
+ <span class="cstat-no" title="statement not covered" > members: {</span>
935
+ <span class="cstat-no" title="statement not covered" > include: {</span>
936
+ <span class="cstat-no" title="statement not covered" > user: {</span>
937
+ <span class="cstat-no" title="statement not covered" > select: {</span>
938
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
939
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
940
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
941
+ <span class="cstat-no" title="statement not covered" > select: {</span>
942
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
943
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
944
+ <span class="cstat-no" title="statement not covered" > },</span>
945
+ <span class="cstat-no" title="statement not covered" > },</span>
946
+ <span class="cstat-no" title="statement not covered" > },</span>
947
+ <span class="cstat-no" title="statement not covered" > },</span>
948
+ <span class="cstat-no" title="statement not covered" > },</span>
949
+ <span class="cstat-no" title="statement not covered" > },</span>
950
+ <span class="cstat-no" title="statement not covered" > },</span>
951
+ <span class="cstat-no" title="statement not covered" > });</span>
952
+ &nbsp;
953
+ <span class="cstat-no" title="statement not covered" > if (!conversation) {</span>
954
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
955
+ <span class="cstat-no" title="statement not covered" > code: 'NOT_FOUND',</span>
956
+ <span class="cstat-no" title="statement not covered" > message: 'Conversation not found or access denied',</span>
957
+ <span class="cstat-no" title="statement not covered" > });</span>
958
+ <span class="cstat-no" title="statement not covered" > }</span>
959
+ &nbsp;
960
+ <span class="cstat-no" title="statement not covered" > return conversation;</span>
961
+ }),
962
+ });
963
+ &nbsp;</pre></td></tr></table></pre>
964
+
965
+ <div class='push'></div><!-- for sticky footer -->
966
+ </div><!-- /wrapper -->
967
+ <div class='footer quiet pad2 space-top1 center small'>
968
+ Code coverage generated by
969
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
970
+ at 2025-11-22T10:42:40.796Z
971
+ </div>
972
+ <script src="../../../prettify.js"></script>
973
+ <script>
974
+ window.onload = function () {
975
+ prettyPrint();
976
+ };
977
+ </script>
978
+ <script src="../../../sorter.js"></script>
979
+ <script src="../../../block-navigation.js"></script>
980
+ </body>
981
+ </html>
982
+