@headless-lms/server 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +5 -0
  2. package/dist/app/community-mail.d.ts +24 -0
  3. package/dist/app/community-mail.js +92 -0
  4. package/dist/app/community-mail.js.map +1 -0
  5. package/dist/app/container.d.ts +40 -19
  6. package/dist/app/container.js +294 -45
  7. package/dist/app/container.js.map +1 -1
  8. package/dist/app/mcp-endpoints.d.ts +13 -0
  9. package/dist/app/mcp-endpoints.js +25 -0
  10. package/dist/app/mcp-endpoints.js.map +1 -0
  11. package/dist/app/notification-channels.d.ts +47 -0
  12. package/dist/app/notification-channels.js +174 -0
  13. package/dist/app/notification-channels.js.map +1 -0
  14. package/dist/app/notification-reads.d.ts +23 -0
  15. package/dist/app/notification-reads.js +95 -0
  16. package/dist/app/notification-reads.js.map +1 -0
  17. package/dist/http/config.d.ts +2 -1
  18. package/dist/http/errors.d.ts +15 -0
  19. package/dist/http/errors.js +162 -0
  20. package/dist/http/errors.js.map +1 -0
  21. package/dist/http/mcp/catalogue.d.ts +37 -0
  22. package/dist/http/mcp/catalogue.js +69 -0
  23. package/dist/http/mcp/catalogue.js.map +1 -0
  24. package/dist/http/mcp/challenge.d.ts +7 -0
  25. package/dist/http/mcp/challenge.js +35 -0
  26. package/dist/http/mcp/challenge.js.map +1 -0
  27. package/dist/http/mcp/input-schema.d.ts +7 -0
  28. package/dist/http/mcp/input-schema.js +28 -0
  29. package/dist/http/mcp/input-schema.js.map +1 -0
  30. package/dist/http/mcp/route.d.ts +8 -0
  31. package/dist/http/mcp/route.js +75 -0
  32. package/dist/http/mcp/route.js.map +1 -0
  33. package/dist/http/mcp/server.d.ts +8 -0
  34. package/dist/http/mcp/server.js +31 -0
  35. package/dist/http/mcp/server.js.map +1 -0
  36. package/dist/http/mcp/test-support.d.ts +55 -0
  37. package/dist/http/mcp/test-support.js +151 -0
  38. package/dist/http/mcp/test-support.js.map +1 -0
  39. package/dist/http/mcp/tool.d.ts +48 -0
  40. package/dist/http/mcp/tool.js +58 -0
  41. package/dist/http/mcp/tool.js.map +1 -0
  42. package/dist/http/mcp/tools/automations.d.ts +6 -0
  43. package/dist/http/mcp/tools/automations.js +120 -0
  44. package/dist/http/mcp/tools/automations.js.map +1 -0
  45. package/dist/http/mcp/tools/catalog.d.ts +6 -0
  46. package/dist/http/mcp/tools/catalog.js +200 -0
  47. package/dist/http/mcp/tools/catalog.js.map +1 -0
  48. package/dist/http/mcp/tools/comments.d.ts +6 -0
  49. package/dist/http/mcp/tools/comments.js +70 -0
  50. package/dist/http/mcp/tools/comments.js.map +1 -0
  51. package/dist/http/mcp/tools/communities.d.ts +6 -0
  52. package/dist/http/mcp/tools/communities.js +175 -0
  53. package/dist/http/mcp/tools/communities.js.map +1 -0
  54. package/dist/http/mcp/tools/community-members.d.ts +6 -0
  55. package/dist/http/mcp/tools/community-members.js +89 -0
  56. package/dist/http/mcp/tools/community-members.js.map +1 -0
  57. package/dist/http/mcp/tools/community-moderation.d.ts +6 -0
  58. package/dist/http/mcp/tools/community-moderation.js +144 -0
  59. package/dist/http/mcp/tools/community-moderation.js.map +1 -0
  60. package/dist/http/mcp/tools/courses.d.ts +6 -0
  61. package/dist/http/mcp/tools/courses.js +121 -0
  62. package/dist/http/mcp/tools/courses.js.map +1 -0
  63. package/dist/http/mcp/tools/index.d.ts +6 -0
  64. package/dist/http/mcp/tools/index.js +23 -0
  65. package/dist/http/mcp/tools/index.js.map +1 -0
  66. package/dist/http/mcp/tools/people.d.ts +6 -0
  67. package/dist/http/mcp/tools/people.js +145 -0
  68. package/dist/http/mcp/tools/people.js.map +1 -0
  69. package/dist/http/plugins/auth.js +13 -5
  70. package/dist/http/plugins/auth.js.map +1 -1
  71. package/dist/http/plugins/error-handler.d.ts +2 -1
  72. package/dist/http/plugins/error-handler.js +51 -65
  73. package/dist/http/plugins/error-handler.js.map +1 -1
  74. package/dist/http/plugins/openapi.js +49 -2
  75. package/dist/http/plugins/openapi.js.map +1 -1
  76. package/dist/http/routes/access.d.ts +7 -0
  77. package/dist/http/routes/access.js +140 -0
  78. package/dist/http/routes/access.js.map +1 -0
  79. package/dist/http/routes/activities.js +68 -23
  80. package/dist/http/routes/activities.js.map +1 -1
  81. package/dist/http/routes/assets.js +60 -55
  82. package/dist/http/routes/assets.js.map +1 -1
  83. package/dist/http/routes/automations.js +44 -24
  84. package/dist/http/routes/automations.js.map +1 -1
  85. package/dist/http/routes/bundles.js +29 -18
  86. package/dist/http/routes/bundles.js.map +1 -1
  87. package/dist/http/routes/communities.d.ts +7 -0
  88. package/dist/http/routes/communities.js +522 -0
  89. package/dist/http/routes/communities.js.map +1 -0
  90. package/dist/http/routes/community-moderation.d.ts +7 -0
  91. package/dist/http/routes/community-moderation.js +425 -0
  92. package/dist/http/routes/community-moderation.js.map +1 -0
  93. package/dist/http/routes/course-analytics.js +9 -7
  94. package/dist/http/routes/course-analytics.js.map +1 -1
  95. package/dist/http/routes/courses.js +30 -15
  96. package/dist/http/routes/courses.js.map +1 -1
  97. package/dist/http/routes/dashboard.js +15 -6
  98. package/dist/http/routes/dashboard.js.map +1 -1
  99. package/dist/http/routes/discussion.js +34 -26
  100. package/dist/http/routes/discussion.js.map +1 -1
  101. package/dist/http/routes/downloads.js +48 -30
  102. package/dist/http/routes/downloads.js.map +1 -1
  103. package/dist/http/routes/entitlements.js +16 -7
  104. package/dist/http/routes/entitlements.js.map +1 -1
  105. package/dist/http/routes/integrations.js +38 -41
  106. package/dist/http/routes/integrations.js.map +1 -1
  107. package/dist/http/routes/member/actor.d.ts +14 -0
  108. package/dist/http/routes/member/actor.js +11 -0
  109. package/dist/http/routes/member/actor.js.map +1 -0
  110. package/dist/http/routes/member/assets.d.ts +7 -0
  111. package/dist/http/routes/member/assets.js +79 -0
  112. package/dist/http/routes/member/assets.js.map +1 -0
  113. package/dist/http/routes/member/chats.d.ts +7 -0
  114. package/dist/http/routes/member/chats.js +435 -0
  115. package/dist/http/routes/member/chats.js.map +1 -0
  116. package/dist/http/routes/member/comments.d.ts +7 -0
  117. package/dist/http/routes/member/comments.js +187 -0
  118. package/dist/http/routes/member/comments.js.map +1 -0
  119. package/dist/http/routes/member/community.d.ts +7 -0
  120. package/dist/http/routes/member/community.js +312 -0
  121. package/dist/http/routes/member/community.js.map +1 -0
  122. package/dist/http/routes/member/courses.d.ts +7 -0
  123. package/dist/http/routes/member/courses.js +101 -0
  124. package/dist/http/routes/member/courses.js.map +1 -0
  125. package/dist/http/routes/member/devices.d.ts +7 -0
  126. package/dist/http/routes/member/devices.js +98 -0
  127. package/dist/http/routes/member/devices.js.map +1 -0
  128. package/dist/http/routes/member/downloads.d.ts +7 -0
  129. package/dist/http/routes/member/downloads.js +56 -0
  130. package/dist/http/routes/member/downloads.js.map +1 -0
  131. package/dist/http/routes/member/files.d.ts +7 -0
  132. package/dist/http/routes/member/files.js +184 -0
  133. package/dist/http/routes/member/files.js.map +1 -0
  134. package/dist/http/routes/member/index.d.ts +7 -0
  135. package/dist/http/routes/member/index.js +35 -0
  136. package/dist/http/routes/member/index.js.map +1 -0
  137. package/dist/http/routes/member/notification-settings.d.ts +7 -0
  138. package/dist/http/routes/member/notification-settings.js +108 -0
  139. package/dist/http/routes/member/notification-settings.js.map +1 -0
  140. package/dist/http/routes/member/notifications.d.ts +7 -0
  141. package/dist/http/routes/member/notifications.js +125 -0
  142. package/dist/http/routes/member/notifications.js.map +1 -0
  143. package/dist/http/routes/member/org.d.ts +7 -0
  144. package/dist/http/routes/member/org.js +56 -0
  145. package/dist/http/routes/member/org.js.map +1 -0
  146. package/dist/http/routes/member/posts.d.ts +7 -0
  147. package/dist/http/routes/member/posts.js +612 -0
  148. package/dist/http/routes/member/posts.js.map +1 -0
  149. package/dist/http/routes/member/profile.d.ts +7 -0
  150. package/dist/http/routes/member/profile.js +48 -0
  151. package/dist/http/routes/member/profile.js.map +1 -0
  152. package/dist/http/routes/member/progress.d.ts +7 -0
  153. package/dist/http/routes/member/progress.js +60 -0
  154. package/dist/http/routes/member/progress.js.map +1 -0
  155. package/dist/http/routes/organizations.js +171 -25
  156. package/dist/http/routes/organizations.js.map +1 -1
  157. package/dist/http/routes/students.js +32 -47
  158. package/dist/http/routes/students.js.map +1 -1
  159. package/dist/http/routes/webhooks.js +26 -18
  160. package/dist/http/routes/webhooks.js.map +1 -1
  161. package/dist/http/routes.js +8 -2
  162. package/dist/http/routes.js.map +1 -1
  163. package/dist/http/schemas/access.d.ts +146 -0
  164. package/dist/http/schemas/access.js +36 -0
  165. package/dist/http/schemas/access.js.map +1 -0
  166. package/dist/http/schemas/activities.d.ts +3 -1
  167. package/dist/http/schemas/activities.js +4 -4
  168. package/dist/http/schemas/activities.js.map +1 -1
  169. package/dist/http/schemas/assets.d.ts +79 -80
  170. package/dist/http/schemas/assets.js +23 -13
  171. package/dist/http/schemas/assets.js.map +1 -1
  172. package/dist/http/schemas/automations.d.ts +6 -0
  173. package/dist/http/schemas/bundles.js +6 -6
  174. package/dist/http/schemas/bundles.js.map +1 -1
  175. package/dist/http/schemas/chats.d.ts +409 -0
  176. package/dist/http/schemas/chats.js +56 -0
  177. package/dist/http/schemas/chats.js.map +1 -0
  178. package/dist/http/schemas/community.d.ts +597 -0
  179. package/dist/http/schemas/community.js +132 -0
  180. package/dist/http/schemas/community.js.map +1 -0
  181. package/dist/http/schemas/content.d.ts +4 -2
  182. package/dist/http/schemas/content.js +11 -8
  183. package/dist/http/schemas/content.js.map +1 -1
  184. package/dist/http/schemas/discussion.d.ts +98 -14
  185. package/dist/http/schemas/discussion.js +25 -12
  186. package/dist/http/schemas/discussion.js.map +1 -1
  187. package/dist/http/schemas/downloads.d.ts +11 -5
  188. package/dist/http/schemas/downloads.js +14 -11
  189. package/dist/http/schemas/downloads.js.map +1 -1
  190. package/dist/http/schemas/entitlements.d.ts +6 -6
  191. package/dist/http/schemas/entitlements.js +6 -6
  192. package/dist/http/schemas/entitlements.js.map +1 -1
  193. package/dist/http/schemas/files.d.ts +45 -0
  194. package/dist/http/schemas/files.js +25 -0
  195. package/dist/http/schemas/files.js.map +1 -0
  196. package/dist/http/schemas/index.d.ts +15 -8
  197. package/dist/http/schemas/index.js +15 -8
  198. package/dist/http/schemas/integrations.d.ts +4 -4
  199. package/dist/http/schemas/invites.d.ts +4 -0
  200. package/dist/http/schemas/invites.js +1 -0
  201. package/dist/http/schemas/invites.js.map +1 -1
  202. package/dist/http/schemas/{learn.d.ts → member.d.ts} +31 -18
  203. package/dist/http/schemas/{learn.js → member.js} +17 -13
  204. package/dist/http/schemas/member.js.map +1 -0
  205. package/dist/http/schemas/members.d.ts +35 -2
  206. package/dist/http/schemas/members.js +17 -3
  207. package/dist/http/schemas/members.js.map +1 -1
  208. package/dist/http/schemas/notifications.d.ts +550 -0
  209. package/dist/http/schemas/notifications.js +164 -0
  210. package/dist/http/schemas/notifications.js.map +1 -0
  211. package/dist/http/schemas/posts.d.ts +350 -0
  212. package/dist/http/schemas/posts.js +47 -0
  213. package/dist/http/schemas/posts.js.map +1 -0
  214. package/dist/http/schemas/profile.d.ts +23 -0
  215. package/dist/http/schemas/profile.js +15 -0
  216. package/dist/http/schemas/profile.js.map +1 -0
  217. package/dist/http/schemas/shared.d.ts +32 -1
  218. package/dist/http/schemas/shared.js +20 -2
  219. package/dist/http/schemas/shared.js.map +1 -1
  220. package/dist/http/schemas/students.d.ts +1 -7
  221. package/dist/http/schemas/students.js +1 -7
  222. package/dist/http/schemas/students.js.map +1 -1
  223. package/dist/http/scope.d.ts +3 -1
  224. package/dist/http/scope.js +26 -4
  225. package/dist/http/scope.js.map +1 -1
  226. package/dist/http/server.js +6 -1
  227. package/dist/http/server.js.map +1 -1
  228. package/dist/http/web-bridge.d.ts +1 -1
  229. package/dist/http/web-bridge.js +2 -2
  230. package/dist/http/web-bridge.js.map +1 -1
  231. package/dist/http/well-known.d.ts +7 -0
  232. package/dist/http/well-known.js +22 -0
  233. package/dist/http/well-known.js.map +1 -0
  234. package/dist/index.d.ts +3 -1
  235. package/dist/index.js +4 -2
  236. package/dist/index.js.map +1 -1
  237. package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +78 -0
  238. package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js.map +1 -0
  239. package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js +1267 -0
  240. package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js.map +1 -0
  241. package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js +814 -0
  242. package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js.map +1 -0
  243. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js +43 -0
  244. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js.map +1 -0
  245. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js +527 -0
  246. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js.map +1 -0
  247. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/utils.js +2 -0
  248. package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js +1737 -0
  249. package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js.map +1 -0
  250. package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js +137 -0
  251. package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js.map +1 -0
  252. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js +118 -0
  253. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js.map +1 -0
  254. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js +1222 -0
  255. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js.map +1 -0
  256. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js +91 -0
  257. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js.map +1 -0
  258. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js +113 -0
  259. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js.map +1 -0
  260. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js +449 -0
  261. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js.map +1 -0
  262. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js +163 -0
  263. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js.map +1 -0
  264. package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js +3187 -0
  265. package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js.map +1 -0
  266. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js +11 -0
  267. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js.map +1 -0
  268. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js +16 -0
  269. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js.map +1 -0
  270. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js +11 -0
  271. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js.map +1 -0
  272. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js +15 -0
  273. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js.map +1 -0
  274. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js +13 -0
  275. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js.map +1 -0
  276. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js +34 -0
  277. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js.map +1 -0
  278. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js +12 -0
  279. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js.map +1 -0
  280. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js +122 -0
  281. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js.map +1 -0
  282. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js +39 -0
  283. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js.map +1 -0
  284. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js +99 -0
  285. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js.map +1 -0
  286. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js +25 -0
  287. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js.map +1 -0
  288. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js +14 -0
  289. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js.map +1 -0
  290. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js +21 -0
  291. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js.map +1 -0
  292. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js +6 -0
  293. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js.map +1 -0
  294. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js +12 -0
  295. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js.map +1 -0
  296. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js +18 -0
  297. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js.map +1 -0
  298. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js +24 -0
  299. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js.map +1 -0
  300. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js +9 -0
  301. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js.map +1 -0
  302. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js +30 -0
  303. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js.map +1 -0
  304. package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +939 -0
  305. package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js.map +1 -0
  306. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js +82 -0
  307. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js.map +1 -0
  308. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js +82 -0
  309. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js.map +1 -0
  310. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js +8 -0
  311. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js.map +1 -0
  312. package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js +83 -0
  313. package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js.map +1 -0
  314. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.js +9 -0
  315. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.js.map +1 -0
  316. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/date.W2xKR2qe.js +51 -0
  317. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/date.W2xKR2qe.js.map +1 -0
  318. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/utils.C8RiOc4B.js +48 -0
  319. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/utils.C8RiOc4B.js.map +1 -0
  320. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/vi.DgezovHB.js +2426 -0
  321. package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/vi.DgezovHB.js.map +1 -0
  322. package/dist/packages/server/package.js +6 -0
  323. package/dist/packages/server/package.js.map +1 -0
  324. package/package.json +9 -7
  325. package/dist/app/notifications.d.ts +0 -7
  326. package/dist/app/notifications.js +0 -26
  327. package/dist/app/notifications.js.map +0 -1
  328. package/dist/http/routes/learn/assets.d.ts +0 -8
  329. package/dist/http/routes/learn/assets.js +0 -32
  330. package/dist/http/routes/learn/assets.js.map +0 -1
  331. package/dist/http/routes/learn/comments.d.ts +0 -7
  332. package/dist/http/routes/learn/comments.js +0 -175
  333. package/dist/http/routes/learn/comments.js.map +0 -1
  334. package/dist/http/routes/learn/courses.d.ts +0 -7
  335. package/dist/http/routes/learn/courses.js +0 -98
  336. package/dist/http/routes/learn/courses.js.map +0 -1
  337. package/dist/http/routes/learn/downloads.d.ts +0 -7
  338. package/dist/http/routes/learn/downloads.js +0 -76
  339. package/dist/http/routes/learn/downloads.js.map +0 -1
  340. package/dist/http/routes/learn/index.d.ts +0 -7
  341. package/dist/http/routes/learn/index.js +0 -19
  342. package/dist/http/routes/learn/index.js.map +0 -1
  343. package/dist/http/routes/learn/org.d.ts +0 -7
  344. package/dist/http/routes/learn/org.js +0 -50
  345. package/dist/http/routes/learn/org.js.map +0 -1
  346. package/dist/http/routes/learn/progress.d.ts +0 -7
  347. package/dist/http/routes/learn/progress.js +0 -63
  348. package/dist/http/routes/learn/progress.js.map +0 -1
  349. package/dist/http/schemas/learn.js.map +0 -1
  350. package/dist/package.js +0 -6
  351. package/dist/package.js.map +0 -1
