@headless-lms/core 0.4.0 → 0.6.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 +15 -9
  2. package/dist/assets/file-urls.d.ts +14 -7
  3. package/dist/assets/file-urls.js +15 -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 +233 -54
  10. package/dist/assets/service.js.map +1 -1
  11. package/dist/automations/actions.js.map +1 -1
  12. package/dist/automations/catalog.js +68 -3
  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 +1 -1
  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 +12 -12
  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 +90 -61
  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 +465 -88
  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 +103 -67
  72. package/dist/content/service.js +739 -152
  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 +392 -160
  83. package/dist/discussion/chats.js.map +1 -1
  84. package/dist/discussion/events.d.ts +85 -47
  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 +266 -152
  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 +250 -186
  104. package/dist/discussion/service.js.map +1 -1
  105. package/dist/discussion/subscriptions.d.ts +8 -8
  106. package/dist/discussion/subscriptions.js +28 -12
  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 +58 -58
  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 +369 -162
  121. package/dist/entitlements/service.js.map +1 -1
  122. package/dist/identity/devices.d.ts +3 -3
  123. package/dist/identity/devices.js +6 -4
  124. package/dist/identity/devices.js.map +1 -1
  125. package/dist/identity/index.d.ts +2 -2
  126. package/dist/identity/index.js +2 -2
  127. package/dist/identity/notification-settings.d.ts +1 -1
  128. package/dist/identity/notification-settings.js +2 -1
  129. package/dist/identity/notification-settings.js.map +1 -1
  130. package/dist/identity/ports.d.ts +7 -7
  131. package/dist/identity/service.d.ts +8 -7
  132. package/dist/identity/service.js +16 -12
  133. package/dist/identity/service.js.map +1 -1
  134. package/dist/integrations/events.d.ts +3 -3
  135. package/dist/integrations/ports.d.ts +9 -8
  136. package/dist/integrations/service.d.ts +9 -8
  137. package/dist/integrations/service.js +31 -14
  138. package/dist/integrations/service.js.map +1 -1
  139. package/dist/organizations/default-roles.d.ts +22 -0
  140. package/dist/organizations/default-roles.js +89 -0
  141. package/dist/organizations/default-roles.js.map +1 -0
  142. package/dist/organizations/effective-permissions.d.ts +47 -0
  143. package/dist/organizations/effective-permissions.js +118 -0
  144. package/dist/organizations/effective-permissions.js.map +1 -0
  145. package/dist/organizations/events.d.ts +326 -181
  146. package/dist/organizations/events.js +90 -18
  147. package/dist/organizations/events.js.map +1 -1
  148. package/dist/organizations/index.d.ts +14 -10
  149. package/dist/organizations/index.js +7 -3
  150. package/dist/organizations/members.d.ts +66 -8
  151. package/dist/organizations/members.js.map +1 -1
  152. package/dist/organizations/model.d.ts +2 -2
  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 +187 -65
  166. package/dist/organizations/service.d.ts +102 -35
  167. package/dist/organizations/service.js +1254 -327
  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 +21 -6
  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 +29 -5
  193. package/dist/reporting/member/ports.d.ts +49 -29
  194. package/dist/reporting/member/service.d.ts +57 -29
  195. package/dist/reporting/member/service.js +345 -114
  196. package/dist/reporting/member/service.js.map +1 -1
  197. package/dist/shared/actor.d.ts +23 -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 +599 -13
  224. package/dist/types/schemas/content.js +219 -8
  225. package/dist/types/schemas/content.js.map +1 -1
  226. package/dist/types/schemas/discussion.d.ts +280 -57
  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 +21 -8
  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 +11 -10
  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 +99 -60
  238. package/dist/types/schemas/organizations.js +80 -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":"entitlements.js","names":[],"sources":["../../../../src/automations/notifications/rules/entitlements.ts"],"sourcesContent":["import { entitlementEvents } from '../../../entitlements/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { RecipientList, SubjectRef } from '../../../types/index.js';\nimport { previousStatusOf } from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\ntype Grant = { orgUserId: string; contentId: string | null; bundleId: string | null };\ntype SpaceMember = { spaceId: string; communityId: string; orgUserId: string; status: string };\n\nfunction seatsLeft(capacity: number | null, active: number): string {\n return capacity == null ? 'No cap' : String(Math.max(capacity - active, 0));\n}\n\nfunction subjectOnly(event: DomainEvent, reads: NotificationReads, orgUserId: string) {\n return recipientsOf(reads, event.orgId, new Reasons().add([orgUserId], 'subject'), {\n exclude: [actorOr(event, null)],\n at: eventAt(event),\n });\n}\n\nasync function grantSubject(\n reads: NotificationReads,\n orgId: string,\n grant: Grant,\n): Promise<{ ref: SubjectRef; title: string; type: string } | null> {\n if (grant.bundleId) {\n const info = await reads.contentInfo(orgId, { bundleId: grant.bundleId });\n return info ? { ref: { type: 'bundle', id: grant.bundleId }, ...info } : null;\n }\n if (!grant.contentId) {\n return null;\n }\n const info = await reads.contentInfo(orgId, { contentId: grant.contentId });\n if (!info) {\n return null;\n }\n const type: SubjectRef['type'] =\n info.type === 'download' ? 'download' : info.type === 'community' ? 'community' : 'course';\n return { ref: { type, id: grant.contentId }, ...info };\n}\n\nasync function membershipEnded(\n event: DomainEvent,\n reads: NotificationReads,\n grant: Grant,\n ref: SubjectRef | null,\n): Promise<RecipientList[] | null> {\n const orgId = event.orgId;\n const communityIds = await reads.communitiesOpenedBy(orgId, grant);\n if (communityIds.length === 0) {\n return null;\n }\n const held = new Set(\n (await reads.memberCommunityTitles(orgId, grant.orgUserId)).map((community) => community.id),\n );\n const communities: { communityId: string; communityTitle: string }[] = [];\n for (const communityId of communityIds.filter((id) => !held.has(id))) {\n const title = await reads.communityTitle(orgId, communityId);\n if (title !== null) {\n communities.push({ communityId, communityTitle: title });\n }\n }\n if (communities.length === 0) {\n return null;\n }\n return listOf(\n {\n type: 'community.membership_ended',\n scope: 'org',\n actorOrgUserId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: ref,\n parent: null,\n display: { communities },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n}\n\nasync function spaceBase(\n reads: NotificationReads,\n orgId: string,\n member: SpaceMember,\n type: string,\n actorOrgUserId: string | null,\n) {\n const space = await reads.space(orgId, member.spaceId);\n return space\n ? {\n space,\n base: {\n type,\n scope: 'space' as const,\n actorOrgUserId,\n communityId: member.communityId,\n spaceId: member.spaceId,\n subject: { type: 'space' as const, id: member.spaceId },\n parent: null,\n },\n }\n : null;\n}\n\nconst spaceMemberCreated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const member = parsed.data.data;\n const orgId = event.orgId;\n if (member.status === 'requested') {\n const found = await spaceBase(reads, orgId, member, 'space.join_requested', member.orgUserId);\n if (!found) {\n return [];\n }\n const active = await reads.activeMemberCount(orgId, member.spaceId);\n return listOf(\n {\n ...found.base,\n display: {\n spaceName: found.space.name,\n spaceId: member.spaceId,\n memberName: await reads.displayName(orgId, member.orgUserId),\n seatsLeft: seatsLeft(found.space.capacity, active),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.moderationAudience(orgId, member.communityId), 'moderator'),\n {\n exclude: [member.orgUserId, actorOr(event, null)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, member.spaceId, orgUserIds),\n },\n ),\n );\n }\n if (member.status === 'invited') {\n const inviter = actorOr(event, null);\n const found = await spaceBase(reads, orgId, member, 'space.invited', inviter);\n if (!found) {\n return [];\n }\n return listOf(\n {\n ...found.base,\n display: {\n spaceName: found.space.name,\n spaceId: member.spaceId,\n inviterName: inviter ? await reads.displayName(orgId, inviter) : 'A member',\n },\n },\n await subjectOnly(event, reads, member.orgUserId),\n );\n }\n return [];\n};\n\nconst spaceMemberUpdated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const member = parsed.data.data;\n if (member.status !== 'active' || previousStatusOf(event) !== 'requested') {\n return [];\n }\n const found = await spaceBase(\n reads,\n event.orgId,\n member,\n 'space.request_approved',\n actorOr(event, null),\n );\n return found\n ? listOf(\n { ...found.base, display: { spaceName: found.space.name, spaceId: member.spaceId } },\n await subjectOnly(event, reads, member.orgUserId),\n )\n : [];\n};\n\nconst spaceMemberDeleted: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberDeleted.safeParse(event);\n if (!parsed.success || previousStatusOf(event) !== 'requested') {\n return [];\n }\n const member = parsed.data.data;\n const found = await spaceBase(\n reads,\n event.orgId,\n member,\n 'space.request_declined',\n actorOr(event, null),\n );\n return found\n ? listOf(\n { ...found.base, display: { spaceName: found.space.name, spaceId: member.spaceId } },\n await subjectOnly(event, reads, member.orgUserId),\n )\n : [];\n};\n\nconst entitlementCreated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const orgId = event.orgId;\n const actor = actorOr(event, null);\n const subject = await subjectOnly(event, reads, grant.orgUserId);\n if (subject.length === 0) {\n return [];\n }\n const lists: RecipientList[] = [];\n const target = await grantSubject(reads, orgId, grant);\n if (target) {\n lists.push(\n ...listOf(\n {\n type: 'access.granted',\n scope: 'org',\n actorOrgUserId: actor,\n communityId: null,\n spaceId: null,\n subject: target.ref,\n parent: null,\n display: { contentTitle: target.title, contentType: target.type },\n },\n subject,\n ),\n );\n }\n for (const communityId of await reads.communitiesOpenedBy(orgId, grant)) {\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n continue;\n }\n lists.push(\n ...listOf(\n {\n type: 'community.welcome',\n scope: 'community',\n actorOrgUserId: actor,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n spaceNames: await reads.openSpaceNames(orgId, grant.orgUserId, communityId),\n },\n },\n subject,\n ),\n );\n }\n return lists;\n};\n\nconst entitlementEndingSoon: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementEndingSoon.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const title = await reads.communityTitle(event.orgId, grant.communityId);\n if (title === null) {\n return [];\n }\n return listOf(\n {\n type: 'community.ending_soon',\n scope: 'community',\n actorOrgUserId: null,\n communityId: grant.communityId,\n spaceId: null,\n subject: { type: 'community', id: grant.communityId },\n parent: null,\n display: {\n communityTitle: title,\n expiresAt: grant.expiresAt ? grant.expiresAt.toISOString() : '',\n },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n};\n\nconst entitlementDeleted: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementDeleted.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const target = await grantSubject(reads, event.orgId, grant);\n const ended = await membershipEnded(event, reads, grant, target?.ref ?? null);\n if (ended) {\n return ended;\n }\n if (!target || (await reads.contentLostBy(event.orgId, grant)).length === 0) {\n return [];\n }\n return listOf(\n {\n type: 'access.revoked',\n scope: 'org',\n actorOrgUserId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: target.ref,\n parent: null,\n display: { contentTitle: target.title },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n};\n\nconst entitlementExpired: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementExpired.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const target = await grantSubject(reads, event.orgId, grant);\n return (await membershipEnded(event, reads, grant, target?.ref ?? null)) ?? [];\n};\n\nexport const ENTITLEMENT_RULES: Record<string, RecipientRule> = {\n 'entitlement.space_member.created': spaceMemberCreated,\n 'entitlement.space_member.updated': spaceMemberUpdated,\n 'entitlement.space_member.deleted': spaceMemberDeleted,\n 'entitlement.created': entitlementCreated,\n 'entitlement.ending_soon': entitlementEndingSoon,\n 'entitlement.deleted': entitlementDeleted,\n 'entitlement.expired': entitlementExpired,\n};\n"],"mappings":";;;;AAUA,SAAS,UAAU,UAAyB,QAAwB;CAClE,OAAO,YAAY,OAAO,WAAW,OAAO,KAAK,IAAI,WAAW,QAAQ,CAAC,CAAC;AAC5E;AAEA,SAAS,YAAY,OAAoB,OAA0B,WAAmB;CACpF,OAAO,aAAa,OAAO,MAAM,OAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,SAAS,GAAG;EACjF,SAAS,CAAC,QAAQ,OAAO,IAAI,CAAC;EAC9B,IAAI,QAAQ,KAAK;CACnB,CAAC;AACH;AAEA,eAAe,aACb,OACA,OACA,OACkE;CAClE,IAAI,MAAM,UAAU;EAClB,MAAM,OAAO,MAAM,MAAM,YAAY,OAAO,EAAE,UAAU,MAAM,SAAS,CAAC;EACxE,OAAO,OAAO;GAAE,KAAK;IAAE,MAAM;IAAU,IAAI,MAAM;GAAS;GAAG,GAAG;EAAK,IAAI;CAC3E;CACA,IAAI,CAAC,MAAM,WACT,OAAO;CAET,MAAM,OAAO,MAAM,MAAM,YAAY,OAAO,EAAE,WAAW,MAAM,UAAU,CAAC;CAC1E,IAAI,CAAC,MACH,OAAO;CAIT,OAAO;EAAE,KAAK;GAAE,MADd,KAAK,SAAS,aAAa,aAAa,KAAK,SAAS,cAAc,cAAc;GAC9D,IAAI,MAAM;EAAU;EAAG,GAAG;CAAK;AACvD;AAEA,eAAe,gBACb,OACA,OACA,OACA,KACiC;CACjC,MAAM,QAAQ,MAAM;CACpB,MAAM,eAAe,MAAM,MAAM,oBAAoB,OAAO,KAAK;CACjE,IAAI,aAAa,WAAW,GAC1B,OAAO;CAET,MAAM,OAAO,IAAI,KACd,MAAM,MAAM,sBAAsB,OAAO,MAAM,SAAS,EAAA,CAAG,KAAK,cAAc,UAAU,EAAE,CAC7F;CACA,MAAM,cAAiE,CAAC;CACxE,KAAK,MAAM,eAAe,aAAa,QAAQ,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG;EACpE,MAAM,QAAQ,MAAM,MAAM,eAAe,OAAO,WAAW;EAC3D,IAAI,UAAU,MACZ,YAAY,KAAK;GAAE;GAAa,gBAAgB;EAAM,CAAC;CAE3D;CACA,IAAI,YAAY,WAAW,GACzB,OAAO;CAET,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,gBAAgB,QAAQ,OAAO,IAAI;EACnC,aAAa;EACb,SAAS;EACT,SAAS;EACT,QAAQ;EACR,SAAS,EAAE,YAAY;CACzB,GACA,MAAM,YAAY,OAAO,OAAO,MAAM,SAAS,CACjD;AACF;AAEA,eAAe,UACb,OACA,OACA,QACA,MACA,gBACA;CACA,MAAM,QAAQ,MAAM,MAAM,MAAM,OAAO,OAAO,OAAO;CACrD,OAAO,QACH;EACE;EACA,MAAM;GACJ;GACA,OAAO;GACP;GACA,aAAa,OAAO;GACpB,SAAS,OAAO;GAChB,SAAS;IAAE,MAAM;IAAkB,IAAI,OAAO;GAAQ;GACtD,QAAQ;EACV;CACF,IACA;AACN;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,QAAQ,MAAM;CACpB,IAAI,OAAO,WAAW,aAAa;EACjC,MAAM,QAAQ,MAAM,UAAU,OAAO,OAAO,QAAQ,wBAAwB,OAAO,SAAS;EAC5F,IAAI,CAAC,OACH,OAAO,CAAC;EAEV,MAAM,SAAS,MAAM,MAAM,kBAAkB,OAAO,OAAO,OAAO;EAClE,OAAO,OACL;GACE,GAAG,MAAM;GACT,SAAS;IACP,WAAW,MAAM,MAAM;IACvB,SAAS,OAAO;IAChB,YAAY,MAAM,MAAM,YAAY,OAAO,OAAO,SAAS;IAC3D,WAAW,UAAU,MAAM,MAAM,UAAU,MAAM;GACnD;EACF,GACA,MAAM,aACJ,OACA,OACA,IAAI,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,mBAAmB,OAAO,OAAO,WAAW,GAAG,WAAW,GACxF;GACE,SAAS,CAAC,OAAO,WAAW,QAAQ,OAAO,IAAI,CAAC;GAChD,IAAI,QAAQ,KAAK;GACjB,UAAU,eAAe,MAAM,kBAAkB,OAAO,OAAO,SAAS,UAAU;EACpF,CACF,CACF;CACF;CACA,IAAI,OAAO,WAAW,WAAW;EAC/B,MAAM,UAAU,QAAQ,OAAO,IAAI;EACnC,MAAM,QAAQ,MAAM,UAAU,OAAO,OAAO,QAAQ,iBAAiB,OAAO;EAC5E,IAAI,CAAC,OACH,OAAO,CAAC;EAEV,OAAO,OACL;GACE,GAAG,MAAM;GACT,SAAS;IACP,WAAW,MAAM,MAAM;IACvB,SAAS,OAAO;IAChB,aAAa,UAAU,MAAM,MAAM,YAAY,OAAO,OAAO,IAAI;GACnE;EACF,GACA,MAAM,YAAY,OAAO,OAAO,OAAO,SAAS,CAClD;CACF;CACA,OAAO,CAAC;AACV;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,SAAS,OAAO,KAAK;CAC3B,IAAI,OAAO,WAAW,YAAY,iBAAiB,KAAK,MAAM,aAC5D,OAAO,CAAC;CAEV,MAAM,QAAQ,MAAM,UAClB,OACA,MAAM,OACN,QACA,0BACA,QAAQ,OAAO,IAAI,CACrB;CACA,OAAO,QACH,OACE;EAAE,GAAG,MAAM;EAAM,SAAS;GAAE,WAAW,MAAM,MAAM;GAAM,SAAS,OAAO;EAAQ;CAAE,GACnF,MAAM,YAAY,OAAO,OAAO,OAAO,SAAS,CAClD,IACA,CAAC;AACP;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,WAAW,iBAAiB,KAAK,MAAM,aACjD,OAAO,CAAC;CAEV,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,QAAQ,MAAM,UAClB,OACA,MAAM,OACN,QACA,0BACA,QAAQ,OAAO,IAAI,CACrB;CACA,OAAO,QACH,OACE;EAAE,GAAG,MAAM;EAAM,SAAS;GAAE,WAAW,MAAM,MAAM;GAAM,SAAS,OAAO;EAAQ;CAAE,GACnF,MAAM,YAAY,OAAO,OAAO,OAAO,SAAS,CAClD,IACA,CAAC;AACP;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,QAAQ,OAAO,KAAK;CAC1B,MAAM,QAAQ,MAAM;CACpB,MAAM,QAAQ,QAAQ,OAAO,IAAI;CACjC,MAAM,UAAU,MAAM,YAAY,OAAO,OAAO,MAAM,SAAS;CAC/D,IAAI,QAAQ,WAAW,GACrB,OAAO,CAAC;CAEV,MAAM,QAAyB,CAAC;CAChC,MAAM,SAAS,MAAM,aAAa,OAAO,OAAO,KAAK;CACrD,IAAI,QACF,MAAM,KACJ,GAAG,OACD;EACE,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,aAAa;EACb,SAAS;EACT,SAAS,OAAO;EAChB,QAAQ;EACR,SAAS;GAAE,cAAc,OAAO;GAAO,aAAa,OAAO;EAAK;CAClE,GACA,OACF,CACF;CAEF,KAAK,MAAM,eAAe,MAAM,MAAM,oBAAoB,OAAO,KAAK,GAAG;EACvE,MAAM,QAAQ,MAAM,MAAM,eAAe,OAAO,WAAW;EAC3D,IAAI,UAAU,MACZ;EAEF,MAAM,KACJ,GAAG,OACD;GACE,MAAM;GACN,OAAO;GACP,gBAAgB;GAChB;GACA,SAAS;GACT,SAAS;IAAE,MAAM;IAAa,IAAI;GAAY;GAC9C,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,YAAY,MAAM,MAAM,eAAe,OAAO,MAAM,WAAW,WAAW;GAC5E;EACF,GACA,OACF,CACF;CACF;CACA,OAAO;AACT;AAEA,MAAM,wBAAuC,OAAO,OAAO,UAAU;CACnE,MAAM,SAAS,kBAAkB,sBAAsB,UAAU,KAAK;CACtE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,QAAQ,OAAO,KAAK;CAC1B,MAAM,QAAQ,MAAM,MAAM,eAAe,MAAM,OAAO,MAAM,WAAW;CACvE,IAAI,UAAU,MACZ,OAAO,CAAC;CAEV,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,aAAa,MAAM;EACnB,SAAS;EACT,SAAS;GAAE,MAAM;GAAa,IAAI,MAAM;EAAY;EACpD,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,WAAW,MAAM,YAAY,MAAM,UAAU,YAAY,IAAI;EAC/D;CACF,GACA,MAAM,YAAY,OAAO,OAAO,MAAM,SAAS,CACjD;AACF;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,QAAQ,OAAO,KAAK;CAC1B,MAAM,SAAS,MAAM,aAAa,OAAO,MAAM,OAAO,KAAK;CAC3D,MAAM,QAAQ,MAAM,gBAAgB,OAAO,OAAO,OAAO,QAAQ,OAAO,IAAI;CAC5E,IAAI,OACF,OAAO;CAET,IAAI,CAAC,WAAW,MAAM,MAAM,cAAc,MAAM,OAAO,KAAK,EAAA,CAAG,WAAW,GACxE,OAAO,CAAC;CAEV,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,gBAAgB,QAAQ,OAAO,IAAI;EACnC,aAAa;EACb,SAAS;EACT,SAAS,OAAO;EAChB,QAAQ;EACR,SAAS,EAAE,cAAc,OAAO,MAAM;CACxC,GACA,MAAM,YAAY,OAAO,OAAO,MAAM,SAAS,CACjD;AACF;AAEA,MAAM,qBAAoC,OAAO,OAAO,UAAU;CAChE,MAAM,SAAS,kBAAkB,mBAAmB,UAAU,KAAK;CACnE,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,QAAQ,OAAO,KAAK;CAE1B,OAAQ,MAAM,gBAAgB,OAAO,OAAO,QAAO,MAD9B,aAAa,OAAO,MAAM,OAAO,KAAK,EAAA,EACA,OAAO,IAAI,KAAM,CAAC;AAC/E;AAEA,MAAa,oBAAmD;CAC9D,oCAAoC;CACpC,oCAAoC;CACpC,oCAAoC;CACpC,uBAAuB;CACvB,2BAA2B;CAC3B,uBAAuB;CACvB,uBAAuB;AACzB"}
