@headless-lms/core 0.4.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 (249) hide show
  1. package/dist/assets/events.d.ts +27 -21
  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 +4 -4
  6. package/dist/assets/index.js +3 -3
  7. package/dist/assets/ports.d.ts +34 -15
  8. package/dist/assets/service.d.ts +30 -14
  9. package/dist/assets/service.js +230 -56
  10. package/dist/assets/service.js.map +1 -1
  11. package/dist/automations/actions.js.map +1 -1
  12. package/dist/automations/catalog.js +69 -4
  13. package/dist/automations/catalog.js.map +1 -1
  14. package/dist/automations/community-derivations.js +16 -16
  15. package/dist/automations/community-derivations.js.map +1 -1
  16. package/dist/automations/community-mail.d.ts +34 -4
  17. package/dist/automations/community-mail.js +32 -4
  18. package/dist/automations/community-mail.js.map +1 -1
  19. package/dist/automations/event-permissions.d.ts +12 -0
  20. package/dist/automations/event-permissions.js +38 -0
  21. package/dist/automations/event-permissions.js.map +1 -0
  22. package/dist/automations/index.d.ts +2 -1
  23. package/dist/automations/index.js +2 -1
  24. package/dist/automations/notifications/applicable.d.ts +8 -0
  25. package/dist/automations/notifications/applicable.js +12 -0
  26. package/dist/automations/notifications/applicable.js.map +1 -0
  27. package/dist/automations/notifications/debounce.js +1 -1
  28. package/dist/automations/notifications/debounce.js.map +1 -1
  29. package/dist/automations/notifications/defaults.js +33 -3
  30. package/dist/automations/notifications/defaults.js.map +1 -1
  31. package/dist/automations/notifications/processor.js +3 -3
  32. package/dist/automations/notifications/processor.js.map +1 -1
  33. package/dist/automations/notifications/rules/content.js +60 -3
  34. package/dist/automations/notifications/rules/content.js.map +1 -1
  35. package/dist/automations/notifications/rules/discussion.js +29 -29
  36. package/dist/automations/notifications/rules/discussion.js.map +1 -1
  37. package/dist/automations/notifications/rules/entitlements.js +36 -9
  38. package/dist/automations/notifications/rules/entitlements.js.map +1 -1
  39. package/dist/automations/notifications/rules/events.d.ts +9 -0
  40. package/dist/automations/notifications/rules/events.js +27 -0
  41. package/dist/automations/notifications/rules/events.js.map +1 -0
  42. package/dist/automations/notifications/rules/organizations.js +17 -10
  43. package/dist/automations/notifications/rules/organizations.js.map +1 -1
  44. package/dist/automations/notifications/rules/recipients.js +0 -1
  45. package/dist/automations/notifications/rules/recipients.js.map +1 -1
  46. package/dist/automations/notifications/service.d.ts +8 -6
  47. package/dist/automations/notifications/service.js +13 -13
  48. package/dist/automations/notifications/service.js.map +1 -1
  49. package/dist/automations/notifications/types.js +94 -7
  50. package/dist/automations/notifications/types.js.map +1 -1
  51. package/dist/automations/ports.d.ts +30 -31
  52. package/dist/automations/service.d.ts +20 -17
  53. package/dist/automations/service.js +91 -62
  54. package/dist/automations/service.js.map +1 -1
  55. package/dist/content/event-sight.d.ts +11 -0
  56. package/dist/content/event-sight.js +11 -0
  57. package/dist/content/event-sight.js.map +1 -0
  58. package/dist/content/events.d.ts +413 -72
  59. package/dist/content/events.js +34 -1
  60. package/dist/content/events.js.map +1 -1
  61. package/dist/content/index.d.ts +6 -4
  62. package/dist/content/index.js +3 -1
  63. package/dist/content/jobs.d.ts +16 -0
  64. package/dist/content/jobs.js +37 -0
  65. package/dist/content/jobs.js.map +1 -0
  66. package/dist/content/model.d.ts +2 -2
  67. package/dist/content/notification-categories.d.ts +5 -4
  68. package/dist/content/notification-categories.js +15 -6
  69. package/dist/content/notification-categories.js.map +1 -1
  70. package/dist/content/ports.d.ts +113 -68
  71. package/dist/content/service.d.ts +99 -67
  72. package/dist/content/service.js +680 -139
  73. package/dist/content/service.js.map +1 -1
  74. package/dist/content/titles.d.ts +6 -3
  75. package/dist/content/titles.js +37 -24
  76. package/dist/content/titles.js.map +1 -1
  77. package/dist/content/types.d.ts +2 -2
  78. package/dist/discussion/authors.d.ts +4 -2
  79. package/dist/discussion/authors.js +9 -5
  80. package/dist/discussion/authors.js.map +1 -1
  81. package/dist/discussion/chats.d.ts +56 -37
  82. package/dist/discussion/chats.js +393 -161
  83. package/dist/discussion/chats.js.map +1 -1
  84. package/dist/discussion/events.d.ts +77 -39
  85. package/dist/discussion/events.js +41 -3
  86. package/dist/discussion/events.js.map +1 -1
  87. package/dist/discussion/index.d.ts +8 -5
  88. package/dist/discussion/index.js +5 -3
  89. package/dist/discussion/live.d.ts +106 -0
  90. package/dist/discussion/live.js +642 -0
  91. package/dist/discussion/live.js.map +1 -0
  92. package/dist/discussion/mentions.js +2 -2
  93. package/dist/discussion/mentions.js.map +1 -1
  94. package/dist/discussion/ports.d.ts +182 -100
  95. package/dist/discussion/ports.js.map +1 -1
  96. package/dist/discussion/posts.d.ts +45 -39
  97. package/dist/discussion/posts.js +268 -154
  98. package/dist/discussion/posts.js.map +1 -1
  99. package/dist/discussion/rules.d.ts +18 -0
  100. package/dist/discussion/rules.js +22 -0
  101. package/dist/discussion/rules.js.map +1 -0
  102. package/dist/discussion/service.d.ts +37 -31
  103. package/dist/discussion/service.js +252 -188
  104. package/dist/discussion/service.js.map +1 -1
  105. package/dist/discussion/subscriptions.d.ts +8 -8
  106. package/dist/discussion/subscriptions.js +29 -13
  107. package/dist/discussion/subscriptions.js.map +1 -1
  108. package/dist/discussion/titles.d.ts +4 -2
  109. package/dist/discussion/titles.js +27 -13
  110. package/dist/discussion/titles.js.map +1 -1
  111. package/dist/entitlements/events.d.ts +20 -20
  112. package/dist/entitlements/index.d.ts +4 -4
  113. package/dist/entitlements/index.js +2 -2
  114. package/dist/entitlements/model.d.ts +2 -2
  115. package/dist/entitlements/ports.d.ts +65 -39
  116. package/dist/entitlements/rules.d.ts +3 -6
  117. package/dist/entitlements/rules.js +5 -10
  118. package/dist/entitlements/rules.js.map +1 -1
  119. package/dist/entitlements/service.d.ts +40 -28
  120. package/dist/entitlements/service.js +370 -163
  121. package/dist/entitlements/service.js.map +1 -1
  122. package/dist/identity/devices.d.ts +3 -3
  123. package/dist/identity/devices.js +7 -5
  124. package/dist/identity/devices.js.map +1 -1
  125. package/dist/identity/events.d.ts +2 -2
  126. package/dist/identity/index.d.ts +2 -2
  127. package/dist/identity/index.js +2 -2
  128. package/dist/identity/notification-settings.d.ts +1 -1
  129. package/dist/identity/notification-settings.js +3 -2
  130. package/dist/identity/notification-settings.js.map +1 -1
  131. package/dist/identity/ports.d.ts +7 -7
  132. package/dist/identity/service.d.ts +8 -7
  133. package/dist/identity/service.js +17 -13
  134. package/dist/identity/service.js.map +1 -1
  135. package/dist/integrations/events.d.ts +3 -3
  136. package/dist/integrations/ports.d.ts +9 -8
  137. package/dist/integrations/service.d.ts +9 -8
  138. package/dist/integrations/service.js +33 -16
  139. package/dist/integrations/service.js.map +1 -1
  140. package/dist/organizations/default-roles.d.ts +22 -0
  141. package/dist/organizations/default-roles.js +89 -0
  142. package/dist/organizations/default-roles.js.map +1 -0
  143. package/dist/organizations/effective-permissions.d.ts +45 -0
  144. package/dist/organizations/effective-permissions.js +113 -0
  145. package/dist/organizations/effective-permissions.js.map +1 -0
  146. package/dist/organizations/events.d.ts +320 -181
  147. package/dist/organizations/events.js +90 -18
  148. package/dist/organizations/events.js.map +1 -1
  149. package/dist/organizations/index.d.ts +14 -10
  150. package/dist/organizations/index.js +7 -3
  151. package/dist/organizations/members.d.ts +66 -8
  152. package/dist/organizations/members.js.map +1 -1
  153. package/dist/organizations/notification-catalog.d.ts +31 -0
  154. package/dist/organizations/notification-catalog.js +32 -0
  155. package/dist/organizations/notification-catalog.js.map +1 -0
  156. package/dist/organizations/notification-categories.d.ts +6 -4
  157. package/dist/organizations/notification-categories.js +25 -10
  158. package/dist/organizations/notification-categories.js.map +1 -1
  159. package/dist/organizations/org-roles.d.ts +33 -0
  160. package/dist/organizations/org-roles.js +49 -0
  161. package/dist/organizations/org-roles.js.map +1 -0
  162. package/dist/organizations/permissions.d.ts +311 -0
  163. package/dist/organizations/permissions.js +327 -0
  164. package/dist/organizations/permissions.js.map +1 -0
  165. package/dist/organizations/ports.d.ts +184 -65
  166. package/dist/organizations/service.d.ts +102 -35
  167. package/dist/organizations/service.js +1245 -328
  168. package/dist/organizations/service.js.map +1 -1
  169. package/dist/organizations/testing.d.ts +18 -0
  170. package/dist/organizations/testing.js +37 -0
  171. package/dist/organizations/testing.js.map +1 -0
  172. package/dist/organizations/types.d.ts +5 -16
  173. package/dist/progress/events.d.ts +14 -14
  174. package/dist/progress/index.d.ts +2 -2
  175. package/dist/progress/ports.d.ts +11 -3
  176. package/dist/progress/service.d.ts +6 -5
  177. package/dist/progress/service.js +23 -8
  178. package/dist/progress/service.js.map +1 -1
  179. package/dist/reporting/admin/index.d.ts +6 -4
  180. package/dist/reporting/admin/model.d.ts +36 -3
  181. package/dist/reporting/admin/ports.d.ts +39 -14
  182. package/dist/reporting/admin/service.d.ts +32 -11
  183. package/dist/reporting/admin/service.js +102 -18
  184. package/dist/reporting/admin/service.js.map +1 -1
  185. package/dist/reporting/events/index.d.ts +27 -0
  186. package/dist/reporting/events/index.js +20 -0
  187. package/dist/reporting/events/index.js.map +1 -0
  188. package/dist/reporting/member/calendar.d.ts +11 -0
  189. package/dist/reporting/member/calendar.js +75 -0
  190. package/dist/reporting/member/calendar.js.map +1 -0
  191. package/dist/reporting/member/index.d.ts +3 -2
  192. package/dist/reporting/member/model.d.ts +26 -5
  193. package/dist/reporting/member/ports.d.ts +48 -29
  194. package/dist/reporting/member/service.d.ts +56 -29
  195. package/dist/reporting/member/service.js +328 -113
  196. package/dist/reporting/member/service.js.map +1 -1
  197. package/dist/shared/actor.d.ts +22 -3
  198. package/dist/shared/errors.d.ts +2 -1
  199. package/dist/shared/errors.js +3 -1
  200. package/dist/shared/errors.js.map +1 -1
  201. package/dist/shared/id.d.ts +4 -0
  202. package/dist/shared/id.js +4 -0
  203. package/dist/shared/id.js.map +1 -1
  204. package/dist/shared/logger.d.ts +2 -1
  205. package/dist/shared/logger.js +10 -1
  206. package/dist/shared/logger.js.map +1 -1
  207. package/dist/shared/ports.d.ts +25 -5
  208. package/dist/types/content.d.ts +2 -2
  209. package/dist/types/discussion.d.ts +4 -5
  210. package/dist/types/email-templates.d.ts +22 -3
  211. package/dist/types/entitlements.d.ts +2 -2
  212. package/dist/types/identity.d.ts +13 -16
  213. package/dist/types/index.d.ts +9 -9
  214. package/dist/types/index.js +2 -1
  215. package/dist/types/notifications.d.ts +4 -4
  216. package/dist/types/organizations.d.ts +3 -2
  217. package/dist/types/ports.d.ts +8 -1
  218. package/dist/types/ports.js +7 -1
  219. package/dist/types/ports.js.map +1 -0
  220. package/dist/types/schemas/assets.d.ts +5 -5
  221. package/dist/types/schemas/assets.js +4 -3
  222. package/dist/types/schemas/assets.js.map +1 -1
  223. package/dist/types/schemas/content.d.ts +537 -13
  224. package/dist/types/schemas/content.js +201 -7
  225. package/dist/types/schemas/content.js.map +1 -1
  226. package/dist/types/schemas/discussion.d.ts +282 -59
  227. package/dist/types/schemas/discussion.js +77 -3
  228. package/dist/types/schemas/discussion.js.map +1 -1
  229. package/dist/types/schemas/entitlements.d.ts +14 -1
  230. package/dist/types/schemas/entitlements.js +11 -4
  231. package/dist/types/schemas/entitlements.js.map +1 -1
  232. package/dist/types/schemas/index.d.ts +5 -5
  233. package/dist/types/schemas/index.js +5 -5
  234. package/dist/types/schemas/notifications.d.ts +13 -12
  235. package/dist/types/schemas/notifications.js +3 -2
  236. package/dist/types/schemas/notifications.js.map +1 -1
  237. package/dist/types/schemas/organizations.d.ts +96 -60
  238. package/dist/types/schemas/organizations.js +78 -27
  239. package/dist/types/schemas/organizations.js.map +1 -1
  240. package/dist/types/schemas/progress.d.ts +3 -4
  241. package/dist/types/schemas/progress.js +0 -1
  242. package/dist/types/schemas/progress.js.map +1 -1
  243. package/package.json +1 -1
  244. package/dist/organizations/access-scopes.d.ts +0 -19
  245. package/dist/organizations/access-scopes.js +0 -89
  246. package/dist/organizations/access-scopes.js.map +0 -1
  247. package/dist/organizations/roles.d.ts +0 -19
  248. package/dist/organizations/roles.js +0 -82
  249. package/dist/organizations/roles.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"content.js","names":[],"sources":["../../../../src/automations/notifications/rules/content.ts"],"sourcesContent":["import { contentEvents } from '../../../content/index.js';\nimport type { RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst activityPublished: RecipientRule = async (event, reads) => {\n const parsed = contentEvents.activityPublished.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { activityId, courseId } = parsed.data.data;\n const orgId = event.orgId;\n const activity = await reads.activity(orgId, activityId);\n if (!activity) {\n return [];\n }\n return listOf(\n {\n type: 'course.activity_added',\n scope: 'org',\n actorOrgUserId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: { type: 'activity', id: activityId },\n parent: { type: 'course', id: courseId },\n display: {\n courseTitle: activity.courseTitle,\n moduleTitle: activity.moduleTitle,\n activityTitle: activity.title,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.courseHolders(orgId, courseId), 'course_member'),\n { exclude: [actorOr(event, null)], at: eventAt(event) },\n ),\n );\n};\n\nexport const CONTENT_RULES: Record<string, RecipientRule> = {\n 'content.course.activity.published': activityPublished,\n};\n"],"mappings":";;;AAIA,MAAM,oBAAmC,OAAO,OAAO,UAAU;CAC/D,MAAM,SAAS,cAAc,kBAAkB,UAAU,KAAK;CAC9D,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,EAAE,YAAY,aAAa,OAAO,KAAK;CAC7C,MAAM,QAAQ,MAAM;CACpB,MAAM,WAAW,MAAM,MAAM,SAAS,OAAO,UAAU;CACvD,IAAI,CAAC,UACH,OAAO,CAAC;CAEV,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,gBAAgB,QAAQ,OAAO,IAAI;EACnC,aAAa;EACb,SAAS;EACT,SAAS;GAAE,MAAM;GAAY,IAAI;EAAW;EAC5C,QAAQ;GAAE,MAAM;GAAU,IAAI;EAAS;EACvC,SAAS;GACP,aAAa,SAAS;GACtB,aAAa,SAAS;GACtB,eAAe,SAAS;EAC1B;CACF,GACA,MAAM,aACJ,OACA,OACA,IAAI,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,cAAc,OAAO,QAAQ,GAAG,eAAe,GAC7E;EAAE,SAAS,CAAC,QAAQ,OAAO,IAAI,CAAC;EAAG,IAAI,QAAQ,KAAK;CAAE,CACxD,CACF;AACF;AAEA,MAAa,gBAA+C,EAC1D,qCAAqC,kBACvC"}