@@ -0,0 +1,425 @@
1
+ import { PageQuery, refusals } from "../schemas/shared.js";
2
+ import { resolveScope } from "../scope.js";
3
+ import { CommentView, ResolveCommentFlags } from "../schemas/discussion.js";
4
+ import { CommunityChatParam, CommunityCommentParam, CommunityIdParam, CommunityMembersPage, CommunityMembersQuery, CommunityMessageParam, CommunityPostParam, CommunitySpaceParam, SpaceMember, SpaceMemberParam, SpaceMembersPage } from "../schemas/community.js";
5
+ import { PostView, ResolvePostFlags, SpaceQueue } from "../schemas/posts.js";
6
+ import { Chat, OrgUserBody, ResolveMessageFlags } from "../schemas/chats.js";
7
+ import "../schemas/index.js";
8
+ import { z } from "zod";
9
+ import { NotFoundError } from "@headless-lms/core/shared/errors";
10
+ //#region src/http/routes/community-moderation.ts
11
+ async function communityModerationRoutes(app, container) {
12
+ const r = app.withTypeProvider();
13
+ const tags = ["Communities"];
14
+ r.route({
15
+ method: "GET",
16
+ url: "/api/communities/:communityId/members",
17
+ schema: {
18
+ operationId: "listCommunityMembers",
19
+ tags,
20
+ summary: "List the people who hold a community (staff)",
21
+ description: "Staff only (owner, admin, instructor). Everyone with active access to the community, granted directly or through a bundle, paged and searched by name or email.",
22
+ params: CommunityIdParam,
23
+ querystring: CommunityMembersQuery,
24
+ response: {
25
+ 200: CommunityMembersPage,
26
+ ...refusals(403, 404)
27
+ }
28
+ },
29
+ handler: async (req) => {
30
+ const scope = await resolveScope(container, req);
31
+ const page = await container.reporting.admin.communityMembers(scope.orgId, req.params.communityId, req.query);
32
+ if (!page) throw new NotFoundError("Community", req.params.communityId);
33
+ return page;
34
+ }
35
+ });
36
+ r.route({
37
+ method: "GET",
38
+ url: "/api/communities/:communityId/spaces/:spaceId/members",
39
+ schema: {
40
+ operationId: "listCommunitySpaceMembers",
41
+ tags,
42
+ summary: "List the members, requests and invitations of a space (staff)",
43
+ description: "Staff only (owner, admin, instructor). The space's members, its open requests to join and its open invitations.",
44
+ params: CommunitySpaceParam,
45
+ querystring: PageQuery,
46
+ response: {
47
+ 200: SpaceMembersPage,
48
+ ...refusals(403, 404)
49
+ }
50
+ },
51
+ handler: async (req) => {
52
+ const scope = await resolveScope(container, req);
53
+ return container.entitlements.listSpaceMembers(scope.orgId, {
54
+ id: scope.orgUserId,
55
+ role: scope.role
56
+ }, req.params.communityId, req.params.spaceId, req.query);
57
+ }
58
+ });
59
+ r.route({
60
+ method: "POST",
61
+ url: "/api/communities/:communityId/spaces/:spaceId/members",
62
+ schema: {
63
+ operationId: "addCommunitySpaceMember",
64
+ tags,
65
+ summary: "Add a person to a space (staff)",
66
+ description: "Staff only (owner, admin, instructor). Places a member of the community straight into the space, with no request or invitation. 409 when the space is open to all members, the person is already placed, or the space is full.",
67
+ params: CommunitySpaceParam,
68
+ body: OrgUserBody,
69
+ response: {
70
+ 201: SpaceMember,
71
+ ...refusals(403, 404, 409)
72
+ }
73
+ },
74
+ handler: async (req, reply) => {
75
+ const scope = await resolveScope(container, req);
76
+ const member = await container.entitlements.addSpaceMember(scope.orgId, {
77
+ id: scope.orgUserId,
78
+ role: scope.role
79
+ }, req.params.communityId, req.params.spaceId, req.body.orgUserId);
80
+ return reply.code(201).send(member);
81
+ }
82
+ });
83
+ r.route({
84
+ method: "POST",
85
+ url: "/api/communities/:communityId/spaces/:spaceId/invites",
86
+ schema: {
87
+ operationId: "inviteCommunitySpaceMember",
88
+ tags,
89
+ summary: "Invite a person into a space (staff)",
90
+ description: "Staff only (owner, admin, instructor). Invites a member of the community into a `by_invite` space; they join when they accept. 403 when the person is staff or does not hold the community; 409 when the space is not invite-only or the person is already placed.",
91
+ params: CommunitySpaceParam,
92
+ body: OrgUserBody,
93
+ response: {
94
+ 201: SpaceMember,
95
+ ...refusals(403, 404, 409)
96
+ }
97
+ },
98
+ handler: async (req, reply) => {
99
+ const scope = await resolveScope(container, req);
100
+ const member = await container.entitlements.invite(scope.orgId, {
101
+ id: scope.orgUserId,
102
+ role: scope.role
103
+ }, req.params.communityId, req.params.spaceId, req.body.orgUserId);
104
+ return reply.code(201).send(member);
105
+ }
106
+ });
107
+ r.route({
108
+ method: "POST",
109
+ url: "/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/approval",
110
+ schema: {
111
+ operationId: "approveCommunitySpaceRequest",
112
+ tags,
113
+ summary: "Approve a person's request to join a space (staff)",
114
+ description: "Staff only (owner, admin, instructor). Makes the requester an active member. 404 when the person has no open request; 409 when the space is full or they are already a member.",
115
+ params: SpaceMemberParam,
116
+ response: {
117
+ 200: SpaceMember,
118
+ ...refusals(403, 404, 409)
119
+ }
120
+ },
121
+ handler: async (req) => {
122
+ const scope = await resolveScope(container, req);
123
+ return container.entitlements.approve(scope.orgId, {
124
+ id: scope.orgUserId,
125
+ role: scope.role
126
+ }, req.params.communityId, req.params.spaceId, req.params.orgUserId);
127
+ }
128
+ });
129
+ r.route({
130
+ method: "POST",
131
+ url: "/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/decline",
132
+ schema: {
133
+ operationId: "declineCommunitySpaceRequest",
134
+ tags,
135
+ summary: "Decline a person's request to join a space (staff)",
136
+ description: "Staff only (owner, admin, instructor). Closes the open request. 404 when the person has no open request; 409 when they are already a member.",
137
+ params: SpaceMemberParam,
138
+ response: {
139
+ 200: SpaceMember,
140
+ ...refusals(403, 404, 409)
141
+ }
142
+ },
143
+ handler: async (req) => {
144
+ const scope = await resolveScope(container, req);
145
+ return container.entitlements.decline(scope.orgId, {
146
+ id: scope.orgUserId,
147
+ role: scope.role
148
+ }, req.params.communityId, req.params.spaceId, req.params.orgUserId);
149
+ }
150
+ });
151
+ r.route({
152
+ method: "POST",
153
+ url: "/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/removal",
154
+ schema: {
155
+ operationId: "removeCommunitySpaceMember",
156
+ tags,
157
+ summary: "Remove a person from a space (staff)",
158
+ description: "Staff only (owner, admin, instructor). Revokes the placement, whether it is a membership, a request or an invitation. 409 when the space is open to all members or the placement is already revoked.",
159
+ params: SpaceMemberParam,
160
+ response: {
161
+ 200: SpaceMember,
162
+ ...refusals(403, 404, 409)
163
+ }
164
+ },
165
+ handler: async (req) => {
166
+ const scope = await resolveScope(container, req);
167
+ return container.entitlements.remove(scope.orgId, {
168
+ id: scope.orgUserId,
169
+ role: scope.role
170
+ }, req.params.communityId, req.params.spaceId, req.params.orgUserId);
171
+ }
172
+ });
173
+ r.route({
174
+ method: "GET",
175
+ url: "/api/communities/:communityId/spaces/:spaceId/queue",
176
+ schema: {
177
+ operationId: "getCommunitySpaceQueue",
178
+ tags,
179
+ summary: "The moderation queue of a space (staff)",
180
+ description: "Staff only (owner, admin, instructor). Posts awaiting review, and the open flags on posts and on comments in the space. Each list holds at most the 100 oldest entries: pending posts by creation, flags by when they were raised; working the queue brings in the next ones.",
181
+ params: CommunitySpaceParam,
182
+ response: {
183
+ 200: SpaceQueue,
184
+ ...refusals(403, 404)
185
+ }
186
+ },
187
+ handler: async (req) => {
188
+ const scope = await resolveScope(container, req);
189
+ return container.posts.moderationQueue(scope.orgId, {
190
+ id: scope.orgUserId,
191
+ role: scope.role
192
+ }, req.params.communityId, req.params.spaceId);
193
+ }
194
+ });
195
+ r.route({
196
+ method: "POST",
197
+ url: "/api/communities/:communityId/posts/:postId/approval",
198
+ schema: {
199
+ operationId: "approveCommunityPost",
200
+ tags,
201
+ summary: "Publish a post that is awaiting review (staff)",
202
+ description: "Staff only (owner, admin, instructor). 409 when the post is not awaiting review.",
203
+ params: CommunityPostParam,
204
+ response: {
205
+ 200: PostView,
206
+ ...refusals(403, 404, 409)
207
+ }
208
+ },
209
+ handler: async (req) => {
210
+ const scope = await resolveScope(container, req);
211
+ return container.posts.approve(scope.orgId, req.params.postId, {
212
+ id: scope.orgUserId,
213
+ role: scope.role
214
+ }, req.params.communityId);
215
+ }
216
+ });
217
+ r.route({
218
+ method: "POST",
219
+ url: "/api/communities/:communityId/posts/:postId/removal",
220
+ schema: {
221
+ operationId: "removeCommunityPost",
222
+ tags,
223
+ summary: "Remove a post (staff)",
224
+ description: "Staff only (owner, admin, instructor). Takes a published or pending post down and resolves its open flags as `removed`. 409 when it is already removed or was never submitted.",
225
+ params: CommunityPostParam,
226
+ response: {
227
+ 200: PostView,
228
+ ...refusals(403, 404, 409)
229
+ }
230
+ },
231
+ handler: async (req) => {
232
+ const scope = await resolveScope(container, req);
233
+ return container.posts.remove(scope.orgId, req.params.postId, {
234
+ id: scope.orgUserId,
235
+ role: scope.role
236
+ }, req.params.communityId);
237
+ }
238
+ });
239
+ r.route({
240
+ method: "POST",
241
+ url: "/api/communities/:communityId/posts/:postId/restoration",
242
+ schema: {
243
+ operationId: "restoreCommunityPost",
244
+ tags,
245
+ summary: "Restore a removed post (staff)",
246
+ description: "Staff only (owner, admin, instructor). 409 when the post is not removed.",
247
+ params: CommunityPostParam,
248
+ response: {
249
+ 200: PostView,
250
+ ...refusals(403, 404, 409)
251
+ }
252
+ },
253
+ handler: async (req) => {
254
+ const scope = await resolveScope(container, req);
255
+ return container.posts.restore(scope.orgId, req.params.postId, {
256
+ id: scope.orgUserId,
257
+ role: scope.role
258
+ }, req.params.communityId);
259
+ }
260
+ });
261
+ r.route({
262
+ method: "POST",
263
+ url: "/api/communities/:communityId/posts/:postId/flags/resolution",
264
+ schema: {
265
+ operationId: "resolveCommunityPostFlags",
266
+ tags,
267
+ summary: "Dismiss the open flags on a post (staff)",
268
+ description: "Staff only (owner, admin, instructor). Closes every open flag on the post and leaves it up.",
269
+ params: CommunityPostParam,
270
+ body: ResolvePostFlags,
271
+ response: {
272
+ 204: z.void(),
273
+ ...refusals(403, 404)
274
+ }
275
+ },
276
+ handler: async (req, reply) => {
277
+ const scope = await resolveScope(container, req);
278
+ await container.posts.resolveFlags(scope.orgId, req.params.postId, {
279
+ id: scope.orgUserId,
280
+ role: scope.role
281
+ }, req.body.resolution, req.params.communityId);
282
+ return reply.code(204).send();
283
+ }
284
+ });
285
+ r.route({
286
+ method: "POST",
287
+ url: "/api/communities/:communityId/comments/:commentId/removal",
288
+ schema: {
289
+ operationId: "removeCommunityComment",
290
+ tags,
291
+ summary: "Remove a comment on a post (staff)",
292
+ description: "Staff only (owner, admin, instructor). Hides the comment and resolves its open flags as `removed`. Removing a removed comment returns it unchanged.",
293
+ params: CommunityCommentParam,
294
+ response: {
295
+ 200: CommentView,
296
+ ...refusals(403, 404)
297
+ }
298
+ },
299
+ handler: async (req) => {
300
+ const scope = await resolveScope(container, req);
301
+ return container.discussion.remove(scope.orgId, req.params.commentId, {
302
+ id: scope.orgUserId,
303
+ role: scope.role
304
+ }, req.params.communityId);
305
+ }
306
+ });
307
+ r.route({
308
+ method: "POST",
309
+ url: "/api/communities/:communityId/comments/:commentId/restoration",
310
+ schema: {
311
+ operationId: "restoreCommunityComment",
312
+ tags,
313
+ summary: "Restore a removed comment on a post (staff)",
314
+ description: "Staff only (owner, admin, instructor). Publishes the comment again. Restoring a comment that is not removed returns it unchanged.",
315
+ params: CommunityCommentParam,
316
+ response: {
317
+ 200: CommentView,
318
+ ...refusals(403, 404)
319
+ }
320
+ },
321
+ handler: async (req) => {
322
+ const scope = await resolveScope(container, req);
323
+ return container.discussion.restore(scope.orgId, req.params.commentId, {
324
+ id: scope.orgUserId,
325
+ role: scope.role
326
+ }, req.params.communityId);
327
+ }
328
+ });
329
+ r.route({
330
+ method: "POST",
331
+ url: "/api/communities/:communityId/comments/:commentId/flags/resolution",
332
+ schema: {
333
+ operationId: "resolveCommunityCommentFlags",
334
+ tags,
335
+ summary: "Dismiss the open flags on a comment (staff)",
336
+ description: "Staff only (owner, admin, instructor). Closes every open flag on the comment and leaves it up.",
337
+ params: CommunityCommentParam,
338
+ body: ResolveCommentFlags,
339
+ response: {
340
+ 204: z.void(),
341
+ ...refusals(403, 404)
342
+ }
343
+ },
344
+ handler: async (req, reply) => {
345
+ const scope = await resolveScope(container, req);
346
+ await container.discussion.resolveReports(scope.orgId, req.params.commentId, {
347
+ id: scope.orgUserId,
348
+ role: scope.role
349
+ }, req.params.communityId);
350
+ return reply.code(204).send();
351
+ }
352
+ });
353
+ r.route({
354
+ method: "POST",
355
+ url: "/api/communities/:communityId/messages/:messageId/flags/resolution",
356
+ schema: {
357
+ operationId: "resolveCommunityMessageFlags",
358
+ tags,
359
+ summary: "Dismiss the open flags on a message (staff)",
360
+ description: "Staff only (owner, admin, instructor). Closes every open flag on the message and leaves it up.",
361
+ params: CommunityMessageParam,
362
+ body: ResolveMessageFlags,
363
+ response: {
364
+ 204: z.void(),
365
+ ...refusals(403, 404)
366
+ }
367
+ },
368
+ handler: async (req, reply) => {
369
+ const scope = await resolveScope(container, req);
370
+ await container.chats.resolveMessageFlags(scope.orgId, {
371
+ id: scope.orgUserId,
372
+ role: scope.role
373
+ }, req.params.messageId, req.body.resolution, req.params.communityId);
374
+ return reply.code(204).send();
375
+ }
376
+ });
377
+ r.route({
378
+ method: "POST",
379
+ url: "/api/communities/:communityId/chats/:chatId/lock",
380
+ schema: {
381
+ operationId: "lockCommunityChat",
382
+ tags,
383
+ summary: "Lock a chat (staff)",
384
+ description: "Staff only (owner, admin, instructor). Nobody can send or edit messages until it is unlocked; its open message flags are resolved as `locked`. Locking a locked chat returns it unchanged.",
385
+ params: CommunityChatParam,
386
+ response: {
387
+ 200: Chat,
388
+ ...refusals(403, 404)
389
+ }
390
+ },
391
+ handler: async (req) => {
392
+ const scope = await resolveScope(container, req);
393
+ return container.chats.lock(scope.orgId, {
394
+ id: scope.orgUserId,
395
+ role: scope.role
396
+ }, req.params.chatId, req.params.communityId);
397
+ }
398
+ });
399
+ r.route({
400
+ method: "POST",
401
+ url: "/api/communities/:communityId/chats/:chatId/unlock",
402
+ schema: {
403
+ operationId: "unlockCommunityChat",
404
+ tags,
405
+ summary: "Unlock a chat (staff)",
406
+ description: "Staff only (owner, admin, instructor). Lets participants send messages again. Unlocking an unlocked chat returns it unchanged.",
407
+ params: CommunityChatParam,
408
+ response: {
409
+ 200: Chat,
410
+ ...refusals(403, 404)
411
+ }
412
+ },
413
+ handler: async (req) => {
414
+ const scope = await resolveScope(container, req);
415
+ return container.chats.unlock(scope.orgId, {
416
+ id: scope.orgUserId,
417
+ role: scope.role
418
+ }, req.params.chatId, req.params.communityId);
419
+ }
420
+ });
421
+ }
422
+ //#endregion
423
+ export { communityModerationRoutes };
424
+
425
+ //# sourceMappingURL=community-moderation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"community-moderation.js","names":[],"sources":["../../../src/http/routes/community-moderation.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport type { Container } from '../../app/container.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport { resolveScope } from '../scope.js';\nimport {\n Chat,\n CommentView,\n CommunityChatParam,\n CommunityCommentParam,\n CommunityIdParam,\n CommunityMembersPage,\n CommunityMembersQuery,\n CommunityMessageParam,\n CommunityPostParam,\n CommunitySpaceParam,\n OrgUserBody,\n PageQuery,\n PostView,\n ResolveCommentFlags,\n ResolveMessageFlags,\n ResolvePostFlags,\n SpaceMember,\n SpaceMemberParam,\n SpaceMembersPage,\n SpaceQueue,\n refusals,\n} from '../schemas/index.js';\n\nexport async function communityModerationRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const tags = ['Communities'];\n\n r.route({\n method: 'GET',\n url: '/api/communities/:communityId/members',\n schema: {\n operationId: 'listCommunityMembers',\n tags,\n summary: 'List the people who hold a community (staff)',\n description:\n 'Staff only (owner, admin, instructor). Everyone with active access to the community, granted directly or through a bundle, paged and searched by name or email.',\n params: CommunityIdParam,\n querystring: CommunityMembersQuery,\n response: { 200: CommunityMembersPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const page = await container.reporting.admin.communityMembers(\n scope.orgId,\n req.params.communityId,\n req.query,\n );\n if (!page) {\n throw new NotFoundError('Community', req.params.communityId);\n }\n return page;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/communities/:communityId/spaces/:spaceId/members',\n schema: {\n operationId: 'listCommunitySpaceMembers',\n tags,\n summary: 'List the members, requests and invitations of a space (staff)',\n description:\n \"Staff only (owner, admin, instructor). The space's members, its open requests to join and its open invitations.\",\n params: CommunitySpaceParam,\n querystring: PageQuery,\n response: { 200: SpaceMembersPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.entitlements.listSpaceMembers(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.query,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/spaces/:spaceId/members',\n schema: {\n operationId: 'addCommunitySpaceMember',\n tags,\n summary: 'Add a person to a space (staff)',\n description:\n 'Staff only (owner, admin, instructor). Places a member of the community straight into the space, with no request or invitation. 409 when the space is open to all members, the person is already placed, or the space is full.',\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const member = await container.entitlements.addSpaceMember(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/spaces/:spaceId/invites',\n schema: {\n operationId: 'inviteCommunitySpaceMember',\n tags,\n summary: 'Invite a person into a space (staff)',\n description:\n 'Staff only (owner, admin, instructor). Invites a member of the community into a `by_invite` space; they join when they accept. 403 when the person is staff or does not hold the community; 409 when the space is not invite-only or the person is already placed.',\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const member = await container.entitlements.invite(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/approval',\n schema: {\n operationId: 'approveCommunitySpaceRequest',\n tags,\n summary: \"Approve a person's request to join a space (staff)\",\n description:\n 'Staff only (owner, admin, instructor). Makes the requester an active member. 404 when the person has no open request; 409 when the space is full or they are already a member.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.entitlements.approve(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/decline',\n schema: {\n operationId: 'declineCommunitySpaceRequest',\n tags,\n summary: \"Decline a person's request to join a space (staff)\",\n description:\n 'Staff only (owner, admin, instructor). Closes the open request. 404 when the person has no open request; 409 when they are already a member.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.entitlements.decline(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/spaces/:spaceId/members/:orgUserId/removal',\n schema: {\n operationId: 'removeCommunitySpaceMember',\n tags,\n summary: 'Remove a person from a space (staff)',\n description:\n 'Staff only (owner, admin, instructor). Revokes the placement, whether it is a membership, a request or an invitation. 409 when the space is open to all members or the placement is already revoked.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.entitlements.remove(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/communities/:communityId/spaces/:spaceId/queue',\n schema: {\n operationId: 'getCommunitySpaceQueue',\n tags,\n summary: 'The moderation queue of a space (staff)',\n description:\n 'Staff only (owner, admin, instructor). Posts awaiting review, and the open flags on posts and on comments in the space. Each list holds at most the 100 oldest entries: pending posts by creation, flags by when they were raised; working the queue brings in the next ones.',\n params: CommunitySpaceParam,\n response: { 200: SpaceQueue, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.posts.moderationQueue(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n req.params.spaceId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/posts/:postId/approval',\n schema: {\n operationId: 'approveCommunityPost',\n tags,\n summary: 'Publish a post that is awaiting review (staff)',\n description:\n 'Staff only (owner, admin, instructor). 409 when the post is not awaiting review.',\n params: CommunityPostParam,\n response: { 200: PostView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.posts.approve(\n scope.orgId,\n req.params.postId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/posts/:postId/removal',\n schema: {\n operationId: 'removeCommunityPost',\n tags,\n summary: 'Remove a post (staff)',\n description:\n 'Staff only (owner, admin, instructor). Takes a published or pending post down and resolves its open flags as `removed`. 409 when it is already removed or was never submitted.',\n params: CommunityPostParam,\n response: { 200: PostView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.posts.remove(\n scope.orgId,\n req.params.postId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/posts/:postId/restoration',\n schema: {\n operationId: 'restoreCommunityPost',\n tags,\n summary: 'Restore a removed post (staff)',\n description: 'Staff only (owner, admin, instructor). 409 when the post is not removed.',\n params: CommunityPostParam,\n response: { 200: PostView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.posts.restore(\n scope.orgId,\n req.params.postId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/posts/:postId/flags/resolution',\n schema: {\n operationId: 'resolveCommunityPostFlags',\n tags,\n summary: 'Dismiss the open flags on a post (staff)',\n description:\n 'Staff only (owner, admin, instructor). Closes every open flag on the post and leaves it up.',\n params: CommunityPostParam,\n body: ResolvePostFlags,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await container.posts.resolveFlags(\n scope.orgId,\n req.params.postId,\n { id: scope.orgUserId, role: scope.role },\n req.body.resolution,\n req.params.communityId,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/comments/:commentId/removal',\n schema: {\n operationId: 'removeCommunityComment',\n tags,\n summary: 'Remove a comment on a post (staff)',\n description:\n 'Staff only (owner, admin, instructor). Hides the comment and resolves its open flags as `removed`. Removing a removed comment returns it unchanged.',\n params: CommunityCommentParam,\n response: { 200: CommentView, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.discussion.remove(\n scope.orgId,\n req.params.commentId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/comments/:commentId/restoration',\n schema: {\n operationId: 'restoreCommunityComment',\n tags,\n summary: 'Restore a removed comment on a post (staff)',\n description:\n 'Staff only (owner, admin, instructor). Publishes the comment again. Restoring a comment that is not removed returns it unchanged.',\n params: CommunityCommentParam,\n response: { 200: CommentView, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.discussion.restore(\n scope.orgId,\n req.params.commentId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/comments/:commentId/flags/resolution',\n schema: {\n operationId: 'resolveCommunityCommentFlags',\n tags,\n summary: 'Dismiss the open flags on a comment (staff)',\n description:\n 'Staff only (owner, admin, instructor). Closes every open flag on the comment and leaves it up.',\n params: CommunityCommentParam,\n body: ResolveCommentFlags,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await container.discussion.resolveReports(\n scope.orgId,\n req.params.commentId,\n { id: scope.orgUserId, role: scope.role },\n req.params.communityId,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/messages/:messageId/flags/resolution',\n schema: {\n operationId: 'resolveCommunityMessageFlags',\n tags,\n summary: 'Dismiss the open flags on a message (staff)',\n description:\n 'Staff only (owner, admin, instructor). Closes every open flag on the message and leaves it up.',\n params: CommunityMessageParam,\n body: ResolveMessageFlags,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await container.chats.resolveMessageFlags(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.messageId,\n req.body.resolution,\n req.params.communityId,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/chats/:chatId/lock',\n schema: {\n operationId: 'lockCommunityChat',\n tags,\n summary: 'Lock a chat (staff)',\n description:\n 'Staff only (owner, admin, instructor). Nobody can send or edit messages until it is unlocked; its open message flags are resolved as `locked`. Locking a locked chat returns it unchanged.',\n params: CommunityChatParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.chats.lock(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.chatId,\n req.params.communityId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/communities/:communityId/chats/:chatId/unlock',\n schema: {\n operationId: 'unlockCommunityChat',\n tags,\n summary: 'Unlock a chat (staff)',\n description:\n 'Staff only (owner, admin, instructor). Lets participants send messages again. Unlocking an unlocked chat returns it unchanged.',\n params: CommunityChatParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.chats.unlock(\n scope.orgId,\n { id: scope.orgUserId, role: scope.role },\n req.params.chatId,\n req.params.communityId,\n );\n },\n });\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
+ import { refusals } from "../schemas/shared.js";
1
2
  import { resolveScope } from "../scope.js";
