@headless-lms/server 0.2.0 → 0.3.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 (339) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +5 -0
  2. package/dist/app/community-mail.d.ts +26 -0
  3. package/dist/app/community-mail.js +96 -0
  4. package/dist/app/community-mail.js.map +1 -0
  5. package/dist/app/container.d.ts +18 -14
  6. package/dist/app/container.js +136 -43
  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/http/config.d.ts +2 -1
  12. package/dist/http/errors.d.ts +14 -0
  13. package/dist/http/errors.js +147 -0
  14. package/dist/http/errors.js.map +1 -0
  15. package/dist/http/mcp/catalogue.d.ts +37 -0
  16. package/dist/http/mcp/catalogue.js +69 -0
  17. package/dist/http/mcp/catalogue.js.map +1 -0
  18. package/dist/http/mcp/challenge.d.ts +7 -0
  19. package/dist/http/mcp/challenge.js +35 -0
  20. package/dist/http/mcp/challenge.js.map +1 -0
  21. package/dist/http/mcp/input-schema.d.ts +7 -0
  22. package/dist/http/mcp/input-schema.js +28 -0
  23. package/dist/http/mcp/input-schema.js.map +1 -0
  24. package/dist/http/mcp/route.d.ts +8 -0
  25. package/dist/http/mcp/route.js +75 -0
  26. package/dist/http/mcp/route.js.map +1 -0
  27. package/dist/http/mcp/server.d.ts +8 -0
  28. package/dist/http/mcp/server.js +31 -0
  29. package/dist/http/mcp/server.js.map +1 -0
  30. package/dist/http/mcp/test-support.d.ts +55 -0
  31. package/dist/http/mcp/test-support.js +151 -0
  32. package/dist/http/mcp/test-support.js.map +1 -0
  33. package/dist/http/mcp/tool.d.ts +48 -0
  34. package/dist/http/mcp/tool.js +58 -0
  35. package/dist/http/mcp/tool.js.map +1 -0
  36. package/dist/http/mcp/tools/automations.d.ts +6 -0
  37. package/dist/http/mcp/tools/automations.js +120 -0
  38. package/dist/http/mcp/tools/automations.js.map +1 -0
  39. package/dist/http/mcp/tools/catalog.d.ts +6 -0
  40. package/dist/http/mcp/tools/catalog.js +200 -0
  41. package/dist/http/mcp/tools/catalog.js.map +1 -0
  42. package/dist/http/mcp/tools/comments.d.ts +6 -0
  43. package/dist/http/mcp/tools/comments.js +70 -0
  44. package/dist/http/mcp/tools/comments.js.map +1 -0
  45. package/dist/http/mcp/tools/communities.d.ts +6 -0
  46. package/dist/http/mcp/tools/communities.js +175 -0
  47. package/dist/http/mcp/tools/communities.js.map +1 -0
  48. package/dist/http/mcp/tools/community-members.d.ts +6 -0
  49. package/dist/http/mcp/tools/community-members.js +89 -0
  50. package/dist/http/mcp/tools/community-members.js.map +1 -0
  51. package/dist/http/mcp/tools/community-moderation.d.ts +6 -0
  52. package/dist/http/mcp/tools/community-moderation.js +144 -0
  53. package/dist/http/mcp/tools/community-moderation.js.map +1 -0
  54. package/dist/http/mcp/tools/courses.d.ts +6 -0
  55. package/dist/http/mcp/tools/courses.js +121 -0
  56. package/dist/http/mcp/tools/courses.js.map +1 -0
  57. package/dist/http/mcp/tools/index.d.ts +6 -0
  58. package/dist/http/mcp/tools/index.js +23 -0
  59. package/dist/http/mcp/tools/index.js.map +1 -0
  60. package/dist/http/mcp/tools/people.d.ts +6 -0
  61. package/dist/http/mcp/tools/people.js +145 -0
  62. package/dist/http/mcp/tools/people.js.map +1 -0
  63. package/dist/http/plugins/auth.js +13 -5
  64. package/dist/http/plugins/auth.js.map +1 -1
  65. package/dist/http/plugins/error-handler.d.ts +2 -1
  66. package/dist/http/plugins/error-handler.js +49 -65
  67. package/dist/http/plugins/error-handler.js.map +1 -1
  68. package/dist/http/plugins/openapi.js +49 -2
  69. package/dist/http/plugins/openapi.js.map +1 -1
  70. package/dist/http/routes/access.d.ts +7 -0
  71. package/dist/http/routes/access.js +140 -0
  72. package/dist/http/routes/access.js.map +1 -0
  73. package/dist/http/routes/activities.js +68 -23
  74. package/dist/http/routes/activities.js.map +1 -1
  75. package/dist/http/routes/assets.js +60 -55
  76. package/dist/http/routes/assets.js.map +1 -1
  77. package/dist/http/routes/automations.js +44 -24
  78. package/dist/http/routes/automations.js.map +1 -1
  79. package/dist/http/routes/bundles.js +29 -18
  80. package/dist/http/routes/bundles.js.map +1 -1
  81. package/dist/http/routes/communities.d.ts +7 -0
  82. package/dist/http/routes/communities.js +462 -0
  83. package/dist/http/routes/communities.js.map +1 -0
  84. package/dist/http/routes/community-moderation.d.ts +7 -0
  85. package/dist/http/routes/community-moderation.js +425 -0
  86. package/dist/http/routes/community-moderation.js.map +1 -0
  87. package/dist/http/routes/course-analytics.js +9 -7
  88. package/dist/http/routes/course-analytics.js.map +1 -1
  89. package/dist/http/routes/courses.js +30 -15
  90. package/dist/http/routes/courses.js.map +1 -1
  91. package/dist/http/routes/dashboard.js +15 -6
  92. package/dist/http/routes/dashboard.js.map +1 -1
  93. package/dist/http/routes/discussion.js +34 -26
  94. package/dist/http/routes/discussion.js.map +1 -1
  95. package/dist/http/routes/downloads.js +48 -30
  96. package/dist/http/routes/downloads.js.map +1 -1
  97. package/dist/http/routes/entitlements.js +16 -7
  98. package/dist/http/routes/entitlements.js.map +1 -1
  99. package/dist/http/routes/integrations.js +38 -41
  100. package/dist/http/routes/integrations.js.map +1 -1
  101. package/dist/http/routes/member/actor.d.ts +14 -0
  102. package/dist/http/routes/member/actor.js +11 -0
  103. package/dist/http/routes/member/actor.js.map +1 -0
  104. package/dist/http/routes/member/assets.d.ts +7 -0
  105. package/dist/http/routes/member/assets.js +79 -0
  106. package/dist/http/routes/member/assets.js.map +1 -0
  107. package/dist/http/routes/member/chats.d.ts +7 -0
  108. package/dist/http/routes/member/chats.js +456 -0
  109. package/dist/http/routes/member/chats.js.map +1 -0
  110. package/dist/http/routes/member/comments.d.ts +7 -0
  111. package/dist/http/routes/member/comments.js +187 -0
  112. package/dist/http/routes/member/comments.js.map +1 -0
  113. package/dist/http/routes/member/community.d.ts +7 -0
  114. package/dist/http/routes/member/community.js +288 -0
  115. package/dist/http/routes/member/community.js.map +1 -0
  116. package/dist/http/routes/member/courses.d.ts +7 -0
  117. package/dist/http/routes/member/courses.js +101 -0
  118. package/dist/http/routes/member/courses.js.map +1 -0
  119. package/dist/http/routes/member/downloads.d.ts +7 -0
  120. package/dist/http/routes/member/downloads.js +56 -0
  121. package/dist/http/routes/member/downloads.js.map +1 -0
  122. package/dist/http/routes/member/files.d.ts +7 -0
  123. package/dist/http/routes/member/files.js +184 -0
  124. package/dist/http/routes/member/files.js.map +1 -0
  125. package/dist/http/routes/member/index.d.ts +7 -0
  126. package/dist/http/routes/member/index.js +31 -0
  127. package/dist/http/routes/member/index.js.map +1 -0
  128. package/dist/http/routes/member/notifications.d.ts +7 -0
  129. package/dist/http/routes/member/notifications.js +101 -0
  130. package/dist/http/routes/member/notifications.js.map +1 -0
  131. package/dist/http/routes/member/org.d.ts +7 -0
  132. package/dist/http/routes/member/org.js +56 -0
  133. package/dist/http/routes/member/org.js.map +1 -0
  134. package/dist/http/routes/member/posts.d.ts +7 -0
  135. package/dist/http/routes/member/posts.js +612 -0
  136. package/dist/http/routes/member/posts.js.map +1 -0
  137. package/dist/http/routes/member/profile.d.ts +7 -0
  138. package/dist/http/routes/member/profile.js +48 -0
  139. package/dist/http/routes/member/profile.js.map +1 -0
  140. package/dist/http/routes/member/progress.d.ts +7 -0
  141. package/dist/http/routes/member/progress.js +60 -0
  142. package/dist/http/routes/member/progress.js.map +1 -0
  143. package/dist/http/routes/organizations.js +49 -24
  144. package/dist/http/routes/organizations.js.map +1 -1
  145. package/dist/http/routes/students.js +32 -47
  146. package/dist/http/routes/students.js.map +1 -1
  147. package/dist/http/routes/webhooks.js +26 -18
  148. package/dist/http/routes/webhooks.js.map +1 -1
  149. package/dist/http/routes.js +8 -2
  150. package/dist/http/routes.js.map +1 -1
  151. package/dist/http/schemas/access.d.ts +146 -0
  152. package/dist/http/schemas/access.js +36 -0
  153. package/dist/http/schemas/access.js.map +1 -0
  154. package/dist/http/schemas/activities.d.ts +3 -1
  155. package/dist/http/schemas/activities.js +4 -4
  156. package/dist/http/schemas/activities.js.map +1 -1
  157. package/dist/http/schemas/assets.d.ts +73 -74
  158. package/dist/http/schemas/assets.js +23 -13
  159. package/dist/http/schemas/assets.js.map +1 -1
  160. package/dist/http/schemas/automations.d.ts +10 -0
  161. package/dist/http/schemas/bundles.js +6 -6
  162. package/dist/http/schemas/bundles.js.map +1 -1
  163. package/dist/http/schemas/chats.d.ts +386 -0
  164. package/dist/http/schemas/chats.js +58 -0
  165. package/dist/http/schemas/chats.js.map +1 -0
  166. package/dist/http/schemas/community.d.ts +537 -0
  167. package/dist/http/schemas/community.js +129 -0
  168. package/dist/http/schemas/community.js.map +1 -0
  169. package/dist/http/schemas/content.d.ts +4 -2
  170. package/dist/http/schemas/content.js +11 -8
  171. package/dist/http/schemas/content.js.map +1 -1
  172. package/dist/http/schemas/discussion.d.ts +76 -14
  173. package/dist/http/schemas/discussion.js +12 -11
  174. package/dist/http/schemas/discussion.js.map +1 -1
  175. package/dist/http/schemas/downloads.d.ts +11 -5
  176. package/dist/http/schemas/downloads.js +14 -11
  177. package/dist/http/schemas/downloads.js.map +1 -1
  178. package/dist/http/schemas/entitlements.d.ts +6 -6
  179. package/dist/http/schemas/entitlements.js +6 -6
  180. package/dist/http/schemas/entitlements.js.map +1 -1
  181. package/dist/http/schemas/files.d.ts +45 -0
  182. package/dist/http/schemas/files.js +25 -0
  183. package/dist/http/schemas/files.js.map +1 -0
  184. package/dist/http/schemas/index.d.ts +15 -8
  185. package/dist/http/schemas/index.js +15 -8
  186. package/dist/http/schemas/integrations.d.ts +2 -2
  187. package/dist/http/schemas/invites.d.ts +4 -0
  188. package/dist/http/schemas/invites.js +1 -0
  189. package/dist/http/schemas/invites.js.map +1 -1
  190. package/dist/http/schemas/{learn.d.ts → member.d.ts} +31 -18
  191. package/dist/http/schemas/{learn.js → member.js} +17 -13
  192. package/dist/http/schemas/member.js.map +1 -0
  193. package/dist/http/schemas/members.d.ts +39 -6
  194. package/dist/http/schemas/members.js +17 -3
  195. package/dist/http/schemas/members.js.map +1 -1
  196. package/dist/http/schemas/notifications.d.ts +227 -0
  197. package/dist/http/schemas/notifications.js +44 -0
  198. package/dist/http/schemas/notifications.js.map +1 -0
  199. package/dist/http/schemas/posts.d.ts +316 -0
  200. package/dist/http/schemas/posts.js +47 -0
  201. package/dist/http/schemas/posts.js.map +1 -0
  202. package/dist/http/schemas/profile.d.ts +23 -0
  203. package/dist/http/schemas/profile.js +15 -0
  204. package/dist/http/schemas/profile.js.map +1 -0
  205. package/dist/http/schemas/shared.d.ts +25 -1
  206. package/dist/http/schemas/shared.js +19 -2
  207. package/dist/http/schemas/shared.js.map +1 -1
  208. package/dist/http/schemas/students.d.ts +4 -10
  209. package/dist/http/schemas/students.js +1 -7
  210. package/dist/http/schemas/students.js.map +1 -1
  211. package/dist/http/scope.d.ts +2 -1
  212. package/dist/http/scope.js +20 -4
  213. package/dist/http/scope.js.map +1 -1
  214. package/dist/http/server.js +6 -1
  215. package/dist/http/server.js.map +1 -1
  216. package/dist/http/web-bridge.d.ts +1 -1
  217. package/dist/http/web-bridge.js +2 -2
  218. package/dist/http/web-bridge.js.map +1 -1
  219. package/dist/http/well-known.d.ts +7 -0
  220. package/dist/http/well-known.js +22 -0
  221. package/dist/http/well-known.js.map +1 -0
  222. package/dist/index.d.ts +2 -1
  223. package/dist/index.js +4 -2
  224. package/dist/index.js.map +1 -1
  225. package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +78 -0
  226. package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js.map +1 -0
  227. package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js +1267 -0
  228. package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js.map +1 -0
  229. package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js +814 -0
  230. package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js.map +1 -0
  231. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js +43 -0
  232. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js.map +1 -0
  233. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js +527 -0
  234. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js.map +1 -0
  235. package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/utils.js +2 -0
  236. package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js +1737 -0
  237. package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js.map +1 -0
  238. package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js +137 -0
  239. package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js.map +1 -0
  240. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js +118 -0
  241. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js.map +1 -0
  242. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js +1222 -0
  243. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js.map +1 -0
  244. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js +91 -0
  245. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js.map +1 -0
  246. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js +113 -0
  247. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js.map +1 -0
  248. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js +449 -0
  249. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js.map +1 -0
  250. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js +163 -0
  251. package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js.map +1 -0
  252. package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js +3187 -0
  253. package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js.map +1 -0
  254. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js +11 -0
  255. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js.map +1 -0
  256. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js +16 -0
  257. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js.map +1 -0
  258. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js +11 -0
  259. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js.map +1 -0
  260. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js +15 -0
  261. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js.map +1 -0
  262. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js +13 -0
  263. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js.map +1 -0
  264. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js +34 -0
  265. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js.map +1 -0
  266. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js +12 -0
  267. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js.map +1 -0
  268. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js +122 -0
  269. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js.map +1 -0
  270. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js +39 -0
  271. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js.map +1 -0
  272. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js +99 -0
  273. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js.map +1 -0
  274. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js +25 -0
  275. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js.map +1 -0
  276. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js +14 -0
  277. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js.map +1 -0
  278. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js +21 -0
  279. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js.map +1 -0
  280. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js +6 -0
  281. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js.map +1 -0
  282. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js +12 -0
  283. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js.map +1 -0
  284. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js +18 -0
  285. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js.map +1 -0
  286. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js +24 -0
  287. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js.map +1 -0
  288. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js +9 -0
  289. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js.map +1 -0
  290. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js +30 -0
  291. package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js.map +1 -0
  292. package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +939 -0
  293. package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js.map +1 -0
  294. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js +82 -0
  295. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js.map +1 -0
  296. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js +82 -0
  297. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js.map +1 -0
  298. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js +8 -0
  299. package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js.map +1 -0
  300. package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js +83 -0
  301. package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js.map +1 -0
  302. 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
  303. 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
  304. 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
  305. 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
  306. 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
  307. 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
  308. 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
  309. 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
  310. package/dist/packages/server/package.js +6 -0
  311. package/dist/packages/server/package.js.map +1 -0
  312. package/package.json +9 -7
  313. package/dist/app/notifications.d.ts +0 -7
  314. package/dist/app/notifications.js +0 -26
  315. package/dist/app/notifications.js.map +0 -1
  316. package/dist/http/routes/learn/assets.d.ts +0 -8
  317. package/dist/http/routes/learn/assets.js +0 -32
  318. package/dist/http/routes/learn/assets.js.map +0 -1
  319. package/dist/http/routes/learn/comments.d.ts +0 -7
  320. package/dist/http/routes/learn/comments.js +0 -175
  321. package/dist/http/routes/learn/comments.js.map +0 -1
  322. package/dist/http/routes/learn/courses.d.ts +0 -7
  323. package/dist/http/routes/learn/courses.js +0 -98
  324. package/dist/http/routes/learn/courses.js.map +0 -1
  325. package/dist/http/routes/learn/downloads.d.ts +0 -7
  326. package/dist/http/routes/learn/downloads.js +0 -76
  327. package/dist/http/routes/learn/downloads.js.map +0 -1
  328. package/dist/http/routes/learn/index.d.ts +0 -7
  329. package/dist/http/routes/learn/index.js +0 -19
  330. package/dist/http/routes/learn/index.js.map +0 -1
  331. package/dist/http/routes/learn/org.d.ts +0 -7
  332. package/dist/http/routes/learn/org.js +0 -50
  333. package/dist/http/routes/learn/org.js.map +0 -1
  334. package/dist/http/routes/learn/progress.d.ts +0 -7
  335. package/dist/http/routes/learn/progress.js +0 -63
  336. package/dist/http/routes/learn/progress.js.map +0 -1
  337. package/dist/http/schemas/learn.js.map +0 -1
  338. package/dist/package.js +0 -6
  339. package/dist/package.js.map +0 -1