1
+ {"version":3,"file":"content.js","names":[],"sources":["../../../../src/automations/notifications/rules/content.ts"],"sourcesContent":["import { contentEvents, type Event } from '../../../content/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport { previousStatusOf } from '../../community-mail.js';\nimport { eventBase, eventDisplay } from './events.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst activityPublished: RecipientRule = async (event, reads) => {\n const parsed = contentEvents.activityPublished.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { activityId, courseId } = parsed.data.data;\n const orgId = event.orgId;\n const activity = await reads.activity(orgId, activityId);\n if (!activity) {\n return [];\n }\n return listOf(\n {\n type: 'course.activity_added',\n scope: 'org',\n actorId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: { type: 'activity', id: activityId },\n parent: { type: 'course', id: courseId },\n display: {\n courseTitle: activity.courseTitle,\n moduleTitle: activity.moduleTitle,\n activityTitle: activity.title,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.courseMembers(orgId, courseId), 'course_member'),\n { exclude: [actorOr(event, null)], at: eventAt(event) },\n ),\n );\n};\n\nconst LEAD_TEXT = { '1d': '1 day', '1h': '1 hour' } as const;\n\nfunction metadataText(event: DomainEvent, key: string): string | undefined {\n const value = event.metadata?.[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction whatChanged(\n event: DomainEvent,\n next: Event,\n): 'time' | 'location' | 'time_and_location' | null {\n const time =\n metadataText(event, 'previousStartsAt') !== next.startsAt.toISOString() ||\n metadataText(event, 'previousEndsAt') !== next.endsAt.toISOString();\n const location = event.metadata?.locationChanged === true;\n if (time && location) {\n return 'time_and_location';\n }\n return time ? 'time' : location ? 'location' : null;\n}\n\nasync function toAttendees(\n reads: NotificationReads,\n domainEvent: DomainEvent,\n event: Event,\n type: string,\n actorId: string | null,\n display: Record<string, string>,\n) {\n return listOf(\n { ...eventBase(type, event, actorId), display },\n await recipientsOf(\n reads,\n domainEvent.orgId,\n new Reasons().add(await reads.eventAttendees(domainEvent.orgId, event.id), 'event_member'),\n { exclude: [actorId], at: eventAt(domainEvent) },\n ),\n );\n}\n\nconst eventUpdated: RecipientRule = async (domainEvent, reads) => {\n const parsed = contentEvents.eventUpdated.safeParse(domainEvent);\n if (!parsed.success) {\n return [];\n }\n const next = parsed.data.data;\n const event = await reads.event(domainEvent.orgId, next.id);\n if (!event?.settings.notifications) {\n return [];\n }\n const actor = actorOr(domainEvent, null);\n const previousStatus = previousStatusOf(domainEvent);\n if (next.status === 'canceled' && previousStatus !== 'canceled') {\n return toAttendees(reads, domainEvent, event, 'event.canceled', actor, eventDisplay(next));\n }\n if (\n previousStatus !== 'published' ||\n next.status !== 'published' ||\n next.endsAt.getTime() <= eventAt(domainEvent).getTime()\n ) {\n return [];\n }\n const changed = whatChanged(domainEvent, next);\n if (!changed) {\n return [];\n }\n return toAttendees(reads, domainEvent, event, 'event.changed', actor, {\n ...eventDisplay(next),\n changed,\n });\n};\n\nconst eventStartingSoon: RecipientRule = async (domainEvent, reads) => {\n const parsed = contentEvents.eventStartingSoon.safeParse(domainEvent);\n if (!parsed.success) {\n return [];\n }\n const { eventId, lead } = parsed.data.data;\n const event = await reads.event(domainEvent.orgId, eventId);\n if (!event?.settings.notifications || event.status !== 'published') {\n return [];\n }\n return toAttendees(reads, domainEvent, event, 'event.starting_soon', null, {\n ...eventDisplay(event),\n leadText: LEAD_TEXT[lead],\n });\n};\n\nexport const CONTENT_RULES: Record<string, RecipientRule> = {\n 'content.course.activity.published': activityPublished,\n 'content.event.updated': eventUpdated,\n 'content.event.starting_soon': eventStartingSoon,\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { discussionEvents } from "../../../discussion/events.js";
2
- import { previousStatusOf } from "../../community-mail.js";
2
+ import { communityModerators, previousStatusOf } from "../../community-mail.js";
3
3
  import { Reasons, actorOr, chatReach, chatTitle, eventAt, listOf, participantNames, recipientsOf, textExcerpt } from "./recipients.js";
4
4
  //#region src/automations/notifications/rules/discussion.ts
5
5
  const CHAT_STATUS = "chatStatus";
@@ -22,8 +22,8 @@ function courseReach(reads, orgId, courseId, exclude, at) {
22
22
  exclude,
23
23
  at,
24
24
  canOpen: async (orgUserIds) => {
25
- const [holders, staff] = await Promise.all([reads.courseHolders(orgId, courseId), reads.staffIds(orgId)]);
26
- const open = /* @__PURE__ */ new Set([...holders, ...staff]);
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
27
  return orgUserIds.filter((orgUserId) => open.has(orgUserId));
28
28
  }
29
29
  };
@@ -55,7 +55,7 @@ function placeReach(reads, orgId, place, exclude, at) {
55
55
  spaceId: place.post.spaceId
56
56
  }, exclude, at) : courseReach(reads, orgId, place.activity.courseId, exclude, at);
57
57
  }