2
- import { ErrorBody } from "../schemas/shared.js";
3
3
  import { CourseIdParam } from "../schemas/content.js";
4
4
  import { EnrollmentSeries, EnrollmentSeriesQuery } from "../schemas/dashboard.js";
5
5
  import { CourseAnalytics } from "../schemas/course-analytics.js";
@@ -15,16 +15,17 @@ async function courseAnalyticsRoutes(app, container) {
15
15
  schema: {
16
16
  operationId: "getCourseAnalytics",
17
17
  tags: ["Reporting"],
18
- summary: "Completion and engagement stats for a course",
18
+ summary: "Completion and engagement stats for a course (staff)",
19
+ description: "Staff only (owner, admin, instructor).",
19
20
  params: CourseIdParam,
20
21
  response: {
21
22
  200: CourseAnalytics,
22
- 404: ErrorBody
23
+ ...refusals(403, 404)
23
24
  }
24
25
  },
25
26
  handler: async (req) => {
26
27
  const scope = await resolveScope(container, req);
27
- const analytics = await container.reporting.courses.analytics(scope.orgId, req.params.id);
28
+ const analytics = await container.reporting.admin.courseAnalytics(scope.orgId, req.params.id);
28
29
  if (!analytics) throw new NotFoundError("Course", req.params.id);
29
30
  return analytics;
30
31
  }
@@ -36,17 +37,18 @@ async function courseAnalyticsRoutes(app, container) {
36
37
  schema: {
37
38
  operationId: "getCourseEnrollmentSeries",
38
39
  tags: ["Reporting"],
39
- summary: "Enrollments granted per day for a course over a trailing window",
40
+ summary: "Enrollments granted per day for a course over a trailing window (staff)",
41
+ description: "Staff only (owner, admin, instructor).",
40
42
  params: CourseIdParam,
41
43
  querystring: EnrollmentSeriesQuery,
42
44
  response: {
43
45
  200: EnrollmentSeries,
44
- 404: ErrorBody
46
+ ...refusals(403, 404)
45
47
  }
46
48
  },
47
49
  handler: async (req) => {
48
50
  const scope = await resolveScope(container, req);
49
- const series = await container.reporting.courses.enrollments(scope.orgId, req.params.id, req.query.days);
51
+ const series = await container.reporting.admin.courseEnrollments(scope.orgId, req.params.id, req.query.days);
50
52
  if (!series) throw new NotFoundError("Course", req.params.id);
51
53
  return series;
52
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"course-analytics.js","names":[],"sources":["../../../src/http/routes/course-analytics.ts"],"sourcesContent":["// HTTP routes for per-course analytics (reporting).\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n CourseAnalytics,\n CourseIdParam,\n EnrollmentSeries,\n EnrollmentSeriesQuery,\n ErrorBody,\n} from '../schemas/index.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function courseAnalyticsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n\n r.route({\n method: 'GET',\n url: '/api/courses/:id/analytics',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getCourseAnalytics',\n tags: ['Reporting'],\n summary: 'Completion and engagement stats for a course',\n params: CourseIdParam,\n response: { 200: CourseAnalytics, 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const analytics = await container.reporting.courses.analytics(scope.orgId, req.params.id);\n if (!analytics) {\n throw new NotFoundError('Course', req.params.id);\n }\n return analytics;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:id/analytics/enrollments',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getCourseEnrollmentSeries',\n tags: ['Reporting'],\n summary: 'Enrollments granted per day for a course over a trailing window',\n params: CourseIdParam,\n querystring: EnrollmentSeriesQuery,\n response: { 200: EnrollmentSeries, 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const series = await container.reporting.courses.enrollments(\n scope.orgId,\n req.params.id,\n req.query.days,\n );\n if (!series) {\n throw new NotFoundError('Course', req.params.id);\n }\n return series;\n },\n });\n}\n"],"mappings":";;;;;;;;AAcA,eAAsB,sBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAEhD,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,QAAQ;GACR,UAAU;IAAE,KAAK;IAAiB,KAAK;GAAU;EACnD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,YAAY,MAAM,UAAU,UAAU,QAAQ,UAAU,MAAM,OAAO,IAAI,OAAO,EAAE;GACxF,IAAI,CAAC,WACH,MAAM,IAAI,cAAc,UAAU,IAAI,OAAO,EAAE;GAEjD,OAAO;EACT;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,QAAQ;GACR,aAAa;GACb,UAAU;IAAE,KAAK;IAAkB,KAAK;GAAU;EACpD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,SAAS,MAAM,UAAU,UAAU,QAAQ,YAC/C,MAAM,OACN,IAAI,OAAO,IACX,IAAI,MAAM,IACZ;GACA,IAAI,CAAC,QACH,MAAM,IAAI,cAAc,UAAU,IAAI,OAAO,EAAE;GAEjD,OAAO;EACT;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"course-analytics.js","names":[],"sources":["../../../src/http/routes/course-analytics.ts"],"sourcesContent":["// HTTP routes for per-course analytics (reporting).\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n CourseAnalytics,\n CourseIdParam,\n EnrollmentSeries,\n EnrollmentSeriesQuery,\n refusals,\n} from '../schemas/index.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function courseAnalyticsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n\n r.route({\n method: 'GET',\n url: '/api/courses/:id/analytics',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getCourseAnalytics',\n tags: ['Reporting'],\n summary: 'Completion and engagement stats for a course (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: CourseIdParam,\n response: { 200: CourseAnalytics, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const analytics = await container.reporting.admin.courseAnalytics(scope.orgId, req.params.id);\n if (!analytics) {\n throw new NotFoundError('Course', req.params.id);\n }\n return analytics;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:id/analytics/enrollments',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getCourseEnrollmentSeries',\n tags: ['Reporting'],\n summary: 'Enrollments granted per day for a course over a trailing window (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: CourseIdParam,\n querystring: EnrollmentSeriesQuery,\n response: { 200: EnrollmentSeries, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const series = await container.reporting.admin.courseEnrollments(\n scope.orgId,\n req.params.id,\n req.query.days,\n );\n if (!series) {\n throw new NotFoundError('Course', req.params.id);\n }\n return series;\n },\n });\n}\n"],"mappings":";;;;;;;;AAcA,eAAsB,sBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAEhD,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,aAAa;GACb,QAAQ;GACR,UAAU;IAAE,KAAK;IAAiB,GAAG,SAAS,KAAK,GAAG;GAAE;EAC1D;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,YAAY,MAAM,UAAU,UAAU,MAAM,gBAAgB,MAAM,OAAO,IAAI,OAAO,EAAE;GAC5F,IAAI,CAAC,WACH,MAAM,IAAI,cAAc,UAAU,IAAI,OAAO,EAAE;GAEjD,OAAO;EACT;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,aAAa;GACb,QAAQ;GACR,aAAa;GACb,UAAU;IAAE,KAAK;IAAkB,GAAG,SAAS,KAAK,GAAG;GAAE;EAC3D;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,SAAS,MAAM,UAAU,UAAU,MAAM,kBAC7C,MAAM,OACN,IAAI,OAAO,IACX,IAAI,MAAM,IACZ;GACA,IAAI,CAAC,QACH,MAAM,IAAI,cAAc,UAAU,IAAI,OAAO,EAAE;GAEjD,OAAO;EACT;CACF,CAAC;AACH"}
@@ -1,9 +1,9 @@
1
+ import { refusals } from "../schemas/shared.js";
1
2
  import { resolveScope } from "../scope.js";
2
- import { ErrorBody } from "../schemas/shared.js";
3
3
  import { Course, CourseIdParam, CourseSettings, CoursesPage, CoursesQuery, CreateCourse, PatchCourseSettings, UpdateCourse } from "../schemas/content.js";
4
4
  import "../schemas/index.js";
5
- import { NotFoundError } from "@headless-lms/core/shared/errors";
6
5
  import { z } from "zod";
6
+ import { NotFoundError } from "@headless-lms/core/shared/errors";
7
7
  //#region src/http/routes/courses.ts
8
8
  async function coursesRoutes(app, container) {
9
9
  const r = app.withTypeProvider();
@@ -15,9 +15,13 @@ async function coursesRoutes(app, container) {
15
15
  schema: {
16
16
  operationId: "listCourses",
17
17
  tags: ["Content"],
18
- summary: "List courses",
18
+ summary: "List courses (staff)",
19
+ description: "Staff only (owner, admin, instructor). Every course in the organization, drafts included, filtered by status and category and searched by title.",
19
20
  querystring: CoursesQuery,
20
- response: { 200: CoursesPage }
21
+ response: {
22
+ 200: CoursesPage,
23
+ ...refusals(403)
24
+ }
21
25
  },
22
26
  handler: async (req) => {
23
27
  const scope = await resolveScope(container, req);
@@ -31,11 +35,12 @@ async function coursesRoutes(app, container) {
31
35
  schema: {
32
36
  operationId: "getCourse",
33
37
  tags: ["Content"],
34
- summary: "Get a course by id",
38
+ summary: "Get a course (staff)",
39
+ description: "Staff only (owner, admin, instructor).",
35
40
  params: CourseIdParam,
36
41
  response: {
37
42
  200: Course,
38
- 404: ErrorBody
43
+ ...refusals(403, 404)
39
44
  }
40
45
  },
41
46
  handler: async (req) => {
@@ -52,9 +57,13 @@ async function coursesRoutes(app, container) {
52
57
  schema: {
53
58
  operationId: "createCourse",
54
59
  tags: ["Content"],
55
- summary: "Create a course",
60
+ summary: "Create a course (staff)",
61
+ description: "Staff only (owner, admin, instructor). The course starts as a draft. 409 when its slug is taken.",
56
62
  body: CreateCourse,
57
- response: { 201: Course }
63
+ response: {
64
+ 201: Course,
65
+ ...refusals(403, 409)
66
+ }
58
67
  },
59
68
  handler: async (req, reply) => {
60
69
  const scope = await resolveScope(container, req);
@@ -69,12 +78,13 @@ async function coursesRoutes(app, container) {
69
78
  schema: {
70
79
  operationId: "updateCourse",
71
80
  tags: ["Content"],
72
- summary: "Update a course",
81
+ summary: "Update a course (staff)",
82
+ description: "Staff only (owner, admin, instructor). Changes only the fields sent. `thumbnailAssetId` must be a ready library image (409 otherwise); null clears it.",
73
83
  params: CourseIdParam,
74
84
  body: UpdateCourse,
75
85
  response: {
76
86
  200: Course,
77
- 404: ErrorBody
87
+ ...refusals(403, 404, 409)
78
88
  }
79
89
  },
80
90
  handler: async (req) => {
@@ -89,12 +99,13 @@ async function coursesRoutes(app, container) {
89
99
  schema: {
90
100
  operationId: "updateCourseSettings",
91
101
  tags: ["Content"],
92
- summary: "Update a course settings",
102
+ summary: "Update a course's settings (staff)",
103
+ description: "Staff only (owner, admin, instructor). Merges the settings sent into the current ones.",
93
104
  params: CourseIdParam,
94
105
  body: PatchCourseSettings,
95
106
  response: {
96
107
  200: CourseSettings,
97
- 404: ErrorBody
108
+ ...refusals(403, 404)
98
109
  }
99
110
  },
100
111
  handler: async (req) => {
@@ -110,16 +121,20 @@ async function coursesRoutes(app, container) {
110
121
  schema: {
111
122
  operationId: "deleteCourse",
112
123
  tags: ["Content"],
113
- summary: "Delete a course",
124
+ summary: "Delete a course (staff)",
125
+ description: "Staff only (owner, admin, instructor).",
114
126
  params: CourseIdParam,
115
127
  response: {
116
128
  204: z.void(),
117
- 404: ErrorBody
129
+ ...refusals(403, 404)
118
130
  }
119
131
  },
120
132
  handler: async (req, reply) => {
121
133
  const scope = await resolveScope(container, req);
122
- await courses.deleteCourse(scope.orgId, req.params.id);
134
+ await courses.deleteCourse(scope.orgId, req.params.id, {
135
+ id: scope.orgUserId,
136
+ role: scope.role
137
+ });
123
138
  return reply.code(204).send();
124
139
  }
125
140
  });