@headless-lms/core 0.3.0 → 0.5.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 (307) hide show
  1. package/dist/assets/events.d.ts +24 -18
  2. package/dist/assets/file-urls.d.ts +11 -7
  3. package/dist/assets/file-urls.js +14 -4
  4. package/dist/assets/file-urls.js.map +1 -1
  5. package/dist/assets/index.d.ts +5 -4
  6. package/dist/assets/index.js +4 -3
  7. package/dist/assets/jobs.d.ts +15 -0
  8. package/dist/assets/jobs.js +30 -0
  9. package/dist/assets/jobs.js.map +1 -0
  10. package/dist/assets/ports.d.ts +37 -17
  11. package/dist/assets/service.d.ts +30 -15
  12. package/dist/assets/service.js +229 -59
  13. package/dist/assets/service.js.map +1 -1
  14. package/dist/automations/actions.js +2 -63
  15. package/dist/automations/actions.js.map +1 -1
  16. package/dist/automations/catalog.d.ts +1 -2
  17. package/dist/automations/catalog.js +137 -65
  18. package/dist/automations/catalog.js.map +1 -1
  19. package/dist/automations/community-derivations.js +20 -20
  20. package/dist/automations/community-derivations.js.map +1 -1
  21. package/dist/automations/community-mail.d.ts +36 -20
  22. package/dist/automations/community-mail.js +32 -24
  23. package/dist/automations/community-mail.js.map +1 -1
  24. package/dist/automations/event-permissions.d.ts +12 -0
  25. package/dist/automations/event-permissions.js +38 -0
  26. package/dist/automations/event-permissions.js.map +1 -0
  27. package/dist/automations/events.d.ts +0 -10
  28. package/dist/automations/index.d.ts +12 -4
  29. package/dist/automations/index.js +9 -1
  30. package/dist/automations/notifications/applicable.d.ts +8 -0
  31. package/dist/automations/notifications/applicable.js +12 -0
  32. package/dist/automations/notifications/applicable.js.map +1 -0
  33. package/dist/automations/notifications/debounce.d.ts +25 -0
  34. package/dist/automations/notifications/debounce.js +93 -0
  35. package/dist/automations/notifications/debounce.js.map +1 -0
  36. package/dist/automations/notifications/defaults.d.ts +8 -0
  37. package/dist/automations/notifications/defaults.js +346 -0
  38. package/dist/automations/notifications/defaults.js.map +1 -0
  39. package/dist/automations/notifications/delivery.d.ts +28 -0
  40. package/dist/automations/notifications/delivery.js +88 -0
  41. package/dist/automations/notifications/delivery.js.map +1 -0
  42. package/dist/automations/notifications/processor.d.ts +64 -0
  43. package/dist/automations/notifications/processor.js +270 -0
  44. package/dist/automations/notifications/processor.js.map +1 -0
  45. package/dist/automations/notifications/rules/content.d.ts +6 -0
  46. package/dist/automations/notifications/rules/content.js +96 -0
  47. package/dist/automations/notifications/rules/content.js.map +1 -0
  48. package/dist/automations/notifications/rules/discussion.d.ts +7 -0
  49. package/dist/automations/notifications/rules/discussion.js +678 -0
  50. package/dist/automations/notifications/rules/discussion.js.map +1 -0
  51. package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
  52. package/dist/automations/notifications/rules/entitlements.js +276 -0
  53. package/dist/automations/notifications/rules/entitlements.js.map +1 -0
  54. package/dist/automations/notifications/rules/events.d.ts +9 -0
  55. package/dist/automations/notifications/rules/events.js +27 -0
  56. package/dist/automations/notifications/rules/events.js.map +1 -0
  57. package/dist/automations/notifications/rules/index.d.ts +6 -0
  58. package/dist/automations/notifications/rules/index.js +15 -0
  59. package/dist/automations/notifications/rules/index.js.map +1 -0
  60. package/dist/automations/notifications/rules/organizations.d.ts +6 -0
  61. package/dist/automations/notifications/rules/organizations.js +35 -0
  62. package/dist/automations/notifications/rules/organizations.js.map +1 -0
  63. package/dist/automations/notifications/rules/recipients.d.ts +32 -0
  64. package/dist/automations/notifications/rules/recipients.js +98 -0
  65. package/dist/automations/notifications/rules/recipients.js.map +1 -0
  66. package/dist/automations/notifications/service.d.ts +29 -0
  67. package/dist/automations/notifications/service.js +45 -0
  68. package/dist/automations/notifications/service.js.map +1 -0
  69. package/dist/automations/notifications/types.d.ts +7 -0
  70. package/dist/automations/notifications/types.js +560 -0
  71. package/dist/automations/notifications/types.js.map +1 -0
  72. package/dist/automations/ports.d.ts +134 -21
  73. package/dist/automations/service.d.ts +30 -30
  74. package/dist/automations/service.js +111 -144
  75. package/dist/automations/service.js.map +1 -1
  76. package/dist/content/event-sight.d.ts +11 -0
  77. package/dist/content/event-sight.js +11 -0
  78. package/dist/content/event-sight.js.map +1 -0
  79. package/dist/content/events.d.ts +437 -46
  80. package/dist/content/events.js +45 -1
  81. package/dist/content/events.js.map +1 -1
  82. package/dist/content/index.d.ts +8 -4
  83. package/dist/content/index.js +5 -1
  84. package/dist/content/jobs.d.ts +16 -0
  85. package/dist/content/jobs.js +37 -0
  86. package/dist/content/jobs.js.map +1 -0
  87. package/dist/content/model.d.ts +2 -2
  88. package/dist/content/notification-categories.d.ts +37 -0
  89. package/dist/content/notification-categories.js +73 -0
  90. package/dist/content/notification-categories.js.map +1 -0
  91. package/dist/content/ports.d.ts +132 -68
  92. package/dist/content/service.d.ts +100 -68
  93. package/dist/content/service.js +703 -146
  94. package/dist/content/service.js.map +1 -1
  95. package/dist/content/titles.d.ts +25 -0
  96. package/dist/content/titles.js +82 -0
  97. package/dist/content/titles.js.map +1 -0
  98. package/dist/content/types.d.ts +2 -2
  99. package/dist/discussion/authors.d.ts +4 -2
  100. package/dist/discussion/authors.js +9 -5
  101. package/dist/discussion/authors.js.map +1 -1
  102. package/dist/discussion/chats.d.ts +63 -39
  103. package/dist/discussion/chats.js +455 -190
  104. package/dist/discussion/chats.js.map +1 -1
  105. package/dist/discussion/digests.d.ts +24 -0
  106. package/dist/discussion/digests.js +104 -0
  107. package/dist/discussion/digests.js.map +1 -0
  108. package/dist/discussion/events.d.ts +227 -23
  109. package/dist/discussion/events.js +114 -19
  110. package/dist/discussion/events.js.map +1 -1
  111. package/dist/discussion/index.d.ts +12 -4
  112. package/dist/discussion/index.js +9 -2
  113. package/dist/discussion/jobs.d.ts +16 -0
  114. package/dist/discussion/jobs.js +40 -0
  115. package/dist/discussion/jobs.js.map +1 -0
  116. package/dist/discussion/live.d.ts +106 -0
  117. package/dist/discussion/live.js +642 -0
  118. package/dist/discussion/live.js.map +1 -0
  119. package/dist/discussion/mentions.d.ts +11 -0
  120. package/dist/discussion/mentions.js +35 -0
  121. package/dist/discussion/mentions.js.map +1 -0
  122. package/dist/discussion/ports.d.ts +279 -114
  123. package/dist/discussion/ports.js.map +1 -1
  124. package/dist/discussion/posts.d.ts +60 -44
  125. package/dist/discussion/posts.js +453 -287
  126. package/dist/discussion/posts.js.map +1 -1
  127. package/dist/discussion/rules.d.ts +18 -0
  128. package/dist/discussion/rules.js +22 -0
  129. package/dist/discussion/rules.js.map +1 -0
  130. package/dist/discussion/service.d.ts +50 -35
  131. package/dist/discussion/service.js +333 -205
  132. package/dist/discussion/service.js.map +1 -1
  133. package/dist/discussion/subscriptions.d.ts +37 -0
  134. package/dist/discussion/subscriptions.js +115 -0
  135. package/dist/discussion/subscriptions.js.map +1 -0
  136. package/dist/discussion/titles.d.ts +28 -0
  137. package/dist/discussion/titles.js +98 -0
  138. package/dist/discussion/titles.js.map +1 -0
  139. package/dist/entitlements/events.d.ts +20 -20
  140. package/dist/entitlements/index.d.ts +5 -4
  141. package/dist/entitlements/index.js +3 -2
  142. package/dist/entitlements/jobs.d.ts +12 -0
  143. package/dist/entitlements/jobs.js +18 -0
  144. package/dist/entitlements/jobs.js.map +1 -0
  145. package/dist/entitlements/model.d.ts +2 -2
  146. package/dist/entitlements/ports.d.ts +68 -38
  147. package/dist/entitlements/rules.d.ts +3 -6
  148. package/dist/entitlements/rules.js +5 -10
  149. package/dist/entitlements/rules.js.map +1 -1
  150. package/dist/entitlements/service.d.ts +43 -28
  151. package/dist/entitlements/service.js +387 -160
  152. package/dist/entitlements/service.js.map +1 -1
  153. package/dist/identity/devices.d.ts +30 -0
  154. package/dist/identity/devices.js +109 -0
  155. package/dist/identity/devices.js.map +1 -0
  156. package/dist/identity/index.d.ts +6 -5
  157. package/dist/identity/index.js +4 -3
  158. package/dist/identity/model.d.ts +2 -2
  159. package/dist/identity/notification-settings.d.ts +28 -0
  160. package/dist/identity/notification-settings.js +114 -0
  161. package/dist/identity/notification-settings.js.map +1 -0
  162. package/dist/identity/ports.d.ts +80 -56
  163. package/dist/identity/service.d.ts +8 -7
  164. package/dist/identity/service.js +17 -13
  165. package/dist/identity/service.js.map +1 -1
  166. package/dist/integrations/ports.d.ts +9 -8
  167. package/dist/integrations/service.d.ts +9 -8
  168. package/dist/integrations/service.js +33 -16
  169. package/dist/integrations/service.js.map +1 -1
  170. package/dist/organizations/default-roles.d.ts +22 -0
  171. package/dist/organizations/default-roles.js +89 -0
  172. package/dist/organizations/default-roles.js.map +1 -0
  173. package/dist/organizations/effective-permissions.d.ts +45 -0
  174. package/dist/organizations/effective-permissions.js +113 -0
  175. package/dist/organizations/effective-permissions.js.map +1 -0
  176. package/dist/organizations/events.d.ts +320 -181
  177. package/dist/organizations/events.js +90 -18
  178. package/dist/organizations/events.js.map +1 -1
  179. package/dist/organizations/index.d.ts +15 -10
  180. package/dist/organizations/index.js +8 -3
  181. package/dist/organizations/members.d.ts +66 -8
  182. package/dist/organizations/members.js.map +1 -1
  183. package/dist/organizations/notification-catalog.d.ts +31 -0
  184. package/dist/organizations/notification-catalog.js +32 -0
  185. package/dist/organizations/notification-catalog.js.map +1 -0
  186. package/dist/organizations/notification-categories.d.ts +34 -0
  187. package/dist/organizations/notification-categories.js +66 -0
  188. package/dist/organizations/notification-categories.js.map +1 -0
  189. package/dist/organizations/org-roles.d.ts +33 -0
  190. package/dist/organizations/org-roles.js +49 -0
  191. package/dist/organizations/org-roles.js.map +1 -0
  192. package/dist/organizations/permissions.d.ts +311 -0
  193. package/dist/organizations/permissions.js +327 -0
  194. package/dist/organizations/permissions.js.map +1 -0
  195. package/dist/organizations/ports.d.ts +187 -65
  196. package/dist/organizations/service.d.ts +104 -35
  197. package/dist/organizations/service.js +1247 -323
  198. package/dist/organizations/service.js.map +1 -1
  199. package/dist/organizations/testing.d.ts +18 -0
  200. package/dist/organizations/testing.js +37 -0
  201. package/dist/organizations/testing.js.map +1 -0
  202. package/dist/organizations/types.d.ts +5 -16
  203. package/dist/progress/index.d.ts +2 -2
  204. package/dist/progress/ports.d.ts +11 -3
  205. package/dist/progress/service.d.ts +6 -5
  206. package/dist/progress/service.js +23 -8
  207. package/dist/progress/service.js.map +1 -1
  208. package/dist/reporting/admin/index.d.ts +6 -4
  209. package/dist/reporting/admin/model.d.ts +36 -3
  210. package/dist/reporting/admin/ports.d.ts +39 -14
  211. package/dist/reporting/admin/service.d.ts +32 -11
  212. package/dist/reporting/admin/service.js +102 -18
  213. package/dist/reporting/admin/service.js.map +1 -1
  214. package/dist/reporting/events/index.d.ts +27 -0
  215. package/dist/reporting/events/index.js +20 -0
  216. package/dist/reporting/events/index.js.map +1 -0
  217. package/dist/reporting/member/calendar.d.ts +11 -0
  218. package/dist/reporting/member/calendar.js +75 -0
  219. package/dist/reporting/member/calendar.js.map +1 -0
  220. package/dist/reporting/member/index.d.ts +3 -2
  221. package/dist/reporting/member/model.d.ts +80 -26
  222. package/dist/reporting/member/ports.d.ts +50 -28
  223. package/dist/reporting/member/service.d.ts +81 -35
  224. package/dist/reporting/member/service.js +438 -145
  225. package/dist/reporting/member/service.js.map +1 -1
  226. package/dist/shared/actor.d.ts +22 -3
  227. package/dist/shared/errors.d.ts +15 -2
  228. package/dist/shared/errors.js +21 -2
  229. package/dist/shared/errors.js.map +1 -1
  230. package/dist/shared/id.d.ts +7 -0
  231. package/dist/shared/id.js +8 -1
  232. package/dist/shared/id.js.map +1 -1
  233. package/dist/shared/logger.d.ts +2 -1
  234. package/dist/shared/logger.js +10 -1
  235. package/dist/shared/logger.js.map +1 -1
  236. package/dist/shared/mailer.d.ts +11 -1
  237. package/dist/shared/mailer.js +32 -5
  238. package/dist/shared/mailer.js.map +1 -1
  239. package/dist/shared/notification-categories.d.ts +16 -0
  240. package/dist/shared/notification-categories.js +94 -0
  241. package/dist/shared/notification-categories.js.map +1 -0
  242. package/dist/shared/notification-settings.d.ts +14 -0
  243. package/dist/shared/notification-settings.js +61 -0
  244. package/dist/shared/notification-settings.js.map +1 -0
  245. package/dist/shared/ports.d.ts +68 -2
  246. package/dist/shared/settings.d.ts +2 -1
  247. package/dist/shared/settings.js +1 -0
  248. package/dist/shared/settings.js.map +1 -1
  249. package/dist/types/automations.d.ts +8 -2
  250. package/dist/types/content.d.ts +2 -2
  251. package/dist/types/discussion.d.ts +4 -5
  252. package/dist/types/email-templates.d.ts +119 -6
  253. package/dist/types/entitlements.d.ts +2 -2
  254. package/dist/types/identity.d.ts +14 -17
  255. package/dist/types/index.d.ts +13 -12
  256. package/dist/types/index.js +2 -1
  257. package/dist/types/notifications.d.ts +157 -0
  258. package/dist/types/notifications.js +1 -0
  259. package/dist/types/organizations.d.ts +3 -2
  260. package/dist/types/ports.d.ts +8 -1
  261. package/dist/types/ports.js +7 -1
  262. package/dist/types/ports.js.map +1 -0
  263. package/dist/types/schemas/assets.d.ts +5 -5
  264. package/dist/types/schemas/assets.js +4 -3
  265. package/dist/types/schemas/assets.js.map +1 -1
  266. package/dist/types/schemas/automations.d.ts +1 -10
  267. package/dist/types/schemas/automations.js +1 -3
  268. package/dist/types/schemas/automations.js.map +1 -1
  269. package/dist/types/schemas/content.d.ts +596 -11
  270. package/dist/types/schemas/content.js +225 -9
  271. package/dist/types/schemas/content.js.map +1 -1
  272. package/dist/types/schemas/discussion.d.ts +362 -66
  273. package/dist/types/schemas/discussion.js +123 -15
  274. package/dist/types/schemas/discussion.js.map +1 -1
  275. package/dist/types/schemas/entitlements.d.ts +14 -1
  276. package/dist/types/schemas/entitlements.js +11 -4
  277. package/dist/types/schemas/entitlements.js.map +1 -1
  278. package/dist/types/schemas/identity.d.ts +1 -85
  279. package/dist/types/schemas/identity.js +1 -42
  280. package/dist/types/schemas/identity.js.map +1 -1
  281. package/dist/types/schemas/index.d.ts +8 -7
  282. package/dist/types/schemas/index.js +8 -7
  283. package/dist/types/schemas/notifications.d.ts +96 -0
  284. package/dist/types/schemas/notifications.js +57 -0
  285. package/dist/types/schemas/notifications.js.map +1 -0
  286. package/dist/types/schemas/organizations.d.ts +96 -60
  287. package/dist/types/schemas/organizations.js +78 -27
  288. package/dist/types/schemas/organizations.js.map +1 -1
  289. package/dist/types/schemas/progress.d.ts +0 -1
  290. package/dist/types/schemas/progress.js +0 -1
  291. package/dist/types/schemas/progress.js.map +1 -1
  292. package/package.json +1 -1
  293. package/dist/automations/community-notifications.d.ts +0 -16
  294. package/dist/automations/community-notifications.js +0 -84
  295. package/dist/automations/community-notifications.js.map +0 -1
  296. package/dist/automations/seeds.d.ts +0 -17
  297. package/dist/automations/seeds.js +0 -235
  298. package/dist/automations/seeds.js.map +0 -1
  299. package/dist/identity/notifications.d.ts +0 -27
  300. package/dist/identity/notifications.js +0 -101
  301. package/dist/identity/notifications.js.map +0 -1
  302. package/dist/organizations/access-scopes.d.ts +0 -19
  303. package/dist/organizations/access-scopes.js +0 -89
  304. package/dist/organizations/access-scopes.js.map +0 -1
  305. package/dist/organizations/roles.d.ts +0 -19
  306. package/dist/organizations/roles.js +0 -82
  307. package/dist/organizations/roles.js.map +0 -1