@@ -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 { AddBundleItem, Bundle, BundleIdParam, BundleItem, BundleItemParams, BundlesPage, BundlesQuery, CreateBundle, UpdateBundle } from "../schemas/bundles.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/bundles.ts
8
8
  async function bundlesRoutes(app, container) {
9
9
  const r = app.withTypeProvider();
@@ -15,9 +15,13 @@ async function bundlesRoutes(app, container) {
15
15
  schema: {
16
16
  operationId: "listBundles",
17
17
  tags: ["Content"],
18
- summary: "List bundles",
18
+ summary: "List bundles (staff)",
19
+ description: "Staff only (owner, admin, instructor).",
19
20
  querystring: BundlesQuery,
20
- response: { 200: BundlesPage }
21
+ response: {
22
+ 200: BundlesPage,
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 bundlesRoutes(app, container) {
31
35
  schema: {
32
36
  operationId: "getBundle",
33
37
  tags: ["Content"],
34
- summary: "Get a bundle by id",
38
+ summary: "Get a bundle (staff)",
39
+ description: "Staff only (owner, admin, instructor).",
35
40
  params: BundleIdParam,
36
41
  response: {
37
42
  200: Bundle,
38
- 404: ErrorBody
43
+ ...refusals(403, 404)
39
44
  }
40
45
  },
41
46
  handler: async (req) => {
@@ -52,11 +57,12 @@ async function bundlesRoutes(app, container) {
52
57
  schema: {
53
58
  operationId: "createBundle",
54
59
  tags: ["Content"],
55
- summary: "Create a bundle, optionally with initial content",
60
+ summary: "Create a bundle, optionally with initial content (staff)",
61
+ description: "Staff only (owner, admin, instructor). 404 when an initial content id is unknown.",
56
62
  body: CreateBundle,
57
63
  response: {
58
64
  201: Bundle,
59
- 404: ErrorBody
65
+ ...refusals(403, 404)
60
66
  }
61
67
  },
62
68
  handler: async (req, reply) => {
@@ -72,12 +78,13 @@ async function bundlesRoutes(app, container) {
72
78
  schema: {
73
79
  operationId: "updateBundle",
74
80
  tags: ["Content"],
75
- summary: "Update a bundle",
81
+ summary: "Rename a bundle (staff)",
82
+ description: "Staff only (owner, admin, instructor).",
76
83
  params: BundleIdParam,
77
84
  body: UpdateBundle,
78
85
  response: {
79
86
  200: Bundle,
80
- 404: ErrorBody
87
+ ...refusals(403, 404)
81
88
  }
82
89
  },
83
90
  handler: async (req) => {
@@ -92,11 +99,12 @@ async function bundlesRoutes(app, container) {
92
99
  schema: {
93
100
  operationId: "deleteBundle",
94
101
  tags: ["Content"],
95
- summary: "Delete a bundle (its content survives)",
102
+ summary: "Delete a bundle (staff)",
103
+ description: "Staff only (owner, admin, instructor). Its content survives; access granted through the bundle ends.",
96
104
  params: BundleIdParam,
97
105
  response: {
98
106
  204: z.void(),
99
- 404: ErrorBody
107
+ ...refusals(403, 404)
100
108
  }
101
109
  },
102
110
  handler: async (req, reply) => {
@@ -112,11 +120,12 @@ async function bundlesRoutes(app, container) {
112
120
  schema: {
113
121
  operationId: "listBundleItems",
114
122
  tags: ["Content"],
115
- summary: "List a bundle's content items",
123
+ summary: "List a bundle's content (staff)",
124
+ description: "Staff only (owner, admin, instructor).",
116
125
  params: BundleIdParam,
117
126
  response: {
118
127
  200: z.array(BundleItem),
119
- 404: ErrorBody
128
+ ...refusals(403)
120
129
  }
121
130
  },
122
131
  handler: async (req) => {
@@ -131,12 +140,13 @@ async function bundlesRoutes(app, container) {
131
140
  schema: {
132
141
  operationId: "addBundleItem",
133
142
  tags: ["Content"],
134
- summary: "Add a content item to a bundle",
143
+ summary: "Add content to a bundle (staff)",
144
+ description: "Staff only (owner, admin, instructor). Everyone who holds the bundle can open the content from then on. Returns the bundle's content.",
135
145
  params: BundleIdParam,
136
146
  body: AddBundleItem,
137
147
  response: {
138
148
  200: z.array(BundleItem),
139
- 404: ErrorBody
149
+ ...refusals(403, 404)
140
150
  }
141
151
  },
142
152
  handler: async (req) => {
@@ -151,11 +161,12 @@ async function bundlesRoutes(app, container) {
151
161
  schema: {
152
162
  operationId: "removeBundleItem",
153
163
  tags: ["Content"],
154
- summary: "Remove a content item from a bundle (the content survives)",
164
+ summary: "Remove content from a bundle (staff)",
165
+ description: "Staff only (owner, admin, instructor). The content survives; access to it through the bundle ends. Returns the bundle's content.",
155
166
  params: BundleItemParams,
156
167
  response: {
157
168
  200: z.array(BundleItem),
158
- 404: ErrorBody
169
+ ...refusals(403, 404)
159
170
  }
160
171
  },
161
172
  handler: async (req) => {
@@ -1 +1 @@
1
- {"version":3,"file":"bundles.js","names":[],"sources":["../../../src/http/routes/bundles.ts"],"sourcesContent":["// HTTP routes for bundles — named groupings of content items. Request +\n// response are validated against the shared contract schemas by the Zod type\n// provider, and @fastify/swagger reads the same schemas to build the OpenAPI\n// spec.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n AddBundleItem,\n Bundle,\n BundleIdParam,\n BundleItem,\n BundleItemParams,\n BundlesPage,\n BundlesQuery,\n CreateBundle,\n ErrorBody,\n UpdateBundle,\n} from '../schemas/index.js';\nimport { z } from 'zod';\nimport type { Container } from '../../app/container.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport { resolveScope } from '../scope.js';\n\nexport async function bundlesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const content = container.content;\n\n r.route({\n method: 'GET',\n url: '/api/bundles',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listBundles',\n tags: ['Content'],\n summary: 'List bundles',\n querystring: BundlesQuery,\n response: { 200: BundlesPage },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listBundles(scope.orgId, req.query);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getBundle',\n tags: ['Content'],\n summary: 'Get a bundle by id',\n params: BundleIdParam,\n response: { 200: Bundle, 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const bundle = await content.getBundle(scope.orgId, req.params.bundleId);\n if (!bundle) {\n throw new NotFoundError('Bundle', req.params.bundleId);\n }\n return bundle;\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/bundles',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createBundle',\n tags: ['Content'],\n summary: 'Create a bundle, optionally with initial content',\n body: CreateBundle,\n response: { 201: Bundle, 404: ErrorBody },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const bundle = await content.createBundle(scope.orgId, req.body);\n return reply.code(201).send(bundle);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateBundle',\n tags: ['Content'],\n summary: 'Update a bundle',\n params: BundleIdParam,\n body: UpdateBundle,\n response: { 200: Bundle, 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.updateBundle(scope.orgId, req.params.bundleId, req.body);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteBundle',\n tags: ['Content'],\n summary: 'Delete a bundle (its content survives)',\n params: BundleIdParam,\n response: { 204: z.void(), 404: ErrorBody },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await content.deleteBundle(scope.orgId, req.params.bundleId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/bundles/:bundleId/items',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listBundleItems',\n tags: ['Content'],\n summary: \"List a bundle's content items\",\n params: BundleIdParam,\n response: { 200: z.array(BundleItem), 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listBundleItems(scope.orgId, req.params.bundleId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/bundles/:bundleId/items',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addBundleItem',\n tags: ['Content'],\n summary: 'Add a content item to a bundle',\n params: BundleIdParam,\n body: AddBundleItem,\n response: { 200: z.array(BundleItem), 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.addBundleItem(scope.orgId, req.params.bundleId, req.body.contentId);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/bundles/:bundleId/items/:contentId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeBundleItem',\n tags: ['Content'],\n summary: 'Remove a content item from a bundle (the content survives)',\n params: BundleItemParams,\n response: { 200: z.array(BundleItem), 404: ErrorBody },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.removeBundleItem(scope.orgId, req.params.bundleId, req.params.contentId);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bundles.js","names":[],"sources":["../../../src/http/routes/bundles.ts"],"sourcesContent":["// HTTP routes for bundles — named groupings of content items. Request +\n// response are validated against the shared contract schemas by the Zod type\n// provider, and @fastify/swagger reads the same schemas to build the OpenAPI\n// spec.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n AddBundleItem,\n Bundle,\n BundleIdParam,\n BundleItem,\n BundleItemParams,\n BundlesPage,\n BundlesQuery,\n CreateBundle,\n UpdateBundle,\n refusals,\n} from '../schemas/index.js';\nimport { z } from 'zod';\nimport type { Container } from '../../app/container.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport { resolveScope } from '../scope.js';\n\nexport async function bundlesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const content = container.content;\n\n r.route({\n method: 'GET',\n url: '/api/bundles',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listBundles',\n tags: ['Content'],\n summary: 'List bundles (staff)',\n description: 'Staff only (owner, admin, instructor).',\n querystring: BundlesQuery,\n response: { 200: BundlesPage, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listBundles(scope.orgId, req.query);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getBundle',\n tags: ['Content'],\n summary: 'Get a bundle (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: BundleIdParam,\n response: { 200: Bundle, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const bundle = await content.getBundle(scope.orgId, req.params.bundleId);\n if (!bundle) {\n throw new NotFoundError('Bundle', req.params.bundleId);\n }\n return bundle;\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/bundles',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createBundle',\n tags: ['Content'],\n summary: 'Create a bundle, optionally with initial content (staff)',\n description:\n 'Staff only (owner, admin, instructor). 404 when an initial content id is unknown.',\n body: CreateBundle,\n response: { 201: Bundle, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const bundle = await content.createBundle(scope.orgId, req.body);\n return reply.code(201).send(bundle);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateBundle',\n tags: ['Content'],\n summary: 'Rename a bundle (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: BundleIdParam,\n body: UpdateBundle,\n response: { 200: Bundle, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.updateBundle(scope.orgId, req.params.bundleId, req.body);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/bundles/:bundleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteBundle',\n tags: ['Content'],\n summary: 'Delete a bundle (staff)',\n description:\n 'Staff only (owner, admin, instructor). Its content survives; access granted through the bundle ends.',\n params: BundleIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await content.deleteBundle(scope.orgId, req.params.bundleId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/bundles/:bundleId/items',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listBundleItems',\n tags: ['Content'],\n summary: \"List a bundle's content (staff)\",\n description: 'Staff only (owner, admin, instructor).',\n params: BundleIdParam,\n response: { 200: z.array(BundleItem), ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listBundleItems(scope.orgId, req.params.bundleId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/bundles/:bundleId/items',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addBundleItem',\n tags: ['Content'],\n summary: 'Add content to a bundle (staff)',\n description:\n \"Staff only (owner, admin, instructor). Everyone who holds the bundle can open the content from then on. Returns the bundle's content.\",\n params: BundleIdParam,\n body: AddBundleItem,\n response: { 200: z.array(BundleItem), ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.addBundleItem(scope.orgId, req.params.bundleId, req.body.contentId);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/bundles/:bundleId/items/:contentId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeBundleItem',\n tags: ['Content'],\n summary: 'Remove content from a bundle (staff)',\n description:\n \"Staff only (owner, admin, instructor). The content survives; access to it through the bundle ends. Returns the bundle's content.\",\n params: BundleItemParams,\n response: { 200: z.array(BundleItem), ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.removeBundleItem(scope.orgId, req.params.bundleId, req.params.contentId);\n },\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Container } from "../../app/container.js";
2
+ import { FastifyInstance } from "fastify";
3
+ //#region src/http/routes/communities.d.ts
4
+ declare function communitiesRoutes(app: FastifyInstance, container: Container): Promise<void>;
5
+ //#endregion
6
+ export { communitiesRoutes };
7
+ //# sourceMappingURL=communities.d.ts.map
@@ -0,0 +1,462 @@
1
+ import { refusals } from "../schemas/shared.js";
2
+ import { resolveScope } from "../scope.js";
3
+ import { CommunitiesPage, CommunitiesQuery, Community, CommunityAnalytics, CommunityIdParam, CommunitySpaceParam, CreateCommunity, CreateSpace, OrderedIds, PatchDmSettings, SetSpaceTopics, SpaceDetail, SpaceLinkBody, SpaceLinkParam, UpdateCommunity, UpdateSpace } from "../schemas/community.js";
4
+ import { MessageQueue } from "../schemas/chats.js";
5
+ import "../schemas/index.js";
6
+ import { z } from "zod";
7
+ import { NotFoundError } from "@headless-lms/core/shared/errors";
8
+ //#region src/http/routes/communities.ts
9
+ async function communitiesRoutes(app, container) {
10
+ const r = app.withTypeProvider();
11
+ const content = container.content;
12
+ const tags = ["Communities"];
13
+ r.route({
14
+ method: "GET",
15
+ url: "/api/communities",
16
+ schema: {
17
+ operationId: "listCommunities",
18
+ tags,
19
+ summary: "List communities (staff)",
20
+ description: "Staff only (owner, admin, instructor). Pages every community in the organization, drafts included, filtered by `status` and searched by title.",
21
+ querystring: CommunitiesQuery,
22
+ response: {
23
+ 200: CommunitiesPage,
24
+ ...refusals(403)
25
+ }
26
+ },
27
+ handler: async (req) => {
28
+ const scope = await resolveScope(container, req);
29
+ return content.listCommunities(scope.orgId, req.query);
30
+ }
31
+ });
32
+ r.route({
33
+ method: "POST",
34
+ url: "/api/communities",
35
+ schema: {
36
+ operationId: "createCommunity",
37
+ tags,
38
+ summary: "Create a community (staff)",
39
+ description: "Owner or admin only. The community starts as a draft with the default direct-message settings and no spaces. Members see it once it is published and they hold it.",
40
+ body: CreateCommunity,
41
+ response: {
42
+ 201: Community,
43
+ ...refusals(403, 409)
44
+ }
45
+ },
46
+ handler: async (req, reply) => {
47
+ const scope = await resolveScope(container, req);
48
+ const community = await content.createCommunity(scope.orgId, req.body, {
49
+ id: scope.orgUserId,
50
+ role: scope.role
51
+ });
52
+ req.log.info({ communityId: community.id }, "community created");
53
+ return reply.code(201).send(community);
54
+ }
55
+ });
56
+ r.route({
57
+ method: "GET",
58
+ url: "/api/communities/:communityId",
59
+ schema: {
60
+ operationId: "getCommunity",
61
+ tags,
62
+ summary: "Get a community (staff)",
63
+ description: "Staff only (owner, admin, instructor). Any community of the organization, drafts included.",
64
+ params: CommunityIdParam,
65
+ response: {
66
+ 200: Community,
67
+ ...refusals(403, 404)
68
+ }
69
+ },
70
+ handler: async (req) => {
71
+ const scope = await resolveScope(container, req);
72
+ const community = await content.getCommunity(scope.orgId, req.params.communityId);
73
+ if (!community) throw new NotFoundError("Community", req.params.communityId);
74
+ return community;
75
+ }
76
+ });
77
+ r.route({
78
+ method: "PATCH",
79
+ url: "/api/communities/:communityId",
80
+ schema: {
81
+ operationId: "updateCommunity",
82
+ tags,
83
+ summary: "Update a community (staff)",
84
+ description: "Owner or admin only. Changes only the fields sent. `thumbnailAssetId` must be a ready library image (409 otherwise); null clears it.",
85
+ params: CommunityIdParam,
86
+ body: UpdateCommunity,
87
+ response: {
88
+ 200: Community,
89
+ ...refusals(403, 404, 409)
90
+ }
91
+ },
92
+ handler: async (req) => {
93
+ const scope = await resolveScope(container, req);
94
+ return content.updateCommunity(scope.orgId, req.params.communityId, req.body, {
95
+ id: scope.orgUserId,
96
+ role: scope.role
97
+ });
98
+ }
99
+ });
100
+ r.route({
101
+ method: "DELETE",
102
+ url: "/api/communities/:communityId",
103
+ schema: {
104
+ operationId: "deleteCommunity",
105
+ tags,
106
+ summary: "Delete a community (staff)",
107
+ description: "Owner or admin only. Links to the community from other spaces are removed with it.",
108
+ params: CommunityIdParam,
109
+ response: {
110
+ 204: z.void(),
111
+ ...refusals(403, 404)
112
+ }
113
+ },
114
+ handler: async (req, reply) => {
115
+ const scope = await resolveScope(container, req);
116
+ await content.deleteCommunity(scope.orgId, req.params.communityId, {
117
+ id: scope.orgUserId,
118
+ role: scope.role
119
+ });
120
+ return reply.code(204).send();
121
+ }
122
+ });
123
+ r.route({
124
+ method: "PATCH",
125
+ url: "/api/communities/:communityId/settings",
126
+ schema: {
127
+ operationId: "patchCommunityDmSettings",
128
+ tags,
129
+ summary: "Change direct-message settings for a community (staff)",
130
+ description: "Owner or admin only. Changes only the settings sent; the rest keep their values. They decide who may message whom from then on.",
131
+ params: CommunityIdParam,
132
+ body: PatchDmSettings,
133
+ response: {
134
+ 200: Community,
135
+ ...refusals(403, 404)
136
+ }
137
+ },
138
+ handler: async (req) => {
139
+ const scope = await resolveScope(container, req);
140
+ return content.patchDmSettings(scope.orgId, req.params.communityId, req.body, {
141
+ id: scope.orgUserId,
142
+ role: scope.role
143
+ });
144
+ }
145
+ });
146
+ r.route({
147
+ method: "POST",
148
+ url: "/api/communities/:communityId/publish",
149
+ schema: {
150
+ operationId: "publishCommunity",
151
+ tags,
152
+ summary: "Publish a community (staff)",
153
+ description: "Owner or admin only. Makes the community visible to the people who hold it.",
154
+ params: CommunityIdParam,
155
+ response: {
156
+ 200: Community,
157
+ ...refusals(403, 404, 409)
158
+ }
159
+ },
160
+ handler: async (req) => {
161
+ const scope = await resolveScope(container, req);
162
+ return content.publishCommunity(scope.orgId, req.params.communityId, {
163
+ id: scope.orgUserId,
164
+ role: scope.role
165
+ });
166
+ }
167
+ });
168
+ r.route({
169
+ method: "POST",
170
+ url: "/api/communities/:communityId/unpublish",
171
+ schema: {
172
+ operationId: "unpublishCommunity",
173
+ tags,
174
+ summary: "Unpublish a community (staff)",
175
+ description: "Owner or admin only. Hides the community from members again; nothing in it is deleted.",
176
+ params: CommunityIdParam,
177
+ response: {
178
+ 200: Community,
179
+ ...refusals(403, 404, 409)
180
+ }
181
+ },
182
+ handler: async (req) => {
183
+ const scope = await resolveScope(container, req);
184
+ return content.unpublishCommunity(scope.orgId, req.params.communityId, {
185
+ id: scope.orgUserId,
186
+ role: scope.role
187
+ });
188
+ }
189
+ });
190
+ r.route({
191
+ method: "GET",
192
+ url: "/api/communities/:communityId/analytics",
193
+ schema: {
194
+ operationId: "getCommunityAnalytics",
195
+ tags,
196
+ summary: "Staff analytics for a community",
197
+ description: "Staff only (owner, admin, instructor). Membership, activity and moderation counts for one community.",
198
+ params: CommunityIdParam,
199
+ response: {
200
+ 200: CommunityAnalytics,
201
+ ...refusals(403, 404)
202
+ }
203
+ },
204
+ handler: async (req) => {
205
+ const scope = await resolveScope(container, req);
206
+ const stats = await container.reporting.admin.communityAnalytics(scope.orgId, req.params.communityId);
207
+ if (!stats) throw new NotFoundError("Community", req.params.communityId);
208
+ return stats;
209
+ }
210
+ });
211
+ r.route({
212
+ method: "GET",
213
+ url: "/api/communities/:communityId/message-queue",
214
+ schema: {
215
+ operationId: "getCommunityMessageQueue",
216
+ tags,
217
+ summary: "Open message flags in a community (staff)",
218
+ description: "Staff only (owner, admin, instructor). The messages in the community's chats with open flags, with the flags and the chat each is in. Holds at most the 100 oldest open flags; working the queue brings in the next ones.",
219
+ params: CommunityIdParam,
220
+ response: {
221
+ 200: MessageQueue,
222
+ ...refusals(403, 404)
223
+ }
224
+ },
225
+ handler: async (req) => {
226
+ const scope = await resolveScope(container, req);
227
+ return container.chats.messageQueue(scope.orgId, {
228
+ id: scope.orgUserId,
229
+ role: scope.role
230
+ }, req.params.communityId);
231
+ }
232
+ });
233
+ r.route({
234
+ method: "GET",
235
+ url: "/api/communities/:communityId/spaces",
236
+ schema: {
237
+ operationId: "listCommunitySpaces",
238
+ tags,
239
+ summary: "List the spaces in a community (staff)",
240
+ description: "Staff only (owner, admin, instructor). Every space in order, with its topics and links.",
241
+ params: CommunityIdParam,
242
+ response: {
243
+ 200: z.array(SpaceDetail),
244
+ ...refusals(403, 404)
245
+ }
246
+ },
247
+ handler: async (req) => {
248
+ const scope = await resolveScope(container, req);
249
+ return content.listSpaces(scope.orgId, req.params.communityId);
250
+ }
251
+ });
252
+ r.route({
253
+ method: "POST",
254
+ url: "/api/communities/:communityId/spaces",
255
+ schema: {
256
+ operationId: "createSpace",
257
+ tags,
258
+ summary: "Create a space (staff)",
259
+ description: "Owner or admin only. The space is added last. An `all_members` space cannot have a capacity (409).",
260
+ params: CommunityIdParam,
261
+ body: CreateSpace,
262
+ response: {
263
+ 201: SpaceDetail,
264
+ ...refusals(403, 404, 409)
265
+ }
266
+ },
267
+ handler: async (req, reply) => {
268
+ const scope = await resolveScope(container, req);
269
+ const space = await content.createSpace(scope.orgId, req.params.communityId, req.body, {
270
+ id: scope.orgUserId,
271
+ role: scope.role
272
+ });
273
+ return reply.code(201).send(space);
274
+ }
275
+ });
276
+ r.route({
277
+ method: "PUT",
278
+ url: "/api/communities/:communityId/spaces/order",
279
+ schema: {
280
+ operationId: "reorderSpaces",
281
+ tags,
282
+ summary: "Reorder the spaces in a community (staff)",
283
+ description: "Owner or admin only. Send every space id of the community exactly once (409 otherwise).",
284
+ params: CommunityIdParam,
285
+ body: OrderedIds,
286
+ response: {
287
+ 200: z.array(SpaceDetail),
288
+ ...refusals(403, 404, 409)
289
+ }
290
+ },
291
+ handler: async (req) => {
292
+ const scope = await resolveScope(container, req);
293
+ return content.reorderSpaces(scope.orgId, req.params.communityId, req.body.ids, {
294
+ id: scope.orgUserId,
295
+ role: scope.role
296
+ });
297
+ }
298
+ });
299
+ r.route({
300
+ method: "GET",
301
+ url: "/api/communities/:communityId/spaces/:spaceId",
302
+ schema: {
303
+ operationId: "getSpace",
304
+ tags,
305
+ summary: "Get a space (staff)",
306
+ description: "Staff only (owner, admin, instructor). The space with its topics and links.",
307
+ params: CommunitySpaceParam,
308
+ response: {
309
+ 200: SpaceDetail,
310
+ ...refusals(403, 404)
311
+ }
312
+ },
313
+ handler: async (req) => {
314
+ const scope = await resolveScope(container, req);
315
+ const space = await content.getCommunitySpace(scope.orgId, req.params.communityId, req.params.spaceId);
316
+ if (!space) throw new NotFoundError("Space", req.params.spaceId);
317
+ return space;
318
+ }
319
+ });
320
+ r.route({
321
+ method: "PATCH",
322
+ url: "/api/communities/:communityId/spaces/:spaceId",
323
+ schema: {
324
+ operationId: "updateSpace",
325
+ tags,
326
+ summary: "Update a space (staff)",
327
+ description: "Owner or admin only. Changes only the fields sent; `settings` merges into the current settings. An `all_members` space cannot have a capacity (409).",
328
+ params: CommunitySpaceParam,
329
+ body: UpdateSpace,
330
+ response: {
331
+ 200: SpaceDetail,
332
+ ...refusals(403, 404, 409)
333
+ }
334
+ },
335
+ handler: async (req) => {
336
+ const scope = await resolveScope(container, req);
337
+ return content.updateSpace(scope.orgId, req.params.communityId, req.params.spaceId, req.body, {
338
+ id: scope.orgUserId,
339
+ role: scope.role
340
+ });
341
+ }
342
+ });
343
+ r.route({
344
+ method: "DELETE",
345
+ url: "/api/communities/:communityId/spaces/:spaceId",
346
+ schema: {
347
+ operationId: "deleteSpace",
348
+ tags,
349
+ summary: "Delete a space (staff)",
350
+ description: "Owner or admin only. The space and everything in it go.",
351
+ params: CommunitySpaceParam,
352
+ response: {
353
+ 204: z.void(),
354
+ ...refusals(403, 404)
355
+ }
356
+ },
357
+ handler: async (req, reply) => {
358
+ const scope = await resolveScope(container, req);
359
+ await content.deleteSpace(scope.orgId, req.params.communityId, req.params.spaceId, {
360
+ id: scope.orgUserId,
361
+ role: scope.role
362
+ });
363
+ return reply.code(204).send();
364
+ }
365
+ });
366
+ r.route({
367
+ method: "PUT",
368
+ url: "/api/communities/:communityId/spaces/:spaceId/topics",
369
+ schema: {
370
+ operationId: "setSpaceTopics",
371
+ tags,
372
+ summary: "Replace the topics on a space (staff)",
373
+ description: "Owner or admin only. The list replaces the current topics: an entry with an `id` keeps and renames that topic, one without adds a topic, and a topic left out is deleted. Names must be unique (409), and a topic that posts use cannot be deleted (409).",
374
+ params: CommunitySpaceParam,
375
+ body: SetSpaceTopics,
376
+ response: {
377
+ 200: SpaceDetail,
378
+ ...refusals(403, 404, 409)
379
+ }
380
+ },
381
+ handler: async (req) => {
382
+ const scope = await resolveScope(container, req);
383
+ return content.setSpaceTopics(scope.orgId, req.params.communityId, req.params.spaceId, req.body, {
384
+ id: scope.orgUserId,
385
+ role: scope.role
386
+ });
387
+ }
388
+ });
389
+ r.route({
390
+ method: "POST",
391
+ url: "/api/communities/:communityId/spaces/:spaceId/links",
392
+ schema: {
393
+ operationId: "addSpaceLink",
394
+ tags,
395
+ summary: "Link a course, download, or community into a space (staff)",
396
+ description: "Owner or admin only. The link is added last. Linking the same content twice is a 409.",
397
+ params: CommunitySpaceParam,
398
+ body: SpaceLinkBody,
399
+ response: {
400
+ 201: SpaceDetail,
401
+ ...refusals(403, 404, 409)
402
+ }
403
+ },
404
+ handler: async (req, reply) => {
405
+ const scope = await resolveScope(container, req);
406
+ const space = await content.addSpaceLink(scope.orgId, req.params.communityId, req.params.spaceId, req.body.contentId, {
407
+ id: scope.orgUserId,
408
+ role: scope.role
409
+ });
410
+ return reply.code(201).send(space);
411
+ }
412
+ });
413
+ r.route({
414
+ method: "DELETE",
415
+ url: "/api/communities/:communityId/spaces/:spaceId/links/:linkId",
416
+ schema: {
417
+ operationId: "removeSpaceLink",
418
+ tags,
419
+ summary: "Remove a link from a space (staff)",
420
+ description: "Owner or admin only. The linked content itself is untouched.",
421
+ params: SpaceLinkParam,
422
+ response: {
423
+ 200: SpaceDetail,
424
+ ...refusals(403, 404)
425
+ }
426
+ },
427
+ handler: async (req) => {
428
+ const scope = await resolveScope(container, req);
429
+ return content.removeSpaceLink(scope.orgId, req.params.communityId, req.params.spaceId, req.params.linkId, {
430
+ id: scope.orgUserId,
431
+ role: scope.role
432
+ });
433
+ }
434
+ });
435
+ r.route({
436
+ method: "PUT",
437
+ url: "/api/communities/:communityId/spaces/:spaceId/links/order",
438
+ schema: {
439
+ operationId: "reorderSpaceLinks",
440
+ tags,
441
+ summary: "Reorder the links in a space (staff)",
442
+ description: "Owner or admin only. Send every link id of the space exactly once (409 otherwise).",
443
+ params: CommunitySpaceParam,
444
+ body: OrderedIds,
445
+ response: {
446
+ 200: SpaceDetail,
447
+ ...refusals(403, 404, 409)
448
+ }
449
+ },
450
+ handler: async (req) => {
451
+ const scope = await resolveScope(container, req);
452
+ return content.reorderSpaceLinks(scope.orgId, req.params.communityId, req.params.spaceId, req.body.ids, {
453
+ id: scope.orgUserId,
454
+ role: scope.role
455
+ });
456
+ }
457
+ });
458
+ }
459
+ //#endregion
460
+ export { communitiesRoutes };
461
+
462
+ //# sourceMappingURL=communities.js.map