@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
@@ -9,6 +9,36 @@ declare const ErrorBody: z.ZodObject<{
9
9
  requestId: z.ZodOptional<z.ZodString>;
10
10
  }, z.core.$strip>;
11
11
  type ErrorBody = z.infer<typeof ErrorBody>;
12
+ /** A 400 from request validation: `message` names the first problem, `issues` lists them all. */
13
+ declare const ValidationErrorBody: z.ZodObject<{
14
+ error: z.ZodString;
15
+ message: z.ZodOptional<z.ZodString>;
16
+ requestId: z.ZodOptional<z.ZodString>;
17
+ issues: z.ZodOptional<z.ZodArray<z.ZodObject<{
18
+ path: z.ZodString;
19
+ message: z.ZodString;
20
+ }, z.core.$strip>>>;
21
+ }, z.core.$strip>;
22
+ type ValidationErrorBody = z.infer<typeof ValidationErrorBody>;
23
+ declare const UnavailableErrorBody: z.ZodObject<{
24
+ error: z.ZodString;
25
+ message: z.ZodOptional<z.ZodString>;
26
+ requestId: z.ZodOptional<z.ZodString>;
27
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
28
+ }, z.core.$strip>;
29
+ type UnavailableErrorBody = z.infer<typeof UnavailableErrorBody>;
30
+ type RefusalStatus = 400 | 403 | 404 | 409 | 413 | 415 | 422 | 502 | 503;
31
+ type RefusalBodies<S extends RefusalStatus> = { [K in S]: K extends 400 | 422 ? typeof ValidationErrorBody : K extends 503 ? typeof UnavailableErrorBody : typeof ErrorBody; };
32
+ /** Response schemas for the refusals a route can answer. A 400 keeps the validation `issues`. */
33
+ declare function refusals<S extends RefusalStatus>(...statuses: S[]): RefusalBodies<S>;
34
+ /** An RFC 3339 date-time in a request, such as `2026-10-29T12:00:00Z`, read as a Date. */
35
+ declare const DateTimeInput: z.ZodPipe<z.ZodISODateTime, z.ZodCoercedDate<string>>;
36
+ /** Page position only, for lists that take no search or sort. */
37
+ declare const PageQuery: z.ZodObject<{
38
+ page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
39
+ pageSize: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
40
+ }, z.core.$strict>;
41
+ type PageQuery = z.infer<typeof PageQuery>;
12
42
  /**
13
43
  * Common list query for page-based collections. `z.coerce` because query-string
14
44
  * values arrive as strings; defaults make the params optional for callers.
@@ -33,6 +63,7 @@ declare const OrgRole: z.ZodEnum<{
33
63
  owner: "owner";
34
64
  admin: "admin";
35
65
  instructor: "instructor";
66
+ moderator: "moderator";
36
67
  student: "student";
37
68
  }>;
38
69
  type OrgRole = z.infer<typeof OrgRole>;
@@ -54,5 +85,5 @@ declare const OrgUserProfileSchema: z.ZodObject<{
54
85
  }, z.core.$strip>;
55
86
  type OrgUserProfileSchema = z.infer<typeof OrgUserProfileSchema>;
56
87
  //#endregion
57
- export { ErrorBody, ListQuery, Matches, OrgRole, OrgUserProfileSchema, UserProfileSchema, paginated };
88
+ export { DateTimeInput, ErrorBody, ListQuery, Matches, OrgRole, OrgUserProfileSchema, PageQuery, UnavailableErrorBody, UserProfileSchema, ValidationErrorBody, paginated, refusals };
58
89
  //# sourceMappingURL=shared.d.ts.map
@@ -7,6 +7,23 @@ const ErrorBody = z.object({
7
7
  /** Server-side correlation id — quote it to find the matching API log line. */
8
8
  requestId: z.string().optional()
9
9
  });
10
+ /** A 400 from request validation: `message` names the first problem, `issues` lists them all. */
11
+ const ValidationErrorBody = ErrorBody.extend({ issues: z.array(z.object({
12
+ path: z.string().describe("Where in the request, such as `body.topics[1].name`"),
13
+ message: z.string()
14
+ })).optional() });
15
+ const UnavailableErrorBody = ErrorBody.extend({ details: z.record(z.string(), z.string()).optional().describe("Ids of what the request left behind, such as the post kept as a draft") });
16
+ /** Response schemas for the refusals a route can answer. A 400 keeps the validation `issues`. */
17
+ function refusals(...statuses) {
18
+ return Object.fromEntries(statuses.map((status) => [status, status === 400 || status === 422 ? ValidationErrorBody : status === 503 ? UnavailableErrorBody : ErrorBody]));
19
+ }
20
+ /** An RFC 3339 date-time in a request, such as `2026-10-29T12:00:00Z`, read as a Date. */
21
+ const DateTimeInput = z.iso.datetime({ offset: true }).pipe(z.coerce.date());
22
+ /** Page position only, for lists that take no search or sort. */
23
+ const PageQuery = z.object({
24
+ page: z.coerce.number().int().min(1).default(1),
25
+ pageSize: z.coerce.number().int().min(1).max(100).default(20)
26
+ }).strict();
10
27
  /**
11
28
  * Common list query for page-based collections. `z.coerce` because query-string
12
29
  * values arrive as strings; defaults make the params optional for callers.
@@ -14,7 +31,7 @@ const ErrorBody = z.object({
14
31
  const ListQuery = z.object({
15
32
  page: z.coerce.number().int().min(1).default(1),
16
33
  pageSize: z.coerce.number().int().min(1).max(100).default(20),
17
- search: z.string().trim().optional(),
34
+ search: z.string().trim().max(200).optional(),
18
35
  /** Sort field, optionally prefixed with `-` for descending (e.g. `-updatedAt`). */
19
36
  sort: z.string().optional()
20
37
  });
@@ -33,6 +50,7 @@ const OrgRole = z.enum([
33
50
  "owner",
34
51
  "admin",
35
52
  "instructor",
53
+ "moderator",
36
54
  "student"
37
55
  ]);
38
56
  /** Mirrors UserProfile in @headless-lms/core/types — keyed on the auth user id. */
@@ -51,6 +69,6 @@ const OrgUserProfileSchema = z.object({
51
69
  image: z.string().nullable()
52
70
  });
53
71
  //#endregion
54
- export { ErrorBody, ListQuery, OrgRole, OrgUserProfileSchema, UserProfileSchema, paginated };
72
+ export { DateTimeInput, ErrorBody, ListQuery, OrgRole, OrgUserProfileSchema, PageQuery, UnavailableErrorBody, UserProfileSchema, ValidationErrorBody, paginated, refusals };
55
73
 
56
74
  //# sourceMappingURL=shared.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","names":[],"sources":["../../../src/http/schemas/shared.ts"],"sourcesContent":["// Shared contract primitives reused across resource contracts.\nimport { z } from 'zod';\n\n/** Fails typecheck when a schema and its domain type drift apart. */\nexport type Matches<A, _B extends A> = true;\n\n/** Uniform error envelope returned by every non-2xx response. */\nexport const ErrorBody = z.object({\n error: z.string(),\n message: z.string().optional(),\n /** Server-side correlation id — quote it to find the matching API log line. */\n requestId: z.string().optional(),\n});\nexport type ErrorBody = z.infer<typeof ErrorBody>;\n\n/**\n * Common list query for page-based collections. `z.coerce` because query-string\n * values arrive as strings; defaults make the params optional for callers.\n */\nexport const ListQuery = z.object({\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n search: z.string().trim().optional(),\n /** Sort field, optionally prefixed with `-` for descending (e.g. `-updatedAt`). */\n sort: z.string().optional(),\n});\nexport type ListQuery = z.infer<typeof ListQuery>;\n\n/** Wrap a row schema into the standard paginated envelope. */\nexport function paginated<T extends z.ZodTypeAny>(row: T) {\n return z.object({\n rows: z.array(row),\n total: z.number().int(),\n page: z.number().int(),\n pageSize: z.number().int(),\n });\n}\n\n/** All four org roles. `members.ts` exports a staff-only three-value `Role`;\n * this is the full set, used wherever a learner can also appear. */\nexport const OrgRole = z.enum(['owner', 'admin', 'instructor', 'student']);\nexport type OrgRole = z.infer<typeof OrgRole>;\n\n/** Mirrors UserProfile in @headless-lms/core/types — keyed on the auth user id. */\nexport const UserProfileSchema = z.object({\n id: z.string(),\n name: z.string(),\n email: z.string(),\n image: z.string().nullable(),\n});\nexport type UserProfileSchema = z.infer<typeof UserProfileSchema>;\n\n/** Mirrors OrgUserProfile in @headless-lms/core/types — keyed on org_users.id. */\nexport const OrgUserProfileSchema = z.object({\n id: z.string(),\n firstName: z.string().nullable(),\n lastName: z.string().nullable(),\n email: z.string(),\n image: z.string().nullable(),\n});\nexport type OrgUserProfileSchema = z.infer<typeof OrgUserProfileSchema>;\n"],"mappings":";;;AAOA,MAAa,YAAY,EAAE,OAAO;CAChC,OAAO,EAAE,OAAO;CAChB,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE7B,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;AACjC,CAAC;;;;;AAOD,MAAa,YAAY,EAAE,OAAO;CAChC,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;CAC9C,UAAU,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE;CAC5D,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS;;CAEnC,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;AAC5B,CAAC;;AAID,SAAgB,UAAkC,KAAQ;CACxD,OAAO,EAAE,OAAO;EACd,MAAM,EAAE,MAAM,GAAG;EACjB,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI;EACtB,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI;EACrB,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CAC3B,CAAC;AACH;;;AAIA,MAAa,UAAU,EAAE,KAAK;CAAC;CAAS;CAAS;CAAc;AAAS,CAAC;;AAIzE,MAAa,oBAAoB,EAAE,OAAO;CACxC,IAAI,EAAE,OAAO;CACb,MAAM,EAAE,OAAO;CACf,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC;;AAID,MAAa,uBAAuB,EAAE,OAAO;CAC3C,IAAI,EAAE,OAAO;CACb,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,UAAU,EAAE,OAAO,CAAC,CAAC,SAAS;CAC9B,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC"}