1
+ {"version":3,"file":"entitlements.js","names":[],"sources":["../../../../src/automations/notifications/rules/entitlements.ts"],"sourcesContent":["import { entitlementEvents } from '../../../entitlements/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { RecipientList, SubjectRef } from '../../../types/index.js';\nimport { communityModerators, previousStatusOf } from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\nimport { eventBase, eventDisplay } from './events.js';\n\ntype Grant = { orgUserId: string; contentId: string | null; bundleId: string | null };\ntype SpaceMember = { spaceId: string; communityId: string; orgUserId: string; status: string };\n\nfunction seatsLeft(capacity: number | null, active: number): string {\n return capacity == null ? 'No cap' : String(Math.max(capacity - active, 0));\n}\n\nfunction subjectOnly(event: DomainEvent, reads: NotificationReads, orgUserId: string) {\n return recipientsOf(reads, event.orgId, new Reasons().add([orgUserId], 'subject'), {\n exclude: [actorOr(event, null)],\n at: eventAt(event),\n });\n}\n\nasync function grantSubject(\n reads: NotificationReads,\n orgId: string,\n grant: Grant,\n): Promise<{ ref: SubjectRef; title: string; type: string } | null> {\n if (grant.bundleId) {\n const info = await reads.contentInfo(orgId, { bundleId: grant.bundleId });\n return info ? { ref: { type: 'bundle', id: grant.bundleId }, ...info } : null;\n }\n if (!grant.contentId) {\n return null;\n }\n const info = await reads.contentInfo(orgId, { contentId: grant.contentId });\n if (!info) {\n return null;\n }\n const type: SubjectRef['type'] =\n info.type === 'download' ? 'download' : info.type === 'community' ? 'community' : 'course';\n return { ref: { type, id: grant.contentId }, ...info };\n}\n\nasync function membershipEnded(\n event: DomainEvent,\n reads: NotificationReads,\n grant: Grant,\n ref: SubjectRef | null,\n): Promise<RecipientList[] | null> {\n const orgId = event.orgId;\n const communityIds = await reads.communitiesOpenedBy(orgId, grant);\n if (communityIds.length === 0) {\n return null;\n }\n const held = new Set(\n (await reads.memberCommunityTitles(orgId, grant.orgUserId)).map((community) => community.id),\n );\n const communities: { communityId: string; communityTitle: string }[] = [];\n for (const communityId of communityIds.filter((id) => !held.has(id))) {\n const title = await reads.communityTitle(orgId, communityId);\n if (title !== null) {\n communities.push({ communityId, communityTitle: title });\n }\n }\n if (communities.length === 0) {\n return null;\n }\n return listOf(\n {\n type: 'community.membership_ended',\n scope: 'org',\n actorId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: ref,\n parent: null,\n display: { communities },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n}\n\nasync function spaceBase(\n reads: NotificationReads,\n orgId: string,\n member: SpaceMember,\n type: string,\n actorId: string | null,\n) {\n const space = await reads.space(orgId, member.spaceId);\n return space\n ? {\n space,\n base: {\n type,\n scope: 'space' as const,\n actorId,\n communityId: member.communityId,\n spaceId: member.spaceId,\n subject: { type: 'space' as const, id: member.spaceId },\n parent: null,\n },\n }\n : null;\n}\n\nconst spaceMemberCreated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const member = parsed.data.data;\n const orgId = event.orgId;\n if (member.status === 'requested') {\n const found = await spaceBase(reads, orgId, member, 'space.join_requested', member.orgUserId);\n if (!found) {\n return [];\n }\n const active = await reads.activeMemberCount(orgId, member.spaceId);\n return listOf(\n {\n ...found.base,\n display: {\n spaceName: found.space.name,\n spaceId: member.spaceId,\n memberName: await reads.displayName(orgId, member.orgUserId),\n seatsLeft: seatsLeft(found.space.capacity, active),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, member.communityId), 'moderator'),\n {\n exclude: [member.orgUserId, actorOr(event, null)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, member.spaceId, orgUserIds),\n },\n ),\n );\n }\n if (member.status === 'invited') {\n const inviter = actorOr(event, null);\n const found = await spaceBase(reads, orgId, member, 'space.invited', inviter);\n if (!found) {\n return [];\n }\n return listOf(\n {\n ...found.base,\n display: {\n spaceName: found.space.name,\n spaceId: member.spaceId,\n inviterName: inviter ? await reads.displayName(orgId, inviter) : 'A member',\n },\n },\n await subjectOnly(event, reads, member.orgUserId),\n );\n }\n return [];\n};\n\nconst spaceMemberUpdated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const member = parsed.data.data;\n if (member.status !== 'active' || previousStatusOf(event) !== 'requested') {\n return [];\n }\n const found = await spaceBase(\n reads,\n event.orgId,\n member,\n 'space.request_approved',\n actorOr(event, null),\n );\n return found\n ? listOf(\n { ...found.base, display: { spaceName: found.space.name, spaceId: member.spaceId } },\n await subjectOnly(event, reads, member.orgUserId),\n )\n : [];\n};\n\nconst spaceMemberDeleted: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.spaceMemberDeleted.safeParse(event);\n if (!parsed.success || previousStatusOf(event) !== 'requested') {\n return [];\n }\n const member = parsed.data.data;\n const found = await spaceBase(\n reads,\n event.orgId,\n member,\n 'space.request_declined',\n actorOr(event, null),\n );\n return found\n ? listOf(\n { ...found.base, display: { spaceName: found.space.name, spaceId: member.spaceId } },\n await subjectOnly(event, reads, member.orgUserId),\n )\n : [];\n};\n\nasync function grantedEvent(reads: NotificationReads, orgId: string, grant: Grant) {\n return grant.contentId ? reads.event(orgId, grant.contentId) : null;\n}\n\nconst entitlementCreated: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const orgId = event.orgId;\n const actor = actorOr(event, null);\n const granted = await grantedEvent(reads, orgId, grant);\n if (granted) {\n if (!granted.settings.notifications) {\n return [];\n }\n return listOf(\n { ...eventBase('event.granted', granted, actor), display: eventDisplay(granted) },\n await recipientsOf(reads, orgId, new Reasons().add([grant.orgUserId], 'event_member'), {\n exclude: [],\n at: eventAt(event),\n }),\n );\n }\n const subject = await subjectOnly(event, reads, grant.orgUserId);\n if (subject.length === 0) {\n return [];\n }\n const lists: RecipientList[] = [];\n const target = await grantSubject(reads, orgId, grant);\n if (target) {\n lists.push(\n ...listOf(\n {\n type: 'access.granted',\n scope: 'org',\n actorId: actor,\n communityId: null,\n spaceId: null,\n subject: target.ref,\n parent: null,\n display: { contentTitle: target.title, contentType: target.type },\n },\n subject,\n ),\n );\n }\n for (const communityId of await reads.communitiesOpenedBy(orgId, grant)) {\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n continue;\n }\n lists.push(\n ...listOf(\n {\n type: 'community.welcome',\n scope: 'community',\n actorId: actor,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n spaceNames: await reads.openSpaceNames(orgId, grant.orgUserId, communityId),\n },\n },\n subject,\n ),\n );\n }\n return lists;\n};\n\nconst entitlementEndingSoon: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementEndingSoon.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const title = await reads.communityTitle(event.orgId, grant.communityId);\n if (title === null) {\n return [];\n }\n return listOf(\n {\n type: 'community.ending_soon',\n scope: 'community',\n actorId: null,\n communityId: grant.communityId,\n spaceId: null,\n subject: { type: 'community', id: grant.communityId },\n parent: null,\n display: {\n communityTitle: title,\n expiresAt: grant.expiresAt ? grant.expiresAt.toISOString() : '',\n },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n};\n\nconst entitlementDeleted: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementDeleted.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const revokedFrom = await grantedEvent(reads, event.orgId, grant);\n if (revokedFrom) {\n if (\n !revokedFrom.settings.notifications ||\n !(await reads.contentLostBy(event.orgId, grant)).includes(revokedFrom.id)\n ) {\n return [];\n }\n const actor = actorOr(event, null);\n return listOf(\n { ...eventBase('event.revoked', revokedFrom, actor), display: eventDisplay(revokedFrom) },\n await recipientsOf(reads, event.orgId, new Reasons().add([grant.orgUserId], 'event_member'), {\n exclude: [actor],\n at: eventAt(event),\n }),\n );\n }\n const target = await grantSubject(reads, event.orgId, grant);\n const ended = await membershipEnded(event, reads, grant, target?.ref ?? null);\n if (ended) {\n return ended;\n }\n if (!target || (await reads.contentLostBy(event.orgId, grant)).length === 0) {\n return [];\n }\n return listOf(\n {\n type: 'access.revoked',\n scope: 'org',\n actorId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: target.ref,\n parent: null,\n display: { contentTitle: target.title },\n },\n await subjectOnly(event, reads, grant.orgUserId),\n );\n};\n\nconst entitlementExpired: RecipientRule = async (event, reads) => {\n const parsed = entitlementEvents.entitlementExpired.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const grant = parsed.data.data;\n const target = await grantSubject(reads, event.orgId, grant);\n return (await membershipEnded(event, reads, grant, target?.ref ?? null)) ?? [];\n};\n\nexport const ENTITLEMENT_RULES: Record<string, RecipientRule> = {\n 'entitlement.space_member.created': spaceMemberCreated,\n 'entitlement.space_member.updated': spaceMemberUpdated,\n 'entitlement.space_member.deleted': spaceMemberDeleted,\n 'entitlement.created': entitlementCreated,\n 'entitlement.ending_soon': entitlementEndingSoon,\n 'entitlement.deleted': entitlementDeleted,\n 'entitlement.expired': entitlementExpired,\n};\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Event } from "../../../types/schemas/content.js";
2
+ import "../../../content/index.js";
3
+ import { ListBase } from "./recipients.js";
4
+ //#region src/automations/notifications/rules/events.d.ts
5
+ declare function eventBase(type: string, event: Event, actorId: string | null): Omit<ListBase, 'display'>;
6
+ declare function eventDisplay(event: Event): Record<string, string>;
7
+ //#endregion
8
+ export { eventBase, eventDisplay };
9
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1,27 @@
1
+ //#region src/automations/notifications/rules/events.ts
2
+ function eventBase(type, event, actorId) {
3
+ return {
4
+ type,
5
+ scope: "org",
6
+ actorId,
7
+ communityId: null,
8
+ spaceId: null,
9
+ subject: {
10
+ type: "event",
11
+ id: event.id
12
+ },
13
+ parent: null
14
+ };
15
+ }
16
+ function eventDisplay(event) {
17
+ return {
18
+ eventTitle: event.title,
19
+ startsAt: event.startsAt.toISOString(),
20
+ endsAt: event.endsAt.toISOString(),
21
+ timeZone: event.timeZone
22
+ };
23
+ }
24
+ //#endregion
25
+ export { eventBase, eventDisplay };
26
+
27
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","names":[],"sources":["../../../../src/automations/notifications/rules/events.ts"],"sourcesContent":["import type { Event } from '../../../content/index.js';\nimport type { ListBase } from './recipients.js';\n\nexport function eventBase(\n type: string,\n event: Event,\n actorId: string | null,\n): Omit<ListBase, 'display'> {\n return {\n type,\n scope: 'org',\n actorId,\n communityId: null,\n spaceId: null,\n subject: { type: 'event', id: event.id },\n parent: null,\n };\n}\n\nexport function eventDisplay(event: Event): Record<string, string> {\n return {\n eventTitle: event.title,\n startsAt: event.startsAt.toISOString(),\n endsAt: event.endsAt.toISOString(),\n timeZone: event.timeZone,\n };\n}\n"],"mappings":";AAGA,SAAgB,UACd,MACA,OACA,SAC2B;CAC3B,OAAO;EACL;EACA,OAAO;EACP;EACA,aAAa;EACb,SAAS;EACT,SAAS;GAAE,MAAM;GAAS,IAAI,MAAM;EAAG;EACvC,QAAQ;CACV;AACF;AAEA,SAAgB,aAAa,OAAsC;CACjE,OAAO;EACL,YAAY,MAAM;EAClB,UAAU,MAAM,SAAS,YAAY;EACrC,QAAQ,MAAM,OAAO,YAAY;EACjC,UAAU,MAAM;CAClB;AACF"}
@@ -1,27 +1,34 @@
1
1
  import { organizationEvents } from "../../../organizations/events.js";
2
+ import { roleGain } from "../../community-mail.js";
2
3
  import { Reasons, actorOr, eventAt, listOf, recipientsOf } from "./recipients.js";
3
4
  //#region src/automations/notifications/rules/organizations.ts
4
- const orgUserUpdated = async (event, reads) => {
5
- const parsed = organizationEvents.orgUserUpdated.safeParse(event);
6
- if (!parsed.success || parsed.data.data.role !== "moderator") return [];
7
- const orgUser = parsed.data.data;
5
+ const roleAssigned = async (event, reads) => {
6
+ const parsed = organizationEvents.roleAssigned.safeParse(event);
7
+ if (!parsed.success) return [];
8
+ const assigned = parsed.data.data;
8
9
  const orgId = event.orgId;
9
- const communities = await reads.memberCommunityTitles(orgId, orgUser.id);
10
+ const gain = await roleGain(reads, orgId, assigned);
11
+ if (!gain) return [];
10
12
  return listOf({
11
- type: "moderator.assigned",
13
+ type: "role.assigned",
12
14
  scope: "org",
13
- actorOrgUserId: actorOr(event, null),
15
+ actorId: actorOr(event, null),
14
16
  communityId: null,
15
17
  spaceId: null,
16
18
  subject: null,
17
19
  parent: null,
18
- display: { communityTitles: communities.map((community) => community.title) }
19
- }, await recipientsOf(reads, orgId, new Reasons().add([orgUser.id], "subject"), {
20
+ display: {
21
+ roleName: gain.roleName,
22
+ place: gain.place,
23
+ contentId: gain.contentId,
24
+ contentType: gain.contentType
25
+ }
26
+ }, await recipientsOf(reads, orgId, new Reasons().add([assigned.orgUserId], "subject"), {
20
27
  exclude: [actorOr(event, null)],
21
28
  at: eventAt(event)
22
29
  }));
23
30
  };
24
- const ORGANIZATION_RULES = { "organization.user.updated": orgUserUpdated };
31
+ const ORGANIZATION_RULES = { "organization.role.assigned": roleAssigned };
25
32
  //#endregion
26
33
  export { ORGANIZATION_RULES };
27
34
 
@@ -1 +1 @@
1
- {"version":3,"file":"organizations.js","names":[],"sources":["../../../../src/automations/notifications/rules/organizations.ts"],"sourcesContent":["import { organizationEvents } from '../../../organizations/index.js';\nimport type { RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst orgUserUpdated: RecipientRule = async (event, reads) => {\n const parsed = organizationEvents.orgUserUpdated.safeParse(event);\n if (!parsed.success || parsed.data.data.role !== 'moderator') {\n return [];\n }\n const orgUser = parsed.data.data;\n const orgId = event.orgId;\n const communities = await reads.memberCommunityTitles(orgId, orgUser.id);\n return listOf(\n {\n type: 'moderator.assigned',\n scope: 'org',\n actorOrgUserId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: null,\n parent: null,\n display: { communityTitles: communities.map((community) => community.title) },\n },\n await recipientsOf(reads, orgId, new Reasons().add([orgUser.id], 'subject'), {\n exclude: [actorOr(event, null)],\n at: eventAt(event),\n }),\n );\n};\n\nexport const ORGANIZATION_RULES: Record<string, RecipientRule> = {\n 'organization.user.updated': orgUserUpdated,\n};\n"],"mappings":";;;AAIA,MAAM,iBAAgC,OAAO,OAAO,UAAU;CAC5D,MAAM,SAAS,mBAAmB,eAAe,UAAU,KAAK;CAChE,IAAI,CAAC,OAAO,WAAW,OAAO,KAAK,KAAK,SAAS,aAC/C,OAAO,CAAC;CAEV,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,QAAQ,MAAM;CACpB,MAAM,cAAc,MAAM,MAAM,sBAAsB,OAAO,QAAQ,EAAE;CACvE,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,gBAAgB,QAAQ,OAAO,IAAI;EACnC,aAAa;EACb,SAAS;EACT,SAAS;EACT,QAAQ;EACR,SAAS,EAAE,iBAAiB,YAAY,KAAK,cAAc,UAAU,KAAK,EAAE;CAC9E,GACA,MAAM,aAAa,OAAO,OAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG;EAC3E,SAAS,CAAC,QAAQ,OAAO,IAAI,CAAC;EAC9B,IAAI,QAAQ,KAAK;CACnB,CAAC,CACH;AACF;AAEA,MAAa,qBAAoD,EAC/D,6BAA6B,eAC/B"}
1
+ {"version":3,"file":"organizations.js","names":[],"sources":["../../../../src/automations/notifications/rules/organizations.ts"],"sourcesContent":["import { organizationEvents } from '../../../organizations/index.js';\nimport { roleGain } from '../../community-mail.js';\nimport type { RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst roleAssigned: RecipientRule = async (event, reads) => {\n const parsed = organizationEvents.roleAssigned.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const assigned = parsed.data.data;\n const orgId = event.orgId;\n const gain = await roleGain(reads, orgId, assigned);\n if (!gain) {\n return [];\n }\n return listOf(\n {\n type: 'role.assigned',\n scope: 'org',\n actorId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: null,\n parent: null,\n display: {\n roleName: gain.roleName,\n place: gain.place,\n contentId: gain.contentId,\n contentType: gain.contentType,\n },\n },\n await recipientsOf(reads, orgId, new Reasons().add([assigned.orgUserId], 'subject'), {\n exclude: [actorOr(event, null)],\n at: eventAt(event),\n }),\n );\n};\n\nexport const ORGANIZATION_RULES: Record<string, RecipientRule> = {\n 'organization.role.assigned': roleAssigned,\n};\n"],"mappings":";;;;AAKA,MAAM,eAA8B,OAAO,OAAO,UAAU;CAC1D,MAAM,SAAS,mBAAmB,aAAa,UAAU,KAAK;CAC9D,IAAI,CAAC,OAAO,SACV,OAAO,CAAC;CAEV,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,QAAQ,MAAM;CACpB,MAAM,OAAO,MAAM,SAAS,OAAO,OAAO,QAAQ;CAClD,IAAI,CAAC,MACH,OAAO,CAAC;CAEV,OAAO,OACL;EACE,MAAM;EACN,OAAO;EACP,SAAS,QAAQ,OAAO,IAAI;EAC5B,aAAa;EACb,SAAS;EACT,SAAS;EACT,QAAQ;EACR,SAAS;GACP,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,WAAW,KAAK;GAChB,aAAa,KAAK;EACpB;CACF,GACA,MAAM,aAAa,OAAO,OAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,SAAS,GAAG;EACnF,SAAS,CAAC,QAAQ,OAAO,IAAI,CAAC;EAC9B,IAAI,QAAQ,KAAK;CACnB,CAAC,CACH;AACF;AAEA,MAAa,qBAAoD,EAC/D,8BAA8B,aAChC"}
@@ -4,7 +4,6 @@ import { actorOf, excerpt } from "../../community-mail.js";
4
4
  const MUTE_PROOF = [
5
5
  "subject",
6
6
  "moderator",
7
- "staff",
8
7
  "mentioned"
9
8
  ];
10
9
  var Reasons = class {
@@ -1 +1 @@
1
- {"version":3,"file":"recipients.js","names":[],"sources":["../../../../src/automations/notifications/rules/recipients.ts"],"sourcesContent":["import { nameMentions } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { Reason, RecipientList, SubjectRef } from '../../../types/index.js';\nimport { actorOf, excerpt } from '../../community-mail.js';\nimport type { NotificationReads } from '../../ports.js';\n\nexport type Recipient = NonNullable<RecipientList['recipients']>[number];\nexport type ListBase = Omit<RecipientList, 'recipients' | 'audience'>;\nexport type Chat = NonNullable<Awaited<ReturnType<NotificationReads['chat']>>>;\n\nconst MUTE_PROOF: Reason[] = ['subject', 'moderator', 'staff', 'mentioned'];\n\nexport class Reasons {\n private readonly byPerson = new Map<string, Reason[]>();\n\n add(orgUserIds: (string | null | undefined)[], reason: Reason): this {\n for (const orgUserId of orgUserIds) {\n if (!orgUserId) {\n continue;\n }\n const reasons = this.byPerson.get(orgUserId) ?? [];\n if (!reasons.includes(reason)) {\n reasons.push(reason);\n }\n this.byPerson.set(orgUserId, reasons);\n }\n return this;\n }\n\n ids(): string[] {\n return [...this.byPerson.keys()];\n }\n\n entries(): [string, Reason[]][] {\n return [...this.byPerson.entries()];\n }\n}\n\nexport interface Reach {\n exclude: (string | null | undefined)[];\n canOpen?: (orgUserIds: string[]) => Promise<string[]>;\n mutedOn?: SubjectRef[];\n at: Date;\n}\n\nexport async function recipientsOf(\n reads: NotificationReads,\n orgId: string,\n reasons: Reasons,\n reach: Reach,\n): Promise<Recipient[]> {\n const excluded = new Set(reach.exclude.filter((id): id is string => Boolean(id)));\n let people = new Map(reasons.entries().filter(([orgUserId]) => !excluded.has(orgUserId)));\n if (people.size > 0 && reach.canOpen) {\n const open = new Set(await reach.canOpen([...people.keys()]));\n people = new Map([...people].filter(([orgUserId]) => open.has(orgUserId)));\n }\n for (const item of reach.mutedOn ?? []) {\n const exposed = [...people]\n .filter(([, held]) => held.some((reason) => !MUTE_PROOF.includes(reason)))\n .map(([orgUserId]) => orgUserId);\n if (exposed.length === 0) {\n break;\n }\n for (const orgUserId of await reads.mutedAmong(orgId, item, exposed, reach.at)) {\n const kept = (people.get(orgUserId) ?? []).filter((reason) => MUTE_PROOF.includes(reason));\n if (kept.length > 0) {\n people.set(orgUserId, kept);\n } else {\n people.delete(orgUserId);\n }\n }\n }\n if (people.size === 0) {\n return [];\n }\n const userIds = await reads.userIdsOf(orgId, [...people.keys()]);\n return [...people].flatMap(([orgUserId, held]) => {\n const userId = userIds[orgUserId];\n return userId ? [{ orgUserId, userId, reasons: held }] : [];\n });\n}\n\nexport function listOf(base: ListBase, recipients: Recipient[]): RecipientList[] {\n return recipients.length > 0 ? [{ ...base, recipients }] : [];\n}\n\nexport function eventAt(event: DomainEvent): Date {\n return new Date(event.occurredAt);\n}\n\nexport function actorOr(event: DomainEvent, fallback: string | null): string | null {\n return actorOf(event) ?? fallback;\n}\n\nexport async function textExcerpt(\n reads: NotificationReads,\n orgId: string,\n text: string,\n max: number,\n): Promise<string> {\n return excerpt(await nameMentions(text, (orgUserId) => reads.displayName(orgId, orgUserId)), max);\n}\n\nexport async function participantNames(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n): Promise<string[]> {\n const names: string[] = [];\n for (const participant of chat.participants) {\n if (!participant.leftAt) {\n names.push(await reads.displayName(orgId, participant.orgUserId));\n }\n }\n return names;\n}\n\nexport async function chatTitle(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n senderOrgUserId: string,\n): Promise<string> {\n if (chat.kind === 'direct') {\n return reads.displayName(orgId, senderOrgUserId);\n }\n const names = await participantNames(reads, orgId, chat);\n return names.length > 0 ? names.join(', ') : 'Group chat';\n}\n\nexport function chatReach(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n chatId: string,\n actor: string,\n at: Date,\n): Reach {\n return {\n exclude: [actor],\n at,\n mutedOn: [{ type: 'chat', id: chatId }],\n canOpen: async (orgUserIds) => {\n const present = new Set(\n chat.participants\n .filter((participant) => participant.leftAt === null)\n .map((participant) => participant.orgUserId),\n );\n const unblocked: string[] = [];\n for (const orgUserId of orgUserIds) {\n if (\n present.has(orgUserId) &&\n !(await reads.pairBlocked(orgId, chat.communityId, actor, orgUserId))\n ) {\n unblocked.push(orgUserId);\n }\n }\n return unblocked.length > 0\n ? reads.communityMembersAmong(orgId, chat.communityId, unblocked)\n : [];\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"recipients.js","names":[],"sources":["../../../../src/automations/notifications/rules/recipients.ts"],"sourcesContent":["import { nameMentions } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { Reason, RecipientList, SubjectRef } from '../../../types/index.js';\nimport { actorOf, excerpt } from '../../community-mail.js';\nimport type { NotificationReads } from '../../ports.js';\n\nexport type Recipient = NonNullable<RecipientList['recipients']>[number];\nexport type ListBase = Omit<RecipientList, 'recipients' | 'audience'>;\nexport type Chat = NonNullable<Awaited<ReturnType<NotificationReads['chat']>>>;\n\nconst MUTE_PROOF: Reason[] = ['subject', 'moderator', 'mentioned'];\n\nexport class Reasons {\n private readonly byPerson = new Map<string, Reason[]>();\n\n add(orgUserIds: (string | null | undefined)[], reason: Reason): this {\n for (const orgUserId of orgUserIds) {\n if (!orgUserId) {\n continue;\n }\n const reasons = this.byPerson.get(orgUserId) ?? [];\n if (!reasons.includes(reason)) {\n reasons.push(reason);\n }\n this.byPerson.set(orgUserId, reasons);\n }\n return this;\n }\n\n ids(): string[] {\n return [...this.byPerson.keys()];\n }\n\n entries(): [string, Reason[]][] {\n return [...this.byPerson.entries()];\n }\n}\n\nexport interface Reach {\n exclude: (string | null | undefined)[];\n canOpen?: (orgUserIds: string[]) => Promise<string[]>;\n mutedOn?: SubjectRef[];\n at: Date;\n}\n\nexport async function recipientsOf(\n reads: NotificationReads,\n orgId: string,\n reasons: Reasons,\n reach: Reach,\n): Promise<Recipient[]> {\n const excluded = new Set(reach.exclude.filter((id): id is string => Boolean(id)));\n let people = new Map(reasons.entries().filter(([orgUserId]) => !excluded.has(orgUserId)));\n if (people.size > 0 && reach.canOpen) {\n const open = new Set(await reach.canOpen([...people.keys()]));\n people = new Map([...people].filter(([orgUserId]) => open.has(orgUserId)));\n }\n for (const item of reach.mutedOn ?? []) {\n const exposed = [...people]\n .filter(([, held]) => held.some((reason) => !MUTE_PROOF.includes(reason)))\n .map(([orgUserId]) => orgUserId);\n if (exposed.length === 0) {\n break;\n }\n for (const orgUserId of await reads.mutedAmong(orgId, item, exposed, reach.at)) {\n const kept = (people.get(orgUserId) ?? []).filter((reason) => MUTE_PROOF.includes(reason));\n if (kept.length > 0) {\n people.set(orgUserId, kept);\n } else {\n people.delete(orgUserId);\n }\n }\n }\n if (people.size === 0) {\n return [];\n }\n const userIds = await reads.userIdsOf(orgId, [...people.keys()]);\n return [...people].flatMap(([orgUserId, held]) => {\n const userId = userIds[orgUserId];\n return userId ? [{ orgUserId, userId, reasons: held }] : [];\n });\n}\n\nexport function listOf(base: ListBase, recipients: Recipient[]): RecipientList[] {\n return recipients.length > 0 ? [{ ...base, recipients }] : [];\n}\n\nexport function eventAt(event: DomainEvent): Date {\n return new Date(event.occurredAt);\n}\n\nexport function actorOr(event: DomainEvent, fallback: string | null): string | null {\n return actorOf(event) ?? fallback;\n}\n\nexport async function textExcerpt(\n reads: NotificationReads,\n orgId: string,\n text: string,\n max: number,\n): Promise<string> {\n return excerpt(await nameMentions(text, (orgUserId) => reads.displayName(orgId, orgUserId)), max);\n}\n\nexport async function participantNames(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n): Promise<string[]> {\n const names: string[] = [];\n for (const participant of chat.participants) {\n if (!participant.leftAt) {\n names.push(await reads.displayName(orgId, participant.orgUserId));\n }\n }\n return names;\n}\n\nexport async function chatTitle(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n senderOrgUserId: string,\n): Promise<string> {\n if (chat.kind === 'direct') {\n return reads.displayName(orgId, senderOrgUserId);\n }\n const names = await participantNames(reads, orgId, chat);\n return names.length > 0 ? names.join(', ') : 'Group chat';\n}\n\nexport function chatReach(\n reads: NotificationReads,\n orgId: string,\n chat: Chat,\n chatId: string,\n actor: string,\n at: Date,\n): Reach {\n return {\n exclude: [actor],\n at,\n mutedOn: [{ type: 'chat', id: chatId }],\n canOpen: async (orgUserIds) => {\n const present = new Set(\n chat.participants\n .filter((participant) => participant.leftAt === null)\n .map((participant) => participant.orgUserId),\n );\n const unblocked: string[] = [];\n for (const orgUserId of orgUserIds) {\n if (\n present.has(orgUserId) &&\n !(await reads.pairBlocked(orgId, chat.communityId, actor, orgUserId))\n ) {\n unblocked.push(orgUserId);\n }\n }\n return unblocked.length > 0\n ? reads.communityMembersAmong(orgId, chat.communityId, unblocked)\n : [];\n },\n };\n}\n"],"mappings":";;;AAUA,MAAM,aAAuB;CAAC;CAAW;CAAa;AAAW;AAEjE,IAAa,UAAb,MAAqB;CACnB,2BAA4B,IAAI,IAAsB;CAEtD,IAAI,YAA2C,QAAsB;EACnE,KAAK,MAAM,aAAa,YAAY;GAClC,IAAI,CAAC,WACH;GAEF,MAAM,UAAU,KAAK,SAAS,IAAI,SAAS,KAAK,CAAC;GACjD,IAAI,CAAC,QAAQ,SAAS,MAAM,GAC1B,QAAQ,KAAK,MAAM;GAErB,KAAK,SAAS,IAAI,WAAW,OAAO;EACtC;EACA,OAAO;CACT;CAEA,MAAgB;EACd,OAAO,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;CACjC;CAEA,UAAgC;EAC9B,OAAO,CAAC,GAAG,KAAK,SAAS,QAAQ,CAAC;CACpC;AACF;AASA,eAAsB,aACpB,OACA,OACA,SACA,OACsB;CACtB,MAAM,WAAW,IAAI,IAAI,MAAM,QAAQ,QAAQ,OAAqB,QAAQ,EAAE,CAAC,CAAC;CAChF,IAAI,SAAS,IAAI,IAAI,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;CACxF,IAAI,OAAO,OAAO,KAAK,MAAM,SAAS;EACpC,MAAM,OAAO,IAAI,IAAI,MAAM,MAAM,QAAQ,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC;EAC5D,SAAS,IAAI,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,eAAe,KAAK,IAAI,SAAS,CAAC,CAAC;CAC3E;CACA,KAAK,MAAM,QAAQ,MAAM,WAAW,CAAC,GAAG;EACtC,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CACxB,QAAQ,GAAG,UAAU,KAAK,MAAM,WAAW,CAAC,WAAW,SAAS,MAAM,CAAC,CAAC,CAAC,CACzE,KAAK,CAAC,eAAe,SAAS;EACjC,IAAI,QAAQ,WAAW,GACrB;EAEF,KAAK,MAAM,aAAa,MAAM,MAAM,WAAW,OAAO,MAAM,SAAS,MAAM,EAAE,GAAG;GAC9E,MAAM,QAAQ,OAAO,IAAI,SAAS,KAAK,CAAC,EAAA,CAAG,QAAQ,WAAW,WAAW,SAAS,MAAM,CAAC;GACzF,IAAI,KAAK,SAAS,GAChB,OAAO,IAAI,WAAW,IAAI;QAE1B,OAAO,OAAO,SAAS;EAE3B;CACF;CACA,IAAI,OAAO,SAAS,GAClB,OAAO,CAAC;CAEV,MAAM,UAAU,MAAM,MAAM,UAAU,OAAO,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC;CAC/D,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,UAAU;EAChD,MAAM,SAAS,QAAQ;EACvB,OAAO,SAAS,CAAC;GAAE;GAAW;GAAQ,SAAS;EAAK,CAAC,IAAI,CAAC;CAC5D,CAAC;AACH;AAEA,SAAgB,OAAO,MAAgB,YAA0C;CAC/E,OAAO,WAAW,SAAS,IAAI,CAAC;EAAE,GAAG;EAAM;CAAW,CAAC,IAAI,CAAC;AAC9D;AAEA,SAAgB,QAAQ,OAA0B;CAChD,OAAO,IAAI,KAAK,MAAM,UAAU;AAClC;AAEA,SAAgB,QAAQ,OAAoB,UAAwC;CAClF,OAAO,QAAQ,KAAK,KAAK;AAC3B;AAEA,eAAsB,YACpB,OACA,OACA,MACA,KACiB;CACjB,OAAO,QAAQ,MAAM,aAAa,OAAO,cAAc,MAAM,YAAY,OAAO,SAAS,CAAC,GAAG,GAAG;AAClG;AAEA,eAAsB,iBACpB,OACA,OACA,MACmB;CACnB,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,eAAe,KAAK,cAC7B,IAAI,CAAC,YAAY,QACf,MAAM,KAAK,MAAM,MAAM,YAAY,OAAO,YAAY,SAAS,CAAC;CAGpE,OAAO;AACT;AAEA,eAAsB,UACpB,OACA,OACA,MACA,iBACiB;CACjB,IAAI,KAAK,SAAS,UAChB,OAAO,MAAM,YAAY,OAAO,eAAe;CAEjD,MAAM,QAAQ,MAAM,iBAAiB,OAAO,OAAO,IAAI;CACvD,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;AAEA,SAAgB,UACd,OACA,OACA,MACA,QACA,OACA,IACO;CACP,OAAO;EACL,SAAS,CAAC,KAAK;EACf;EACA,SAAS,CAAC;GAAE,MAAM;GAAQ,IAAI;EAAO,CAAC;EACtC,SAAS,OAAO,eAAe;GAC7B,MAAM,UAAU,IAAI,IAClB,KAAK,aACF,QAAQ,gBAAgB,YAAY,WAAW,IAAI,CAAC,CACpD,KAAK,gBAAgB,YAAY,SAAS,CAC/C;GACA,MAAM,YAAsB,CAAC;GAC7B,KAAK,MAAM,aAAa,YACtB,IACE,QAAQ,IAAI,SAAS,KACrB,CAAE,MAAM,MAAM,YAAY,OAAO,KAAK,aAAa,OAAO,SAAS,GAEnE,UAAU,KAAK,SAAS;GAG5B,OAAO,UAAU,SAAS,IACtB,MAAM,sBAAsB,OAAO,KAAK,aAAa,SAAS,IAC9D,CAAC;EACP;CACF;AACF"}
@@ -2,6 +2,8 @@ import { Logger } from "../../types/ports.js";
2
2
  import { NotificationFilter } from "../../types/notifications.js";
3
3
  import "../../types/index.js";
4
4
  import "../../shared/ports.js";
5
+ import { MemberActor } from "../../identity/ports.js";
6
+ import "../../identity/index.js";
5
7
  import { ListedNotification, NotificationPage, NotificationsRepository, NotificationsService, UnreadCounts } from "../ports.js";
6
8
  //#region src/automations/notifications/service.d.ts
7
9
  declare class NotificationsServiceImpl implements NotificationsService {
@@ -11,14 +13,14 @@ declare class NotificationsServiceImpl implements NotificationsService {
11
13
  repo: NotificationsRepository;
12
14
  logger?: Logger;
13
15
  });
14
- list(orgId: string, userId: string, filter: NotificationFilter, page: {
16
+ list(filter: NotificationFilter, page: {
15
17
  page: number;
16
18
  pageSize: number;
17
- }): Promise<NotificationPage>;
18
- get(orgId: string, userId: string, notificationId: string): Promise<ListedNotification | null>;
19
- unreadCounts(orgId: string, userId: string, communityIds: string[]): Promise<UnreadCounts>;
20
- markRead(orgId: string, userId: string, notificationId: string): Promise<void>;
21
- markAllRead(orgId: string, userId: string, filter: NotificationFilter): Promise<{
19
+ }, actor: MemberActor): Promise<NotificationPage>;
20
+ get(notificationId: string, actor: MemberActor): Promise<ListedNotification | null>;
21
+ unreadCounts(communityIds: string[], actor: MemberActor): Promise<UnreadCounts>;
22
+ markRead(notificationId: string, actor: MemberActor): Promise<void>;
23
+ markAllRead(filter: NotificationFilter, actor: MemberActor): Promise<{
22
24
  marked: number;
23
25
  }>;
24
26
  }
@@ -8,15 +8,15 @@ var NotificationsServiceImpl = class {
8
8
  this.repo = params.repo;
9
9
  this.logger = params.logger ?? noopLogger;
10
10
  }
11
- list(orgId, userId, filter, page) {
12
- return this.repo.page(orgId, userId, filter, page);
11
+ list(filter, page, actor) {
12
+ return this.repo.page(actor.orgId, actor.userId, filter, page);
13
13
  }
14
- get(orgId, userId, notificationId) {
15
- return this.repo.find(orgId, userId, notificationId);
14
+ get(notificationId, actor) {
15
+ return this.repo.find(actor.orgId, actor.userId, notificationId);
16
16
  }
17
- async unreadCounts(orgId, userId, communityIds) {
17
+ async unreadCounts(communityIds, actor) {
18
18
  const ids = [...new Set(communityIds)];
19
- const counts = await this.repo.unreadCounts(orgId, userId, ids);
19
+ const counts = await this.repo.unreadCounts(actor.orgId, actor.userId, ids);
20
20
  const byCommunity = new Map(counts.communities.map((row) => [row.communityId, row.unread]));
21
21
  return {
22
22
  org: counts.org,
@@ -26,14 +26,14 @@ var NotificationsServiceImpl = class {
26
26
  }))
27
27
  };
28
28
  }
29
- async markRead(orgId, userId, notificationId) {
30
- if (!await this.repo.markRead(orgId, userId, notificationId, /* @__PURE__ */ new Date())) throw new NotFoundError("Notification", notificationId);
29
+ async markRead(notificationId, actor) {
30
+ if (!await this.repo.markRead(actor.orgId, actor.userId, notificationId, /* @__PURE__ */ new Date())) throw new NotFoundError("Notification", notificationId);
31
31
  }
32
- async markAllRead(orgId, userId, filter) {
33
- const marked = await this.repo.markAllRead(orgId, userId, filter, /* @__PURE__ */ new Date());
32
+ async markAllRead(filter, actor) {
33
+ const marked = await this.repo.markAllRead(actor.orgId, actor.userId, filter, /* @__PURE__ */ new Date());
34
34
  this.logger.debug("notifications marked read", {
35
- orgId,
36
- userId,
35
+ orgId: actor.orgId,
36
+ userId: actor.userId,
37
37
  marked
38
38
  });
39
39
  return { marked };
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","names":[],"sources":["../../../src/automations/notifications/service.ts"],"sourcesContent":["import { NotFoundError } from '../../shared/errors.js';\nimport { noopLogger } from '../../shared/logger.js';\nimport type { Logger } from '../../shared/ports.js';\nimport type { NotificationFilter } from '../../types/index.js';\nimport type {\n ListedNotification,\n NotificationPage,\n NotificationsRepository,\n NotificationsService,\n UnreadCounts,\n} from '../ports.js';\n\nexport class NotificationsServiceImpl implements NotificationsService {\n private readonly repo: NotificationsRepository;\n private readonly logger: Logger;\n\n constructor(params: { repo: NotificationsRepository; logger?: Logger }) {\n this.repo = params.repo;\n this.logger = params.logger ?? noopLogger;\n }\n\n list(\n orgId: string,\n userId: string,\n filter: NotificationFilter,\n page: { page: number; pageSize: number },\n ): Promise<NotificationPage> {\n return this.repo.page(orgId, userId, filter, page);\n }\n\n get(orgId: string, userId: string, notificationId: string): Promise<ListedNotification | null> {\n return this.repo.find(orgId, userId, notificationId);\n }\n\n async unreadCounts(orgId: string, userId: string, communityIds: string[]): Promise<UnreadCounts> {\n const ids = [...new Set(communityIds)];\n const counts = await this.repo.unreadCounts(orgId, userId, ids);\n const byCommunity = new Map(counts.communities.map((row) => [row.communityId, row.unread]));\n return {\n org: counts.org,\n communities: ids.map((communityId) => ({\n communityId,\n unread: byCommunity.get(communityId) ?? 0,\n })),\n };\n }\n\n async markRead(orgId: string, userId: string, notificationId: string): Promise<void> {\n if (!(await this.repo.markRead(orgId, userId, notificationId, new Date()))) {\n throw new NotFoundError('Notification', notificationId);\n }\n }\n\n async markAllRead(\n orgId: string,\n userId: string,\n filter: NotificationFilter,\n ): Promise<{ marked: number }> {\n const marked = await this.repo.markAllRead(orgId, userId, filter, new Date());\n this.logger.debug('notifications marked read', { orgId, userId, marked });\n return { marked };\n }\n}\n"],"mappings":";;;AAYA,IAAa,2BAAb,MAAsE;CACpE;CACA;CAEA,YAAY,QAA4D;EACtE,KAAK,OAAO,OAAO;EACnB,KAAK,SAAS,OAAO,UAAU;CACjC;CAEA,KACE,OACA,QACA,QACA,MAC2B;EAC3B,OAAO,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,IAAI;CACnD;CAEA,IAAI,OAAe,QAAgB,gBAA4D;EAC7F,OAAO,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc;CACrD;CAEA,MAAM,aAAa,OAAe,QAAgB,cAA+C;EAC/F,MAAM,MAAM,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;EACrC,MAAM,SAAS,MAAM,KAAK,KAAK,aAAa,OAAO,QAAQ,GAAG;EAC9D,MAAM,cAAc,IAAI,IAAI,OAAO,YAAY,KAAK,QAAQ,CAAC,IAAI,aAAa,IAAI,MAAM,CAAC,CAAC;EAC1F,OAAO;GACL,KAAK,OAAO;GACZ,aAAa,IAAI,KAAK,iBAAiB;IACrC;IACA,QAAQ,YAAY,IAAI,WAAW,KAAK;GAC1C,EAAE;EACJ;CACF;CAEA,MAAM,SAAS,OAAe,QAAgB,gBAAuC;EACnF,IAAI,CAAE,MAAM,KAAK,KAAK,SAAS,OAAO,QAAQ,gCAAgB,IAAI,KAAK,CAAC,GACtE,MAAM,IAAI,cAAc,gBAAgB,cAAc;CAE1D;CAEA,MAAM,YACJ,OACA,QACA,QAC6B;EAC7B,MAAM,SAAS,MAAM,KAAK,KAAK,YAAY,OAAO,QAAQ,wBAAQ,IAAI,KAAK,CAAC;EAC5E,KAAK,OAAO,MAAM,6BAA6B;GAAE;GAAO;GAAQ;EAAO,CAAC;EACxE,OAAO,EAAE,OAAO;CAClB;AACF"}
1
+ {"version":3,"file":"service.js","names":[],"sources":["../../../src/automations/notifications/service.ts"],"sourcesContent":["import { NotFoundError } from '../../shared/errors.js';\nimport { noopLogger } from '../../shared/logger.js';\nimport type { Logger } from '../../shared/ports.js';\nimport type { NotificationFilter } from '../../types/index.js';\nimport type { MemberActor } from '../../identity/index.js';\nimport type {\n ListedNotification,\n NotificationPage,\n NotificationsRepository,\n NotificationsService,\n UnreadCounts,\n} from '../ports.js';\n\nexport class NotificationsServiceImpl implements NotificationsService {\n private readonly repo: NotificationsRepository;\n private readonly logger: Logger;\n\n constructor(params: { repo: NotificationsRepository; logger?: Logger }) {\n this.repo = params.repo;\n this.logger = params.logger ?? noopLogger;\n }\n\n list(\n filter: NotificationFilter,\n page: { page: number; pageSize: number },\n actor: MemberActor,\n ): Promise<NotificationPage> {\n return this.repo.page(actor.orgId, actor.userId, filter, page);\n }\n\n get(notificationId: string, actor: MemberActor): Promise<ListedNotification | null> {\n return this.repo.find(actor.orgId, actor.userId, notificationId);\n }\n\n async unreadCounts(communityIds: string[], actor: MemberActor): Promise<UnreadCounts> {\n const ids = [...new Set(communityIds)];\n const counts = await this.repo.unreadCounts(actor.orgId, actor.userId, ids);\n const byCommunity = new Map(counts.communities.map((row) => [row.communityId, row.unread]));\n return {\n org: counts.org,\n communities: ids.map((communityId) => ({\n communityId,\n unread: byCommunity.get(communityId) ?? 0,\n })),\n };\n }\n\n async markRead(notificationId: string, actor: MemberActor): Promise<void> {\n if (!(await this.repo.markRead(actor.orgId, actor.userId, notificationId, new Date()))) {\n throw new NotFoundError('Notification', notificationId);\n }\n }\n\n async markAllRead(filter: NotificationFilter, actor: MemberActor): Promise<{ marked: number }> {\n const marked = await this.repo.markAllRead(actor.orgId, actor.userId, filter, new Date());\n this.logger.debug('notifications marked read', {\n orgId: actor.orgId,\n userId: actor.userId,\n marked,\n });\n return { marked };\n }\n}\n"],"mappings":";;;AAaA,IAAa,2BAAb,MAAsE;CACpE;CACA;CAEA,YAAY,QAA4D;EACtE,KAAK,OAAO,OAAO;EACnB,KAAK,SAAS,OAAO,UAAU;CACjC;CAEA,KACE,QACA,MACA,OAC2B;EAC3B,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;CAC/D;CAEA,IAAI,gBAAwB,OAAwD;EAClF,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,MAAM,QAAQ,cAAc;CACjE;CAEA,MAAM,aAAa,cAAwB,OAA2C;EACpF,MAAM,MAAM,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;EACrC,MAAM,SAAS,MAAM,KAAK,KAAK,aAAa,MAAM,OAAO,MAAM,QAAQ,GAAG;EAC1E,MAAM,cAAc,IAAI,IAAI,OAAO,YAAY,KAAK,QAAQ,CAAC,IAAI,aAAa,IAAI,MAAM,CAAC,CAAC;EAC1F,OAAO;GACL,KAAK,OAAO;GACZ,aAAa,IAAI,KAAK,iBAAiB;IACrC;IACA,QAAQ,YAAY,IAAI,WAAW,KAAK;GAC1C,EAAE;EACJ;CACF;CAEA,MAAM,SAAS,gBAAwB,OAAmC;EACxE,IAAI,CAAE,MAAM,KAAK,KAAK,SAAS,MAAM,OAAO,MAAM,QAAQ,gCAAgB,IAAI,KAAK,CAAC,GAClF,MAAM,IAAI,cAAc,gBAAgB,cAAc;CAE1D;CAEA,MAAM,YAAY,QAA4B,OAAiD;EAC7F,MAAM,SAAS,MAAM,KAAK,KAAK,YAAY,MAAM,OAAO,MAAM,QAAQ,wBAAQ,IAAI,KAAK,CAAC;EACxF,KAAK,OAAO,MAAM,6BAA6B;GAC7C,OAAO,MAAM;GACb,QAAQ,MAAM;GACd;EACF,CAAC;EACD,OAAO,EAAE,OAAO;CAClB;AACF"}
@@ -174,7 +174,7 @@ const NOTIFICATION_TYPES = [
174
174
  {
175
175
  type: "content.flagged",
176
176
  scopes: ["space", "org"],
177
- reasons: ["moderator", "staff"],
177
+ reasons: ["moderator"],
178
178
  display: {
179
179
  space: [
180
180
  "spaceName",
@@ -286,7 +286,7 @@ const NOTIFICATION_TYPES = [
286
286
  {
287
287
  type: "message.flagged",
288
288
  scopes: ["chat"],
289
- reasons: ["staff"],
289
+ reasons: ["moderator"],
290
290
  display: { chat: ["reason"] },
291
291
  email: { chat: { template: "messageWasFlagged" } },
292
292
  push: { chat: {
@@ -456,14 +456,101 @@ const NOTIFICATION_TYPES = [
456
456
  } }
457
457
  },
458
458
  {
459
- type: "moderator.assigned",
459
+ type: "role.assigned",
460
460
  scopes: ["org"],
461
461
  reasons: ["subject"],
462
- display: { org: ["communityTitles"] },
463
- email: { org: { template: "youAreNowAModerator" } },
462
+ display: { org: [
463
+ "roleName",
464
+ "place",
465
+ "contentId",
466
+ "contentType"
467
+ ] },
468
+ email: { org: { template: "roleAssigned" } },
469
+ push: { org: {
470
+ title: "You are now {{roleName}}",
471
+ body: "You are now {{roleName}} {{place}}"
472
+ } }
473
+ },
474
+ {
475
+ type: "event.granted",
476
+ scopes: ["org"],
477
+ reasons: ["event_member"],
478
+ display: { org: [
479
+ "eventTitle",
480
+ "startsAt",
481
+ "endsAt",
482
+ "timeZone"
483
+ ] },
484
+ email: { org: { template: "eventGranted" } },
485
+ push: { org: {
486
+ title: "You're going to {{eventTitle}}",
487
+ body: "Add it to your calendar"
488
+ } }
489
+ },
490
+ {
491
+ type: "event.starting_soon",
492
+ scopes: ["org"],
493
+ reasons: ["event_member"],
494
+ display: { org: [
495
+ "eventTitle",
496
+ "startsAt",
497
+ "endsAt",
498
+ "timeZone",
499
+ "leadText"
500
+ ] },
501
+ email: { org: { template: "eventStartingSoon" } },
502
+ push: { org: {
503
+ title: "{{eventTitle}} starts in {{leadText}}",
504
+ body: "Open the event for the link"
505
+ } }
506
+ },
507
+ {
508
+ type: "event.changed",
509
+ scopes: ["org"],
510
+ reasons: ["event_member"],
511
+ display: { org: [
512
+ "eventTitle",
513
+ "startsAt",
514
+ "endsAt",
515
+ "timeZone",
516
+ "changed"
517
+ ] },
518
+ email: { org: { template: "eventChanged" } },
519
+ push: { org: {
520
+ title: "{{eventTitle}} has changed",
521
+ body: "See the new details"
522
+ } }
523
+ },
524
+ {
525
+ type: "event.canceled",
526
+ scopes: ["org"],
527
+ reasons: ["event_member"],
528
+ display: { org: [
529
+ "eventTitle",
530
+ "startsAt",
531
+ "endsAt",
532
+ "timeZone"
533
+ ] },
534
+ email: { org: { template: "eventCanceled" } },
535
+ push: { org: {
536
+ title: "{{eventTitle}} was canceled",
537
+ body: ""
538
+ } }
539
+ },
540
+ {
541
+ type: "event.revoked",
542
+ scopes: ["org"],
543
+ reasons: ["event_member"],
544
+ display: { org: [
545
+ "eventTitle",
546
+ "startsAt",
547
+ "endsAt",
548
+ "timeZone"
549
+ ] },
550
+ email: { org: { template: "eventRevoked" } },
464
551
  push: { org: {
465
- title: "You are now a moderator",
466
- body: "You can moderate {{communityTitles}}"
552
+ title: "You're no longer going to {{eventTitle}}",
553
+ body: ""
467
554
  } }
468
555
  }
469
556
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/automations/notifications/types.ts"],"sourcesContent":["import type { NotificationTypeDeclaration } from '../../types/index.js';\n\nexport const NOTIFICATION_TYPES: NotificationTypeDeclaration[] = [\n {\n type: 'post.published',\n scopes: ['space'],\n reasons: ['space_member'],\n display: { space: ['spaceName', 'postTitle', 'authorName', 'excerpt'] },\n email: { space: { template: 'newPostInSpace' } },\n push: { space: { title: 'New post in {{spaceName}}', body: '{{authorName}}: {{postTitle}}' } },\n },\n {\n type: 'post.approved',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['postTitle', 'spaceName'] },\n email: { space: { template: 'yourPostWasPublished' } },\n push: {\n space: {\n title: 'Your post was published',\n body: '{{postTitle}} is live in {{spaceName}}',\n },\n },\n },\n {\n type: 'post.awaiting_review',\n scopes: ['space'],\n reasons: ['moderator'],\n display: { space: ['spaceName', 'postTitle', 'authorName'] },\n email: { space: { template: 'postAwaitingReview' } },\n push: {\n space: {\n title: 'Post awaiting review in {{spaceName}}',\n body: '{{authorName}}: {{postTitle}}',\n },\n },\n },\n {\n type: 'post.removed',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['postTitle', 'spaceName'] },\n email: { space: { template: 'yourPostWasRemoved' } },\n push: {\n space: {\n title: 'Your post was removed',\n body: '{{postTitle}} was removed from {{spaceName}}',\n },\n },\n },\n {\n type: 'post.reacted',\n scopes: ['space'],\n reasons: ['post_author'],\n display: { space: ['postTitle', 'reactorName', 'reaction'] },\n email: { space: { template: 'postReacted' } },\n push: {\n space: {\n title: '{{reactorName}} reacted to your post',\n body: '{{reaction}} on {{postTitle}}',\n },\n },\n },\n {\n type: 'comment.created',\n scopes: ['space', 'org'],\n reasons: ['post_author', 'comment_author', 'follower', 'thread_participant'],\n display: {\n space: ['postTitle', 'commenterName', 'excerpt'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'commenterName', 'excerpt'],\n },\n email: {\n space: { template: 'newCommentOnPost', byReason: { comment_author: 'replyToYourComment' } },\n org: { template: 'activityCommentCreated' },\n },\n push: {\n space: { title: '{{commenterName}} commented on {{postTitle}}', body: '{{excerpt}}' },\n org: { title: '{{commenterName}} commented on {{activityTitle}}', body: '{{excerpt}}' },\n },\n },\n {\n type: 'comment.removed',\n scopes: ['space', 'org'],\n reasons: ['subject'],\n display: {\n space: ['postTitle'],\n org: ['activityTitle', 'courseTitle', 'courseId'],\n },\n email: {\n space: { template: 'yourCommentWasRemoved' },\n org: { template: 'activityCommentRemoved' },\n },\n push: {\n space: {\n title: 'Your comment was removed',\n body: 'Your comment on {{postTitle}} was removed',\n },\n org: {\n title: 'Your comment was removed',\n body: 'Your comment on {{activityTitle}} was removed',\n },\n },\n },\n {\n type: 'comment.reacted',\n scopes: ['space', 'org'],\n reasons: ['comment_author'],\n display: {\n space: ['postTitle', 'excerpt', 'reactorName', 'reaction'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'excerpt', 'reactorName', 'reaction'],\n },\n email: {\n space: { template: 'commentReacted' },\n org: { template: 'activityCommentReacted' },\n },\n push: {\n space: {\n title: '{{reactorName}} reacted to your comment',\n body: '{{reaction}} on your comment in {{postTitle}}',\n },\n org: {\n title: '{{reactorName}} reacted to your comment',\n body: '{{reaction}} on your comment in {{activityTitle}}',\n },\n },\n },\n {\n type: 'content.flagged',\n scopes: ['space', 'org'],\n reasons: ['moderator', 'staff'],\n display: {\n space: ['spaceName', 'excerpt', 'reason'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'excerpt', 'reason'],\n },\n email: {\n space: { template: 'somethingWasFlagged' },\n org: { template: 'activityCommentFlagged' },\n },\n push: {\n space: { title: 'Something was flagged in {{spaceName}}', body: '{{reason}}: {{excerpt}}' },\n org: {\n title: 'A comment was flagged in {{activityTitle}}',\n body: '{{reason}}: {{excerpt}}',\n },\n },\n },\n {\n type: 'mention',\n scopes: ['space', 'chat', 'org'],\n reasons: ['mentioned'],\n display: {\n space: ['authorName', 'excerpt', 'postTitle'],\n chat: ['authorName', 'excerpt', 'chatTitle'],\n org: ['authorName', 'excerpt', 'activityTitle', 'courseTitle', 'courseId'],\n },\n email: {\n space: { template: 'mention' },\n chat: { template: 'mention' },\n org: { template: 'activityMention' },\n },\n push: {\n space: { title: '{{authorName}} mentioned you in {{postTitle}}', body: '{{excerpt}}' },\n chat: { title: '{{authorName}} mentioned you in {{chatTitle}}', body: '{{excerpt}}' },\n org: { title: '{{authorName}} mentioned you in {{activityTitle}}', body: '{{excerpt}}' },\n },\n },\n {\n type: 'message.sent',\n scopes: ['chat'],\n reasons: ['participant'],\n display: { chat: ['senderName', 'chatTitle', 'excerpt', 'count', 'summary'] },\n email: { chat: { template: 'newMessage' } },\n push: { chat: { title: '{{chatTitle}}', body: '{{senderName}}: {{summary}}' } },\n },\n {\n type: 'message.reacted',\n scopes: ['chat'],\n reasons: ['message_author'],\n display: { chat: ['excerpt', 'reactorName', 'reaction'] },\n email: { chat: { template: 'messageReacted' } },\n push: {\n chat: {\n title: '{{reactorName}} reacted to your message',\n body: '{{reaction}} on {{excerpt}}',\n },\n },\n },\n {\n type: 'message.flagged',\n scopes: ['chat'],\n reasons: ['staff'],\n display: { chat: ['reason'] },\n email: { chat: { template: 'messageWasFlagged' } },\n push: { chat: { title: 'A message was flagged', body: '{{reason}}' } },\n },\n {\n type: 'chat.request',\n scopes: ['chat'],\n reasons: ['participant'],\n display: { chat: ['senderName', 'excerpt'] },\n email: { chat: { template: 'messageRequest' } },\n push: { chat: { title: '{{senderName}} sent you a message request', body: '{{excerpt}}' } },\n },\n {\n type: 'chat.added',\n scopes: ['chat'],\n reasons: ['subject'],\n display: { chat: ['adderName', 'participantNames'] },\n email: { chat: { template: 'addedToGroupChat' } },\n push: {\n chat: { title: '{{adderName}} added you to a chat', body: 'With {{participantNames}}' },\n },\n },\n {\n type: 'digest',\n scopes: ['community'],\n reasons: ['community_member'],\n display: { community: ['communityTitle', 'from', 'to', 'posts'] },\n email: { community: { template: 'digest' } },\n push: {\n community: {\n title: '{{communityTitle}} digest',\n body: 'The latest posts in {{communityTitle}}',\n },\n },\n },\n {\n type: 'space.join_requested',\n scopes: ['space'],\n reasons: ['moderator'],\n display: { space: ['spaceName', 'spaceId', 'memberName', 'seatsLeft'] },\n email: { space: { template: 'joinRequest' } },\n push: {\n space: {\n title: '{{memberName}} asked to join {{spaceName}}',\n body: 'Seats left: {{seatsLeft}}',\n },\n },\n },\n {\n type: 'space.invited',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId', 'inviterName'] },\n email: { space: { template: 'invitedToSpace' } },\n push: {\n space: {\n title: '{{inviterName}} invited you to {{spaceName}}',\n body: 'Open {{spaceName}} to accept',\n },\n },\n },\n {\n type: 'space.request_approved',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId'] },\n email: { space: { template: 'requestApproved' } },\n push: {\n space: {\n title: \"You're in {{spaceName}}\",\n body: 'Your request to join {{spaceName}} was approved',\n },\n },\n },\n {\n type: 'space.request_declined',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId'] },\n email: { space: { template: 'requestDeclined' } },\n push: {\n space: {\n title: 'Request declined',\n body: 'Your request to join {{spaceName}} was declined',\n },\n },\n },\n {\n type: 'community.welcome',\n scopes: ['community'],\n reasons: ['subject'],\n display: { community: ['communityTitle', 'spaceNames'] },\n email: { community: { template: 'welcomeToCommunity' } },\n push: {\n community: { title: 'Welcome to {{communityTitle}}', body: 'You can open {{spaceNames}}' },\n },\n },\n {\n type: 'community.ending_soon',\n scopes: ['community'],\n reasons: ['subject'],\n display: { community: ['communityTitle', 'expiresAt'] },\n email: { community: { template: 'membershipEndingSoon' } },\n push: {\n community: {\n title: '{{communityTitle}} ends soon',\n body: 'Your access to {{communityTitle}} ends within a week',\n },\n },\n },\n {\n type: 'community.membership_ended',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['communities'] },\n email: { org: { template: 'membershipEnded' } },\n push: { org: { title: 'Your membership has ended', body: 'Your access to a community ended' } },\n },\n {\n type: 'access.granted',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['contentTitle', 'contentType'] },\n email: { org: { template: 'accessGranted' } },\n push: {\n org: {\n title: 'You now have access to {{contentTitle}}',\n body: 'Your {{contentType}} is ready',\n },\n },\n },\n {\n type: 'access.revoked',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['contentTitle'] },\n email: { org: { template: 'accessRevoked' } },\n push: {\n org: { title: 'Access removed', body: 'You no longer have access to {{contentTitle}}' },\n },\n },\n {\n type: 'course.activity_added',\n scopes: ['org'],\n reasons: ['course_member'],\n display: { org: ['courseTitle', 'moduleTitle', 'activityTitle'] },\n email: { org: { template: 'courseActivityAdded' } },\n push: {\n org: { title: 'New in {{courseTitle}}', body: '{{activityTitle}} in {{moduleTitle}}' },\n },\n },\n {\n type: 'moderator.assigned',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['communityTitles'] },\n email: { org: { template: 'youAreNowAModerator' } },\n push: {\n org: { title: 'You are now a moderator', body: 'You can moderate {{communityTitles}}' },\n },\n },\n];\n"],"mappings":"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"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/automations/notifications/types.ts"],"sourcesContent":["import type { NotificationTypeDeclaration } from '../../types/index.js';\n\nexport const NOTIFICATION_TYPES: NotificationTypeDeclaration[] = [\n {\n type: 'post.published',\n scopes: ['space'],\n reasons: ['space_member'],\n display: { space: ['spaceName', 'postTitle', 'authorName', 'excerpt'] },\n email: { space: { template: 'newPostInSpace' } },\n push: { space: { title: 'New post in {{spaceName}}', body: '{{authorName}}: {{postTitle}}' } },\n },\n {\n type: 'post.approved',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['postTitle', 'spaceName'] },\n email: { space: { template: 'yourPostWasPublished' } },\n push: {\n space: {\n title: 'Your post was published',\n body: '{{postTitle}} is live in {{spaceName}}',\n },\n },\n },\n {\n type: 'post.awaiting_review',\n scopes: ['space'],\n reasons: ['moderator'],\n display: { space: ['spaceName', 'postTitle', 'authorName'] },\n email: { space: { template: 'postAwaitingReview' } },\n push: {\n space: {\n title: 'Post awaiting review in {{spaceName}}',\n body: '{{authorName}}: {{postTitle}}',\n },\n },\n },\n {\n type: 'post.removed',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['postTitle', 'spaceName'] },\n email: { space: { template: 'yourPostWasRemoved' } },\n push: {\n space: {\n title: 'Your post was removed',\n body: '{{postTitle}} was removed from {{spaceName}}',\n },\n },\n },\n {\n type: 'post.reacted',\n scopes: ['space'],\n reasons: ['post_author'],\n display: { space: ['postTitle', 'reactorName', 'reaction'] },\n email: { space: { template: 'postReacted' } },\n push: {\n space: {\n title: '{{reactorName}} reacted to your post',\n body: '{{reaction}} on {{postTitle}}',\n },\n },\n },\n {\n type: 'comment.created',\n scopes: ['space', 'org'],\n reasons: ['post_author', 'comment_author', 'follower', 'thread_participant'],\n display: {\n space: ['postTitle', 'commenterName', 'excerpt'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'commenterName', 'excerpt'],\n },\n email: {\n space: { template: 'newCommentOnPost', byReason: { comment_author: 'replyToYourComment' } },\n org: { template: 'activityCommentCreated' },\n },\n push: {\n space: { title: '{{commenterName}} commented on {{postTitle}}', body: '{{excerpt}}' },\n org: { title: '{{commenterName}} commented on {{activityTitle}}', body: '{{excerpt}}' },\n },\n },\n {\n type: 'comment.removed',\n scopes: ['space', 'org'],\n reasons: ['subject'],\n display: {\n space: ['postTitle'],\n org: ['activityTitle', 'courseTitle', 'courseId'],\n },\n email: {\n space: { template: 'yourCommentWasRemoved' },\n org: { template: 'activityCommentRemoved' },\n },\n push: {\n space: {\n title: 'Your comment was removed',\n body: 'Your comment on {{postTitle}} was removed',\n },\n org: {\n title: 'Your comment was removed',\n body: 'Your comment on {{activityTitle}} was removed',\n },\n },\n },\n {\n type: 'comment.reacted',\n scopes: ['space', 'org'],\n reasons: ['comment_author'],\n display: {\n space: ['postTitle', 'excerpt', 'reactorName', 'reaction'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'excerpt', 'reactorName', 'reaction'],\n },\n email: {\n space: { template: 'commentReacted' },\n org: { template: 'activityCommentReacted' },\n },\n push: {\n space: {\n title: '{{reactorName}} reacted to your comment',\n body: '{{reaction}} on your comment in {{postTitle}}',\n },\n org: {\n title: '{{reactorName}} reacted to your comment',\n body: '{{reaction}} on your comment in {{activityTitle}}',\n },\n },\n },\n {\n type: 'content.flagged',\n scopes: ['space', 'org'],\n reasons: ['moderator'],\n display: {\n space: ['spaceName', 'excerpt', 'reason'],\n org: ['activityTitle', 'courseTitle', 'courseId', 'excerpt', 'reason'],\n },\n email: {\n space: { template: 'somethingWasFlagged' },\n org: { template: 'activityCommentFlagged' },\n },\n push: {\n space: { title: 'Something was flagged in {{spaceName}}', body: '{{reason}}: {{excerpt}}' },\n org: {\n title: 'A comment was flagged in {{activityTitle}}',\n body: '{{reason}}: {{excerpt}}',\n },\n },\n },\n {\n type: 'mention',\n scopes: ['space', 'chat', 'org'],\n reasons: ['mentioned'],\n display: {\n space: ['authorName', 'excerpt', 'postTitle'],\n chat: ['authorName', 'excerpt', 'chatTitle'],\n org: ['authorName', 'excerpt', 'activityTitle', 'courseTitle', 'courseId'],\n },\n email: {\n space: { template: 'mention' },\n chat: { template: 'mention' },\n org: { template: 'activityMention' },\n },\n push: {\n space: { title: '{{authorName}} mentioned you in {{postTitle}}', body: '{{excerpt}}' },\n chat: { title: '{{authorName}} mentioned you in {{chatTitle}}', body: '{{excerpt}}' },\n org: { title: '{{authorName}} mentioned you in {{activityTitle}}', body: '{{excerpt}}' },\n },\n },\n {\n type: 'message.sent',\n scopes: ['chat'],\n reasons: ['participant'],\n display: { chat: ['senderName', 'chatTitle', 'excerpt', 'count', 'summary'] },\n email: { chat: { template: 'newMessage' } },\n push: { chat: { title: '{{chatTitle}}', body: '{{senderName}}: {{summary}}' } },\n },\n {\n type: 'message.reacted',\n scopes: ['chat'],\n reasons: ['message_author'],\n display: { chat: ['excerpt', 'reactorName', 'reaction'] },\n email: { chat: { template: 'messageReacted' } },\n push: {\n chat: {\n title: '{{reactorName}} reacted to your message',\n body: '{{reaction}} on {{excerpt}}',\n },\n },\n },\n {\n type: 'message.flagged',\n scopes: ['chat'],\n reasons: ['moderator'],\n display: { chat: ['reason'] },\n email: { chat: { template: 'messageWasFlagged' } },\n push: { chat: { title: 'A message was flagged', body: '{{reason}}' } },\n },\n {\n type: 'chat.request',\n scopes: ['chat'],\n reasons: ['participant'],\n display: { chat: ['senderName', 'excerpt'] },\n email: { chat: { template: 'messageRequest' } },\n push: { chat: { title: '{{senderName}} sent you a message request', body: '{{excerpt}}' } },\n },\n {\n type: 'chat.added',\n scopes: ['chat'],\n reasons: ['subject'],\n display: { chat: ['adderName', 'participantNames'] },\n email: { chat: { template: 'addedToGroupChat' } },\n push: {\n chat: { title: '{{adderName}} added you to a chat', body: 'With {{participantNames}}' },\n },\n },\n {\n type: 'digest',\n scopes: ['community'],\n reasons: ['community_member'],\n display: { community: ['communityTitle', 'from', 'to', 'posts'] },\n email: { community: { template: 'digest' } },\n push: {\n community: {\n title: '{{communityTitle}} digest',\n body: 'The latest posts in {{communityTitle}}',\n },\n },\n },\n {\n type: 'space.join_requested',\n scopes: ['space'],\n reasons: ['moderator'],\n display: { space: ['spaceName', 'spaceId', 'memberName', 'seatsLeft'] },\n email: { space: { template: 'joinRequest' } },\n push: {\n space: {\n title: '{{memberName}} asked to join {{spaceName}}',\n body: 'Seats left: {{seatsLeft}}',\n },\n },\n },\n {\n type: 'space.invited',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId', 'inviterName'] },\n email: { space: { template: 'invitedToSpace' } },\n push: {\n space: {\n title: '{{inviterName}} invited you to {{spaceName}}',\n body: 'Open {{spaceName}} to accept',\n },\n },\n },\n {\n type: 'space.request_approved',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId'] },\n email: { space: { template: 'requestApproved' } },\n push: {\n space: {\n title: \"You're in {{spaceName}}\",\n body: 'Your request to join {{spaceName}} was approved',\n },\n },\n },\n {\n type: 'space.request_declined',\n scopes: ['space'],\n reasons: ['subject'],\n display: { space: ['spaceName', 'spaceId'] },\n email: { space: { template: 'requestDeclined' } },\n push: {\n space: {\n title: 'Request declined',\n body: 'Your request to join {{spaceName}} was declined',\n },\n },\n },\n {\n type: 'community.welcome',\n scopes: ['community'],\n reasons: ['subject'],\n display: { community: ['communityTitle', 'spaceNames'] },\n email: { community: { template: 'welcomeToCommunity' } },\n push: {\n community: { title: 'Welcome to {{communityTitle}}', body: 'You can open {{spaceNames}}' },\n },\n },\n {\n type: 'community.ending_soon',\n scopes: ['community'],\n reasons: ['subject'],\n display: { community: ['communityTitle', 'expiresAt'] },\n email: { community: { template: 'membershipEndingSoon' } },\n push: {\n community: {\n title: '{{communityTitle}} ends soon',\n body: 'Your access to {{communityTitle}} ends within a week',\n },\n },\n },\n {\n type: 'community.membership_ended',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['communities'] },\n email: { org: { template: 'membershipEnded' } },\n push: { org: { title: 'Your membership has ended', body: 'Your access to a community ended' } },\n },\n {\n type: 'access.granted',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['contentTitle', 'contentType'] },\n email: { org: { template: 'accessGranted' } },\n push: {\n org: {\n title: 'You now have access to {{contentTitle}}',\n body: 'Your {{contentType}} is ready',\n },\n },\n },\n {\n type: 'access.revoked',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['contentTitle'] },\n email: { org: { template: 'accessRevoked' } },\n push: {\n org: { title: 'Access removed', body: 'You no longer have access to {{contentTitle}}' },\n },\n },\n {\n type: 'course.activity_added',\n scopes: ['org'],\n reasons: ['course_member'],\n display: { org: ['courseTitle', 'moduleTitle', 'activityTitle'] },\n email: { org: { template: 'courseActivityAdded' } },\n push: {\n org: { title: 'New in {{courseTitle}}', body: '{{activityTitle}} in {{moduleTitle}}' },\n },\n },\n {\n type: 'role.assigned',\n scopes: ['org'],\n reasons: ['subject'],\n display: { org: ['roleName', 'place', 'contentId', 'contentType'] },\n email: { org: { template: 'roleAssigned' } },\n push: {\n org: { title: 'You are now {{roleName}}', body: 'You are now {{roleName}} {{place}}' },\n },\n },\n {\n type: 'event.granted',\n scopes: ['org'],\n reasons: ['event_member'],\n display: { org: ['eventTitle', 'startsAt', 'endsAt', 'timeZone'] },\n email: { org: { template: 'eventGranted' } },\n push: { org: { title: \"You're going to {{eventTitle}}\", body: 'Add it to your calendar' } },\n },\n {\n type: 'event.starting_soon',\n scopes: ['org'],\n reasons: ['event_member'],\n display: { org: ['eventTitle', 'startsAt', 'endsAt', 'timeZone', 'leadText'] },\n email: { org: { template: 'eventStartingSoon' } },\n push: {\n org: { title: '{{eventTitle}} starts in {{leadText}}', body: 'Open the event for the link' },\n },\n },\n {\n type: 'event.changed',\n scopes: ['org'],\n reasons: ['event_member'],\n display: { org: ['eventTitle', 'startsAt', 'endsAt', 'timeZone', 'changed'] },\n email: { org: { template: 'eventChanged' } },\n push: { org: { title: '{{eventTitle}} has changed', body: 'See the new details' } },\n },\n {\n type: 'event.canceled',\n scopes: ['org'],\n reasons: ['event_member'],\n display: { org: ['eventTitle', 'startsAt', 'endsAt', 'timeZone'] },\n email: { org: { template: 'eventCanceled' } },\n push: { org: { title: '{{eventTitle}} was canceled', body: '' } },\n },\n {\n type: 'event.revoked',\n scopes: ['org'],\n reasons: ['event_member'],\n display: { org: ['eventTitle', 'startsAt', 'endsAt', 'timeZone'] },\n email: { org: { template: 'eventRevoked' } },\n push: { org: { title: \"You're no longer going to {{eventTitle}}\", body: '' } },\n },\n];\n"],"mappings":"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"}