58
- function commentBase(type, place, commentId, actorOrgUserId, display) {
58
+ function commentBase(type, place, commentId, actorId, display) {
59
59
  const subject = {
60
60
  type: "comment",
61
61
  id: commentId
@@ -63,7 +63,7 @@ function commentBase(type, place, commentId, actorOrgUserId, display) {
63
63
  if (place.kind === "post") return {
64
64
  type,
65
65
  scope: "space",
66
- actorOrgUserId,
66
+ actorId,
67
67
  communityId: place.post.communityId,
68
68
  spaceId: place.post.spaceId,
69
69
  subject,
@@ -79,7 +79,7 @@ function commentBase(type, place, commentId, actorOrgUserId, display) {
79
79
  return {
80
80
  type,
81
81
  scope: "org",
82
- actorOrgUserId,
82
+ actorId,
83
83
  communityId: null,
84
84
  spaceId: null,
85
85
  subject,
@@ -158,7 +158,7 @@ const postPublished = async (event, reads) => {
158
158
  if (previousStatusOf(event) === "pending") lists.push(...listOf({
159
159
  ...base,
160
160
  type: "post.approved",
161
- actorOrgUserId: actor,
161
+ actorId: actor,
162
162
  display: {
163
163
  postTitle: post.title,
164
164
  spaceName: space.name
@@ -168,10 +168,10 @@ const postPublished = async (event, reads) => {
168
168
  exclude: [actor]
169
169
  })));
170
170
  const authorName = await reads.displayName(orgId, post.orgUserId);
171
- const text = await textExcerpt(reads, orgId, post.body || post.title, 280);
171
+ const text = await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280);
172
172
  lists.push(...await mentionsOf(reads, orgId, {
173
173
  ...base,
174
- actorOrgUserId: post.orgUserId,
174
+ actorId: post.orgUserId,
175
175
  display: {
176
176
  authorName,
177
177
  excerpt: text,
@@ -181,7 +181,7 @@ const postPublished = async (event, reads) => {
181
181
  lists.push({
182
182
  ...base,
183
183
  type: "post.published",
184
- actorOrgUserId: post.orgUserId,
184
+ actorId: post.orgUserId,
185
185
  display: {
186
186
  spaceName: space.name,
187
187
  postTitle: post.title,
@@ -205,7 +205,7 @@ async function awaitingReview(event, reads, post) {
205
205
  return listOf({
206
206
  type: "post.awaiting_review",
207
207
  scope: "space",
208
- actorOrgUserId: post.orgUserId,
208
+ actorId: post.orgUserId,
209
209
  communityId: post.communityId,
210
210
  spaceId: post.spaceId,
211
211
  subject: {
@@ -218,7 +218,7 @@ async function awaitingReview(event, reads, post) {
218
218
  postTitle: post.title,
219
219
  authorName: await reads.displayName(orgId, post.orgUserId)
220
220
  }
221
- }, await recipientsOf(reads, orgId, new Reasons().add(await reads.moderationAudience(orgId, post.communityId), "moderator"), {
221
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, post.communityId), "moderator"), {
222
222
  exclude: [actor, post.orgUserId],
223
223
  at: eventAt(event),
224
224
  canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
@@ -238,7 +238,7 @@ const postUpdated = async (event, reads) => {
238
238
  const actor = actorOr(event, post.orgUserId);
239
239
  lists.push(...await mentionsOf(reads, orgId, {
240
240
  scope: "space",
241
- actorOrgUserId: post.orgUserId,
241
+ actorId: post.orgUserId,
242
242
  communityId: post.communityId,
243
243
  spaceId: post.spaceId,
244
244
  subject: {
@@ -248,7 +248,7 @@ const postUpdated = async (event, reads) => {
248
248
  parent: null,
249
249
  display: {
250
250
  authorName: await reads.displayName(orgId, post.orgUserId),
251
- excerpt: await textExcerpt(reads, orgId, post.body || post.title, 280),
251
+ excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
252
252
  postTitle: post.title
253
253
  }
254
254
  }, post.mentionedOrgUserIds, postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event))));
@@ -266,7 +266,7 @@ const postRemoved = async (event, reads) => {
266
266
  return listOf({
267
267
  type: "post.removed",
268
268
  scope: "space",
269
- actorOrgUserId: remover,
269
+ actorId: remover,
270
270
  communityId: post.communityId,
271
271
  spaceId: post.spaceId,
272
272
  subject: {
@@ -290,7 +290,7 @@ const postReacted = async (event, reads) => {
290
290
  return listOf({
291
291
  type: "post.reacted",
292
292
  scope: "space",
293
- actorOrgUserId: reaction.orgUserId,
293
+ actorId: reaction.orgUserId,
294
294
  communityId: post.communityId,
295
295
  spaceId: post.spaceId,
296
296
  subject: {
@@ -366,7 +366,7 @@ const postReported = async (event, reads) => {
366
366
  return listOf({
367
367
  type: "content.flagged",
368
368
  scope: "space",
369
- actorOrgUserId: flag.orgUserId,
369
+ actorId: flag.orgUserId,
370
370
  communityId: flag.communityId,
371
371
  spaceId: post.spaceId,
372
372
  subject: {
@@ -376,10 +376,10 @@ const postReported = async (event, reads) => {
376
376
  parent: null,
377
377
  display: {
378
378
  spaceName: space.name,
379
- excerpt: await textExcerpt(reads, orgId, post.body || post.title, 280),
379
+ excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
380
380
  reason: flag.reason
381
381
  }
382
- }, await recipientsOf(reads, orgId, new Reasons().add(await reads.moderationAudience(orgId, flag.communityId), "moderator"), {
382
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
383
383
  exclude: [actorOr(event, flag.orgUserId)],
384
384
  at: eventAt(event),
385
385
  canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
@@ -402,7 +402,7 @@ const commentReported = async (event, reads) => {
402
402
  excerpt: text,
403
403
  reason: flag.reason
404
404
  }
405
- }, await recipientsOf(reads, orgId, new Reasons().add(await reads.moderationAudience(orgId, place.post.communityId), "moderator"), {
405
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, place.post.communityId), "moderator"), {
406
406
  exclude: [actor],
407
407
  at: eventAt(event),
408
408
  canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds)
@@ -410,7 +410,7 @@ const commentReported = async (event, reads) => {
410
410
  return listOf(commentBase("content.flagged", place, flag.commentId, actor, {
411
411
  excerpt: text,
412
412
  reason: flag.reason
413
- }), await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), "staff"), {
413
+ }), await recipientsOf(reads, orgId, new Reasons().add(await reads.holders(orgId, "courses:moderate", place.activity.courseId), "moderator"), {
414
414
  exclude: [actor],
415
415
  at: eventAt(event)
416
416
  }));
@@ -425,7 +425,7 @@ async function chatMentions(event, reads, message, mentioned) {
425
425
  if (!chat || chatPending(event, chat.status)) return [];
426
426
  return mentionsOf(reads, orgId, {
427
427
  scope: "chat",
428
- actorOrgUserId: message.orgUserId,
428
+ actorId: message.orgUserId,
429
429
  communityId: chat.communityId,
430
430
  spaceId: null,
431
431
  subject: {
@@ -457,7 +457,7 @@ const messageSent = async (event, reads) => {
457
457
  return [...listOf({
458
458
  type: "message.sent",
459
459
  scope: "chat",
460
- actorOrgUserId: message.orgUserId,
460
+ actorId: message.orgUserId,
461
461
  communityId: chat.communityId,
462
462
  spaceId: null,
463
463
  subject: {
@@ -493,7 +493,7 @@ const messageReacted = async (event, reads) => {
493
493
  return listOf({
494
494
  type: "message.reacted",
495
495
  scope: "chat",
496
- actorOrgUserId: reaction.orgUserId,
496
+ actorId: reaction.orgUserId,
497
497
  communityId: chat.communityId,
498
498
  spaceId: null,
499
499
  subject: {
@@ -520,7 +520,7 @@ const messageReported = async (event, reads) => {
520
520
  return listOf({
521
521
  type: "message.flagged",
522
522
  scope: "chat",
523
- actorOrgUserId: flag.orgUserId,
523
+ actorId: flag.orgUserId,
524
524
  communityId: flag.communityId,
525
525
  spaceId: null,
526
526
  subject: {
@@ -532,7 +532,7 @@ const messageReported = async (event, reads) => {
532
532
  id: message.chatId
533
533
  } : null,
534
534
  display: { reason: flag.reason }
535
- }, await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), "staff"), {
535
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
536
536
  exclude: [actorOr(event, flag.orgUserId)],
537
537
  at: eventAt(event)
538
538
  }));
@@ -549,7 +549,7 @@ const chatCreated = async (event, reads) => {
549
549
  return listOf({
550
550
  type: "chat.request",
551
551
  scope: "chat",
552
- actorOrgUserId: created.createdBy,
552
+ actorId: created.createdBy,
553
553
  communityId: created.communityId,
554
554
  spaceId: null,
555
555
  subject: {
@@ -573,7 +573,7 @@ const chatParticipantAdded = async (event, reads) => {
573
573
  return listOf({
574
574
  type: "chat.added",
575
575
  scope: "chat",
576
- actorOrgUserId: added.addedBy,
576
+ actorId: added.addedBy,
577
577
  communityId: added.communityId,
578
578
  spaceId: null,
579
579
  subject: {
@@ -624,7 +624,7 @@ const digestDue = async (event, reads) => {
624
624
  lists.push(...listOf({
625
625
  type: "digest",
626
626
  scope: "community",
627
- actorOrgUserId: null,
627
+ actorId: null,
628
628
  communityId,
629
629
  spaceId: null,
630
630
  subject: {
@@ -1 +1 @@
1
- {"version":3,"file":"discussion.js","names":[],"sources":["../../../../src/automations/notifications/rules/discussion.ts"],"sourcesContent":["import { discussionEvents } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { JsonValue, RecipientList, SubjectRef } from '../../../types/index.js';\nimport { MESSAGE_EXCERPT, POST_EXCERPT, previousStatusOf } from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport {\n actorOr,\n chatReach,\n chatTitle,\n eventAt,\n listOf,\n participantNames,\n Reasons,\n recipientsOf,\n textExcerpt,\n type ListBase,\n type Reach,\n} from './recipients.js';\n\ntype Post = NonNullable<Awaited<ReturnType<NotificationReads['post']>>>;\ntype Activity = NonNullable<Awaited<ReturnType<NotificationReads['activity']>>>;\n\ntype Place =\n | { kind: 'post'; postId: string; post: Post; spaceName: string }\n | { kind: 'activity'; activityId: string; activity: Activity };\n\nconst CHAT_STATUS = 'chatStatus';\n\nfunction postReach(\n reads: NotificationReads,\n orgId: string,\n post: { id: string; spaceId: string },\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n mutedOn: [\n { type: 'post', id: post.id },\n { type: 'space', id: post.spaceId },\n ],\n };\n}\n\nfunction courseReach(\n reads: NotificationReads,\n orgId: string,\n courseId: string,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: async (orgUserIds) => {\n const [holders, staff] = await Promise.all([\n reads.courseHolders(orgId, courseId),\n reads.staffIds(orgId),\n ]);\n const open = new Set([...holders, ...staff]);\n return orgUserIds.filter((orgUserId) => open.has(orgUserId));\n },\n };\n}\n\nasync function placeOf(\n reads: NotificationReads,\n orgId: string,\n comment: { postId: string | null; activityId: string | null },\n): Promise<Place | null> {\n if (comment.postId) {\n const post = await reads.post(orgId, comment.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n return post && space\n ? { kind: 'post', postId: comment.postId, post, spaceName: space.name }\n : null;\n }\n if (comment.activityId) {\n const activity = await reads.activity(orgId, comment.activityId);\n return activity ? { kind: 'activity', activityId: comment.activityId, activity } : null;\n }\n return null;\n}\n\nfunction placeReach(\n reads: NotificationReads,\n orgId: string,\n place: Place,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return place.kind === 'post'\n ? postReach(reads, orgId, { id: place.postId, spaceId: place.post.spaceId }, exclude, at)\n : courseReach(reads, orgId, place.activity.courseId, exclude, at);\n}\n\nfunction commentBase(\n type: string,\n place: Place,\n commentId: string,\n actorOrgUserId: string | null,\n display: Record<string, JsonValue>,\n): ListBase {\n const subject: SubjectRef = { type: 'comment', id: commentId };\n if (place.kind === 'post') {\n return {\n type,\n scope: 'space',\n actorOrgUserId,\n communityId: place.post.communityId,\n spaceId: place.post.spaceId,\n subject,\n parent: { type: 'post', id: place.postId },\n display: { postTitle: place.post.title, ...display },\n };\n }\n return {\n type,\n scope: 'org',\n actorOrgUserId,\n communityId: null,\n spaceId: null,\n subject,\n parent: { type: 'activity', id: place.activityId },\n display: {\n activityTitle: place.activity.title,\n courseTitle: place.activity.courseTitle,\n courseId: place.activity.courseId,\n ...display,\n },\n };\n}\n\nasync function mentionsOf(\n reads: NotificationReads,\n orgId: string,\n base: Omit<ListBase, 'type'>,\n mentioned: string[],\n reach: Reach,\n): Promise<RecipientList[]> {\n if (mentioned.length === 0) {\n return [];\n }\n const recipients = await recipientsOf(\n reads,\n orgId,\n new Reasons().add(mentioned, 'mentioned'),\n reach,\n );\n return listOf({ ...base, type: 'mention' }, recipients);\n}\n\nasync function commentLists(\n event: DomainEvent,\n reads: NotificationReads,\n comment: {\n id: string;\n postId: string | null;\n activityId: string | null;\n parentId: string | null;\n orgUserId: string;\n body: string;\n mentionedOrgUserIds: string[];\n },\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n const at = eventAt(event);\n const exclude = [comment.orgUserId, actorOr(event, comment.orgUserId)];\n const reasons = new Reasons();\n if (place.kind === 'post') {\n reasons.add([place.post.orgUserId], 'post_author');\n }\n const parent = comment.parentId ? await reads.comment(orgId, comment.parentId) : null;\n reasons.add([parent?.orgUserId], 'comment_author');\n if (place.kind === 'post') {\n reasons.add(await reads.followerIds(orgId, place.postId), 'follower');\n }\n reasons.add(\n await reads.threadParticipants(\n orgId,\n place.kind === 'post'\n ? { type: 'post', id: place.postId }\n : { type: 'activity', id: place.activityId },\n ),\n 'thread_participant',\n );\n const name = await reads.displayName(orgId, comment.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n const created = listOf(\n commentBase('comment.created', place, comment.id, comment.orgUserId, {\n commenterName: name,\n excerpt: text,\n }),\n await recipientsOf(reads, orgId, reasons, placeReach(reads, orgId, place, exclude, at)),\n );\n const mentions = await mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: name,\n excerpt: text,\n }),\n comment.mentionedOrgUserIds,\n placeReach(reads, orgId, place, exclude, at),\n );\n return [...created, ...mentions];\n}\n\nconst postPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success || previousStatusOf(event) === 'removed') {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const at = eventAt(event);\n const actor = actorOr(event, null);\n const exclude = [...new Set([post.orgUserId, ...(actor ? [actor] : [])])];\n const reach = postReach(reads, orgId, post, exclude, at);\n const base = {\n scope: 'space' as const,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post' as const, id: post.id },\n parent: null,\n };\n const lists: RecipientList[] = [];\n if (previousStatusOf(event) === 'pending') {\n lists.push(\n ...listOf(\n {\n ...base,\n type: 'post.approved',\n actorOrgUserId: actor,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], 'subject'), {\n ...reach,\n exclude: [actor],\n }),\n ),\n );\n }\n const authorName = await reads.displayName(orgId, post.orgUserId);\n const text = await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n ...base,\n actorOrgUserId: post.orgUserId,\n display: { authorName, excerpt: text, postTitle: post.title },\n },\n post.mentionedOrgUserIds,\n reach,\n )),\n );\n lists.push({\n ...base,\n type: 'post.published',\n actorOrgUserId: post.orgUserId,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName,\n excerpt: text,\n },\n audience: { reason: 'space_member', spaceId: post.spaceId, exclude },\n });\n return lists;\n};\n\nasync function awaitingReview(\n event: DomainEvent,\n reads: NotificationReads,\n post: {\n id: string;\n communityId: string;\n spaceId: string;\n orgUserId: string;\n title: string;\n status: string;\n },\n): Promise<RecipientList[]> {\n if (post.status !== 'pending' || previousStatusOf(event) === 'pending') {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const actor = actorOr(event, post.orgUserId);\n return listOf(\n {\n type: 'post.awaiting_review',\n scope: 'space',\n actorOrgUserId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await reads.displayName(orgId, post.orgUserId),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.moderationAudience(orgId, post.communityId), 'moderator'),\n {\n exclude: [actor, post.orgUserId],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n}\n\nconst postCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postCreated.safeParse(event);\n return parsed.success ? awaitingReview(event, reads, parsed.data.data) : [];\n};\n\nconst postUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const lists = await awaitingReview(event, reads, post);\n if (post.mentionedOrgUserIds.length === 0) {\n return lists;\n }\n const actor = actorOr(event, post.orgUserId);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n scope: 'space',\n actorOrgUserId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n authorName: await reads.displayName(orgId, post.orgUserId),\n excerpt: await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT),\n postTitle: post.title,\n },\n },\n post.mentionedOrgUserIds,\n postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event)),\n )),\n );\n return lists;\n};\n\nconst postRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const remover = post.removedBy ?? actorOr(event, null);\n if (!remover || remover === post.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n return listOf(\n {\n type: 'post.removed',\n scope: 'space',\n actorOrgUserId: remover,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'subject'),\n postReach(reads, orgId, post, [remover], eventAt(event)),\n ),\n );\n};\n\nconst postReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, reaction.postId);\n if (!post) {\n return [];\n }\n return listOf(\n {\n type: 'post.reacted',\n scope: 'space',\n actorOrgUserId: reaction.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: reaction.postId },\n parent: null,\n display: {\n postTitle: post.title,\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'post_author'),\n postReach(\n reads,\n orgId,\n { id: reaction.postId, spaceId: post.spaceId },\n [reaction.orgUserId, actorOr(event, null)],\n eventAt(event),\n ),\n ),\n );\n};\n\nconst commentCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success || parsed.data.data.status !== 'published') {\n return [];\n }\n return commentLists(event, reads, parsed.data.data);\n};\n\nconst commentPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentPublished.safeParse(event);\n return parsed.success ? commentLists(event, reads, parsed.data.data) : [];\n};\n\nconst commentUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n if (comment.status !== 'published' || comment.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: await reads.displayName(orgId, comment.orgUserId),\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n }),\n comment.mentionedOrgUserIds,\n placeReach(\n reads,\n orgId,\n place,\n [comment.orgUserId, actorOr(event, comment.orgUserId)],\n eventAt(event),\n ),\n );\n};\n\nconst commentRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n const remover = comment.removedBy ?? actorOr(event, null);\n if (!remover || remover === comment.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return listOf(\n commentBase('comment.removed', place, comment.id, remover, {}),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'subject'),\n placeReach(reads, orgId, place, [remover], eventAt(event)),\n ),\n );\n};\n\nconst commentReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, reaction.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n return listOf(\n commentBase('comment.reacted', place, reaction.commentId, reaction.orgUserId, {\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'comment_author'),\n placeReach(reads, orgId, place, [reaction.orgUserId, actorOr(event, null)], eventAt(event)),\n ),\n );\n};\n\nconst postReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, flag.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n if (!post || !space) {\n return [];\n }\n return listOf(\n {\n type: 'content.flagged',\n scope: 'space',\n actorOrgUserId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: flag.postId },\n parent: null,\n display: {\n spaceName: space.name,\n excerpt: await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT),\n reason: flag.reason,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.moderationAudience(orgId, flag.communityId), 'moderator'),\n {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n};\n\nconst commentReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, flag.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n const actor = actorOr(event, flag.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n if (place.kind === 'post') {\n return listOf(\n {\n ...commentBase('content.flagged', place, flag.commentId, actor, {}),\n display: { spaceName: place.spaceName, excerpt: text, reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await reads.moderationAudience(orgId, place.post.communityId),\n 'moderator',\n ),\n {\n exclude: [actor],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds),\n },\n ),\n );\n }\n return listOf(\n commentBase('content.flagged', place, flag.commentId, actor, {\n excerpt: text,\n reason: flag.reason,\n }),\n await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), 'staff'), {\n exclude: [actor],\n at: eventAt(event),\n }),\n );\n};\n\nfunction chatPending(event: DomainEvent, status: string): boolean {\n const value = event.metadata?.[CHAT_STATUS];\n return (typeof value === 'string' ? value : status) === 'pending';\n}\n\nasync function chatMentions(\n event: DomainEvent,\n reads: NotificationReads,\n message: { id: string; chatId: string; orgUserId: string; body: string },\n mentioned: string[],\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n {\n scope: 'chat',\n actorOrgUserId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n authorName: await reads.displayName(orgId, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n },\n },\n mentioned,\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n );\n}\n\nexport function messageSummary(count: number): string {\n return count === 1 ? '1 new message' : `${count} new messages`;\n}\n\nconst messageSent: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageSent.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const message = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n const senderName = await reads.displayName(orgId, message.orgUserId);\n const sent = listOf(\n {\n type: 'message.sent',\n scope: 'chat',\n actorOrgUserId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n senderName,\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n count: '1',\n summary: messageSummary(1),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n chat.participants.map((participant) => participant.orgUserId),\n 'participant',\n ),\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n ),\n );\n return [...sent, ...(await chatMentions(event, reads, message, message.mentionedOrgUserIds))];\n};\n\nconst messageUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageUpdated.safeParse(event);\n if (!parsed.success || parsed.data.data.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const message = parsed.data.data;\n return chatMentions(event, reads, message, message.mentionedOrgUserIds);\n};\n\nconst messageReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const [message, chat] = await Promise.all([\n reads.message(orgId, reaction.messageId),\n reads.chat(orgId, reaction.chatId),\n ]);\n if (!message || !chat) {\n return [];\n }\n return listOf(\n {\n type: 'message.reacted',\n scope: 'chat',\n actorOrgUserId: reaction.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: reaction.messageId },\n parent: { type: 'chat', id: reaction.chatId },\n display: {\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([message.orgUserId], 'message_author'),\n chatReach(reads, orgId, chat, reaction.chatId, reaction.orgUserId, eventAt(event)),\n ),\n );\n};\n\nconst messageReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const message = await reads.message(orgId, flag.messageId);\n return listOf(\n {\n type: 'message.flagged',\n scope: 'chat',\n actorOrgUserId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: null,\n subject: { type: 'message', id: flag.messageId },\n parent: message ? { type: 'chat', id: message.chatId } : null,\n display: { reason: flag.reason },\n },\n await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), 'staff'), {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n }),\n );\n};\n\nconst chatCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const created = parsed.data.data;\n if (created.kind !== 'direct' || created.status !== 'pending' || !created.createdBy) {\n return [];\n }\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, created.id);\n if (!chat) {\n return [];\n }\n const body = await reads.latestMessageBody(orgId, created.id);\n return listOf(\n {\n type: 'chat.request',\n scope: 'chat',\n actorOrgUserId: created.createdBy,\n communityId: created.communityId,\n spaceId: null,\n subject: { type: 'chat', id: created.id },\n parent: null,\n display: {\n senderName: await reads.displayName(orgId, created.createdBy),\n excerpt: await textExcerpt(reads, orgId, body ?? '', MESSAGE_EXCERPT),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(created.participantIds, 'participant'),\n chatReach(reads, orgId, chat, created.id, created.createdBy, eventAt(event)),\n ),\n );\n};\n\nconst chatParticipantAdded: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatParticipantAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const added = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, added.chatId);\n if (!chat) {\n return [];\n }\n return listOf(\n {\n type: 'chat.added',\n scope: 'chat',\n actorOrgUserId: added.addedBy,\n communityId: added.communityId,\n spaceId: null,\n subject: { type: 'chat', id: added.chatId },\n parent: null,\n display: {\n adderName: await reads.displayName(orgId, added.addedBy),\n participantNames: await participantNames(reads, orgId, chat),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([added.orgUserId], 'subject'),\n chatReach(reads, orgId, chat, added.chatId, added.addedBy, eventAt(event)),\n ),\n );\n};\n\nconst digestDue: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.digestDue.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { communityId, from, to } = parsed.data.data;\n const orgId = event.orgId;\n const posts = await reads.postsPublished(orgId, communityId, from, to);\n if (posts.length === 0) {\n return [];\n }\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n return [];\n }\n const spaceIds = [...new Set(posts.map((post) => post.spaceId))];\n const openers = new Map<string, Set<string>>();\n for (const spaceId of spaceIds) {\n const open = await reads.spaceOpeners(orgId, spaceId);\n const muted = new Set(\n open.length > 0\n ? await reads.mutedAmong(orgId, { type: 'space', id: spaceId }, open, eventAt(event))\n : [],\n );\n openers.set(spaceId, new Set(open.filter((orgUserId) => !muted.has(orgUserId))));\n }\n const groups = new Map<string, { spaceIds: string[]; members: Reasons }>();\n for (const orgUserId of await reads.communityMembers(orgId, communityId)) {\n const open = spaceIds.filter((spaceId) => openers.get(spaceId)?.has(orgUserId));\n if (open.length === 0) {\n continue;\n }\n const key = open.join(' ');\n const group = groups.get(key) ?? { spaceIds: open, members: new Reasons() };\n group.members.add([orgUserId], 'community_member');\n groups.set(key, group);\n }\n const lists: RecipientList[] = [];\n for (const group of groups.values()) {\n const shown = posts.filter((post) => group.spaceIds.includes(post.spaceId));\n lists.push(\n ...listOf(\n {\n type: 'digest',\n scope: 'community',\n actorOrgUserId: null,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n from: from.toISOString(),\n to: to.toISOString(),\n posts: shown.map((post) => ({\n postId: post.postId,\n title: post.title,\n authorName: post.authorName,\n spaceName: post.spaceName,\n commentCount: post.commentCount,\n })),\n },\n },\n await recipientsOf(reads, orgId, group.members, { exclude: [], at: eventAt(event) }),\n ),\n );\n }\n return lists;\n};\n\nexport const DISCUSSION_RULES: Record<string, RecipientRule> = {\n 'discussion.post.published': postPublished,\n 'discussion.post.created': postCreated,\n 'discussion.post.updated': postUpdated,\n 'discussion.post.removed': postRemoved,\n 'discussion.post.reaction.added': postReacted,\n 'discussion.comment.created': commentCreated,\n 'discussion.comment.published': commentPublished,\n 'discussion.comment.updated': commentUpdated,\n 'discussion.comment.removed': commentRemoved,\n 'discussion.comment.reaction.added': commentReacted,\n 'discussion.post.reported': postReported,\n 'discussion.comment.reported': commentReported,\n 'discussion.message.sent': messageSent,\n 'discussion.message.updated': messageUpdated,\n 'discussion.message.reaction.added': messageReacted,\n 'discussion.message.reported': messageReported,\n 'discussion.chat.created': chatCreated,\n 'discussion.chat.participant.added': chatParticipantAdded,\n 'discussion.digest.due': digestDue,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"discussion.js","names":[],"sources":["../../../../src/automations/notifications/rules/discussion.ts"],"sourcesContent":["import { discussionEvents } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { JsonValue, RecipientList, SubjectRef } from '../../../types/index.js';\nimport {\n communityModerators,\n MESSAGE_EXCERPT,\n POST_EXCERPT,\n previousStatusOf,\n} from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport {\n actorOr,\n chatReach,\n chatTitle,\n eventAt,\n listOf,\n participantNames,\n Reasons,\n recipientsOf,\n textExcerpt,\n type ListBase,\n type Reach,\n} from './recipients.js';\n\ntype Post = NonNullable<Awaited<ReturnType<NotificationReads['post']>>>;\ntype Activity = NonNullable<Awaited<ReturnType<NotificationReads['activity']>>>;\n\ntype Place =\n | { kind: 'post'; postId: string; post: Post; spaceName: string }\n | { kind: 'activity'; activityId: string; activity: Activity };\n\nconst CHAT_STATUS = 'chatStatus';\n\nfunction postReach(\n reads: NotificationReads,\n orgId: string,\n post: { id: string; spaceId: string },\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n mutedOn: [\n { type: 'post', id: post.id },\n { type: 'space', id: post.spaceId },\n ],\n };\n}\n\nfunction courseReach(\n reads: NotificationReads,\n orgId: string,\n courseId: string,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: async (orgUserIds) => {\n const [holders, readers] = await Promise.all([\n reads.courseMembers(orgId, courseId),\n reads.holders(orgId, 'courses:read', courseId),\n ]);\n const open = new Set([...holders, ...readers]);\n return orgUserIds.filter((orgUserId) => open.has(orgUserId));\n },\n };\n}\n\nasync function placeOf(\n reads: NotificationReads,\n orgId: string,\n comment: { postId: string | null; activityId: string | null },\n): Promise<Place | null> {\n if (comment.postId) {\n const post = await reads.post(orgId, comment.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n return post && space\n ? { kind: 'post', postId: comment.postId, post, spaceName: space.name }\n : null;\n }\n if (comment.activityId) {\n const activity = await reads.activity(orgId, comment.activityId);\n return activity ? { kind: 'activity', activityId: comment.activityId, activity } : null;\n }\n return null;\n}\n\nfunction placeReach(\n reads: NotificationReads,\n orgId: string,\n place: Place,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return place.kind === 'post'\n ? postReach(reads, orgId, { id: place.postId, spaceId: place.post.spaceId }, exclude, at)\n : courseReach(reads, orgId, place.activity.courseId, exclude, at);\n}\n\nfunction commentBase(\n type: string,\n place: Place,\n commentId: string,\n actorId: string | null,\n display: Record<string, JsonValue>,\n): ListBase {\n const subject: SubjectRef = { type: 'comment', id: commentId };\n if (place.kind === 'post') {\n return {\n type,\n scope: 'space',\n actorId,\n communityId: place.post.communityId,\n spaceId: place.post.spaceId,\n subject,\n parent: { type: 'post', id: place.postId },\n display: { postTitle: place.post.title, ...display },\n };\n }\n return {\n type,\n scope: 'org',\n actorId,\n communityId: null,\n spaceId: null,\n subject,\n parent: { type: 'activity', id: place.activityId },\n display: {\n activityTitle: place.activity.title,\n courseTitle: place.activity.courseTitle,\n courseId: place.activity.courseId,\n ...display,\n },\n };\n}\n\nasync function mentionsOf(\n reads: NotificationReads,\n orgId: string,\n base: Omit<ListBase, 'type'>,\n mentioned: string[],\n reach: Reach,\n): Promise<RecipientList[]> {\n if (mentioned.length === 0) {\n return [];\n }\n const recipients = await recipientsOf(\n reads,\n orgId,\n new Reasons().add(mentioned, 'mentioned'),\n reach,\n );\n return listOf({ ...base, type: 'mention' }, recipients);\n}\n\nasync function commentLists(\n event: DomainEvent,\n reads: NotificationReads,\n comment: {\n id: string;\n postId: string | null;\n activityId: string | null;\n parentId: string | null;\n orgUserId: string;\n body: string;\n mentionedOrgUserIds: string[];\n },\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n const at = eventAt(event);\n const exclude = [comment.orgUserId, actorOr(event, comment.orgUserId)];\n const reasons = new Reasons();\n if (place.kind === 'post') {\n reasons.add([place.post.orgUserId], 'post_author');\n }\n const parent = comment.parentId ? await reads.comment(orgId, comment.parentId) : null;\n reasons.add([parent?.orgUserId], 'comment_author');\n if (place.kind === 'post') {\n reasons.add(await reads.followerIds(orgId, place.postId), 'follower');\n }\n reasons.add(\n await reads.threadParticipants(\n orgId,\n place.kind === 'post'\n ? { type: 'post', id: place.postId }\n : { type: 'activity', id: place.activityId },\n ),\n 'thread_participant',\n );\n const name = await reads.displayName(orgId, comment.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n const created = listOf(\n commentBase('comment.created', place, comment.id, comment.orgUserId, {\n commenterName: name,\n excerpt: text,\n }),\n await recipientsOf(reads, orgId, reasons, placeReach(reads, orgId, place, exclude, at)),\n );\n const mentions = await mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: name,\n excerpt: text,\n }),\n comment.mentionedOrgUserIds,\n placeReach(reads, orgId, place, exclude, at),\n );\n return [...created, ...mentions];\n}\n\nconst postPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success || previousStatusOf(event) === 'removed') {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const at = eventAt(event);\n const actor = actorOr(event, null);\n const exclude = [...new Set([post.orgUserId, ...(actor ? [actor] : [])])];\n const reach = postReach(reads, orgId, post, exclude, at);\n const base = {\n scope: 'space' as const,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post' as const, id: post.id },\n parent: null,\n };\n const lists: RecipientList[] = [];\n if (previousStatusOf(event) === 'pending') {\n lists.push(\n ...listOf(\n {\n ...base,\n type: 'post.approved',\n actorId: actor,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], 'subject'), {\n ...reach,\n exclude: [actor],\n }),\n ),\n );\n }\n const authorName = await reads.displayName(orgId, post.orgUserId);\n const text = await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n );\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n ...base,\n actorId: post.orgUserId,\n display: { authorName, excerpt: text, postTitle: post.title },\n },\n post.mentionedOrgUserIds,\n reach,\n )),\n );\n lists.push({\n ...base,\n type: 'post.published',\n actorId: post.orgUserId,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName,\n excerpt: text,\n },\n audience: { reason: 'space_member', spaceId: post.spaceId, exclude },\n });\n return lists;\n};\n\nasync function awaitingReview(\n event: DomainEvent,\n reads: NotificationReads,\n post: {\n id: string;\n communityId: string;\n spaceId: string;\n orgUserId: string;\n title: string;\n status: string;\n },\n): Promise<RecipientList[]> {\n if (post.status !== 'pending' || previousStatusOf(event) === 'pending') {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const actor = actorOr(event, post.orgUserId);\n return listOf(\n {\n type: 'post.awaiting_review',\n scope: 'space',\n actorId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await reads.displayName(orgId, post.orgUserId),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, post.communityId), 'moderator'),\n {\n exclude: [actor, post.orgUserId],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n}\n\nconst postCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postCreated.safeParse(event);\n return parsed.success ? awaitingReview(event, reads, parsed.data.data) : [];\n};\n\nconst postUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const lists = await awaitingReview(event, reads, post);\n if (post.mentionedOrgUserIds.length === 0) {\n return lists;\n }\n const actor = actorOr(event, post.orgUserId);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n scope: 'space',\n actorId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n authorName: await reads.displayName(orgId, post.orgUserId),\n excerpt: await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n ),\n postTitle: post.title,\n },\n },\n post.mentionedOrgUserIds,\n postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event)),\n )),\n );\n return lists;\n};\n\nconst postRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const remover = post.removedBy ?? actorOr(event, null);\n if (!remover || remover === post.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n return listOf(\n {\n type: 'post.removed',\n scope: 'space',\n actorId: remover,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'subject'),\n postReach(reads, orgId, post, [remover], eventAt(event)),\n ),\n );\n};\n\nconst postReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, reaction.postId);\n if (!post) {\n return [];\n }\n return listOf(\n {\n type: 'post.reacted',\n scope: 'space',\n actorId: reaction.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: reaction.postId },\n parent: null,\n display: {\n postTitle: post.title,\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'post_author'),\n postReach(\n reads,\n orgId,\n { id: reaction.postId, spaceId: post.spaceId },\n [reaction.orgUserId, actorOr(event, null)],\n eventAt(event),\n ),\n ),\n );\n};\n\nconst commentCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success || parsed.data.data.status !== 'published') {\n return [];\n }\n return commentLists(event, reads, parsed.data.data);\n};\n\nconst commentPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentPublished.safeParse(event);\n return parsed.success ? commentLists(event, reads, parsed.data.data) : [];\n};\n\nconst commentUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n if (comment.status !== 'published' || comment.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: await reads.displayName(orgId, comment.orgUserId),\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n }),\n comment.mentionedOrgUserIds,\n placeReach(\n reads,\n orgId,\n place,\n [comment.orgUserId, actorOr(event, comment.orgUserId)],\n eventAt(event),\n ),\n );\n};\n\nconst commentRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n const remover = comment.removedBy ?? actorOr(event, null);\n if (!remover || remover === comment.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return listOf(\n commentBase('comment.removed', place, comment.id, remover, {}),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'subject'),\n placeReach(reads, orgId, place, [remover], eventAt(event)),\n ),\n );\n};\n\nconst commentReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, reaction.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n return listOf(\n commentBase('comment.reacted', place, reaction.commentId, reaction.orgUserId, {\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'comment_author'),\n placeReach(reads, orgId, place, [reaction.orgUserId, actorOr(event, null)], eventAt(event)),\n ),\n );\n};\n\nconst postReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, flag.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n if (!post || !space) {\n return [];\n }\n return listOf(\n {\n type: 'content.flagged',\n scope: 'space',\n actorId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: flag.postId },\n parent: null,\n display: {\n spaceName: space.name,\n excerpt: await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n ),\n reason: flag.reason,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, flag.communityId), 'moderator'),\n {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n};\n\nconst commentReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, flag.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n const actor = actorOr(event, flag.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n if (place.kind === 'post') {\n return listOf(\n {\n ...commentBase('content.flagged', place, flag.commentId, actor, {}),\n display: { spaceName: place.spaceName, excerpt: text, reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await communityModerators(reads, orgId, place.post.communityId),\n 'moderator',\n ),\n {\n exclude: [actor],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds),\n },\n ),\n );\n }\n return listOf(\n commentBase('content.flagged', place, flag.commentId, actor, {\n excerpt: text,\n reason: flag.reason,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await reads.holders(orgId, 'courses:moderate', place.activity.courseId),\n 'moderator',\n ),\n { exclude: [actor], at: eventAt(event) },\n ),\n );\n};\n\nfunction chatPending(event: DomainEvent, status: string): boolean {\n const value = event.metadata?.[CHAT_STATUS];\n return (typeof value === 'string' ? value : status) === 'pending';\n}\n\nasync function chatMentions(\n event: DomainEvent,\n reads: NotificationReads,\n message: { id: string; chatId: string; orgUserId: string; body: string },\n mentioned: string[],\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n {\n scope: 'chat',\n actorId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n authorName: await reads.displayName(orgId, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n },\n },\n mentioned,\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n );\n}\n\nexport function messageSummary(count: number): string {\n return count === 1 ? '1 new message' : `${count} new messages`;\n}\n\nconst messageSent: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageSent.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const message = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n const senderName = await reads.displayName(orgId, message.orgUserId);\n const sent = listOf(\n {\n type: 'message.sent',\n scope: 'chat',\n actorId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n senderName,\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n count: '1',\n summary: messageSummary(1),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n chat.participants.map((participant) => participant.orgUserId),\n 'participant',\n ),\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n ),\n );\n return [...sent, ...(await chatMentions(event, reads, message, message.mentionedOrgUserIds))];\n};\n\nconst messageUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageUpdated.safeParse(event);\n if (!parsed.success || parsed.data.data.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const message = parsed.data.data;\n return chatMentions(event, reads, message, message.mentionedOrgUserIds);\n};\n\nconst messageReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const [message, chat] = await Promise.all([\n reads.message(orgId, reaction.messageId),\n reads.chat(orgId, reaction.chatId),\n ]);\n if (!message || !chat) {\n return [];\n }\n return listOf(\n {\n type: 'message.reacted',\n scope: 'chat',\n actorId: reaction.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: reaction.messageId },\n parent: { type: 'chat', id: reaction.chatId },\n display: {\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([message.orgUserId], 'message_author'),\n chatReach(reads, orgId, chat, reaction.chatId, reaction.orgUserId, eventAt(event)),\n ),\n );\n};\n\nconst messageReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const message = await reads.message(orgId, flag.messageId);\n return listOf(\n {\n type: 'message.flagged',\n scope: 'chat',\n actorId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: null,\n subject: { type: 'message', id: flag.messageId },\n parent: message ? { type: 'chat', id: message.chatId } : null,\n display: { reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, flag.communityId), 'moderator'),\n { exclude: [actorOr(event, flag.orgUserId)], at: eventAt(event) },\n ),\n );\n};\n\nconst chatCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const created = parsed.data.data;\n if (created.kind !== 'direct' || created.status !== 'pending' || !created.createdBy) {\n return [];\n }\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, created.id);\n if (!chat) {\n return [];\n }\n const body = await reads.latestMessageBody(orgId, created.id);\n return listOf(\n {\n type: 'chat.request',\n scope: 'chat',\n actorId: created.createdBy,\n communityId: created.communityId,\n spaceId: null,\n subject: { type: 'chat', id: created.id },\n parent: null,\n display: {\n senderName: await reads.displayName(orgId, created.createdBy),\n excerpt: await textExcerpt(reads, orgId, body ?? '', MESSAGE_EXCERPT),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(created.participantIds, 'participant'),\n chatReach(reads, orgId, chat, created.id, created.createdBy, eventAt(event)),\n ),\n );\n};\n\nconst chatParticipantAdded: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatParticipantAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const added = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, added.chatId);\n if (!chat) {\n return [];\n }\n return listOf(\n {\n type: 'chat.added',\n scope: 'chat',\n actorId: added.addedBy,\n communityId: added.communityId,\n spaceId: null,\n subject: { type: 'chat', id: added.chatId },\n parent: null,\n display: {\n adderName: await reads.displayName(orgId, added.addedBy),\n participantNames: await participantNames(reads, orgId, chat),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([added.orgUserId], 'subject'),\n chatReach(reads, orgId, chat, added.chatId, added.addedBy, eventAt(event)),\n ),\n );\n};\n\nconst digestDue: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.digestDue.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { communityId, from, to } = parsed.data.data;\n const orgId = event.orgId;\n const posts = await reads.postsPublished(orgId, communityId, from, to);\n if (posts.length === 0) {\n return [];\n }\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n return [];\n }\n const spaceIds = [...new Set(posts.map((post) => post.spaceId))];\n const openers = new Map<string, Set<string>>();\n for (const spaceId of spaceIds) {\n const open = await reads.spaceOpeners(orgId, spaceId);\n const muted = new Set(\n open.length > 0\n ? await reads.mutedAmong(orgId, { type: 'space', id: spaceId }, open, eventAt(event))\n : [],\n );\n openers.set(spaceId, new Set(open.filter((orgUserId) => !muted.has(orgUserId))));\n }\n const groups = new Map<string, { spaceIds: string[]; members: Reasons }>();\n for (const orgUserId of await reads.communityMembers(orgId, communityId)) {\n const open = spaceIds.filter((spaceId) => openers.get(spaceId)?.has(orgUserId));\n if (open.length === 0) {\n continue;\n }\n const key = open.join(' ');\n const group = groups.get(key) ?? { spaceIds: open, members: new Reasons() };\n group.members.add([orgUserId], 'community_member');\n groups.set(key, group);\n }\n const lists: RecipientList[] = [];\n for (const group of groups.values()) {\n const shown = posts.filter((post) => group.spaceIds.includes(post.spaceId));\n lists.push(\n ...listOf(\n {\n type: 'digest',\n scope: 'community',\n actorId: null,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n from: from.toISOString(),\n to: to.toISOString(),\n posts: shown.map((post) => ({\n postId: post.postId,\n title: post.title,\n authorName: post.authorName,\n spaceName: post.spaceName,\n commentCount: post.commentCount,\n })),\n },\n },\n await recipientsOf(reads, orgId, group.members, { exclude: [], at: eventAt(event) }),\n ),\n );\n }\n return lists;\n};\n\nexport const DISCUSSION_RULES: Record<string, RecipientRule> = {\n 'discussion.post.published': postPublished,\n 'discussion.post.created': postCreated,\n 'discussion.post.updated': postUpdated,\n 'discussion.post.removed': postRemoved,\n 'discussion.post.reaction.added': postReacted,\n 'discussion.comment.created': commentCreated,\n 'discussion.comment.published': commentPublished,\n 'discussion.comment.updated': commentUpdated,\n 'discussion.comment.removed': commentRemoved,\n 'discussion.comment.reaction.added': commentReacted,\n 'discussion.post.reported': postReported,\n 'discussion.comment.reported': commentReported,\n 'discussion.message.sent': messageSent,\n 'discussion.message.updated': messageUpdated,\n 'discussion.message.reaction.added': messageReacted,\n 'discussion.message.reported': messageReported,\n 'discussion.chat.created': chatCreated,\n 'discussion.chat.participant.added': chatParticipantAdded,\n 'discussion.digest.due': digestDue,\n};\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { entitlementEvents } from "../../../entitlements/events.js";
2
- import { previousStatusOf } from "../../community-mail.js";
2
+ import { communityModerators, previousStatusOf } from "../../community-mail.js";
3
3
  import { Reasons, actorOr, eventAt, listOf, recipientsOf } from "./recipients.js";
4
+ import { eventBase, eventDisplay } from "./events.js";
4
5
  //#region src/automations/notifications/rules/entitlements.ts
5
6
  function seatsLeft(capacity, active) {
6
7
  return capacity == null ? "No cap" : String(Math.max(capacity - active, 0));
@@ -50,7 +51,7 @@ async function membershipEnded(event, reads, grant, ref) {
50
51
  return listOf({
51
52
  type: "community.membership_ended",
52
53
  scope: "org",
53
- actorOrgUserId: actorOr(event, null),
54
+ actorId: actorOr(event, null),
54
55
  communityId: null,
55
56
  spaceId: null,
56
57
  subject: ref,
@@ -58,14 +59,14 @@ async function membershipEnded(event, reads, grant, ref) {
58
59
  display: { communities }
59
60
  }, await subjectOnly(event, reads, grant.orgUserId));
60
61
  }
61
- async function spaceBase(reads, orgId, member, type, actorOrgUserId) {
62
+ async function spaceBase(reads, orgId, member, type, actorId) {
62
63
  const space = await reads.space(orgId, member.spaceId);
63
64
  return space ? {
64
65
  space,
65
66
  base: {
66
67
  type,
67
68
  scope: "space",
68
- actorOrgUserId,
69
+ actorId,
69
70
  communityId: member.communityId,
70
71
  spaceId: member.spaceId,
71
72
  subject: {
@@ -93,7 +94,7 @@ const spaceMemberCreated = async (event, reads) => {
93
94
  memberName: await reads.displayName(orgId, member.orgUserId),
94
95
  seatsLeft: seatsLeft(found.space.capacity, active)
95
96
  }
96
- }, await recipientsOf(reads, orgId, new Reasons().add(await reads.moderationAudience(orgId, member.communityId), "moderator"), {
97
+ }, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, member.communityId), "moderator"), {
97
98
  exclude: [member.orgUserId, actorOr(event, null)],
98
99
  at: eventAt(event),
99
100
  canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, member.spaceId, orgUserIds)
@@ -141,12 +142,26 @@ const spaceMemberDeleted = async (event, reads) => {
141
142
  }
142
143
  }, await subjectOnly(event, reads, member.orgUserId)) : [];
143
144
  };
145
+ async function grantedEvent(reads, orgId, grant) {
146
+ return grant.contentId ? reads.event(orgId, grant.contentId) : null;
147
+ }
144
148
  const entitlementCreated = async (event, reads) => {
145
149
  const parsed = entitlementEvents.entitlementCreated.safeParse(event);
146
150
  if (!parsed.success) return [];
147
151
  const grant = parsed.data.data;
148
152
  const orgId = event.orgId;
149
153
  const actor = actorOr(event, null);
154
+ const granted = await grantedEvent(reads, orgId, grant);
155
+ if (granted) {
156
+ if (!granted.settings.notifications) return [];
157
+ return listOf({
158
+ ...eventBase("event.granted", granted, actor),
159
+ display: eventDisplay(granted)
160
+ }, await recipientsOf(reads, orgId, new Reasons().add([grant.orgUserId], "event_member"), {
161
+ exclude: [],
162
+ at: eventAt(event)
163
+ }));
164
+ }
150
165
  const subject = await subjectOnly(event, reads, grant.orgUserId);
151
166
  if (subject.length === 0) return [];
152
167
  const lists = [];
@@ -154,7 +169,7 @@ const entitlementCreated = async (event, reads) => {
154
169
  if (target) lists.push(...listOf({
155
170
  type: "access.granted",
156
171
  scope: "org",
157
- actorOrgUserId: actor,
172
+ actorId: actor,
158
173
  communityId: null,
159
174
  spaceId: null,
160
175
  subject: target.ref,
@@ -170,7 +185,7 @@ const entitlementCreated = async (event, reads) => {
170
185
  lists.push(...listOf({
171
186
  type: "community.welcome",
172
187
  scope: "community",
173
- actorOrgUserId: actor,
188
+ actorId: actor,
174
189
  communityId,
175
190
  spaceId: null,
176
191
  subject: {
@@ -195,7 +210,7 @@ const entitlementEndingSoon = async (event, reads) => {
195
210
  return listOf({
196
211
  type: "community.ending_soon",
197
212
  scope: "community",
198
- actorOrgUserId: null,
213
+ actorId: null,
199
214
  communityId: grant.communityId,
200
215
  spaceId: null,
201
216
  subject: {
@@ -213,6 +228,18 @@ const entitlementDeleted = async (event, reads) => {
213
228
  const parsed = entitlementEvents.entitlementDeleted.safeParse(event);
214
229
  if (!parsed.success) return [];
215
230
  const grant = parsed.data.data;
231
+ const revokedFrom = await grantedEvent(reads, event.orgId, grant);
232
+ if (revokedFrom) {
233
+ if (!revokedFrom.settings.notifications || !(await reads.contentLostBy(event.orgId, grant)).includes(revokedFrom.id)) return [];
234
+ const actor = actorOr(event, null);
235
+ return listOf({
236
+ ...eventBase("event.revoked", revokedFrom, actor),
237
+ display: eventDisplay(revokedFrom)
238
+ }, await recipientsOf(reads, event.orgId, new Reasons().add([grant.orgUserId], "event_member"), {
239
+ exclude: [actor],
240
+ at: eventAt(event)
241
+ }));
242
+ }
216
243
  const target = await grantSubject(reads, event.orgId, grant);
217
244
  const ended = await membershipEnded(event, reads, grant, target?.ref ?? null);
218
245
  if (ended) return ended;
@@ -220,7 +247,7 @@ const entitlementDeleted = async (event, reads) => {
220
247
  return listOf({
221
248
  type: "access.revoked",
222
249
  scope: "org",
223
- actorOrgUserId: actorOr(event, null),
250
+ actorId: actorOr(event, null),
224
251
  communityId: null,
225
252
  spaceId: null,
226
253
  subject: target.ref,