@@ -0,0 +1,678 @@
1
+ import { discussionEvents } from "../../../discussion/events.js";
2
+ import { communityModerators, previousStatusOf } from "../../community-mail.js";
3
+ import { Reasons, actorOr, chatReach, chatTitle, eventAt, listOf, participantNames, recipientsOf, textExcerpt } from "./recipients.js";
4
+ //#region src/automations/notifications/rules/discussion.ts
5
+ const CHAT_STATUS = "chatStatus";
6
+ function postReach(reads, orgId, post, exclude, at) {
7
+ return {
8
+ exclude,
9
+ at,
10
+ canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),
11
+ mutedOn: [{
12
+ type: "post",
13
+ id: post.id
14
+ }, {
15
+ type: "space",
16
+ id: post.spaceId
17
+ }]
18
+ };
19
+ }
20
+ function courseReach(reads, orgId, courseId, exclude, at) {
21
+ return {
22
+ exclude,
23
+ at,
24
+ canOpen: async (orgUserIds) => {
25
+ const [holders, readers] = await Promise.all([reads.courseMembers(orgId, courseId), reads.holders(orgId, "courses:read", courseId)]);
26
+ const open = /* @__PURE__ */ new Set([...holders, ...readers]);
27
+ return orgUserIds.filter((orgUserId) => open.has(orgUserId));
28
+ }
29
+ };
30
+ }
31
+ async function placeOf(reads, orgId, comment) {
32
+ if (comment.postId) {
33
+ const post = await reads.post(orgId, comment.postId);
34
+ const space = post ? await reads.space(orgId, post.spaceId) : null;
35
+ return post && space ? {
36
+ kind: "post",
37
+ postId: comment.postId,
38
+ post,
39
+ spaceName: space.name
40
+ } : null;
41
+ }
42
+ if (comment.activityId) {
43
+ const activity = await reads.activity(orgId, comment.activityId);
44
+ return activity ? {
45
+ kind: "activity",
46
+ activityId: comment.activityId,
47
+ activity
48
+ } : null;
49
+ }
50
+ return null;
51
+ }
52
+ function placeReach(reads, orgId, place, exclude, at) {
53
+ return place.kind === "post" ? postReach(reads, orgId, {
54
+ id: place.postId,
55
+ spaceId: place.post.spaceId
56
+ }, exclude, at) : courseReach(reads, orgId, place.activity.courseId, exclude, at);
57
+ }
58
+ function commentBase(type, place, commentId, actorId, display) {
59
+ const subject = {
60
+ type: "comment",
61
+ id: commentId
62
+ };
63
+ if (place.kind === "post") return {
64
+ type,
65
+ scope: "space",
66
+ actorId,
67
+ communityId: place.post.communityId,
68
+ spaceId: place.post.spaceId,
69
+ subject,
70
+ parent: {
71
+ type: "post",
72
+ id: place.postId
73
+ },
74
+ display: {
75
+ postTitle: place.post.title,
76
+ ...display
77
+ }
78
+ };
79
+ return {
80
+ type,
81
+ scope: "org",
82
+ actorId,
83
+ communityId: null,
84
+ spaceId: null,
85
+ subject,
86
+ parent: {
87
+ type: "activity",
88
+ id: place.activityId
89
+ },
90
+ display: {
91
+ activityTitle: place.activity.title,
92
+ courseTitle: place.activity.courseTitle,
93
+ courseId: place.activity.courseId,
94
+ ...display
95
+ }
96
+ };
97
+ }
98
+ async function mentionsOf(reads, orgId, base, mentioned, reach) {
99
+ if (mentioned.length === 0) return [];
100
+ const recipients = await recipientsOf(reads, orgId, new Reasons().add(mentioned, "mentioned"), reach);
101
+ return listOf({
102
+ ...base,
103
+ type: "mention"
104
+ }, recipients);
105
+ }
106
+ async function commentLists(event, reads, comment) {
107
+ const orgId = event.orgId;
108
+ const place = await placeOf(reads, orgId, comment);
109
+ if (!place) return [];
110
+ const at = eventAt(event);
111
+ const exclude = [comment.orgUserId, actorOr(event, comment.orgUserId)];
112
+ const reasons = new Reasons();
113
+ if (place.kind === "post") reasons.add([place.post.orgUserId], "post_author");
114
+ const parent = comment.parentId ? await reads.comment(orgId, comment.parentId) : null;
115
+ reasons.add([parent?.orgUserId], "comment_author");
116
+ if (place.kind === "post") reasons.add(await reads.followerIds(orgId, place.postId), "follower");
117
+ reasons.add(await reads.threadParticipants(orgId, place.kind === "post" ? {
118
+ type: "post",
119
+ id: place.postId
120
+ } : {
121
+ type: "activity",
122
+ id: place.activityId
123
+ }), "thread_participant");
124
+ const name = await reads.displayName(orgId, comment.orgUserId);
125
+ const text = await textExcerpt(reads, orgId, comment.body, 280);
126
+ const created = listOf(commentBase("comment.created", place, comment.id, comment.orgUserId, {
127
+ commenterName: name,
128
+ excerpt: text
129
+ }), await recipientsOf(reads, orgId, reasons, placeReach(reads, orgId, place, exclude, at)));
130
+ const mentions = await mentionsOf(reads, orgId, commentBase("mention", place, comment.id, comment.orgUserId, {
131
+ authorName: name,
132
+ excerpt: text
133
+ }), comment.mentionedOrgUserIds, placeReach(reads, orgId, place, exclude, at));
134
+ return [...created, ...mentions];
135
+ }
136
+ const postPublished = async (event, reads) => {
137
+ const parsed = discussionEvents.postPublished.safeParse(event);
138
+ if (!parsed.success || previousStatusOf(event) === "removed") return [];
139
+ const post = parsed.data.data;
140
+ const orgId = event.orgId;
141
+ const space = await reads.space(orgId, post.spaceId);
142
+ if (!space) return [];
143
+ const at = eventAt(event);
144
+ const actor = actorOr(event, null);
145
+ const exclude = [.../* @__PURE__ */ new Set([post.orgUserId, ...actor ? [actor] : []])];
146
+ const reach = postReach(reads, orgId, post, exclude, at);
147
+ const base = {
148
+ scope: "space",
149
+ communityId: post.communityId,
150
+ spaceId: post.spaceId,
151
+ subject: {
152
+ type: "post",
153
+ id: post.id
154
+ },
155
+ parent: null
156
+ };
157
+ const lists = [];
158
+ if (previousStatusOf(event) === "pending") lists.push(...listOf({
159
+ ...base,
160
+ type: "post.approved",
161
+ actorId: actor,
162
+ display: {
163
+ postTitle: post.title,
164
+ spaceName: space.name
165
+ }
166
+ }, await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], "subject"), {
167
+ ...reach,
168
+ exclude: [actor]
169
+ })));
170
+ const authorName = await reads.displayName(orgId, post.orgUserId);
171
+ const text = await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280);
172
+ lists.push(...await mentionsOf(reads, orgId, {
173
+ ...base,
174
+ actorId: post.orgUserId,
175
+ display: {
176
+ authorName,
177
+ excerpt: text,
178
+ postTitle: post.title
179
+ }
180
+ }, post.mentionedOrgUserIds, reach));
181
+ lists.push({
182
+ ...base,
183
+ type: "post.published",
184
+ actorId: post.orgUserId,
185
+ display: {
186
+ spaceName: space.name,
187
+ postTitle: post.title,
188
+ authorName,
189
+ excerpt: text
190
+ },
191
+ audience: {
192
+ reason: "space_member",
193
+ spaceId: post.spaceId,
194
+ exclude
195
+ }
196
+ });
197
+ return lists;
198
+ };
199
+ async function awaitingReview(event, reads, post) {
200
+ if (post.status !== "pending" || previousStatusOf(event) === "pending") return [];
201
+ const orgId = event.orgId;
202
+ const space = await reads.space(orgId, post.spaceId);
203
+ if (!space) return [];
204
+ const actor = actorOr(event, post.orgUserId);
205
+ return listOf({
206
+ type: "post.awaiting_review",
207
+ scope: "space",
208
+ actorId: post.orgUserId,
209
+ communityId: post.communityId,
210
+ spaceId: post.spaceId,
211
+ subject: {
212
+ type: "post",
213
+ id: post.id
214
+ },
215
+ parent: null,
216
+ display: {
217
+ spaceName: space.name,
218
+ postTitle: post.title,
219
+ authorName: await reads.displayName(orgId, post.orgUserId)
220
+ }
221
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, post.communityId), "moderator"), {
222
+ exclude: [actor, post.orgUserId],
223
+ at: eventAt(event),
224
+ canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
225
+ }));
226
+ }
227
+ const postCreated = async (event, reads) => {
228
+ const parsed = discussionEvents.postCreated.safeParse(event);
229
+ return parsed.success ? awaitingReview(event, reads, parsed.data.data) : [];
230
+ };
231
+ const postUpdated = async (event, reads) => {
232
+ const parsed = discussionEvents.postUpdated.safeParse(event);
233
+ if (!parsed.success) return [];
234
+ const post = parsed.data.data;
235
+ const orgId = event.orgId;
236
+ const lists = await awaitingReview(event, reads, post);
237
+ if (post.mentionedOrgUserIds.length === 0) return lists;
238
+ const actor = actorOr(event, post.orgUserId);
239
+ lists.push(...await mentionsOf(reads, orgId, {
240
+ scope: "space",
241
+ actorId: post.orgUserId,
242
+ communityId: post.communityId,
243
+ spaceId: post.spaceId,
244
+ subject: {
245
+ type: "post",
246
+ id: post.id
247
+ },
248
+ parent: null,
249
+ display: {
250
+ authorName: await reads.displayName(orgId, post.orgUserId),
251
+ excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
252
+ postTitle: post.title
253
+ }
254
+ }, post.mentionedOrgUserIds, postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event))));
255
+ return lists;
256
+ };
257
+ const postRemoved = async (event, reads) => {
258
+ const parsed = discussionEvents.postRemoved.safeParse(event);
259
+ if (!parsed.success) return [];
260
+ const post = parsed.data.data;
261
+ const remover = post.removedBy ?? actorOr(event, null);
262
+ if (!remover || remover === post.orgUserId) return [];
263
+ const orgId = event.orgId;
264
+ const space = await reads.space(orgId, post.spaceId);
265
+ if (!space) return [];
266
+ return listOf({
267
+ type: "post.removed",
268
+ scope: "space",
269
+ actorId: remover,
270
+ communityId: post.communityId,
271
+ spaceId: post.spaceId,
272
+ subject: {
273
+ type: "post",
274
+ id: post.id
275
+ },
276
+ parent: null,
277
+ display: {
278
+ postTitle: post.title,
279
+ spaceName: space.name
280
+ }
281
+ }, await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], "subject"), postReach(reads, orgId, post, [remover], eventAt(event))));
282
+ };
283
+ const postReacted = async (event, reads) => {
284
+ const parsed = discussionEvents.postReactionAdded.safeParse(event);
285
+ if (!parsed.success) return [];
286
+ const reaction = parsed.data.data;
287
+ const orgId = event.orgId;
288
+ const post = await reads.post(orgId, reaction.postId);
289
+ if (!post) return [];
290
+ return listOf({
291
+ type: "post.reacted",
292
+ scope: "space",
293
+ actorId: reaction.orgUserId,
294
+ communityId: post.communityId,
295
+ spaceId: post.spaceId,
296
+ subject: {
297
+ type: "post",
298
+ id: reaction.postId
299
+ },
300
+ parent: null,
301
+ display: {
302
+ postTitle: post.title,
303
+ reactorName: await reads.displayName(orgId, reaction.orgUserId),
304
+ reaction: reaction.reaction
305
+ }
306
+ }, await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], "post_author"), postReach(reads, orgId, {
307
+ id: reaction.postId,
308
+ spaceId: post.spaceId
309
+ }, [reaction.orgUserId, actorOr(event, null)], eventAt(event))));
310
+ };
311
+ const commentCreated = async (event, reads) => {
312
+ const parsed = discussionEvents.commentCreated.safeParse(event);
313
+ if (!parsed.success || parsed.data.data.status !== "published") return [];
314
+ return commentLists(event, reads, parsed.data.data);
315
+ };
316
+ const commentPublished = async (event, reads) => {
317
+ const parsed = discussionEvents.commentPublished.safeParse(event);
318
+ return parsed.success ? commentLists(event, reads, parsed.data.data) : [];
319
+ };
320
+ const commentUpdated = async (event, reads) => {
321
+ const parsed = discussionEvents.commentUpdated.safeParse(event);
322
+ if (!parsed.success) return [];
323
+ const comment = parsed.data.data;
324
+ if (comment.status !== "published" || comment.mentionedOrgUserIds.length === 0) return [];
325
+ const orgId = event.orgId;
326
+ const place = await placeOf(reads, orgId, comment);
327
+ if (!place) return [];
328
+ return mentionsOf(reads, orgId, commentBase("mention", place, comment.id, comment.orgUserId, {
329
+ authorName: await reads.displayName(orgId, comment.orgUserId),
330
+ excerpt: await textExcerpt(reads, orgId, comment.body, 280)
331
+ }), comment.mentionedOrgUserIds, placeReach(reads, orgId, place, [comment.orgUserId, actorOr(event, comment.orgUserId)], eventAt(event)));
332
+ };
333
+ const commentRemoved = async (event, reads) => {
334
+ const parsed = discussionEvents.commentRemoved.safeParse(event);
335
+ if (!parsed.success) return [];
336
+ const comment = parsed.data.data;
337
+ const remover = comment.removedBy ?? actorOr(event, null);
338
+ if (!remover || remover === comment.orgUserId) return [];
339
+ const orgId = event.orgId;
340
+ const place = await placeOf(reads, orgId, comment);
341
+ if (!place) return [];
342
+ return listOf(commentBase("comment.removed", place, comment.id, remover, {}), await recipientsOf(reads, orgId, new Reasons().add([comment.orgUserId], "subject"), placeReach(reads, orgId, place, [remover], eventAt(event))));
343
+ };
344
+ const commentReacted = async (event, reads) => {
345
+ const parsed = discussionEvents.commentReactionAdded.safeParse(event);
346
+ if (!parsed.success) return [];
347
+ const reaction = parsed.data.data;
348
+ const orgId = event.orgId;
349
+ const comment = await reads.comment(orgId, reaction.commentId);
350
+ const place = comment ? await placeOf(reads, orgId, comment) : null;
351
+ if (!comment || !place) return [];
352
+ return listOf(commentBase("comment.reacted", place, reaction.commentId, reaction.orgUserId, {
353
+ excerpt: await textExcerpt(reads, orgId, comment.body, 280),
354
+ reactorName: await reads.displayName(orgId, reaction.orgUserId),
355
+ reaction: reaction.reaction
356
+ }), await recipientsOf(reads, orgId, new Reasons().add([comment.orgUserId], "comment_author"), placeReach(reads, orgId, place, [reaction.orgUserId, actorOr(event, null)], eventAt(event))));
357
+ };
358
+ const postReported = async (event, reads) => {
359
+ const parsed = discussionEvents.postReported.safeParse(event);
360
+ if (!parsed.success) return [];
361
+ const flag = parsed.data.data;
362
+ const orgId = event.orgId;
363
+ const post = await reads.post(orgId, flag.postId);
364
+ const space = post ? await reads.space(orgId, post.spaceId) : null;
365
+ if (!post || !space) return [];
366
+ return listOf({
367
+ type: "content.flagged",
368
+ scope: "space",
369
+ actorId: flag.orgUserId,
370
+ communityId: flag.communityId,
371
+ spaceId: post.spaceId,
372
+ subject: {
373
+ type: "post",
374
+ id: flag.postId
375
+ },
376
+ parent: null,
377
+ display: {
378
+ spaceName: space.name,
379
+ excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
380
+ reason: flag.reason
381
+ }
382
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
383
+ exclude: [actorOr(event, flag.orgUserId)],
384
+ at: eventAt(event),
385
+ canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
386
+ }));
387
+ };
388
+ const commentReported = async (event, reads) => {
389
+ const parsed = discussionEvents.commentReported.safeParse(event);
390
+ if (!parsed.success) return [];
391
+ const flag = parsed.data.data;
392
+ const orgId = event.orgId;
393
+ const comment = await reads.comment(orgId, flag.commentId);
394
+ const place = comment ? await placeOf(reads, orgId, comment) : null;
395
+ if (!comment || !place) return [];
396
+ const actor = actorOr(event, flag.orgUserId);
397
+ const text = await textExcerpt(reads, orgId, comment.body, 280);
398
+ if (place.kind === "post") return listOf({
399
+ ...commentBase("content.flagged", place, flag.commentId, actor, {}),
400
+ display: {
401
+ spaceName: place.spaceName,
402
+ excerpt: text,
403
+ reason: flag.reason
404
+ }
405
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, place.post.communityId), "moderator"), {
406
+ exclude: [actor],
407
+ at: eventAt(event),
408
+ canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds)
409
+ }));
410
+ return listOf(commentBase("content.flagged", place, flag.commentId, actor, {
411
+ excerpt: text,
412
+ reason: flag.reason
413
+ }), await recipientsOf(reads, orgId, new Reasons().add(await reads.holders(orgId, "courses:moderate", place.activity.courseId), "moderator"), {
414
+ exclude: [actor],
415
+ at: eventAt(event)
416
+ }));
417
+ };
418
+ function chatPending(event, status) {
419
+ const value = event.metadata?.[CHAT_STATUS];
420
+ return (typeof value === "string" ? value : status) === "pending";
421
+ }
422
+ async function chatMentions(event, reads, message, mentioned) {
423
+ const orgId = event.orgId;
424
+ const chat = await reads.chat(orgId, message.chatId);
425
+ if (!chat || chatPending(event, chat.status)) return [];
426
+ return mentionsOf(reads, orgId, {
427
+ scope: "chat",
428
+ actorId: message.orgUserId,
429
+ communityId: chat.communityId,
430
+ spaceId: null,
431
+ subject: {
432
+ type: "message",
433
+ id: message.id
434
+ },
435
+ parent: {
436
+ type: "chat",
437
+ id: message.chatId
438
+ },
439
+ display: {
440
+ authorName: await reads.displayName(orgId, message.orgUserId),
441
+ excerpt: await textExcerpt(reads, orgId, message.body, 140),
442
+ chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId)
443
+ }
444
+ }, mentioned, chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)));
445
+ }
446
+ function messageSummary(count) {
447
+ return count === 1 ? "1 new message" : `${count} new messages`;
448
+ }
449
+ const messageSent = async (event, reads) => {
450
+ const parsed = discussionEvents.messageSent.safeParse(event);
451
+ if (!parsed.success) return [];
452
+ const message = parsed.data.data;
453
+ const orgId = event.orgId;
454
+ const chat = await reads.chat(orgId, message.chatId);
455
+ if (!chat || chatPending(event, chat.status)) return [];
456
+ const senderName = await reads.displayName(orgId, message.orgUserId);
457
+ return [...listOf({
458
+ type: "message.sent",
459
+ scope: "chat",
460
+ actorId: message.orgUserId,
461
+ communityId: chat.communityId,
462
+ spaceId: null,
463
+ subject: {
464
+ type: "message",
465
+ id: message.id
466
+ },
467
+ parent: {
468
+ type: "chat",
469
+ id: message.chatId
470
+ },
471
+ display: {
472
+ senderName,
473
+ chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),
474
+ excerpt: await textExcerpt(reads, orgId, message.body, 140),
475
+ count: "1",
476
+ summary: messageSummary(1)
477
+ }
478
+ }, await recipientsOf(reads, orgId, new Reasons().add(chat.participants.map((participant) => participant.orgUserId), "participant"), chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)))), ...await chatMentions(event, reads, message, message.mentionedOrgUserIds)];
479
+ };
480
+ const messageUpdated = async (event, reads) => {
481
+ const parsed = discussionEvents.messageUpdated.safeParse(event);
482
+ if (!parsed.success || parsed.data.data.mentionedOrgUserIds.length === 0) return [];
483
+ const message = parsed.data.data;
484
+ return chatMentions(event, reads, message, message.mentionedOrgUserIds);
485
+ };
486
+ const messageReacted = async (event, reads) => {
487
+ const parsed = discussionEvents.messageReactionAdded.safeParse(event);
488
+ if (!parsed.success) return [];
489
+ const reaction = parsed.data.data;
490
+ const orgId = event.orgId;
491
+ const [message, chat] = await Promise.all([reads.message(orgId, reaction.messageId), reads.chat(orgId, reaction.chatId)]);
492
+ if (!message || !chat) return [];
493
+ return listOf({
494
+ type: "message.reacted",
495
+ scope: "chat",
496
+ actorId: reaction.orgUserId,
497
+ communityId: chat.communityId,
498
+ spaceId: null,
499
+ subject: {
500
+ type: "message",
501
+ id: reaction.messageId
502
+ },
503
+ parent: {
504
+ type: "chat",
505
+ id: reaction.chatId
506
+ },
507
+ display: {
508
+ excerpt: await textExcerpt(reads, orgId, message.body, 140),
509
+ reactorName: await reads.displayName(orgId, reaction.orgUserId),
510
+ reaction: reaction.reaction
511
+ }
512
+ }, await recipientsOf(reads, orgId, new Reasons().add([message.orgUserId], "message_author"), chatReach(reads, orgId, chat, reaction.chatId, reaction.orgUserId, eventAt(event))));
513
+ };
514
+ const messageReported = async (event, reads) => {
515
+ const parsed = discussionEvents.messageReported.safeParse(event);
516
+ if (!parsed.success) return [];
517
+ const flag = parsed.data.data;
518
+ const orgId = event.orgId;
519
+ const message = await reads.message(orgId, flag.messageId);
520
+ return listOf({
521
+ type: "message.flagged",
522
+ scope: "chat",
523
+ actorId: flag.orgUserId,
524
+ communityId: flag.communityId,
525
+ spaceId: null,
526
+ subject: {
527
+ type: "message",
528
+ id: flag.messageId
529
+ },
530
+ parent: message ? {
531
+ type: "chat",
532
+ id: message.chatId
533
+ } : null,
534
+ display: { reason: flag.reason }
535
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
536
+ exclude: [actorOr(event, flag.orgUserId)],
537
+ at: eventAt(event)
538
+ }));
539
+ };
540
+ const chatCreated = async (event, reads) => {
541
+ const parsed = discussionEvents.chatCreated.safeParse(event);
542
+ if (!parsed.success) return [];
543
+ const created = parsed.data.data;
544
+ if (created.kind !== "direct" || created.status !== "pending" || !created.createdBy) return [];
545
+ const orgId = event.orgId;
546
+ const chat = await reads.chat(orgId, created.id);
547
+ if (!chat) return [];
548
+ const body = await reads.latestMessageBody(orgId, created.id);
549
+ return listOf({
550
+ type: "chat.request",
551
+ scope: "chat",
552
+ actorId: created.createdBy,
553
+ communityId: created.communityId,
554
+ spaceId: null,
555
+ subject: {
556
+ type: "chat",
557
+ id: created.id
558
+ },
559
+ parent: null,
560
+ display: {
561
+ senderName: await reads.displayName(orgId, created.createdBy),
562
+ excerpt: await textExcerpt(reads, orgId, body ?? "", 140)
563
+ }
564
+ }, await recipientsOf(reads, orgId, new Reasons().add(created.participantIds, "participant"), chatReach(reads, orgId, chat, created.id, created.createdBy, eventAt(event))));
565
+ };
566
+ const chatParticipantAdded = async (event, reads) => {
567
+ const parsed = discussionEvents.chatParticipantAdded.safeParse(event);
568
+ if (!parsed.success) return [];
569
+ const added = parsed.data.data;
570
+ const orgId = event.orgId;
571
+ const chat = await reads.chat(orgId, added.chatId);
572
+ if (!chat) return [];
573
+ return listOf({
574
+ type: "chat.added",
575
+ scope: "chat",
576
+ actorId: added.addedBy,
577
+ communityId: added.communityId,
578
+ spaceId: null,
579
+ subject: {
580
+ type: "chat",
581
+ id: added.chatId
582
+ },
583
+ parent: null,
584
+ display: {
585
+ adderName: await reads.displayName(orgId, added.addedBy),
586
+ participantNames: await participantNames(reads, orgId, chat)
587
+ }
588
+ }, await recipientsOf(reads, orgId, new Reasons().add([added.orgUserId], "subject"), chatReach(reads, orgId, chat, added.chatId, added.addedBy, eventAt(event))));
589
+ };
590
+ const digestDue = async (event, reads) => {
591
+ const parsed = discussionEvents.digestDue.safeParse(event);
592
+ if (!parsed.success) return [];
593
+ const { communityId, from, to } = parsed.data.data;
594
+ const orgId = event.orgId;
595
+ const posts = await reads.postsPublished(orgId, communityId, from, to);
596
+ if (posts.length === 0) return [];
597
+ const title = await reads.communityTitle(orgId, communityId);
598
+ if (title === null) return [];
599
+ const spaceIds = [...new Set(posts.map((post) => post.spaceId))];
600
+ const openers = /* @__PURE__ */ new Map();
601
+ for (const spaceId of spaceIds) {
602
+ const open = await reads.spaceOpeners(orgId, spaceId);
603
+ const muted = new Set(open.length > 0 ? await reads.mutedAmong(orgId, {
604
+ type: "space",
605
+ id: spaceId
606
+ }, open, eventAt(event)) : []);
607
+ openers.set(spaceId, new Set(open.filter((orgUserId) => !muted.has(orgUserId))));
608
+ }
609
+ const groups = /* @__PURE__ */ new Map();
610
+ for (const orgUserId of await reads.communityMembers(orgId, communityId)) {
611
+ const open = spaceIds.filter((spaceId) => openers.get(spaceId)?.has(orgUserId));
612
+ if (open.length === 0) continue;
613
+ const key = open.join(" ");
614
+ const group = groups.get(key) ?? {
615
+ spaceIds: open,
616
+ members: new Reasons()
617
+ };
618
+ group.members.add([orgUserId], "community_member");
619
+ groups.set(key, group);
620
+ }
621
+ const lists = [];
622
+ for (const group of groups.values()) {
623
+ const shown = posts.filter((post) => group.spaceIds.includes(post.spaceId));
624
+ lists.push(...listOf({
625
+ type: "digest",
626
+ scope: "community",
627
+ actorId: null,
628
+ communityId,
629
+ spaceId: null,
630
+ subject: {
631
+ type: "community",
632
+ id: communityId
633
+ },
634
+ parent: null,
635
+ display: {
636
+ communityTitle: title,
637
+ from: from.toISOString(),
638
+ to: to.toISOString(),
639
+ posts: shown.map((post) => ({
640
+ postId: post.postId,
641
+ title: post.title,
642
+ authorName: post.authorName,
643
+ spaceName: post.spaceName,
644
+ commentCount: post.commentCount
645
+ }))
646
+ }
647
+ }, await recipientsOf(reads, orgId, group.members, {
648
+ exclude: [],
649
+ at: eventAt(event)
650
+ })));
651
+ }
652
+ return lists;
653
+ };
654
+ const DISCUSSION_RULES = {
655
+ "discussion.post.published": postPublished,
656
+ "discussion.post.created": postCreated,
657
+ "discussion.post.updated": postUpdated,
658
+ "discussion.post.removed": postRemoved,
659
+ "discussion.post.reaction.added": postReacted,
660
+ "discussion.comment.created": commentCreated,
661
+ "discussion.comment.published": commentPublished,
662
+ "discussion.comment.updated": commentUpdated,
663
+ "discussion.comment.removed": commentRemoved,
664
+ "discussion.comment.reaction.added": commentReacted,
665
+ "discussion.post.reported": postReported,
666
+ "discussion.comment.reported": commentReported,
667
+ "discussion.message.sent": messageSent,
668
+ "discussion.message.updated": messageUpdated,
669
+ "discussion.message.reaction.added": messageReacted,
670
+ "discussion.message.reported": messageReported,
671
+ "discussion.chat.created": chatCreated,
672
+ "discussion.chat.participant.added": chatParticipantAdded,
673
+ "discussion.digest.due": digestDue
674
+ };
675
+ //#endregion
676
+ export { DISCUSSION_RULES, messageSummary };
677
+
678
+ //# sourceMappingURL=discussion.js.map