1
+ {"version":3,"file":"shared.js","names":[],"sources":["../../../src/http/schemas/shared.ts"],"sourcesContent":["// Shared contract primitives reused across resource contracts.\nimport { z } from 'zod';\n\n/** Fails typecheck when a schema and its domain type drift apart. */\nexport type Matches<A, _B extends A> = true;\n\n/** Uniform error envelope returned by every non-2xx response. */\nexport const ErrorBody = z.object({\n error: z.string(),\n message: z.string().optional(),\n /** Server-side correlation id — quote it to find the matching API log line. */\n requestId: z.string().optional(),\n});\nexport type ErrorBody = z.infer<typeof ErrorBody>;\n\n/** A 400 from request validation: `message` names the first problem, `issues` lists them all. */\nexport const ValidationErrorBody = ErrorBody.extend({\n issues: z\n .array(\n z.object({\n path: z.string().describe('Where in the request, such as `body.topics[1].name`'),\n message: z.string(),\n }),\n )\n .optional(),\n});\nexport type ValidationErrorBody = z.infer<typeof ValidationErrorBody>;\n\nexport const UnavailableErrorBody = ErrorBody.extend({\n details: z\n .record(z.string(), z.string())\n .optional()\n .describe('Ids of what the request left behind, such as the post kept as a draft'),\n});\nexport type UnavailableErrorBody = z.infer<typeof UnavailableErrorBody>;\n\ntype RefusalStatus = 400 | 403 | 404 | 409 | 413 | 415 | 422 | 502 | 503;\ntype RefusalBodies<S extends RefusalStatus> = {\n [K in S]: K extends 400 | 422\n ? typeof ValidationErrorBody\n : K extends 503\n ? typeof UnavailableErrorBody\n : typeof ErrorBody;\n};\n\n/** Response schemas for the refusals a route can answer. A 400 keeps the validation `issues`. */\nexport function refusals<S extends RefusalStatus>(...statuses: S[]): RefusalBodies<S> {\n return Object.fromEntries(\n statuses.map((status) => [\n status,\n status === 400 || status === 422\n ? ValidationErrorBody\n : status === 503\n ? UnavailableErrorBody\n : ErrorBody,\n ]),\n ) as RefusalBodies<S>;\n}\n\n/** An RFC 3339 date-time in a request, such as `2026-10-29T12:00:00Z`, read as a Date. */\nexport const DateTimeInput = z.iso.datetime({ offset: true }).pipe(z.coerce.date());\n\n/** Page position only, for lists that take no search or sort. */\nexport const PageQuery = z\n .object({\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n })\n .strict();\nexport type PageQuery = z.infer<typeof PageQuery>;\n\n/**\n * Common list query for page-based collections. `z.coerce` because query-string\n * values arrive as strings; defaults make the params optional for callers.\n */\nexport const ListQuery = z.object({\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n search: z.string().trim().max(200).optional(),\n /** Sort field, optionally prefixed with `-` for descending (e.g. `-updatedAt`). */\n sort: z.string().optional(),\n});\nexport type ListQuery = z.infer<typeof ListQuery>;\n\n/** Wrap a row schema into the standard paginated envelope. */\nexport function paginated<T extends z.ZodTypeAny>(row: T) {\n return z.object({\n rows: z.array(row),\n total: z.number().int(),\n page: z.number().int(),\n pageSize: z.number().int(),\n });\n}\n\n/** All four org roles. `members.ts` exports a staff-only three-value `Role`;\n * this is the full set, used wherever a learner can also appear. */\nexport const OrgRole = z.enum(['owner', 'admin', 'instructor', 'moderator', 'student']);\nexport type OrgRole = z.infer<typeof OrgRole>;\n\n/** Mirrors UserProfile in @headless-lms/core/types — keyed on the auth user id. */\nexport const UserProfileSchema = z.object({\n id: z.string(),\n name: z.string(),\n email: z.string(),\n image: z.string().nullable(),\n});\nexport type UserProfileSchema = z.infer<typeof UserProfileSchema>;\n\n/** Mirrors OrgUserProfile in @headless-lms/core/types — keyed on org_users.id. */\nexport const OrgUserProfileSchema = z.object({\n id: z.string(),\n firstName: z.string().nullable(),\n lastName: z.string().nullable(),\n email: z.string(),\n image: z.string().nullable(),\n});\nexport type OrgUserProfileSchema = z.infer<typeof OrgUserProfileSchema>;\n"],"mappings":";;;AAOA,MAAa,YAAY,EAAE,OAAO;CAChC,OAAO,EAAE,OAAO;CAChB,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE7B,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;AACjC,CAAC;;AAID,MAAa,sBAAsB,UAAU,OAAO,EAClD,QAAQ,EACL,MACC,EAAE,OAAO;CACP,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,qDAAqD;CAC/E,SAAS,EAAE,OAAO;AACpB,CAAC,CACH,CAAC,CACA,SAAS,EACd,CAAC;AAGD,MAAa,uBAAuB,UAAU,OAAO,EACnD,SAAS,EACN,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAC9B,SAAS,CAAC,CACV,SAAS,uEAAuE,EACrF,CAAC;;AAaD,SAAgB,SAAkC,GAAG,UAAiC;CACpF,OAAO,OAAO,YACZ,SAAS,KAAK,WAAW,CACvB,QACA,WAAW,OAAO,WAAW,MACzB,sBACA,WAAW,MACT,uBACA,SACR,CAAC,CACH;AACF;;AAGA,MAAa,gBAAgB,EAAE,IAAI,SAAS,EAAE,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;;AAGlF,MAAa,YAAY,EACtB,OAAO;CACN,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;CAC9C,UAAU,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE;AAC9D,CAAC,CAAC,CACD,OAAO;;;;;AAOV,MAAa,YAAY,EAAE,OAAO;CAChC,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;CAC9C,UAAU,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE;CAC5D,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS;;CAE5C,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;AAC5B,CAAC;;AAID,SAAgB,UAAkC,KAAQ;CACxD,OAAO,EAAE,OAAO;EACd,MAAM,EAAE,MAAM,GAAG;EACjB,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI;EACtB,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI;EACrB,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CAC3B,CAAC;AACH;;;AAIA,MAAa,UAAU,EAAE,KAAK;CAAC;CAAS;CAAS;CAAc;CAAa;AAAS,CAAC;;AAItF,MAAa,oBAAoB,EAAE,OAAO;CACxC,IAAI,EAAE,OAAO;CACb,MAAM,EAAE,OAAO;CACf,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC;;AAID,MAAa,uBAAuB,EAAE,OAAO;CAC3C,IAAI,EAAE,OAAO;CACb,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,UAAU,EAAE,OAAO,CAAC,CAAC,SAAS;CAC9B,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC"}
@@ -81,12 +81,6 @@ declare const StudentIdParam: z.ZodObject<{
81
81
  id: z.ZodString;
82
82
  }, z.core.$strip>;
83
83
  type StudentIdParam = z.infer<typeof StudentIdParam>;
84
- declare const UpdateStudentBody: z.ZodObject<{
85
- firstName: z.ZodString;
86
- lastName: z.ZodString;
87
- email: z.ZodEmail;
88
- }, z.core.$strip>;
89
- type UpdateStudentBody = z.infer<typeof UpdateStudentBody>;
90
84
  //#endregion
91
- export { OrgUserStatus, Student, StudentAnalytics, StudentCourseProgress, StudentIdParam, StudentsPage, StudentsQuery, UpdateStudentBody };
85
+ export { OrgUserStatus, Student, StudentAnalytics, StudentCourseProgress, StudentIdParam, StudentsPage, StudentsQuery };
92
86
  //# sourceMappingURL=students.d.ts.map
@@ -1,6 +1,5 @@
1
1
  import { ListQuery, OrgUserProfileSchema, paginated } from "./shared.js";
2
2
  import { z } from "zod";
3
- import { emailSchema } from "@headless-lms/core/schemas";
4
3
  //#region src/http/schemas/students.ts
5
4
  const OrgUserStatus = z.enum(["invited", "active"]);
6
5
  const Student = OrgUserProfileSchema.extend({
@@ -33,12 +32,7 @@ const StudentAnalytics = z.object({
33
32
  const StudentsQuery = ListQuery;
34
33
  const StudentsPage = paginated(Student);
35
34
  const StudentIdParam = z.object({ id: z.string() });
36
- const UpdateStudentBody = z.object({
37
- firstName: z.string().trim().min(1),
38
- lastName: z.string().trim().min(1),
39
- email: emailSchema
40
- });
41
35
  //#endregion
42
- export { OrgUserStatus, Student, StudentAnalytics, StudentCourseProgress, StudentIdParam, StudentsPage, StudentsQuery, UpdateStudentBody };
36
+ export { OrgUserStatus, Student, StudentAnalytics, StudentCourseProgress, StudentIdParam, StudentsPage, StudentsQuery };
43
37
 
44
38
  //# sourceMappingURL=students.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"students.js","names":[],"sources":["../../../src/http/schemas/students.ts"],"sourcesContent":["// Students resource schemas.\nimport { z } from 'zod';\nimport { emailSchema } from '@headless-lms/core/schemas';\nimport { ListQuery, paginated, OrgUserProfileSchema } from './shared.js';\n\nexport const OrgUserStatus = z.enum(['invited', 'active']);\nexport type OrgUserStatus = z.infer<typeof OrgUserStatus>;\n\nexport const Student = OrgUserProfileSchema.extend({\n entitlementCount: z.number().int(),\n /** 0–100, averaged across active entitlements. */\n avgProgress: z.number().int(),\n /** `invited` means an admin added them and they have not accepted yet. */\n status: OrgUserStatus,\n joinedAt: z.string(),\n lastActiveAt: z.string().nullable(),\n});\nexport type Student = z.infer<typeof Student>;\n\nexport const StudentCourseProgress = z.object({\n courseId: z.string(),\n title: z.string(),\n totalActivities: z.number().int(),\n completedActivities: z.number().int(),\n /** 0–100, completed published activities over the course's total. */\n progress: z.number().int(),\n startedAt: z.string().nullable(),\n lastActivityAt: z.string().nullable(),\n completedAt: z.string().nullable(),\n});\nexport type StudentCourseProgress = z.infer<typeof StudentCourseProgress>;\n\nexport const StudentAnalytics = z.object({\n enrolled: z.number().int(),\n started: z.number().int(),\n completed: z.number().int(),\n avgProgress: z.number().int(),\n courses: z.array(StudentCourseProgress),\n});\nexport type StudentAnalytics = z.infer<typeof StudentAnalytics>;\n\nexport const StudentsQuery = ListQuery;\nexport type StudentsQuery = z.infer<typeof StudentsQuery>;\n\nexport const StudentsPage = paginated(Student);\nexport type StudentsPage = z.infer<typeof StudentsPage>;\n\nexport const StudentIdParam = z.object({ id: z.string() });\nexport type StudentIdParam = z.infer<typeof StudentIdParam>;\n\n// Every field is a correction to what an admin typed, so all three are sent\n// together — the form edits the whole profile, not one attribute at a time.\nexport const UpdateStudentBody = z.object({\n firstName: z.string().trim().min(1),\n lastName: z.string().trim().min(1),\n email: emailSchema,\n});\nexport type UpdateStudentBody = z.infer<typeof UpdateStudentBody>;\n"],"mappings":";;;;AAKA,MAAa,gBAAgB,EAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;AAGzD,MAAa,UAAU,qBAAqB,OAAO;CACjD,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI;;CAEjC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI;;CAE5B,QAAQ;CACR,UAAU,EAAE,OAAO;CACnB,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;AACpC,CAAC;AAGD,MAAa,wBAAwB,EAAE,OAAO;CAC5C,UAAU,EAAE,OAAO;CACnB,OAAO,EAAE,OAAO;CAChB,iBAAiB,EAAE,OAAO,CAAC,CAAC,IAAI;CAChC,qBAAqB,EAAE,OAAO,CAAC,CAAC,IAAI;;CAEpC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CACzB,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,gBAAgB,EAAE,OAAO,CAAC,CAAC,SAAS;CACpC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS;AACnC,CAAC;AAGD,MAAa,mBAAmB,EAAE,OAAO;CACvC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CACzB,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI;CACxB,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI;CAC1B,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI;CAC5B,SAAS,EAAE,MAAM,qBAAqB;AACxC,CAAC;AAGD,MAAa,gBAAgB;AAG7B,MAAa,eAAe,UAAU,OAAO;AAG7C,MAAa,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAKzD,MAAa,oBAAoB,EAAE,OAAO;CACxC,WAAW,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;CAClC,UAAU,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;CACjC,OAAO;AACT,CAAC"}
1
+ {"version":3,"file":"students.js","names":[],"sources":["../../../src/http/schemas/students.ts"],"sourcesContent":["// Students resource schemas.\nimport { z } from 'zod';\nimport { ListQuery, paginated, OrgUserProfileSchema } from './shared.js';\n\nexport const OrgUserStatus = z.enum(['invited', 'active']);\nexport type OrgUserStatus = z.infer<typeof OrgUserStatus>;\n\nexport const Student = OrgUserProfileSchema.extend({\n entitlementCount: z.number().int(),\n /** 0–100, averaged across active entitlements. */\n avgProgress: z.number().int(),\n /** `invited` means an admin added them and they have not accepted yet. */\n status: OrgUserStatus,\n joinedAt: z.string(),\n lastActiveAt: z.string().nullable(),\n});\nexport type Student = z.infer<typeof Student>;\n\nexport const StudentCourseProgress = z.object({\n courseId: z.string(),\n title: z.string(),\n totalActivities: z.number().int(),\n completedActivities: z.number().int(),\n /** 0–100, completed published activities over the course's total. */\n progress: z.number().int(),\n startedAt: z.string().nullable(),\n lastActivityAt: z.string().nullable(),\n completedAt: z.string().nullable(),\n});\nexport type StudentCourseProgress = z.infer<typeof StudentCourseProgress>;\n\nexport const StudentAnalytics = z.object({\n enrolled: z.number().int(),\n started: z.number().int(),\n completed: z.number().int(),\n avgProgress: z.number().int(),\n courses: z.array(StudentCourseProgress),\n});\nexport type StudentAnalytics = z.infer<typeof StudentAnalytics>;\n\nexport const StudentsQuery = ListQuery;\nexport type StudentsQuery = z.infer<typeof StudentsQuery>;\n\nexport const StudentsPage = paginated(Student);\nexport type StudentsPage = z.infer<typeof StudentsPage>;\n\nexport const StudentIdParam = z.object({ id: z.string() });\nexport type StudentIdParam = z.infer<typeof StudentIdParam>;\n"],"mappings":";;;AAIA,MAAa,gBAAgB,EAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;AAGzD,MAAa,UAAU,qBAAqB,OAAO;CACjD,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI;;CAEjC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI;;CAE5B,QAAQ;CACR,UAAU,EAAE,OAAO;CACnB,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;AACpC,CAAC;AAGD,MAAa,wBAAwB,EAAE,OAAO;CAC5C,UAAU,EAAE,OAAO;CACnB,OAAO,EAAE,OAAO;CAChB,iBAAiB,EAAE,OAAO,CAAC,CAAC,IAAI;CAChC,qBAAqB,EAAE,OAAO,CAAC,CAAC,IAAI;;CAEpC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CACzB,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,gBAAgB,EAAE,OAAO,CAAC,CAAC,SAAS;CACpC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS;AACnC,CAAC;AAGD,MAAa,mBAAmB,EAAE,OAAO;CACvC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI;CACzB,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI;CACxB,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI;CAC1B,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI;CAC5B,SAAS,EAAE,MAAM,qBAAqB;AACxC,CAAC;AAGD,MAAa,gBAAgB;AAG7B,MAAa,eAAe,UAAU,OAAO;AAG7C,MAAa,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC"}
@@ -17,6 +17,8 @@ interface OrgScope {
17
17
  /** Thrown when the session has no resolvable active org / domain user. */
18
18
  declare class NoActiveOrgError extends Error {}
19
19
  declare function resolveScope(container: Container, req: FastifyRequest): Promise<OrgScope>;
20
+ declare function resolveScopeFor(container: Container, authUserId: string, authOrgId: string): Promise<OrgScope>;
21
+ declare function resolveConfiguratorScope(container: Container, req: FastifyRequest): Promise<OrgScope>;
20
22
  //#endregion
21
- export { NoActiveOrgError, OrgScope, resolveScope };
23
+ export { NoActiveOrgError, OrgScope, resolveConfiguratorScope, resolveScope, resolveScopeFor };
22
24
  //# sourceMappingURL=scope.d.ts.map
@@ -1,15 +1,32 @@
1
1
  import { isStaffRole } from "@headless-lms/core/organizations";
2
+ import { ForbiddenError } from "@headless-lms/core/shared/errors";
2
3
  //#region src/http/scope.ts
3
4
  /** Thrown when the session has no resolvable active org / domain user. */
4
5
  var NoActiveOrgError = class extends Error {};
5
6
  async function resolveScope(container, req) {
6
7
  const authUser = req.authUser;
7
8
  const authOrgId = req.authOrgId ?? null;
8
- if (!authUser) throw new NoActiveOrgError("no authenticated user");
9
- if (!authOrgId || !req.orgId) throw new NoActiveOrgError("no active organization in session");
9
+ if (!authUser) throw new NoActiveOrgError("Sign in to continue");
10
+ if (!authOrgId || !req.orgId) throw new NoActiveOrgError("Choose an organization to continue");
10
11
  const org = await container.organizations.getById(req.orgId);
11
- if (!org) throw new NoActiveOrgError("active organization not found");
12
+ if (!org) throw new NoActiveOrgError("The active organization no longer exists");
12
13
  const user = await container.identity.getUserByExternalId(authUser.id);
14
+ if (!user) throw new NoActiveOrgError("Your account is not set up yet");
15
+ const orgUser = await container.organizations.getOrgUser(org.id, user.id);
16
+ if (!orgUser || !isStaffRole(orgUser.role)) throw new NoActiveOrgError("Only staff of this organization can do this");
17
+ container.requestContext.set({ orgId: org.id });
18
+ return {
19
+ orgId: org.id,
20
+ userId: user.id,
21
+ orgUserId: orgUser.id,
22
+ role: orgUser.role,
23
+ authOrgId
24
+ };
25
+ }
26
+ async function resolveScopeFor(container, authUserId, authOrgId) {
27
+ const org = await container.organizations.getByExternalId(authOrgId);
28
+ if (!org) throw new NoActiveOrgError("active organization not found");
29
+ const user = await container.identity.getUserByExternalId(authUserId);
13
30
  if (!user) throw new NoActiveOrgError("no domain user for the current user");
14
31
  const orgUser = await container.organizations.getOrgUser(org.id, user.id);
15
32
  if (!orgUser || !isStaffRole(orgUser.role)) throw new NoActiveOrgError("not a staff member of the active organization");
@@ -22,7 +39,12 @@ async function resolveScope(container, req) {
22
39
  authOrgId
23
40
  };
24
41
  }
42
+ async function resolveConfiguratorScope(container, req) {
43
+ const scope = await resolveScope(container, req);
44
+ if (scope.role !== "owner" && scope.role !== "admin") throw new ForbiddenError("Only an owner or an admin can configure notifications");
45
+ return scope;
46
+ }
25
47
  //#endregion
26
- export { NoActiveOrgError, resolveScope };
48
+ export { NoActiveOrgError, resolveConfiguratorScope, resolveScope, resolveScopeFor };
27
49
 
28
50
  //# sourceMappingURL=scope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","names":[],"sources":["../../src/http/scope.ts"],"sourcesContent":["import type { FastifyRequest } from 'fastify';\nimport type { Container } from '../app/container.js';\nimport { isStaffRole, type StaffRole } from '@headless-lms/core/organizations';\n\nexport interface OrgScope {\n /** Domain `organizations.id` for the session's active org. */\n orgId: string;\n /** Domain `users.id` of the acting person. */\n userId: string;\n /** Domain `org_users.id` — the acting org user in this org. */\n orgUserId: string;\n /** The role held in this org. */\n role: StaffRole;\n /** Better-auth organization id (for writes that go through the auth provider). */\n authOrgId: string;\n}\n\n/** Thrown when the session has no resolvable active org / domain user. */\nexport class NoActiveOrgError extends Error {}\n\nexport async function resolveScope(container: Container, req: FastifyRequest): Promise<OrgScope> {\n const authUser = req.authUser;\n const authOrgId = req.authOrgId ?? null;\n if (!authUser) {\n throw new NoActiveOrgError('no authenticated user');\n }\n if (!authOrgId || !req.orgId) {\n throw new NoActiveOrgError('no active organization in session');\n }\n // The session guard already translated the auth org id to the domain org.\n const org = await container.organizations.getById(req.orgId);\n if (!org) {\n throw new NoActiveOrgError('active organization not found');\n }\n const user = await container.identity.getUserByExternalId(authUser.id);\n if (!user) {\n throw new NoActiveOrgError('no domain user for the current user');\n }\n const orgUser = await container.organizations.getOrgUser(org.id, user.id);\n if (!orgUser || !isStaffRole(orgUser.role)) {\n throw new NoActiveOrgError('not a staff member of the active organization');\n }\n container.requestContext.set({ orgId: org.id });\n return {\n orgId: org.id,\n userId: user.id,\n orgUserId: orgUser.id,\n role: orgUser.role,\n authOrgId,\n };\n}\n"],"mappings":";;;AAkBA,IAAa,mBAAb,cAAsC,MAAM,CAAC;AAE7C,eAAsB,aAAa,WAAsB,KAAwC;CAC/F,MAAM,WAAW,IAAI;CACrB,MAAM,YAAY,IAAI,aAAa;CACnC,IAAI,CAAC,UACH,MAAM,IAAI,iBAAiB,uBAAuB;CAEpD,IAAI,CAAC,aAAa,CAAC,IAAI,OACrB,MAAM,IAAI,iBAAiB,mCAAmC;CAGhE,MAAM,MAAM,MAAM,UAAU,cAAc,QAAQ,IAAI,KAAK;CAC3D,IAAI,CAAC,KACH,MAAM,IAAI,iBAAiB,+BAA+B;CAE5D,MAAM,OAAO,MAAM,UAAU,SAAS,oBAAoB,SAAS,EAAE;CACrE,IAAI,CAAC,MACH,MAAM,IAAI,iBAAiB,qCAAqC;CAElE,MAAM,UAAU,MAAM,UAAU,cAAc,WAAW,IAAI,IAAI,KAAK,EAAE;CACxE,IAAI,CAAC,WAAW,CAAC,YAAY,QAAQ,IAAI,GACvC,MAAM,IAAI,iBAAiB,+CAA+C;CAE5E,UAAU,eAAe,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC;CAC9C,OAAO;EACL,OAAO,IAAI;EACX,QAAQ,KAAK;EACb,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd;CACF;AACF"}
1
+ {"version":3,"file":"scope.js","names":[],"sources":["../../src/http/scope.ts"],"sourcesContent":["import type { FastifyRequest } from 'fastify';\nimport type { Container } from '../app/container.js';\nimport { isStaffRole, type StaffRole } from '@headless-lms/core/organizations';\nimport { ForbiddenError } from '@headless-lms/core/shared/errors';\n\nexport interface OrgScope {\n /** Domain `organizations.id` for the session's active org. */\n orgId: string;\n /** Domain `users.id` of the acting person. */\n userId: string;\n /** Domain `org_users.id` — the acting org user in this org. */\n orgUserId: string;\n /** The role held in this org. */\n role: StaffRole;\n /** Better-auth organization id (for writes that go through the auth provider). */\n authOrgId: string;\n}\n\n/** Thrown when the session has no resolvable active org / domain user. */\nexport class NoActiveOrgError extends Error {}\n\nexport async function resolveScope(container: Container, req: FastifyRequest): Promise<OrgScope> {\n const authUser = req.authUser;\n const authOrgId = req.authOrgId ?? null;\n if (!authUser) {\n throw new NoActiveOrgError('Sign in to continue');\n }\n if (!authOrgId || !req.orgId) {\n throw new NoActiveOrgError('Choose an organization to continue');\n }\n // The session guard already translated the auth org id to the domain org.\n const org = await container.organizations.getById(req.orgId);\n if (!org) {\n throw new NoActiveOrgError('The active organization no longer exists');\n }\n const user = await container.identity.getUserByExternalId(authUser.id);\n if (!user) {\n throw new NoActiveOrgError('Your account is not set up yet');\n }\n const orgUser = await container.organizations.getOrgUser(org.id, user.id);\n if (!orgUser || !isStaffRole(orgUser.role)) {\n throw new NoActiveOrgError('Only staff of this organization can do this');\n }\n container.requestContext.set({ orgId: org.id });\n return {\n orgId: org.id,\n userId: user.id,\n orgUserId: orgUser.id,\n role: orgUser.role,\n authOrgId,\n };\n}\n\nexport async function resolveScopeFor(\n container: Container,\n authUserId: string,\n authOrgId: string,\n): Promise<OrgScope> {\n const org = await container.organizations.getByExternalId(authOrgId);\n if (!org) {\n throw new NoActiveOrgError('active organization not found');\n }\n const user = await container.identity.getUserByExternalId(authUserId);\n if (!user) {\n throw new NoActiveOrgError('no domain user for the current user');\n }\n const orgUser = await container.organizations.getOrgUser(org.id, user.id);\n if (!orgUser || !isStaffRole(orgUser.role)) {\n throw new NoActiveOrgError('not a staff member of the active organization');\n }\n container.requestContext.set({ orgId: org.id });\n return { orgId: org.id, userId: user.id, orgUserId: orgUser.id, role: orgUser.role, authOrgId };\n}\n\nexport async function resolveConfiguratorScope(\n container: Container,\n req: FastifyRequest,\n): Promise<OrgScope> {\n const scope = await resolveScope(container, req);\n if (scope.role !== 'owner' && scope.role !== 'admin') {\n throw new ForbiddenError('Only an owner or an admin can configure notifications');\n }\n return scope;\n}\n"],"mappings":";;;;AAmBA,IAAa,mBAAb,cAAsC,MAAM,CAAC;AAE7C,eAAsB,aAAa,WAAsB,KAAwC;CAC/F,MAAM,WAAW,IAAI;CACrB,MAAM,YAAY,IAAI,aAAa;CACnC,IAAI,CAAC,UACH,MAAM,IAAI,iBAAiB,qBAAqB;CAElD,IAAI,CAAC,aAAa,CAAC,IAAI,OACrB,MAAM,IAAI,iBAAiB,oCAAoC;CAGjE,MAAM,MAAM,MAAM,UAAU,cAAc,QAAQ,IAAI,KAAK;CAC3D,IAAI,CAAC,KACH,MAAM,IAAI,iBAAiB,0CAA0C;CAEvE,MAAM,OAAO,MAAM,UAAU,SAAS,oBAAoB,SAAS,EAAE;CACrE,IAAI,CAAC,MACH,MAAM,IAAI,iBAAiB,gCAAgC;CAE7D,MAAM,UAAU,MAAM,UAAU,cAAc,WAAW,IAAI,IAAI,KAAK,EAAE;CACxE,IAAI,CAAC,WAAW,CAAC,YAAY,QAAQ,IAAI,GACvC,MAAM,IAAI,iBAAiB,6CAA6C;CAE1E,UAAU,eAAe,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC;CAC9C,OAAO;EACL,OAAO,IAAI;EACX,QAAQ,KAAK;EACb,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd;CACF;AACF;AAEA,eAAsB,gBACpB,WACA,YACA,WACmB;CACnB,MAAM,MAAM,MAAM,UAAU,cAAc,gBAAgB,SAAS;CACnE,IAAI,CAAC,KACH,MAAM,IAAI,iBAAiB,+BAA+B;CAE5D,MAAM,OAAO,MAAM,UAAU,SAAS,oBAAoB,UAAU;CACpE,IAAI,CAAC,MACH,MAAM,IAAI,iBAAiB,qCAAqC;CAElE,MAAM,UAAU,MAAM,UAAU,cAAc,WAAW,IAAI,IAAI,KAAK,EAAE;CACxE,IAAI,CAAC,WAAW,CAAC,YAAY,QAAQ,IAAI,GACvC,MAAM,IAAI,iBAAiB,+CAA+C;CAE5E,UAAU,eAAe,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC;CAC9C,OAAO;EAAE,OAAO,IAAI;EAAI,QAAQ,KAAK;EAAI,WAAW,QAAQ;EAAI,MAAM,QAAQ;EAAM;CAAU;AAChG;AAEA,eAAsB,yBACpB,WACA,KACmB;CACnB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;CAC/C,IAAI,MAAM,SAAS,WAAW,MAAM,SAAS,SAC3C,MAAM,IAAI,eAAe,uDAAuD;CAElF,OAAO;AACT"}
@@ -1,8 +1,10 @@
1
1
  import { registerCors } from "./plugins/cors.js";
2
2
  import { registerOpenApi } from "./plugins/openapi.js";
3
3
  import { registerAuth } from "./plugins/auth.js";
4
- import { errorHandler } from "./plugins/error-handler.js";
4
+ import { registerWellKnown } from "./well-known.js";
5
+ import { errorHandler, notFoundHandler } from "./plugins/error-handler.js";
5
6
  import { registerRoutes } from "./routes.js";
7
+ import { registerMcp } from "./mcp/route.js";
6
8
  import Fastify from "fastify";
7
9
  import { serializerCompiler, validatorCompiler } from "fastify-type-provider-zod";
8
10
  //#region src/http/server.ts
@@ -19,10 +21,13 @@ async function buildServer(config, container) {
19
21
  app.setValidatorCompiler(validatorCompiler);
20
22
  app.setSerializerCompiler(serializerCompiler);
21
23
  app.setErrorHandler(errorHandler);
24
+ app.setNotFoundHandler(notFoundHandler);
22
25
  registerCors(app, config);
23
26
  registerOpenApi(app, config);
24
27
  registerAuth(app, container);
28
+ if (container.mcp.oauthEnabled) registerWellKnown(app, container);
25
29
  registerRoutes(app, container);
30
+ registerMcp(app, container);
26
31
  app.addHook("onClose", async () => {
27
32
  await container.outboxRelay.stop();
28
33
  await container.automationEngine.stop();
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../../src/http/server.ts"],"sourcesContent":["import Fastify, { type FastifyBaseLogger, type FastifyInstance } from 'fastify';\nimport { serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';\nimport type { Container } from '../app/container.js';\nimport type { ServerConfig } from './config.js';\nimport { registerCors } from './plugins/cors.js';\nimport { registerOpenApi } from './plugins/openapi.js';\nimport { registerAuth } from './plugins/auth.js';\nimport { errorHandler } from './plugins/error-handler.js';\nimport { registerRoutes } from './routes.js';\n\nexport async function buildServer(\n config: ServerConfig,\n container: Container,\n): Promise<FastifyInstance> {\n // One log stream for the whole process: HTTP shares the container's pino root.\n // Widened to FastifyBaseLogger so the instance keeps the default logger\n // generic (a concrete pino type would ripple through every plugin signature).\n const app = Fastify({\n loggerInstance: container.loggerInstance as FastifyBaseLogger,\n // Fastify's own request/response pair per call — noisy in a dev console,\n // useful as an access log in production. Our own logs are unaffected.\n disableRequestLogging: config.requestLogging === false,\n // Adopt the caller's correlation id when it sends one, so one id joins\n // the client's log line to this process's.\n requestIdHeader: 'x-request-id',\n });\n\n // Enter the request-scoped log context: every line logged inside this\n // request's async scope carries its reqId (and orgId once resolveScope runs),\n // wherever it is emitted. The id is echoed on the response so callers can\n // quote it when reporting a failure.\n app.addHook('onRequest', (request, reply, done) => {\n reply.header('x-request-id', request.id);\n container.requestContext.run({ reqId: request.id }, done);\n });\n\n // Validate + serialize request/response bodies from the shared Zod contract.\n app.setValidatorCompiler(validatorCompiler);\n app.setSerializerCompiler(serializerCompiler);\n app.setErrorHandler(errorHandler);\n\n registerCors(app, config);\n registerOpenApi(app, config);\n registerAuth(app, container);\n\n registerRoutes(app, container);\n\n // Drain + stop the outbox relay and the automation engine on shutdown.\n // Harmless when neither was started (gen-openapi boots this app with\n // ready() + close() only).\n app.addHook('onClose', async () => {\n await container.outboxRelay.stop();\n await container.automationEngine.stop();\n });\n\n return app;\n}\n"],"mappings":";;;;;;;;AAUA,eAAsB,YACpB,QACA,WAC0B;CAI1B,MAAM,MAAM,QAAQ;EAClB,gBAAgB,UAAU;EAG1B,uBAAuB,OAAO,mBAAmB;EAGjD,iBAAiB;CACnB,CAAC;CAMD,IAAI,QAAQ,cAAc,SAAS,OAAO,SAAS;EACjD,MAAM,OAAO,gBAAgB,QAAQ,EAAE;EACvC,UAAU,eAAe,IAAI,EAAE,OAAO,QAAQ,GAAG,GAAG,IAAI;CAC1D,CAAC;CAGD,IAAI,qBAAqB,iBAAiB;CAC1C,IAAI,sBAAsB,kBAAkB;CAC5C,IAAI,gBAAgB,YAAY;CAEhC,aAAa,KAAK,MAAM;CACxB,gBAAgB,KAAK,MAAM;CAC3B,aAAa,KAAK,SAAS;CAE3B,eAAe,KAAK,SAAS;CAK7B,IAAI,QAAQ,WAAW,YAAY;EACjC,MAAM,UAAU,YAAY,KAAK;EACjC,MAAM,UAAU,iBAAiB,KAAK;CACxC,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../../src/http/server.ts"],"sourcesContent":["import Fastify, { type FastifyBaseLogger, type FastifyInstance } from 'fastify';\nimport { serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';\nimport type { Container } from '../app/container.js';\nimport type { ServerConfig } from './config.js';\nimport { registerCors } from './plugins/cors.js';\nimport { registerOpenApi } from './plugins/openapi.js';\nimport { registerAuth } from './plugins/auth.js';\nimport { registerWellKnown } from './well-known.js';\nimport { errorHandler, notFoundHandler } from './plugins/error-handler.js';\nimport { registerRoutes } from './routes.js';\nimport { registerMcp } from './mcp/route.js';\n\nexport async function buildServer(\n config: ServerConfig,\n container: Container,\n): Promise<FastifyInstance> {\n // One log stream for the whole process: HTTP shares the container's pino root.\n // Widened to FastifyBaseLogger so the instance keeps the default logger\n // generic (a concrete pino type would ripple through every plugin signature).\n const app = Fastify({\n loggerInstance: container.loggerInstance as FastifyBaseLogger,\n // Fastify's own request/response pair per call — noisy in a dev console,\n // useful as an access log in production. Our own logs are unaffected.\n disableRequestLogging: config.requestLogging === false,\n // Adopt the caller's correlation id when it sends one, so one id joins\n // the client's log line to this process's.\n requestIdHeader: 'x-request-id',\n });\n\n // Enter the request-scoped log context: every line logged inside this\n // request's async scope carries its reqId (and orgId once resolveScope runs),\n // wherever it is emitted. The id is echoed on the response so callers can\n // quote it when reporting a failure.\n app.addHook('onRequest', (request, reply, done) => {\n reply.header('x-request-id', request.id);\n container.requestContext.run({ reqId: request.id }, done);\n });\n\n // Validate + serialize request/response bodies from the shared Zod contract.\n app.setValidatorCompiler(validatorCompiler);\n app.setSerializerCompiler(serializerCompiler);\n app.setErrorHandler(errorHandler);\n app.setNotFoundHandler(notFoundHandler);\n\n registerCors(app, config);\n registerOpenApi(app, config);\n registerAuth(app, container);\n if (container.mcp.oauthEnabled) {\n registerWellKnown(app, container);\n }\n\n registerRoutes(app, container);\n registerMcp(app, container);\n\n // Drain + stop the outbox relay and the automation engine on shutdown.\n // Harmless when neither was started (gen-openapi boots this app with\n // ready() + close() only).\n app.addHook('onClose', async () => {\n await container.outboxRelay.stop();\n await container.automationEngine.stop();\n });\n\n return app;\n}\n"],"mappings":";;;;;;;;;;AAYA,eAAsB,YACpB,QACA,WAC0B;CAI1B,MAAM,MAAM,QAAQ;EAClB,gBAAgB,UAAU;EAG1B,uBAAuB,OAAO,mBAAmB;EAGjD,iBAAiB;CACnB,CAAC;CAMD,IAAI,QAAQ,cAAc,SAAS,OAAO,SAAS;EACjD,MAAM,OAAO,gBAAgB,QAAQ,EAAE;EACvC,UAAU,eAAe,IAAI,EAAE,OAAO,QAAQ,GAAG,GAAG,IAAI;CAC1D,CAAC;CAGD,IAAI,qBAAqB,iBAAiB;CAC1C,IAAI,sBAAsB,kBAAkB;CAC5C,IAAI,gBAAgB,YAAY;CAChC,IAAI,mBAAmB,eAAe;CAEtC,aAAa,KAAK,MAAM;CACxB,gBAAgB,KAAK,MAAM;CAC3B,aAAa,KAAK,SAAS;CAC3B,IAAI,UAAU,IAAI,cAChB,kBAAkB,KAAK,SAAS;CAGlC,eAAe,KAAK,SAAS;CAC7B,YAAY,KAAK,SAAS;CAK1B,IAAI,QAAQ,WAAW,YAAY;EACjC,MAAM,UAAU,YAAY,KAAK;EACjC,MAAM,UAAU,iBAAiB,KAAK;CACxC,CAAC;CAED,OAAO;AACT"}
@@ -1,7 +1,7 @@
1
1
  import { FastifyReply, FastifyRequest } from "fastify";
2
2
  //#region src/http/web-bridge.d.ts
3
3
  /** Builds a Web `Request` from an incoming Fastify request. */
4
- declare function toWebRequest(request: FastifyRequest): Request;
4
+ declare function toWebRequest(request: FastifyRequest, origin: string): Request;
5
5
  /** Copies a Web `Response` back onto a Fastify reply, preserving multiple cookies. */
6
6
  declare function bridgeWebResponse(response: Response, reply: FastifyReply): Promise<void>;
7
7
  //#endregion
@@ -1,8 +1,8 @@
1
1
  import { fromNodeHeaders } from "better-auth/node";
2
2
  //#region src/http/web-bridge.ts
3
3
  /** Builds a Web `Request` from an incoming Fastify request. */
4
- function toWebRequest(request) {
5
- const url = new URL(request.url, `http://${request.headers.host}`);
4
+ function toWebRequest(request, origin) {
5
+ const url = new URL(request.url, origin);
6
6
  const body = request.method !== "GET" && request.method !== "HEAD" && request.method !== "DELETE" ? typeof request.body === "string" ? request.body : request.body ? JSON.stringify(request.body) : void 0 : void 0;
7
7
  return new Request(url.toString(), {
8
8
  method: request.method,
@@ -1 +1 @@
1
- {"version":3,"file":"web-bridge.js","names":[],"sources":["../../src/http/web-bridge.ts"],"sourcesContent":["// Bridges between Fastify's request/reply and the Web `Request`/`Response` that\n// better-auth speaks. The auth catch-all hands a Fastify request to a\n// Web-standard handler and forwards the\n// Web response back, so the conversion lives here once.\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { fromNodeHeaders } from 'better-auth/node';\n\n/** Builds a Web `Request` from an incoming Fastify request. */\nexport function toWebRequest(request: FastifyRequest): Request {\n const url = new URL(request.url, `http://${request.headers.host}`);\n // GET/HEAD/DELETE never carry a body; passing one to `Request` throws. For the\n // rest, forward a string body verbatim and JSON-encode a parsed object.\n const hasBody =\n request.method !== 'GET' && request.method !== 'HEAD' && request.method !== 'DELETE';\n const body = hasBody\n ? typeof request.body === 'string'\n ? request.body\n : request.body\n ? JSON.stringify(request.body)\n : undefined\n : undefined;\n return new Request(url.toString(), {\n method: request.method,\n headers: fromNodeHeaders(request.headers),\n body,\n });\n}\n\n/** Copies a Web `Response` back onto a Fastify reply, preserving multiple cookies. */\nexport async function bridgeWebResponse(response: Response, reply: FastifyReply): Promise<void> {\n reply.status(response.status);\n // Emit each Set-Cookie value individually — forEach() collapses multiple\n // Set-Cookie headers into one comma-joined string (undici behaviour), which\n // corrupts multi-cookie auth responses. getSetCookie() returns them as an\n // array so each one is forwarded as a separate header.\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) {\n reply.raw.setHeader('set-cookie', cookies);\n }\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') {\n return;\n } // already handled above\n reply.header(key, value);\n });\n reply.send(response.body ? await response.text() : null);\n}\n"],"mappings":";;;AAQA,SAAgB,aAAa,SAAkC;CAC7D,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,UAAU,QAAQ,QAAQ,MAAM;CAKjE,MAAM,OADJ,QAAQ,WAAW,SAAS,QAAQ,WAAW,UAAU,QAAQ,WAAW,WAE1E,OAAO,QAAQ,SAAS,WACtB,QAAQ,OACR,QAAQ,OACN,KAAK,UAAU,QAAQ,IAAI,IAC3B,KAAA,IACJ,KAAA;CACJ,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG;EACjC,QAAQ,QAAQ;EAChB,SAAS,gBAAgB,QAAQ,OAAO;EACxC;CACF,CAAC;AACH;;AAGA,eAAsB,kBAAkB,UAAoB,OAAoC;CAC9F,MAAM,OAAO,SAAS,MAAM;CAK5B,MAAM,UAAU,SAAS,QAAQ,aAAa;CAC9C,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,UAAU,cAAc,OAAO;CAE3C,SAAS,QAAQ,SAAS,OAAO,QAAQ;EACvC,IAAI,IAAI,YAAY,MAAM,cACxB;EAEF,MAAM,OAAO,KAAK,KAAK;CACzB,CAAC;CACD,MAAM,KAAK,SAAS,OAAO,MAAM,SAAS,KAAK,IAAI,IAAI;AACzD"}
1
+ {"version":3,"file":"web-bridge.js","names":[],"sources":["../../src/http/web-bridge.ts"],"sourcesContent":["// Bridges between Fastify's request/reply and the Web `Request`/`Response` that\n// better-auth speaks. The auth catch-all hands a Fastify request to a\n// Web-standard handler and forwards the\n// Web response back, so the conversion lives here once.\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { fromNodeHeaders } from 'better-auth/node';\n\n/** Builds a Web `Request` from an incoming Fastify request. */\nexport function toWebRequest(request: FastifyRequest, origin: string): Request {\n const url = new URL(request.url, origin);\n // GET/HEAD/DELETE never carry a body; passing one to `Request` throws. For the\n // rest, forward a string body verbatim and JSON-encode a parsed object.\n const hasBody =\n request.method !== 'GET' && request.method !== 'HEAD' && request.method !== 'DELETE';\n const body = hasBody\n ? typeof request.body === 'string'\n ? request.body\n : request.body\n ? JSON.stringify(request.body)\n : undefined\n : undefined;\n return new Request(url.toString(), {\n method: request.method,\n headers: fromNodeHeaders(request.headers),\n body,\n });\n}\n\n/** Copies a Web `Response` back onto a Fastify reply, preserving multiple cookies. */\nexport async function bridgeWebResponse(response: Response, reply: FastifyReply): Promise<void> {\n reply.status(response.status);\n // Emit each Set-Cookie value individually — forEach() collapses multiple\n // Set-Cookie headers into one comma-joined string (undici behaviour), which\n // corrupts multi-cookie auth responses. getSetCookie() returns them as an\n // array so each one is forwarded as a separate header.\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) {\n reply.raw.setHeader('set-cookie', cookies);\n }\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') {\n return;\n } // already handled above\n reply.header(key, value);\n });\n reply.send(response.body ? await response.text() : null);\n}\n"],"mappings":";;;AAQA,SAAgB,aAAa,SAAyB,QAAyB;CAC7E,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,MAAM;CAKvC,MAAM,OADJ,QAAQ,WAAW,SAAS,QAAQ,WAAW,UAAU,QAAQ,WAAW,WAE1E,OAAO,QAAQ,SAAS,WACtB,QAAQ,OACR,QAAQ,OACN,KAAK,UAAU,QAAQ,IAAI,IAC3B,KAAA,IACJ,KAAA;CACJ,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG;EACjC,QAAQ,QAAQ;EAChB,SAAS,gBAAgB,QAAQ,OAAO;EACxC;CACF,CAAC;AACH;;AAGA,eAAsB,kBAAkB,UAAoB,OAAoC;CAC9F,MAAM,OAAO,SAAS,MAAM;CAK5B,MAAM,UAAU,SAAS,QAAQ,aAAa;CAC9C,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,UAAU,cAAc,OAAO;CAE3C,SAAS,QAAQ,SAAS,OAAO,QAAQ;EACvC,IAAI,IAAI,YAAY,MAAM,cACxB;EAEF,MAAM,OAAO,KAAK,KAAK;CACzB,CAAC;CACD,MAAM,KAAK,SAAS,OAAO,MAAM,SAAS,KAAK,IAAI,IAAI;AACzD"}
@@ -0,0 +1,7 @@
1
+ import { Container } from "../app/container.js";
2
+ import { FastifyInstance } from "fastify";
3
+ //#region src/http/well-known.d.ts
4
+ declare function registerWellKnown(app: FastifyInstance, container: Container): void;
5
+ //#endregion
6
+ export { registerWellKnown };
7
+ //# sourceMappingURL=well-known.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { bridgeWebResponse, toWebRequest } from "./web-bridge.js";
2
+ import { ACCESS_SCOPES } from "@headless-lms/core/organizations";
3
+ //#region src/http/well-known.ts
4
+ function registerWellKnown(app, container) {
5
+ const origin = new URL(container.mcp.issuer).origin;
6
+ const resourceMetadata = () => ({
7
+ resource: container.mcp.resource,
8
+ authorization_servers: [container.mcp.issuer],
9
+ scopes_supported: [...ACCESS_SCOPES],
10
+ bearer_methods_supported: ["header"]
11
+ });
12
+ const hidden = { schema: { hide: true } };
13
+ app.get("/.well-known/oauth-protected-resource/mcp", hidden, async () => resourceMetadata());
14
+ app.get("/.well-known/oauth-protected-resource", hidden, async () => resourceMetadata());
15
+ app.get("/.well-known/oauth-authorization-server/api/auth", hidden, async (request, reply) => {
16
+ await bridgeWebResponse(await container.auth.authorizationServerMetadata(toWebRequest(request, origin)), reply);
17
+ });
18
+ }
19
+ //#endregion
20
+ export { registerWellKnown };
21
+
22
+ //# sourceMappingURL=well-known.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"well-known.js","names":[],"sources":["../../src/http/well-known.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport { ACCESS_SCOPES } from '@headless-lms/core/organizations';\nimport type { Container } from '../app/container.js';\nimport { bridgeWebResponse, toWebRequest } from './web-bridge.js';\n\nexport function registerWellKnown(app: FastifyInstance, container: Container): void {\n const origin = new URL(container.mcp.issuer).origin;\n const resourceMetadata = () => ({\n resource: container.mcp.resource,\n authorization_servers: [container.mcp.issuer],\n scopes_supported: [...ACCESS_SCOPES],\n bearer_methods_supported: ['header'],\n });\n const hidden = { schema: { hide: true } };\n\n app.get('/.well-known/oauth-protected-resource/mcp', hidden, async () => resourceMetadata());\n app.get('/.well-known/oauth-protected-resource', hidden, async () => resourceMetadata());\n app.get('/.well-known/oauth-authorization-server/api/auth', hidden, async (request, reply) => {\n await bridgeWebResponse(\n await container.auth.authorizationServerMetadata(toWebRequest(request, origin)),\n reply,\n );\n });\n}\n"],"mappings":";;;AAKA,SAAgB,kBAAkB,KAAsB,WAA4B;CAClF,MAAM,SAAS,IAAI,IAAI,UAAU,IAAI,MAAM,CAAC,CAAC;CAC7C,MAAM,0BAA0B;EAC9B,UAAU,UAAU,IAAI;EACxB,uBAAuB,CAAC,UAAU,IAAI,MAAM;EAC5C,kBAAkB,CAAC,GAAG,aAAa;EACnC,0BAA0B,CAAC,QAAQ;CACrC;CACA,MAAM,SAAS,EAAE,QAAQ,EAAE,MAAM,KAAK,EAAE;CAExC,IAAI,IAAI,6CAA6C,QAAQ,YAAY,iBAAiB,CAAC;CAC3F,IAAI,IAAI,yCAAyC,QAAQ,YAAY,iBAAiB,CAAC;CACvF,IAAI,IAAI,oDAAoD,QAAQ,OAAO,SAAS,UAAU;EAC5F,MAAM,kBACJ,MAAM,UAAU,KAAK,4BAA4B,aAAa,SAAS,MAAM,CAAC,GAC9E,KACF;CACF,CAAC;AACH"}
package/dist/index.d.ts CHANGED
@@ -2,14 +2,16 @@ import { AuthUser } from "./http/fastify.js";
2
2
  import { AdapterOverrides, BuildContainerOptions, Config, Container, LoggingConfig } from "./app/container.js";
3
3
  import { loadIntegrations } from "./app/integrations.js";
4
4
  import { ServerConfig } from "./http/config.js";
5
+ import { CatalogueField, CatalogueScope, CatalogueTool, McpCatalogue, mcpCatalogue } from "./http/mcp/catalogue.js";
5
6
  import { buildServer } from "./http/server.js";
6
7
  import { runMigrations } from "@headless-lms/adapter-db";
7
8
  import { InlineAutomationEngine } from "@headless-lms/adapter-defaults/workflows";
8
9
  import { AutomationEngine, WebhookSender } from "@headless-lms/core/automations";
9
10
  import { Mailer } from "@headless-lms/core/shared/mailer";
11
+ import { PushConfig } from "@headless-lms/core/types";
10
12
  import { EmailMessage, EmailSender, ObjectStorage } from "@headless-lms/core/shared/ports";
11
13
  //#region src/index.d.ts
12
14
  declare function createContainer(config: ServerConfig, options?: BuildContainerOptions): Promise<Container>;
13
15
  //#endregion
14
- export { type AdapterOverrides, type AuthUser, type AutomationEngine, type BuildContainerOptions, type Container, type Config as ContainerConfig, type EmailMessage, type EmailSender, InlineAutomationEngine, type LoggingConfig, type Mailer, type ObjectStorage, type ServerConfig, type WebhookSender, buildServer, createContainer, loadIntegrations, runMigrations };
16
+ export { type AdapterOverrides, type AuthUser, type AutomationEngine, type BuildContainerOptions, type CatalogueField, type CatalogueScope, type CatalogueTool, type Container, type Config as ContainerConfig, type EmailMessage, type EmailSender, InlineAutomationEngine, type LoggingConfig, type Mailer, type McpCatalogue, type ObjectStorage, type PushConfig, type ServerConfig, type WebhookSender, buildServer, createContainer, loadIntegrations, mcpCatalogue, runMigrations };
15
17
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,16 +1,18 @@
1
1
  import { loadIntegrations } from "./app/integrations.js";
2
2
  import { buildContainer } from "./app/container.js";
3
3
  import { buildServer } from "./http/server.js";
4
+ import { mcpCatalogue } from "./http/mcp/catalogue.js";
4
5
  import { runMigrations } from "@headless-lms/adapter-db";
5
6
  import { InlineAutomationEngine } from "@headless-lms/adapter-defaults/workflows";
6
7
  //#region src/index.ts
7
8
  async function createContainer(config, options) {
8
9
  return buildContainer({
9
10
  ...config.container,
10
- deliveryExpirySeconds: config.deliveryExpirySeconds
11
+ deliveryExpirySeconds: config.deliveryExpirySeconds,
12
+ memberImageMaxBytes: config.memberImageMaxBytes
11
13
  }, options);
12
14
  }
13
15
  //#endregion
14
- export { InlineAutomationEngine, buildServer, createContainer, loadIntegrations, runMigrations };
16
+ export { InlineAutomationEngine, buildServer, createContainer, loadIntegrations, mcpCatalogue, runMigrations };
15
17
 
16
18
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["// Public surface of @headless-lms/server. Installations compose these:\n// const container = await createContainer(config, { pluginsDir, adapters })\n// const app = await buildServer(config, container)\nimport { buildContainer, type BuildContainerOptions, type Container } from './app/container.js';\nimport type { ServerConfig } from './http/config.js';\n\nexport { buildServer } from './http/server.js';\nexport { loadIntegrations } from './app/integrations.js';\nexport { InlineAutomationEngine } from '@headless-lms/adapter-defaults/workflows';\n// Operational functions consumed by the @headless-lms/cli bin.\nexport { runMigrations } from '@headless-lms/adapter-db';\nexport type { ServerConfig } from './http/config.js';\n// Re-exporting AuthUser also pulls its module into any program that imports\n// this file (directly or via the workspace path mapping), which is what\n// applies its ambient `declare module \"fastify\"` augmentation\n// (FastifyRequest.authUser/orgId, FastifyInstance.requireOrgSession) —\n// otherwise nothing imports fastify.d.ts and the augmentation never loads.\nexport type { AuthUser } from './http/fastify.js';\nexport type {\n Config as ContainerConfig,\n Container,\n AdapterOverrides,\n BuildContainerOptions,\n LoggingConfig,\n} from './app/container.js';\nexport type { EmailSender, EmailMessage, ObjectStorage } from '@headless-lms/core/shared/ports';\nexport type { Mailer } from '@headless-lms/core/shared/mailer';\nexport type { AutomationEngine, WebhookSender } from '@headless-lms/core/automations';\n\nexport async function createContainer(\n config: ServerConfig,\n options?: BuildContainerOptions,\n): Promise<Container> {\n return buildContainer(\n { ...config.container, deliveryExpirySeconds: config.deliveryExpirySeconds },\n options,\n );\n}\n"],"mappings":";;;;;;AA6BA,eAAsB,gBACpB,QACA,SACoB;CACpB,OAAO,eACL;EAAE,GAAG,OAAO;EAAW,uBAAuB,OAAO;CAAsB,GAC3E,OACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["// Public surface of @headless-lms/server. Installations compose these:\n// const container = await createContainer(config, { pluginsDir, adapters })\n// const app = await buildServer(config, container)\nimport { buildContainer, type BuildContainerOptions, type Container } from './app/container.js';\nimport type { ServerConfig } from './http/config.js';\n\nexport { buildServer } from './http/server.js';\nexport { mcpCatalogue } from './http/mcp/catalogue.js';\nexport type {\n CatalogueField,\n CatalogueScope,\n CatalogueTool,\n McpCatalogue,\n} from './http/mcp/catalogue.js';\nexport { loadIntegrations } from './app/integrations.js';\nexport { InlineAutomationEngine } from '@headless-lms/adapter-defaults/workflows';\n// Operational functions consumed by the @headless-lms/cli bin.\nexport { runMigrations } from '@headless-lms/adapter-db';\nexport type { ServerConfig } from './http/config.js';\n// Re-exporting AuthUser also pulls its module into any program that imports\n// this file (directly or via the workspace path mapping), which is what\n// applies its ambient `declare module \"fastify\"` augmentation\n// (FastifyRequest.authUser/orgId, FastifyInstance.requireOrgSession) —\n// otherwise nothing imports fastify.d.ts and the augmentation never loads.\nexport type { AuthUser } from './http/fastify.js';\nexport type {\n Config as ContainerConfig,\n Container,\n AdapterOverrides,\n BuildContainerOptions,\n LoggingConfig,\n} from './app/container.js';\nexport type { EmailSender, EmailMessage, ObjectStorage } from '@headless-lms/core/shared/ports';\nexport type { Mailer } from '@headless-lms/core/shared/mailer';\nexport type { AutomationEngine, WebhookSender } from '@headless-lms/core/automations';\nexport type { PushConfig } from '@headless-lms/core/types';\n\nexport async function createContainer(\n config: ServerConfig,\n options?: BuildContainerOptions,\n): Promise<Container> {\n return buildContainer(\n {\n ...config.container,\n deliveryExpirySeconds: config.deliveryExpirySeconds,\n memberImageMaxBytes: config.memberImageMaxBytes,\n },\n options,\n );\n}\n"],"mappings":";;;;;;;AAqCA,eAAsB,gBACpB,QACA,SACoB;CACpB,OAAO,eACL;EACE,GAAG,OAAO;EACV,uBAAuB,OAAO;EAC9B,qBAAqB,OAAO;CAC9B,GACA,OACF;AACF"}
@@ -0,0 +1,78 @@
1
+ //#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
2
+ var comma = ",".charCodeAt(0);
3
+ var semicolon = ";".charCodeAt(0);
4
+ var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5
+ var intToChar = /* @__PURE__ */ new Uint8Array(64);
6
+ var charToInt = /* @__PURE__ */ new Uint8Array(128);
7
+ for (let i = 0; i < chars.length; i++) {
8
+ const c = chars.charCodeAt(i);
9
+ intToChar[i] = c;
10
+ charToInt[c] = i;
11
+ }
12
+ function encodeInteger(builder, num, relative) {
13
+ let delta = num - relative;
14
+ delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
15
+ do {
16
+ let clamped = delta & 31;
17
+ delta >>>= 5;
18
+ if (delta > 0) clamped |= 32;
19
+ builder.write(intToChar[clamped]);
20
+ } while (delta > 0);
21
+ return num;
22
+ }
23
+ var bufLength = 1024 * 16;
24
+ var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? { decode(buf) {
25
+ return Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength).toString();
26
+ } } : { decode(buf) {
27
+ let out = "";
28
+ for (let i = 0; i < buf.length; i++) out += String.fromCharCode(buf[i]);
29
+ return out;
30
+ } };
31
+ var StringWriter = class {
32
+ constructor() {
33
+ this.pos = 0;
34
+ this.out = "";
35
+ this.buffer = new Uint8Array(bufLength);
36
+ }
37
+ write(v) {
38
+ const { buffer } = this;
39
+ buffer[this.pos++] = v;
40
+ if (this.pos === bufLength) {
41
+ this.out += td.decode(buffer);
42
+ this.pos = 0;
43
+ }
44
+ }
45
+ flush() {
46
+ const { buffer, out, pos } = this;
47
+ return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
48
+ }
49
+ };
50
+ function encode(decoded) {
51
+ const writer = new StringWriter();
52
+ let sourcesIndex = 0;
53
+ let sourceLine = 0;
54
+ let sourceColumn = 0;
55
+ let namesIndex = 0;
56
+ for (let i = 0; i < decoded.length; i++) {
57
+ const line = decoded[i];
58
+ if (i > 0) writer.write(semicolon);
59
+ if (line.length === 0) continue;
60
+ let genColumn = 0;
61
+ for (let j = 0; j < line.length; j++) {
62
+ const segment = line[j];
63
+ if (j > 0) writer.write(comma);
64
+ genColumn = encodeInteger(writer, segment[0], genColumn);
65
+ if (segment.length === 1) continue;
66
+ sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
67
+ sourceLine = encodeInteger(writer, segment[2], sourceLine);
68
+ sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
69
+ if (segment.length === 4) continue;
70
+ namesIndex = encodeInteger(writer, segment[4], namesIndex);
71
+ }
72
+ }
73
+ return writer.flush();
74
+ }
75
+ //#endregion
76
+ export { encode };
77
+
78
+ //# sourceMappingURL=sourcemap-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourcemap-codec.js","names":[],"sources":["../../../../../../../../../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs"],"sourcesContent":["// src/vlq.ts\nvar comma = \",\".charCodeAt(0);\nvar semicolon = \";\".charCodeAt(0);\nvar chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nvar intToChar = new Uint8Array(64);\nvar charToInt = new Uint8Array(128);\nfor (let i = 0; i < chars.length; i++) {\n const c = chars.charCodeAt(i);\n intToChar[i] = c;\n charToInt[c] = i;\n}\nfunction decodeInteger(reader, relative) {\n let value = 0;\n let shift = 0;\n let integer = 0;\n do {\n const c = reader.next();\n integer = charToInt[c];\n value |= (integer & 31) << shift;\n shift += 5;\n } while (integer & 32);\n const shouldNegate = value & 1;\n value >>>= 1;\n if (shouldNegate) {\n value = -2147483648 | -value;\n }\n return relative + value;\n}\nfunction encodeInteger(builder, num, relative) {\n let delta = num - relative;\n delta = delta < 0 ? -delta << 1 | 1 : delta << 1;\n do {\n let clamped = delta & 31;\n delta >>>= 5;\n if (delta > 0) clamped |= 32;\n builder.write(intToChar[clamped]);\n } while (delta > 0);\n return num;\n}\nfunction hasMoreVlq(reader, max) {\n if (reader.pos >= max) return false;\n return reader.peek() !== comma;\n}\n\n// src/strings.ts\nvar bufLength = 1024 * 16;\nvar td = typeof TextDecoder !== \"undefined\" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== \"undefined\" ? {\n decode(buf) {\n const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);\n return out.toString();\n }\n} : {\n decode(buf) {\n let out = \"\";\n for (let i = 0; i < buf.length; i++) {\n out += String.fromCharCode(buf[i]);\n }\n return out;\n }\n};\nvar StringWriter = class {\n constructor() {\n this.pos = 0;\n this.out = \"\";\n this.buffer = new Uint8Array(bufLength);\n }\n write(v) {\n const { buffer } = this;\n buffer[this.pos++] = v;\n if (this.pos === bufLength) {\n this.out += td.decode(buffer);\n this.pos = 0;\n }\n }\n flush() {\n const { buffer, out, pos } = this;\n return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;\n }\n};\nvar StringReader = class {\n constructor(buffer) {\n this.pos = 0;\n this.buffer = buffer;\n }\n next() {\n return this.buffer.charCodeAt(this.pos++);\n }\n peek() {\n return this.buffer.charCodeAt(this.pos);\n }\n indexOf(char) {\n const { buffer, pos } = this;\n const idx = buffer.indexOf(char, pos);\n return idx === -1 ? buffer.length : idx;\n }\n};\n\n// src/scopes.ts\nvar EMPTY = [];\nfunction decodeOriginalScopes(input) {\n const { length } = input;\n const reader = new StringReader(input);\n const scopes = [];\n const stack = [];\n let line = 0;\n for (; reader.pos < length; reader.pos++) {\n line = decodeInteger(reader, line);\n const column = decodeInteger(reader, 0);\n if (!hasMoreVlq(reader, length)) {\n const last = stack.pop();\n last[2] = line;\n last[3] = column;\n continue;\n }\n const kind = decodeInteger(reader, 0);\n const fields = decodeInteger(reader, 0);\n const hasName = fields & 1;\n const scope = hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind];\n let vars = EMPTY;\n if (hasMoreVlq(reader, length)) {\n vars = [];\n do {\n const varsIndex = decodeInteger(reader, 0);\n vars.push(varsIndex);\n } while (hasMoreVlq(reader, length));\n }\n scope.vars = vars;\n scopes.push(scope);\n stack.push(scope);\n }\n return scopes;\n}\nfunction encodeOriginalScopes(scopes) {\n const writer = new StringWriter();\n for (let i = 0; i < scopes.length; ) {\n i = _encodeOriginalScopes(scopes, i, writer, [0]);\n }\n return writer.flush();\n}\nfunction _encodeOriginalScopes(scopes, index, writer, state) {\n const scope = scopes[index];\n const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;\n if (index > 0) writer.write(comma);\n state[0] = encodeInteger(writer, startLine, state[0]);\n encodeInteger(writer, startColumn, 0);\n encodeInteger(writer, kind, 0);\n const fields = scope.length === 6 ? 1 : 0;\n encodeInteger(writer, fields, 0);\n if (scope.length === 6) encodeInteger(writer, scope[5], 0);\n for (const v of vars) {\n encodeInteger(writer, v, 0);\n }\n for (index++; index < scopes.length; ) {\n const next = scopes[index];\n const { 0: l, 1: c } = next;\n if (l > endLine || l === endLine && c >= endColumn) {\n break;\n }\n index = _encodeOriginalScopes(scopes, index, writer, state);\n }\n writer.write(comma);\n state[0] = encodeInteger(writer, endLine, state[0]);\n encodeInteger(writer, endColumn, 0);\n return index;\n}\nfunction decodeGeneratedRanges(input) {\n const { length } = input;\n const reader = new StringReader(input);\n const ranges = [];\n const stack = [];\n let genLine = 0;\n let definitionSourcesIndex = 0;\n let definitionScopeIndex = 0;\n let callsiteSourcesIndex = 0;\n let callsiteLine = 0;\n let callsiteColumn = 0;\n let bindingLine = 0;\n let bindingColumn = 0;\n do {\n const semi = reader.indexOf(\";\");\n let genColumn = 0;\n for (; reader.pos < semi; reader.pos++) {\n genColumn = decodeInteger(reader, genColumn);\n if (!hasMoreVlq(reader, semi)) {\n const last = stack.pop();\n last[2] = genLine;\n last[3] = genColumn;\n continue;\n }\n const fields = decodeInteger(reader, 0);\n const hasDefinition = fields & 1;\n const hasCallsite = fields & 2;\n const hasScope = fields & 4;\n let callsite = null;\n let bindings = EMPTY;\n let range;\n if (hasDefinition) {\n const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);\n definitionScopeIndex = decodeInteger(\n reader,\n definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0\n );\n definitionSourcesIndex = defSourcesIndex;\n range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex];\n } else {\n range = [genLine, genColumn, 0, 0];\n }\n range.isScope = !!hasScope;\n if (hasCallsite) {\n const prevCsi = callsiteSourcesIndex;\n const prevLine = callsiteLine;\n callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);\n const sameSource = prevCsi === callsiteSourcesIndex;\n callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);\n callsiteColumn = decodeInteger(\n reader,\n sameSource && prevLine === callsiteLine ? callsiteColumn : 0\n );\n callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];\n }\n range.callsite = callsite;\n if (hasMoreVlq(reader, semi)) {\n bindings = [];\n do {\n bindingLine = genLine;\n bindingColumn = genColumn;\n const expressionsCount = decodeInteger(reader, 0);\n let expressionRanges;\n if (expressionsCount < -1) {\n expressionRanges = [[decodeInteger(reader, 0)]];\n for (let i = -1; i > expressionsCount; i--) {\n const prevBl = bindingLine;\n bindingLine = decodeInteger(reader, bindingLine);\n bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);\n const expression = decodeInteger(reader, 0);\n expressionRanges.push([expression, bindingLine, bindingColumn]);\n }\n } else {\n expressionRanges = [[expressionsCount]];\n }\n bindings.push(expressionRanges);\n } while (hasMoreVlq(reader, semi));\n }\n range.bindings = bindings;\n ranges.push(range);\n stack.push(range);\n }\n genLine++;\n reader.pos = semi + 1;\n } while (reader.pos < length);\n return ranges;\n}\nfunction encodeGeneratedRanges(ranges) {\n if (ranges.length === 0) return \"\";\n const writer = new StringWriter();\n for (let i = 0; i < ranges.length; ) {\n i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);\n }\n return writer.flush();\n}\nfunction _encodeGeneratedRanges(ranges, index, writer, state) {\n const range = ranges[index];\n const {\n 0: startLine,\n 1: startColumn,\n 2: endLine,\n 3: endColumn,\n isScope,\n callsite,\n bindings\n } = range;\n if (state[0] < startLine) {\n catchupLine(writer, state[0], startLine);\n state[0] = startLine;\n state[1] = 0;\n } else if (index > 0) {\n writer.write(comma);\n }\n state[1] = encodeInteger(writer, range[1], state[1]);\n const fields = (range.length === 6 ? 1 : 0) | (callsite ? 2 : 0) | (isScope ? 4 : 0);\n encodeInteger(writer, fields, 0);\n if (range.length === 6) {\n const { 4: sourcesIndex, 5: scopesIndex } = range;\n if (sourcesIndex !== state[2]) {\n state[3] = 0;\n }\n state[2] = encodeInteger(writer, sourcesIndex, state[2]);\n state[3] = encodeInteger(writer, scopesIndex, state[3]);\n }\n if (callsite) {\n const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite;\n if (sourcesIndex !== state[4]) {\n state[5] = 0;\n state[6] = 0;\n } else if (callLine !== state[5]) {\n state[6] = 0;\n }\n state[4] = encodeInteger(writer, sourcesIndex, state[4]);\n state[5] = encodeInteger(writer, callLine, state[5]);\n state[6] = encodeInteger(writer, callColumn, state[6]);\n }\n if (bindings) {\n for (const binding of bindings) {\n if (binding.length > 1) encodeInteger(writer, -binding.length, 0);\n const expression = binding[0][0];\n encodeInteger(writer, expression, 0);\n let bindingStartLine = startLine;\n let bindingStartColumn = startColumn;\n for (let i = 1; i < binding.length; i++) {\n const expRange = binding[i];\n bindingStartLine = encodeInteger(writer, expRange[1], bindingStartLine);\n bindingStartColumn = encodeInteger(writer, expRange[2], bindingStartColumn);\n encodeInteger(writer, expRange[0], 0);\n }\n }\n }\n for (index++; index < ranges.length; ) {\n const next = ranges[index];\n const { 0: l, 1: c } = next;\n if (l > endLine || l === endLine && c >= endColumn) {\n break;\n }\n index = _encodeGeneratedRanges(ranges, index, writer, state);\n }\n if (state[0] < endLine) {\n catchupLine(writer, state[0], endLine);\n state[0] = endLine;\n state[1] = 0;\n } else {\n writer.write(comma);\n }\n state[1] = encodeInteger(writer, endColumn, state[1]);\n return index;\n}\nfunction catchupLine(writer, lastLine, line) {\n do {\n writer.write(semicolon);\n } while (++lastLine < line);\n}\n\n// src/sourcemap-codec.ts\nfunction decode(mappings) {\n const { length } = mappings;\n const reader = new StringReader(mappings);\n const decoded = [];\n let genColumn = 0;\n let sourcesIndex = 0;\n let sourceLine = 0;\n let sourceColumn = 0;\n let namesIndex = 0;\n do {\n const semi = reader.indexOf(\";\");\n const line = [];\n let sorted = true;\n let lastCol = 0;\n genColumn = 0;\n while (reader.pos < semi) {\n let seg;\n genColumn = decodeInteger(reader, genColumn);\n if (genColumn < lastCol) sorted = false;\n lastCol = genColumn;\n if (hasMoreVlq(reader, semi)) {\n sourcesIndex = decodeInteger(reader, sourcesIndex);\n sourceLine = decodeInteger(reader, sourceLine);\n sourceColumn = decodeInteger(reader, sourceColumn);\n if (hasMoreVlq(reader, semi)) {\n namesIndex = decodeInteger(reader, namesIndex);\n seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];\n } else {\n seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];\n }\n } else {\n seg = [genColumn];\n }\n line.push(seg);\n reader.pos++;\n }\n if (!sorted) sort(line);\n decoded.push(line);\n reader.pos = semi + 1;\n } while (reader.pos <= length);\n return decoded;\n}\nfunction sort(line) {\n line.sort(sortComparator);\n}\nfunction sortComparator(a, b) {\n return a[0] - b[0];\n}\nfunction encode(decoded) {\n const writer = new StringWriter();\n let sourcesIndex = 0;\n let sourceLine = 0;\n let sourceColumn = 0;\n let namesIndex = 0;\n for (let i = 0; i < decoded.length; i++) {\n const line = decoded[i];\n if (i > 0) writer.write(semicolon);\n if (line.length === 0) continue;\n let genColumn = 0;\n for (let j = 0; j < line.length; j++) {\n const segment = line[j];\n if (j > 0) writer.write(comma);\n genColumn = encodeInteger(writer, segment[0], genColumn);\n if (segment.length === 1) continue;\n sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);\n sourceLine = encodeInteger(writer, segment[2], sourceLine);\n sourceColumn = encodeInteger(writer, segment[3], sourceColumn);\n if (segment.length === 4) continue;\n namesIndex = encodeInteger(writer, segment[4], namesIndex);\n }\n }\n return writer.flush();\n}\nexport {\n decode,\n decodeGeneratedRanges,\n decodeOriginalScopes,\n encode,\n encodeGeneratedRanges,\n encodeOriginalScopes\n};\n//# sourceMappingURL=sourcemap-codec.mjs.map\n"],"x_google_ignoreList":[0],"mappings":";AACA,IAAI,QAAQ,IAAI,WAAW,CAAC;AAC5B,IAAI,YAAY,IAAI,WAAW,CAAC;AAChC,IAAI,QAAQ;AACZ,IAAI,4BAAY,IAAI,WAAW,EAAE;AACjC,IAAI,4BAAY,IAAI,WAAW,GAAG;AAClC,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;CACrC,MAAM,IAAI,MAAM,WAAW,CAAC;CAC5B,UAAU,KAAK;CACf,UAAU,KAAK;AACjB;AAkBA,SAAS,cAAc,SAAS,KAAK,UAAU;CAC7C,IAAI,QAAQ,MAAM;CAClB,QAAQ,QAAQ,IAAI,CAAC,SAAS,IAAI,IAAI,SAAS;CAC/C,GAAG;EACD,IAAI,UAAU,QAAQ;EACtB,WAAW;EACX,IAAI,QAAQ,GAAG,WAAW;EAC1B,QAAQ,MAAM,UAAU,QAAQ;CAClC,SAAS,QAAQ;CACjB,OAAO;AACT;AAOA,IAAI,YAAY,OAAO;AACvB,IAAI,KAAK,OAAO,gBAAgB,8BAA8B,IAAI,YAAY,IAAI,OAAO,WAAW,cAAc,EAChH,OAAO,KAAK;CAEV,OADY,OAAO,KAAK,IAAI,QAAQ,IAAI,YAAY,IAAI,UAC/C,CAAC,CAAC,SAAS;AACtB,EACF,IAAI,EACF,OAAO,KAAK;CACV,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,OAAO,OAAO,aAAa,IAAI,EAAE;CAEnC,OAAO;AACT,EACF;AACA,IAAI,eAAe,MAAM;CACvB,cAAc;EACZ,KAAK,MAAM;EACX,KAAK,MAAM;EACX,KAAK,SAAS,IAAI,WAAW,SAAS;CACxC;CACA,MAAM,GAAG;EACP,MAAM,EAAE,WAAW;EACnB,OAAO,KAAK,SAAS;EACrB,IAAI,KAAK,QAAQ,WAAW;GAC1B,KAAK,OAAO,GAAG,OAAO,MAAM;GAC5B,KAAK,MAAM;EACb;CACF;CACA,QAAQ;EACN,MAAM,EAAE,QAAQ,KAAK,QAAQ;EAC7B,OAAO,MAAM,IAAI,MAAM,GAAG,OAAO,OAAO,SAAS,GAAG,GAAG,CAAC,IAAI;CAC9D;AACF;AAuTA,SAAS,OAAO,SAAS;CACvB,MAAM,SAAS,IAAI,aAAa;CAChC,IAAI,eAAe;CACnB,IAAI,aAAa;CACjB,IAAI,eAAe;CACnB,IAAI,aAAa;CACjB,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,OAAO,QAAQ;EACrB,IAAI,IAAI,GAAG,OAAO,MAAM,SAAS;EACjC,IAAI,KAAK,WAAW,GAAG;EACvB,IAAI,YAAY;EAChB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,UAAU,KAAK;GACrB,IAAI,IAAI,GAAG,OAAO,MAAM,KAAK;GAC7B,YAAY,cAAc,QAAQ,QAAQ,IAAI,SAAS;GACvD,IAAI,QAAQ,WAAW,GAAG;GAC1B,eAAe,cAAc,QAAQ,QAAQ,IAAI,YAAY;GAC7D,aAAa,cAAc,QAAQ,QAAQ,IAAI,UAAU;GACzD,eAAe,cAAc,QAAQ,QAAQ,IAAI,YAAY;GAC7D,IAAI,QAAQ,WAAW,GAAG;GAC1B,aAAa,cAAc,QAAQ,QAAQ,IAAI,UAAU;EAC3D;CACF;CACA,OAAO,OAAO,MAAM;AACtB"}