@headless-lms/core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/dist/assets/events.d.ts +42 -24
  2. package/dist/assets/events.js +1 -1
  3. package/dist/assets/events.js.map +1 -1
  4. package/dist/assets/file-urls.d.ts +20 -0
  5. package/dist/assets/file-urls.js +25 -0
  6. package/dist/assets/file-urls.js.map +1 -0
  7. package/dist/assets/index.d.ts +6 -4
  8. package/dist/assets/index.js +4 -2
  9. package/dist/assets/jobs.d.ts +15 -0
  10. package/dist/assets/jobs.js +30 -0
  11. package/dist/assets/jobs.js.map +1 -0
  12. package/dist/assets/model.d.ts +2 -2
  13. package/dist/assets/ports.d.ts +46 -15
  14. package/dist/assets/service.d.ts +38 -7
  15. package/dist/assets/service.js +287 -38
  16. package/dist/assets/service.js.map +1 -1
  17. package/dist/automations/actions.d.ts +13 -24
  18. package/dist/automations/actions.js +106 -42
  19. package/dist/automations/actions.js.map +1 -1
  20. package/dist/automations/catalog.js +226 -3
  21. package/dist/automations/catalog.js.map +1 -1
  22. package/dist/automations/community-derivations.d.ts +14 -0
  23. package/dist/automations/community-derivations.js +439 -0
  24. package/dist/automations/community-derivations.js.map +1 -0
  25. package/dist/automations/community-mail.d.ts +98 -0
  26. package/dist/automations/community-mail.js +70 -0
  27. package/dist/automations/community-mail.js.map +1 -0
  28. package/dist/automations/events.d.ts +18 -0
  29. package/dist/automations/index.d.ts +13 -4
  30. package/dist/automations/index.js +10 -2
  31. package/dist/automations/model.d.ts +10 -3
  32. package/dist/automations/model.js +15 -2
  33. package/dist/automations/model.js.map +1 -1
  34. package/dist/automations/notifications/debounce.d.ts +25 -0
  35. package/dist/automations/notifications/debounce.js +93 -0
  36. package/dist/automations/notifications/debounce.js.map +1 -0
  37. package/dist/automations/notifications/defaults.d.ts +8 -0
  38. package/dist/automations/notifications/defaults.js +316 -0
  39. package/dist/automations/notifications/defaults.js.map +1 -0
  40. package/dist/automations/notifications/delivery.d.ts +28 -0
  41. package/dist/automations/notifications/delivery.js +88 -0
  42. package/dist/automations/notifications/delivery.js.map +1 -0
  43. package/dist/automations/notifications/processor.d.ts +64 -0
  44. package/dist/automations/notifications/processor.js +270 -0
  45. package/dist/automations/notifications/processor.js.map +1 -0
  46. package/dist/automations/notifications/rules/content.d.ts +6 -0
  47. package/dist/automations/notifications/rules/content.js +39 -0
  48. package/dist/automations/notifications/rules/content.js.map +1 -0
  49. package/dist/automations/notifications/rules/discussion.d.ts +7 -0
  50. package/dist/automations/notifications/rules/discussion.js +678 -0
  51. package/dist/automations/notifications/rules/discussion.js.map +1 -0
  52. package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
  53. package/dist/automations/notifications/rules/entitlements.js +249 -0
  54. package/dist/automations/notifications/rules/entitlements.js.map +1 -0
  55. package/dist/automations/notifications/rules/index.d.ts +6 -0
  56. package/dist/automations/notifications/rules/index.js +15 -0
  57. package/dist/automations/notifications/rules/index.js.map +1 -0
  58. package/dist/automations/notifications/rules/organizations.d.ts +6 -0
  59. package/dist/automations/notifications/rules/organizations.js +28 -0
  60. package/dist/automations/notifications/rules/organizations.js.map +1 -0
  61. package/dist/automations/notifications/rules/recipients.d.ts +32 -0
  62. package/dist/automations/notifications/rules/recipients.js +99 -0
  63. package/dist/automations/notifications/rules/recipients.js.map +1 -0
  64. package/dist/automations/notifications/service.d.ts +27 -0
  65. package/dist/automations/notifications/service.js +45 -0
  66. package/dist/automations/notifications/service.js.map +1 -0
  67. package/dist/automations/notifications/types.d.ts +7 -0
  68. package/dist/automations/notifications/types.js +473 -0
  69. package/dist/automations/notifications/types.js.map +1 -0
  70. package/dist/automations/ports.d.ts +121 -3
  71. package/dist/automations/schedule.d.ts +6 -0
  72. package/dist/automations/schedule.js +41 -0
  73. package/dist/automations/schedule.js.map +1 -0
  74. package/dist/automations/service.d.ts +20 -4
  75. package/dist/automations/service.js +246 -45
  76. package/dist/automations/service.js.map +1 -1
  77. package/dist/content/events.d.ts +712 -50
  78. package/dist/content/events.js +55 -1
  79. package/dist/content/events.js.map +1 -1
  80. package/dist/content/index.d.ts +6 -4
  81. package/dist/content/index.js +3 -1
  82. package/dist/content/model.d.ts +2 -2
  83. package/dist/content/notification-categories.d.ts +36 -0
  84. package/dist/content/notification-categories.js +64 -0
  85. package/dist/content/notification-categories.js.map +1 -0
  86. package/dist/content/ports.d.ts +90 -18
  87. package/dist/content/service.d.ts +57 -18
  88. package/dist/content/service.js +520 -25
  89. package/dist/content/service.js.map +1 -1
  90. package/dist/content/titles.d.ts +22 -0
  91. package/dist/content/titles.js +69 -0
  92. package/dist/content/titles.js.map +1 -0
  93. package/dist/content/types.d.ts +2 -2
  94. package/dist/discussion/authors.d.ts +10 -0
  95. package/dist/discussion/authors.js +23 -0
  96. package/dist/discussion/authors.js.map +1 -0
  97. package/dist/discussion/chats.d.ts +109 -0
  98. package/dist/discussion/chats.js +831 -0
  99. package/dist/discussion/chats.js.map +1 -0
  100. package/dist/discussion/digests.d.ts +24 -0
  101. package/dist/discussion/digests.js +104 -0
  102. package/dist/discussion/digests.js.map +1 -0
  103. package/dist/discussion/events.d.ts +785 -56
  104. package/dist/discussion/events.js +165 -5
  105. package/dist/discussion/events.js.map +1 -1
  106. package/dist/discussion/index.d.ts +12 -3
  107. package/dist/discussion/index.js +9 -1
  108. package/dist/discussion/jobs.d.ts +16 -0
  109. package/dist/discussion/jobs.js +40 -0
  110. package/dist/discussion/jobs.js.map +1 -0
  111. package/dist/discussion/mentions.d.ts +11 -0
  112. package/dist/discussion/mentions.js +35 -0
  113. package/dist/discussion/mentions.js.map +1 -0
  114. package/dist/discussion/ports.d.ts +372 -28
  115. package/dist/discussion/ports.js +6 -1
  116. package/dist/discussion/ports.js.map +1 -0
  117. package/dist/discussion/posts.d.ts +113 -0
  118. package/dist/discussion/posts.js +775 -0
  119. package/dist/discussion/posts.js.map +1 -0
  120. package/dist/discussion/service.d.ts +42 -11
  121. package/dist/discussion/service.js +364 -85
  122. package/dist/discussion/service.js.map +1 -1
  123. package/dist/discussion/subscriptions.d.ts +37 -0
  124. package/dist/discussion/subscriptions.js +99 -0
  125. package/dist/discussion/subscriptions.js.map +1 -0
  126. package/dist/discussion/titles.d.ts +26 -0
  127. package/dist/discussion/titles.js +84 -0
  128. package/dist/discussion/titles.js.map +1 -0
  129. package/dist/entitlements/events.d.ts +178 -11
  130. package/dist/entitlements/events.js +28 -1
  131. package/dist/entitlements/events.js.map +1 -1
  132. package/dist/entitlements/index.d.ts +6 -4
  133. package/dist/entitlements/index.js +3 -1
  134. package/dist/entitlements/jobs.d.ts +12 -0
  135. package/dist/entitlements/jobs.js +18 -0
  136. package/dist/entitlements/jobs.js.map +1 -0
  137. package/dist/entitlements/model.d.ts +3 -2
  138. package/dist/entitlements/ports.d.ts +128 -11
  139. package/dist/entitlements/rules.d.ts +12 -0
  140. package/dist/entitlements/rules.js +17 -0
  141. package/dist/entitlements/rules.js.map +1 -0
  142. package/dist/entitlements/service.d.ts +57 -3
  143. package/dist/entitlements/service.js +492 -2
  144. package/dist/entitlements/service.js.map +1 -1
  145. package/dist/identity/access.d.ts +6 -0
  146. package/dist/identity/access.js +7 -0
  147. package/dist/identity/access.js.map +1 -0
  148. package/dist/identity/devices.d.ts +30 -0
  149. package/dist/identity/devices.js +107 -0
  150. package/dist/identity/devices.js.map +1 -0
  151. package/dist/identity/events.d.ts +2 -2
  152. package/dist/identity/index.d.ts +7 -4
  153. package/dist/identity/index.js +4 -1
  154. package/dist/identity/model.d.ts +2 -1
  155. package/dist/identity/notification-settings.d.ts +28 -0
  156. package/dist/identity/notification-settings.js +113 -0
  157. package/dist/identity/notification-settings.js.map +1 -0
  158. package/dist/identity/ports.d.ts +97 -3
  159. package/dist/identity/service.d.ts +14 -3
  160. package/dist/identity/service.js +62 -5
  161. package/dist/identity/service.js.map +1 -1
  162. package/dist/integrations/events.d.ts +3 -3
  163. package/dist/integrations/model.js +1 -1
  164. package/dist/integrations/model.js.map +1 -1
  165. package/dist/integrations/service.js +2 -2
  166. package/dist/integrations/service.js.map +1 -1
  167. package/dist/organizations/access-scopes.d.ts +19 -0
  168. package/dist/organizations/access-scopes.js +89 -0
  169. package/dist/organizations/access-scopes.js.map +1 -0
  170. package/dist/organizations/events.d.ts +75 -33
  171. package/dist/organizations/events.js +6 -0
  172. package/dist/organizations/events.js.map +1 -1
  173. package/dist/organizations/index.d.ts +8 -6
  174. package/dist/organizations/index.js +5 -3
  175. package/dist/organizations/members.d.ts +8 -5
  176. package/dist/organizations/members.js.map +1 -1
  177. package/dist/organizations/notification-categories.d.ts +32 -0
  178. package/dist/organizations/notification-categories.js +51 -0
  179. package/dist/organizations/notification-categories.js.map +1 -0
  180. package/dist/organizations/ports.d.ts +17 -11
  181. package/dist/organizations/roles.d.ts +6 -10
  182. package/dist/organizations/roles.js +19 -7
  183. package/dist/organizations/roles.js.map +1 -1
  184. package/dist/organizations/service.d.ts +22 -11
  185. package/dist/organizations/service.js +164 -47
  186. package/dist/organizations/service.js.map +1 -1
  187. package/dist/organizations/types.d.ts +1 -10
  188. package/dist/progress/events.d.ts +14 -14
  189. package/dist/progress/index.d.ts +2 -2
  190. package/dist/progress/ports.d.ts +6 -1
  191. package/dist/progress/service.d.ts +3 -1
  192. package/dist/progress/service.js +6 -2
  193. package/dist/progress/service.js.map +1 -1
  194. package/dist/reporting/admin/index.d.ts +4 -0
  195. package/dist/reporting/admin/index.js +2 -0
  196. package/dist/reporting/admin/model.d.ts +108 -0
  197. package/dist/reporting/admin/ports.d.ts +27 -0
  198. package/dist/reporting/admin/service.d.ts +22 -0
  199. package/dist/reporting/admin/service.js +38 -0
  200. package/dist/reporting/admin/service.js.map +1 -0
  201. package/dist/reporting/member/index.d.ts +5 -0
  202. package/dist/reporting/member/index.js +2 -0
  203. package/dist/reporting/member/model.d.ts +157 -0
  204. package/dist/reporting/member/ports.d.ts +48 -0
  205. package/dist/reporting/member/service.d.ts +92 -0
  206. package/dist/reporting/member/service.js +364 -0
  207. package/dist/reporting/member/service.js.map +1 -0
  208. package/dist/shared/actor.d.ts +9 -0
  209. package/dist/shared/errors.d.ts +19 -1
  210. package/dist/shared/errors.js +27 -1
  211. package/dist/shared/errors.js.map +1 -1
  212. package/dist/shared/id.d.ts +14 -0
  213. package/dist/shared/id.js +15 -1
  214. package/dist/shared/id.js.map +1 -1
  215. package/dist/shared/mailer.d.ts +15 -2
  216. package/dist/shared/mailer.js +32 -5
  217. package/dist/shared/mailer.js.map +1 -1
  218. package/dist/shared/network.d.ts +10 -0
  219. package/dist/shared/network.js +211 -0
  220. package/dist/shared/network.js.map +1 -0
  221. package/dist/shared/notification-categories.d.ts +16 -0
  222. package/dist/shared/notification-categories.js +94 -0
  223. package/dist/shared/notification-categories.js.map +1 -0
  224. package/dist/shared/notification-settings.d.ts +14 -0
  225. package/dist/shared/notification-settings.js +61 -0
  226. package/dist/shared/notification-settings.js.map +1 -0
  227. package/dist/shared/ports.d.ts +48 -2
  228. package/dist/shared/settings.d.ts +2 -1
  229. package/dist/shared/settings.js +1 -0
  230. package/dist/shared/settings.js.map +1 -1
  231. package/dist/types/assets.d.ts +2 -2
  232. package/dist/types/automations.d.ts +15 -1
  233. package/dist/types/content.d.ts +2 -2
  234. package/dist/types/discussion.d.ts +11 -3
  235. package/dist/types/email-templates.d.ts +216 -1
  236. package/dist/types/entitlements.d.ts +2 -2
  237. package/dist/types/identity.d.ts +48 -2
  238. package/dist/types/index.d.ts +9 -8
  239. package/dist/types/notifications.d.ts +157 -0
  240. package/dist/types/ports.d.ts +6 -0
  241. package/dist/types/schemas/assets.d.ts +65 -37
  242. package/dist/types/schemas/assets.js +17 -12
  243. package/dist/types/schemas/assets.js.map +1 -1
  244. package/dist/types/schemas/automations.d.ts +9 -1
  245. package/dist/types/schemas/automations.js +13 -6
  246. package/dist/types/schemas/automations.js.map +1 -1
  247. package/dist/types/schemas/content.d.ts +396 -3
  248. package/dist/types/schemas/content.js +161 -3
  249. package/dist/types/schemas/content.js.map +1 -1
  250. package/dist/types/schemas/discussion.d.ts +443 -3
  251. package/dist/types/schemas/discussion.js +233 -4
  252. package/dist/types/schemas/discussion.js.map +1 -1
  253. package/dist/types/schemas/entitlements.d.ts +36 -2
  254. package/dist/types/schemas/entitlements.js +23 -1
  255. package/dist/types/schemas/entitlements.js.map +1 -1
  256. package/dist/types/schemas/identity.d.ts +27 -1
  257. package/dist/types/schemas/identity.js +14 -2
  258. package/dist/types/schemas/identity.js.map +1 -1
  259. package/dist/types/schemas/index.d.ts +9 -8
  260. package/dist/types/schemas/index.js +9 -8
  261. package/dist/types/schemas/notifications.d.ts +95 -0
  262. package/dist/types/schemas/notifications.js +56 -0
  263. package/dist/types/schemas/notifications.js.map +1 -0
  264. package/dist/types/schemas/organizations.d.ts +8 -0
  265. package/dist/types/schemas/organizations.js +2 -0
  266. package/dist/types/schemas/organizations.js.map +1 -1
  267. package/dist/types/schemas/progress.d.ts +3 -3
  268. package/dist/types/schemas/shared.d.ts +3 -1
  269. package/dist/types/schemas/shared.js +5 -1
  270. package/dist/types/schemas/shared.js.map +1 -1
  271. package/package.json +2 -2
  272. package/dist/reporting/courses/index.d.ts +0 -4
  273. package/dist/reporting/courses/index.js +0 -2
  274. package/dist/reporting/courses/model.d.ts +0 -24
  275. package/dist/reporting/courses/ports.d.ts +0 -13
  276. package/dist/reporting/courses/service.d.ts +0 -19
  277. package/dist/reporting/courses/service.js +0 -20
  278. package/dist/reporting/courses/service.js.map +0 -1
  279. package/dist/reporting/dashboard/index.d.ts +0 -4
  280. package/dist/reporting/dashboard/index.js +0 -2
  281. package/dist/reporting/dashboard/model.d.ts +0 -14
  282. package/dist/reporting/dashboard/ports.d.ts +0 -13
  283. package/dist/reporting/dashboard/service.d.ts +0 -19
  284. package/dist/reporting/dashboard/service.js +0 -20
  285. package/dist/reporting/dashboard/service.js.map +0 -1
  286. package/dist/reporting/learn/index.d.ts +0 -5
  287. package/dist/reporting/learn/index.js +0 -2
  288. package/dist/reporting/learn/model.d.ts +0 -23
  289. package/dist/reporting/learn/ports.d.ts +0 -43
  290. package/dist/reporting/learn/service.d.ts +0 -49
  291. package/dist/reporting/learn/service.js +0 -116
  292. package/dist/reporting/learn/service.js.map +0 -1
  293. package/dist/reporting/students/index.d.ts +0 -4
  294. package/dist/reporting/students/index.js +0 -2
  295. package/dist/reporting/students/model.d.ts +0 -51
  296. package/dist/reporting/students/model.js +0 -1
  297. package/dist/reporting/students/ports.d.ts +0 -15
  298. package/dist/reporting/students/ports.js +0 -1
  299. package/dist/reporting/students/service.d.ts +0 -20
  300. package/dist/reporting/students/service.js +0 -23
  301. package/dist/reporting/students/service.js.map +0 -1
  302. /package/dist/reporting/{courses → admin}/model.js +0 -0
  303. /package/dist/reporting/{courses → admin}/ports.js +0 -0
  304. /package/dist/reporting/{dashboard → member}/model.js +0 -0
  305. /package/dist/reporting/{dashboard → member}/ports.js +0 -0
  306. /package/dist/{reporting/learn/model.js → shared/actor.js} +0 -0
  307. /package/dist/{reporting/learn/ports.js → types/notifications.js} +0 -0
@@ -1,75 +1,128 @@
1
1
  import { deliverWebhookInputSchema } from "../types/schemas/automations.js";
2
+ import { noopLogger } from "../shared/logger.js";
2
3
  import { entitlementEvents } from "../entitlements/events.js";
4
+ import { ActionFailedError } from "./model.js";
3
5
  import { ALL_EMAIL_TEMPLATE_IDS, DELIVER_WEBHOOK_ACTION, publicDataSchema } from "./catalog.js";
4
6
  import { webhookHeaders } from "./webhook-signing.js";
7
+ import { address } from "./community-mail.js";
8
+ import { COMMUNITY_DERIVATIONS } from "./community-derivations.js";
5
9
  //#region src/automations/actions.ts
6
10
  const SEND_EMAIL_DERIVATIONS = {
7
11
  accessGranted: {
8
- trigger: "entitlement.created",
9
- derive: async (event, lookups) => {
12
+ triggers: ["entitlement.created"],
13
+ derive: async (event, deps) => {
10
14
  const result = entitlementEvents.entitlementCreated.safeParse(event);
11
15
  if (!result.success) return;
12
16
  const entitlement = result.data.data;
13
- if (!entitlement.contentId) return;
14
- const [to, content] = await Promise.all([lookups.orgUserEmail(entitlement.orgId, entitlement.orgUserId), lookups.contentInfo(entitlement.orgId, entitlement.contentId)]);
15
- if (!to || !content) return;
16
- return {
17
- to,
18
- params: {
19
- contentTitle: content.title,
20
- contentId: content.id,
21
- contentType: content.type
22
- }
23
- };
17
+ if (!entitlement.contentId) return [];
18
+ const content = await deps.lookups.contentInfo(entitlement.orgId, entitlement.contentId);
19
+ if (!content) return;
20
+ return address(deps, event, entitlement.orgId, [entitlement.orgUserId], {
21
+ contentTitle: content.title,
22
+ contentId: content.id,
23
+ contentType: content.type
24
+ });
24
25
  }
25
26
  },
26
27
  accessRevoked: {
27
- trigger: "entitlement.deleted",
28
- derive: async (event, lookups) => {
28
+ triggers: ["entitlement.deleted"],
29
+ derive: async (event, deps) => {
29
30
  const result = entitlementEvents.entitlementDeleted.safeParse(event);
30
31
  if (!result.success) return;
31
32
  const entitlement = result.data.data;
32
- if (!entitlement.contentId) return;
33
- const [to, content] = await Promise.all([lookups.orgUserEmail(entitlement.orgId, entitlement.orgUserId), lookups.contentInfo(entitlement.orgId, entitlement.contentId)]);
34
- if (!to || !content) return;
35
- return {
36
- to,
37
- params: { contentTitle: content.title }
38
- };
33
+ if (!entitlement.contentId) return [];
34
+ const content = await deps.lookups.contentInfo(entitlement.orgId, entitlement.contentId);
35
+ if (!content) return;
36
+ return address(deps, event, entitlement.orgId, [entitlement.orgUserId], { contentTitle: content.title });
39
37
  }
40
- }
38
+ },
39
+ ...COMMUNITY_DERIVATIONS
41
40
  };
41
+ function reachedNoOne() {
42
+ return {
43
+ recipients: [],
44
+ failed: []
45
+ };
46
+ }
47
+ function assertSomeDelivered(action, outcome) {
48
+ if (outcome.recipients.length === 0 && outcome.failed.length > 0) throw new ActionFailedError(`${action}: delivery failed for all ${outcome.failed.length} recipients`);
49
+ return outcome;
50
+ }
42
51
  function isEmailTemplateId(value) {
43
52
  return typeof value === "string" && value in ALL_EMAIL_TEMPLATE_IDS;
44
53
  }
45
- /** Throws on any failure — the engine owns retry policy and failure bookkeeping. */
54
+ /** Throws on any failure but a partial fan-out — the engine owns retry policy and failure bookkeeping. */
46
55
  async function executeAction(action, event, deps) {
47
56
  switch (action.type) {
48
57
  case "sendEmail": {
49
58
  const template = action.input["template"];
50
- if (!isEmailTemplateId(template)) throw new Error(`sendEmail: unknown template "${String(template)}"`);
59
+ if (!isEmailTemplateId(template)) throw new ActionFailedError(`sendEmail: unknown template "${String(template)}"`);
51
60
  const derivation = SEND_EMAIL_DERIVATIONS[template];
52
- if (!derivation || derivation.trigger !== event.type) throw new Error(`sendEmail: template "${template}" cannot be derived from event "${event.type}"`);
53
- const derived = await derivation.derive(event, deps.lookups);
54
- if (!derived) throw new Error(`sendEmail: event "${event.type}" is missing the data required to derive template "${template}"`);
55
- await deps.mailer.send(derived.to, template, derived.params);
56
- return;
61
+ if (!derivation || !derivation.triggers.includes(event.type)) throw new ActionFailedError(`sendEmail: template "${template}" cannot be derived from event "${event.type}"`);
62
+ const derived = await derivation.derive(event, {
63
+ ...deps,
64
+ actionInput: action.input
65
+ });
66
+ if (!derived) throw new ActionFailedError(`sendEmail: event "${event.type}" is missing the data required to derive template "${template}"`);
67
+ const outcome = reachedNoOne();
68
+ for (const recipient of derived) (await send(template, recipient, event, deps) ? outcome.recipients : outcome.failed).push(recipient.orgUserId);
69
+ return assertSomeDelivered("sendEmail", outcome);
57
70
  }
71
+ case "grantAccess":
72
+ await grantAccess(action, event, deps);
73
+ return reachedNoOne();
58
74
  case DELIVER_WEBHOOK_ACTION:
59
75
  await deliverWebhook(action, event, deps);
60
- return;
61
- default: throw new Error(`unknown automation action type "${action.type}"`);
76
+ return reachedNoOne();
77
+ default: throw new ActionFailedError(`unknown automation action type "${action.type}"`);
78
+ }
79
+ }
80
+ async function send(template, recipient, event, deps) {
81
+ try {
82
+ await deps.mailer.send(recipient.to, template, recipient.params);
83
+ return true;
84
+ } catch (err) {
85
+ (deps.logger ?? noopLogger).warn("automation email not delivered", {
86
+ orgId: event.orgId,
87
+ automationId: deps.automationId,
88
+ trigger: event.type,
89
+ template,
90
+ orgUserId: recipient.orgUserId,
91
+ err
92
+ });
93
+ return false;
62
94
  }
63
95
  }
96
+ function grantRecipient(event) {
97
+ if (typeof event.data !== "object" || event.data === null) return;
98
+ const data = event.data;
99
+ if (event.type === "organization.student.created" && typeof data.id === "string") return data.id;
100
+ if (typeof data.orgUserId === "string") return data.orgUserId;
101
+ }
102
+ async function grantAccess(action, event, deps) {
103
+ const contentId = typeof action.input.contentId === "string" ? action.input.contentId : null;
104
+ const bundleId = typeof action.input.bundleId === "string" ? action.input.bundleId : null;
105
+ if (contentId == null === (bundleId == null)) throw new ActionFailedError("grantAccess: provide exactly one of contentId or bundleId");
106
+ const orgUserId = grantRecipient(event);
107
+ if (!orgUserId) throw new ActionFailedError(`grantAccess: event "${event.type}" has no recipient`);
108
+ const days = action.input.expiresInDays;
109
+ const expiresAt = typeof days === "number" && Number.isFinite(days) ? new Date(Date.now() + days * 864e5) : null;
110
+ await deps.grants.grant(event.orgId, {
111
+ orgUserId,
112
+ contentId,
113
+ bundleId,
114
+ expiresAt
115
+ });
116
+ }
64
117
  async function deliverWebhook(action, event, deps) {
65
118
  const input = deliverWebhookInputSchema.safeParse(action.input);
66
- if (!input.success) throw new Error(`${DELIVER_WEBHOOK_ACTION}: invalid input`);
119
+ if (!input.success) throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: invalid input`);
67
120
  const publicData = publicDataSchema(event.type);
68
- if (!publicData) throw new Error(`${DELIVER_WEBHOOK_ACTION}: event "${event.type}" is not published`);
121
+ if (!publicData) throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: event "${event.type}" is not published`);
69
122
  const data = publicData.safeParse(event.data);
70
- if (!data.success) throw new Error(`${DELIVER_WEBHOOK_ACTION}: event "${event.type}" does not match its published shape`);
123
+ if (!data.success) throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: event "${event.type}" does not match its published shape`);
71
124
  const secret = (await deps.credentials.reveal(event.orgId, input.data.secretRef))?.["secret"];
72
- if (typeof secret !== "string") throw new Error(`${DELIVER_WEBHOOK_ACTION}: signing secret not found`);
125
+ if (typeof secret !== "string") throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: signing secret not found`);
73
126
  const body = JSON.stringify({
74
127
  id: event.id,
75
128
  type: event.type,
@@ -79,12 +132,23 @@ async function deliverWebhook(action, event, deps) {
79
132
  data: data.data
80
133
  });
81
134
  const timestamp = Math.floor(Date.now() / 1e3);
82
- const response = await deps.webhooks.send({
83
- url: input.data.url,
84
- headers: webhookHeaders(secret, event.id, timestamp, body),
85
- body
86
- });
87
- if (response.status < 200 || response.status >= 300) throw new Error(`${DELIVER_WEBHOOK_ACTION}: endpoint responded ${response.status}`);
135
+ let response;
136
+ try {
137
+ response = await deps.webhooks.send({
138
+ url: input.data.url,
139
+ headers: webhookHeaders(secret, event.id, timestamp, body),
140
+ body
141
+ });
142
+ } catch (err) {
143
+ (deps.logger ?? noopLogger).warn("webhook endpoint not reached", {
144
+ orgId: event.orgId,
145
+ automationId: deps.automationId,
146
+ eventId: event.id,
147
+ err
148
+ });
149
+ throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: the endpoint could not be reached`);
150
+ }
151
+ if (response.status < 200 || response.status >= 300) throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: endpoint responded ${response.status}`);
88
152
  }
89
153
  //#endregion
90
154
  export { SEND_EMAIL_DERIVATIONS, executeAction };
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../../src/automations/actions.ts"],"sourcesContent":["// automations context — action runners. `executeAction` maps one\n// AutomationAction against the DomainEvent that triggered its run.\n//\n// SEND_EMAIL_DERIVATIONS is the sendEmail runner's internal derivation table:\n// which (trigger, template) pairings are derivable. A template with no entry\n// (e.g. courseCompleted) makes `executeAction` throw a named error, recorded\n// by the engine as a failed action.\nimport type { EmailTemplateId, EmailTemplateParams } from '../types/index.js';\nimport { deliverWebhookInputSchema } from '../types/schemas/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport type { Mailer, MailerLookups } from '../shared/mailer.js';\nimport type { CredentialStore, DomainEvent } from '../shared/ports.js';\nimport type { AutomationAction } from './model.js';\nimport type { WebhookSender } from './ports.js';\nimport { ALL_EMAIL_TEMPLATE_IDS, DELIVER_WEBHOOK_ACTION, publicDataSchema } from './catalog.js';\nimport { webhookHeaders } from './webhook-signing.js';\n\nexport interface ActionDeps {\n mailer: Pick<Mailer, 'send'>;\n lookups: MailerLookups;\n credentials: Pick<CredentialStore, 'reveal'>;\n webhooks: WebhookSender;\n}\n\ninterface SendEmailDerivation<K extends EmailTemplateId> {\n /** The only event type this template's params can be derived from. */\n trigger: string;\n /** Undefined = the recipient or content behind the event's ids cannot be resolved. */\n derive(\n event: DomainEvent,\n lookups: MailerLookups,\n ): Promise<{ to: string; params: EmailTemplateParams[K] } | undefined>;\n}\n\ntype SendEmailDerivations = { [K in EmailTemplateId]?: SendEmailDerivation<K> };\n\nexport const SEND_EMAIL_DERIVATIONS: SendEmailDerivations = {\n accessGranted: {\n trigger: 'entitlement.created',\n derive: async (event, lookups) => {\n const result = entitlementEvents.entitlementCreated.safeParse(event);\n if (!result.success) {\n return undefined;\n }\n const entitlement = result.data.data;\n // Bundle grants carry no content id — this email is per content item.\n if (!entitlement.contentId) {\n return undefined;\n }\n const [to, content] = await Promise.all([\n lookups.orgUserEmail(entitlement.orgId, entitlement.orgUserId),\n lookups.contentInfo(entitlement.orgId, entitlement.contentId),\n ]);\n if (!to || !content) {\n return undefined;\n }\n return {\n to,\n params: { contentTitle: content.title, contentId: content.id, contentType: content.type },\n };\n },\n },\n accessRevoked: {\n trigger: 'entitlement.deleted',\n derive: async (event, lookups) => {\n const result = entitlementEvents.entitlementDeleted.safeParse(event);\n if (!result.success) {\n return undefined;\n }\n const entitlement = result.data.data;\n // Bundle grants carry no content id — this email is per content item.\n if (!entitlement.contentId) {\n return undefined;\n }\n const [to, content] = await Promise.all([\n lookups.orgUserEmail(entitlement.orgId, entitlement.orgUserId),\n lookups.contentInfo(entitlement.orgId, entitlement.contentId),\n ]);\n if (!to || !content) {\n return undefined;\n }\n return {\n to,\n params: { contentTitle: content.title },\n };\n },\n },\n};\n\nfunction isEmailTemplateId(value: unknown): value is EmailTemplateId {\n return typeof value === 'string' && value in ALL_EMAIL_TEMPLATE_IDS;\n}\n\n/** Throws on any failure — the engine owns retry policy and failure bookkeeping. */\nexport async function executeAction(\n action: AutomationAction,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<void> {\n switch (action.type) {\n case 'sendEmail': {\n const template = action.input['template'];\n if (!isEmailTemplateId(template)) {\n throw new Error(`sendEmail: unknown template \"${String(template)}\"`);\n }\n const derivation = SEND_EMAIL_DERIVATIONS[template];\n if (!derivation || derivation.trigger !== event.type) {\n throw new Error(\n `sendEmail: template \"${template}\" cannot be derived from event \"${event.type}\"`,\n );\n }\n const derived = await derivation.derive(event, deps.lookups);\n if (!derived) {\n throw new Error(\n `sendEmail: event \"${event.type}\" is missing the data required to derive template \"${template}\"`,\n );\n }\n await deps.mailer.send(derived.to, template, derived.params);\n return;\n }\n case DELIVER_WEBHOOK_ACTION: {\n await deliverWebhook(action, event, deps);\n return;\n }\n default: {\n throw new Error(`unknown automation action type \"${action.type}\"`);\n }\n }\n}\n\nasync function deliverWebhook(\n action: AutomationAction,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<void> {\n const input = deliverWebhookInputSchema.safeParse(action.input);\n if (!input.success) {\n throw new Error(`${DELIVER_WEBHOOK_ACTION}: invalid input`);\n }\n const publicData = publicDataSchema(event.type);\n if (!publicData) {\n throw new Error(`${DELIVER_WEBHOOK_ACTION}: event \"${event.type}\" is not published`);\n }\n const data = publicData.safeParse(event.data);\n if (!data.success) {\n throw new Error(\n `${DELIVER_WEBHOOK_ACTION}: event \"${event.type}\" does not match its published shape`,\n );\n }\n const secrets = await deps.credentials.reveal(event.orgId, input.data.secretRef);\n const secret = secrets?.['secret'];\n if (typeof secret !== 'string') {\n throw new Error(`${DELIVER_WEBHOOK_ACTION}: signing secret not found`);\n }\n const body = JSON.stringify({\n id: event.id,\n type: event.type,\n version: event.version,\n orgId: event.orgId,\n occurredAt: event.occurredAt,\n data: data.data,\n });\n const timestamp = Math.floor(Date.now() / 1000);\n const response = await deps.webhooks.send({\n url: input.data.url,\n headers: webhookHeaders(secret, event.id, timestamp, body),\n body,\n });\n if (response.status < 200 || response.status >= 300) {\n throw new Error(`${DELIVER_WEBHOOK_ACTION}: endpoint responded ${response.status}`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"actions.js","names":[],"sources":["../../src/automations/actions.ts"],"sourcesContent":["// automations context — action runners. `executeAction` maps one\n// AutomationAction against the DomainEvent that triggered its run.\n//\n// SEND_EMAIL_DERIVATIONS is the sendEmail runner's internal derivation table:\n// which (trigger, template) pairings are derivable. A template with no entry\n// (e.g. courseCompleted) makes `executeAction` throw a named error, recorded\n// by the engine as a failed action.\nimport type { EmailTemplateId } from '../types/index.js';\nimport { deliverWebhookInputSchema } from '../types/schemas/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport type { DomainEvent } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport { ActionFailedError, type AutomationAction } from './model.js';\nimport type { WebhookResponse } from './ports.js';\nimport { ALL_EMAIL_TEMPLATE_IDS, DELIVER_WEBHOOK_ACTION, publicDataSchema } from './catalog.js';\nimport { webhookHeaders } from './webhook-signing.js';\nimport { address, type ActionDeps, type EmailRecipient } from './community-mail.js';\nimport { COMMUNITY_DERIVATIONS, type EmailDerivation } from './community-derivations.js';\n\ntype SendEmailDerivations = { [K in EmailTemplateId]?: EmailDerivation<K> };\n\nexport const SEND_EMAIL_DERIVATIONS: SendEmailDerivations = {\n accessGranted: {\n triggers: ['entitlement.created'],\n derive: async (event, deps) => {\n const result = entitlementEvents.entitlementCreated.safeParse(event);\n if (!result.success) {\n return undefined;\n }\n const entitlement = result.data.data;\n if (!entitlement.contentId) {\n return [];\n }\n const content = await deps.lookups.contentInfo(entitlement.orgId, entitlement.contentId);\n if (!content) {\n return undefined;\n }\n return address(deps, event, entitlement.orgId, [entitlement.orgUserId], {\n contentTitle: content.title,\n contentId: content.id,\n contentType: content.type,\n });\n },\n },\n accessRevoked: {\n triggers: ['entitlement.deleted'],\n derive: async (event, deps) => {\n const result = entitlementEvents.entitlementDeleted.safeParse(event);\n if (!result.success) {\n return undefined;\n }\n const entitlement = result.data.data;\n if (!entitlement.contentId) {\n return [];\n }\n const content = await deps.lookups.contentInfo(entitlement.orgId, entitlement.contentId);\n if (!content) {\n return undefined;\n }\n return address(deps, event, entitlement.orgId, [entitlement.orgUserId], {\n contentTitle: content.title,\n });\n },\n },\n ...COMMUNITY_DERIVATIONS,\n};\n\nexport type { ActionDeps, EmailRecipient };\n\n/** Who an action reached, and who a delivery to failed for (a partial failure does not throw). */\nexport interface ActionOutcome {\n recipients: string[];\n failed: string[];\n}\n\nfunction reachedNoOne(): ActionOutcome {\n return { recipients: [], failed: [] };\n}\n\nfunction assertSomeDelivered(action: string, outcome: ActionOutcome): ActionOutcome {\n if (outcome.recipients.length === 0 && outcome.failed.length > 0) {\n throw new ActionFailedError(\n `${action}: delivery failed for all ${outcome.failed.length} recipients`,\n );\n }\n return outcome;\n}\n\nfunction isEmailTemplateId(value: unknown): value is EmailTemplateId {\n return typeof value === 'string' && value in ALL_EMAIL_TEMPLATE_IDS;\n}\n\n/** Throws on any failure but a partial fan-out — the engine owns retry policy and failure bookkeeping. */\nexport async function executeAction(\n action: AutomationAction,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<ActionOutcome> {\n switch (action.type) {\n case 'sendEmail': {\n const template = action.input['template'];\n if (!isEmailTemplateId(template)) {\n throw new ActionFailedError(`sendEmail: unknown template \"${String(template)}\"`);\n }\n const derivation = SEND_EMAIL_DERIVATIONS[template];\n if (!derivation || !derivation.triggers.includes(event.type)) {\n throw new ActionFailedError(\n `sendEmail: template \"${template}\" cannot be derived from event \"${event.type}\"`,\n );\n }\n const derived = await derivation.derive(event, { ...deps, actionInput: action.input });\n if (!derived) {\n throw new ActionFailedError(\n `sendEmail: event \"${event.type}\" is missing the data required to derive template \"${template}\"`,\n );\n }\n const outcome = reachedNoOne();\n for (const recipient of derived) {\n const list = (await send(template, recipient, event, deps))\n ? outcome.recipients\n : outcome.failed;\n list.push(recipient.orgUserId);\n }\n return assertSomeDelivered('sendEmail', outcome);\n }\n case 'grantAccess': {\n await grantAccess(action, event, deps);\n return reachedNoOne();\n }\n case DELIVER_WEBHOOK_ACTION: {\n await deliverWebhook(action, event, deps);\n return reachedNoOne();\n }\n default: {\n throw new ActionFailedError(`unknown automation action type \"${action.type}\"`);\n }\n }\n}\n\nasync function send<K extends EmailTemplateId>(\n template: K,\n recipient: EmailRecipient<K>,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<boolean> {\n try {\n await deps.mailer.send(recipient.to, template, recipient.params);\n return true;\n } catch (err) {\n (deps.logger ?? noopLogger).warn('automation email not delivered', {\n orgId: event.orgId,\n automationId: deps.automationId,\n trigger: event.type,\n template,\n orgUserId: recipient.orgUserId,\n err,\n });\n return false;\n }\n}\n\nfunction grantRecipient(event: DomainEvent): string | undefined {\n if (typeof event.data !== 'object' || event.data === null) {\n return undefined;\n }\n const data = event.data as Record<string, unknown>;\n if (event.type === 'organization.student.created' && typeof data.id === 'string') {\n return data.id;\n }\n if (typeof data.orgUserId === 'string') {\n return data.orgUserId;\n }\n return undefined;\n}\n\nasync function grantAccess(\n action: AutomationAction,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<void> {\n const contentId = typeof action.input.contentId === 'string' ? action.input.contentId : null;\n const bundleId = typeof action.input.bundleId === 'string' ? action.input.bundleId : null;\n if ((contentId == null) === (bundleId == null)) {\n throw new ActionFailedError('grantAccess: provide exactly one of contentId or bundleId');\n }\n const orgUserId = grantRecipient(event);\n if (!orgUserId) {\n throw new ActionFailedError(`grantAccess: event \"${event.type}\" has no recipient`);\n }\n const days = action.input.expiresInDays;\n const expiresAt =\n typeof days === 'number' && Number.isFinite(days)\n ? new Date(Date.now() + days * 86_400_000)\n : null;\n await deps.grants.grant(event.orgId, { orgUserId, contentId, bundleId, expiresAt });\n}\n\nasync function deliverWebhook(\n action: AutomationAction,\n event: DomainEvent,\n deps: ActionDeps,\n): Promise<void> {\n const input = deliverWebhookInputSchema.safeParse(action.input);\n if (!input.success) {\n throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: invalid input`);\n }\n const publicData = publicDataSchema(event.type);\n if (!publicData) {\n throw new ActionFailedError(\n `${DELIVER_WEBHOOK_ACTION}: event \"${event.type}\" is not published`,\n );\n }\n const data = publicData.safeParse(event.data);\n if (!data.success) {\n throw new ActionFailedError(\n `${DELIVER_WEBHOOK_ACTION}: event \"${event.type}\" does not match its published shape`,\n );\n }\n const secrets = await deps.credentials.reveal(event.orgId, input.data.secretRef);\n const secret = secrets?.['secret'];\n if (typeof secret !== 'string') {\n throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: signing secret not found`);\n }\n const body = JSON.stringify({\n id: event.id,\n type: event.type,\n version: event.version,\n orgId: event.orgId,\n occurredAt: event.occurredAt,\n data: data.data,\n });\n const timestamp = Math.floor(Date.now() / 1000);\n let response: WebhookResponse;\n try {\n response = await deps.webhooks.send({\n url: input.data.url,\n headers: webhookHeaders(secret, event.id, timestamp, body),\n body,\n });\n } catch (err) {\n (deps.logger ?? noopLogger).warn('webhook endpoint not reached', {\n orgId: event.orgId,\n automationId: deps.automationId,\n eventId: event.id,\n err,\n });\n throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: the endpoint could not be reached`);\n }\n if (response.status < 200 || response.status >= 300) {\n throw new ActionFailedError(`${DELIVER_WEBHOOK_ACTION}: endpoint responded ${response.status}`);\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
- import { entitlementEvents } from "../entitlements/events.js";
2
1
  import { assetEvents } from "../assets/events.js";
2
+ import { organizationEvents } from "../organizations/events.js";
3
+ import { entitlementEvents } from "../entitlements/events.js";
3
4
  import { contentEvents } from "../content/events.js";
4
5
  import { discussionEvents } from "../discussion/events.js";
5
6
  import { identityEvents } from "../identity/events.js";
6
7
  import { integrationEvents } from "../integrations/events.js";
7
- import { organizationEvents } from "../organizations/events.js";
8
8
  import { progressEvents } from "../progress/events.js";
9
9
  //#region src/automations/catalog.ts
10
10
  /** Every EmailTemplateId — a missing key here is a compile error, kept exhaustive by construction. */
@@ -17,7 +17,38 @@ const ALL_EMAIL_TEMPLATE_IDS = {
17
17
  emailVerification: true,
18
18
  accessGranted: true,
19
19
  accessRevoked: true,
20
- courseCompleted: true
20
+ courseCompleted: true,
21
+ welcomeToCommunity: true,
22
+ membershipEndingSoon: true,
23
+ membershipEnded: true,
24
+ newPostInSpace: true,
25
+ yourPostWasPublished: true,
26
+ yourPostWasRemoved: true,
27
+ newCommentOnPost: true,
28
+ replyToYourComment: true,
29
+ yourCommentWasRemoved: true,
30
+ requestApproved: true,
31
+ requestDeclined: true,
32
+ invitedToSpace: true,
33
+ messageRequest: true,
34
+ newMessage: true,
35
+ addedToGroupChat: true,
36
+ youAreNowAModerator: true,
37
+ digest: true,
38
+ postAwaitingReview: true,
39
+ joinRequest: true,
40
+ somethingWasFlagged: true,
41
+ messageWasFlagged: true,
42
+ postReacted: true,
43
+ commentReacted: true,
44
+ mention: true,
45
+ messageReacted: true,
46
+ courseActivityAdded: true,
47
+ activityCommentCreated: true,
48
+ activityCommentRemoved: true,
49
+ activityCommentReacted: true,
50
+ activityCommentFlagged: true,
51
+ activityMention: true
21
52
  };
22
53
  const DELIVER_WEBHOOK_ACTION = "deliverWebhook";
23
54
  function catalogActions() {
@@ -30,6 +61,18 @@ function catalogActions() {
30
61
  properties: { template: { enum: Object.keys(ALL_EMAIL_TEMPLATE_IDS) } }
31
62
  },
32
63
  source: "system"
64
+ }, {
65
+ type: "grantAccess",
66
+ description: "Grant a content item or bundle to the person on the event.",
67
+ inputSchema: {
68
+ type: "object",
69
+ properties: {
70
+ contentId: { type: "string" },
71
+ bundleId: { type: "string" },
72
+ expiresInDays: { type: "number" }
73
+ }
74
+ },
75
+ source: "system"
33
76
  }];
34
77
  }
35
78
  const TRIGGERS = [
@@ -75,6 +118,12 @@ const TRIGGERS = [
75
118
  category: "Organization",
76
119
  description: "a user was removed from an organization"
77
120
  },
121
+ {
122
+ event: organizationEvents.orgUserUpdated,
123
+ label: "Member updated",
124
+ category: "Organization",
125
+ description: "an organization member was updated"
126
+ },
78
127
  {
79
128
  event: organizationEvents.inviteCreated,
80
129
  label: "Invite sent",
@@ -165,6 +214,12 @@ const TRIGGERS = [
165
214
  category: "Courses",
166
215
  description: "a course activity was deleted"
167
216
  },
217
+ {
218
+ event: contentEvents.activityPublished,
219
+ label: "Activity published",
220
+ category: "Courses",
221
+ description: "an activity of a published course was published"
222
+ },
168
223
  {
169
224
  event: contentEvents.activitiesReordered,
170
225
  label: "Activities reordered",
@@ -213,6 +268,48 @@ const TRIGGERS = [
213
268
  category: "Downloads",
214
269
  description: "download assets were reordered"
215
270
  },
271
+ {
272
+ event: contentEvents.communityCreated,
273
+ label: "Community created",
274
+ category: "Communities",
275
+ description: "a community was created"
276
+ },
277
+ {
278
+ event: contentEvents.communityUpdated,
279
+ label: "Community updated",
280
+ category: "Communities",
281
+ description: "a community was updated"
282
+ },
283
+ {
284
+ event: contentEvents.communityDeleted,
285
+ label: "Community deleted",
286
+ category: "Communities",
287
+ description: "a community was deleted"
288
+ },
289
+ {
290
+ event: contentEvents.spaceCreated,
291
+ label: "Space created",
292
+ category: "Communities",
293
+ description: "a space was created"
294
+ },
295
+ {
296
+ event: contentEvents.spaceUpdated,
297
+ label: "Space updated",
298
+ category: "Communities",
299
+ description: "a space was updated"
300
+ },
301
+ {
302
+ event: contentEvents.spaceDeleted,
303
+ label: "Space deleted",
304
+ category: "Communities",
305
+ description: "a space was deleted"
306
+ },
307
+ {
308
+ event: contentEvents.spacesReordered,
309
+ label: "Spaces reordered",
310
+ category: "Communities",
311
+ description: "spaces were reordered"
312
+ },
216
313
  {
217
314
  event: entitlementEvents.entitlementCreated,
218
315
  label: "Access granted",
@@ -237,6 +334,30 @@ const TRIGGERS = [
237
334
  category: "Access",
238
335
  description: "an entitlement passed its expiry"
239
336
  },
337
+ {
338
+ event: entitlementEvents.entitlementEndingSoon,
339
+ label: "Access ending soon",
340
+ category: "Access",
341
+ description: "an entitlement expires within a week"
342
+ },
343
+ {
344
+ event: entitlementEvents.spaceMemberCreated,
345
+ label: "Space member created",
346
+ category: "Access",
347
+ description: "a person was added to a space"
348
+ },
349
+ {
350
+ event: entitlementEvents.spaceMemberUpdated,
351
+ label: "Space member updated",
352
+ category: "Access",
353
+ description: "a space membership changed"
354
+ },
355
+ {
356
+ event: entitlementEvents.spaceMemberDeleted,
357
+ label: "Space member removed",
358
+ category: "Access",
359
+ description: "a space membership was removed"
360
+ },
240
361
  {
241
362
  event: progressEvents.progressStarted,
242
363
  label: "Progress started",
@@ -279,6 +400,18 @@ const TRIGGERS = [
279
400
  category: "Discussion",
280
401
  description: "a comment was published"
281
402
  },
403
+ {
404
+ event: discussionEvents.commentUpdated,
405
+ label: "Comment updated",
406
+ category: "Discussion",
407
+ description: "a comment was edited"
408
+ },
409
+ {
410
+ event: discussionEvents.commentReactionAdded,
411
+ label: "Comment reaction added",
412
+ category: "Discussion",
413
+ description: "a person reacted to a comment for the first time"
414
+ },
282
415
  {
283
416
  event: discussionEvents.commentRemoved,
284
417
  label: "Comment removed",
@@ -291,6 +424,96 @@ const TRIGGERS = [
291
424
  category: "Discussion",
292
425
  description: "a comment was reported"
293
426
  },
427
+ {
428
+ event: discussionEvents.postCreated,
429
+ label: "Post created",
430
+ category: "Discussion",
431
+ description: "a post was created"
432
+ },
433
+ {
434
+ event: discussionEvents.postUpdated,
435
+ label: "Post updated",
436
+ category: "Discussion",
437
+ description: "a post was updated"
438
+ },
439
+ {
440
+ event: discussionEvents.postPublished,
441
+ label: "Post published",
442
+ category: "Discussion",
443
+ description: "a post was published"
444
+ },
445
+ {
446
+ event: discussionEvents.postReactionAdded,
447
+ label: "Post reaction added",
448
+ category: "Discussion",
449
+ description: "a person reacted to a post for the first time"
450
+ },
451
+ {
452
+ event: discussionEvents.postRemoved,
453
+ label: "Post removed",
454
+ category: "Discussion",
455
+ description: "a post was removed"
456
+ },
457
+ {
458
+ event: discussionEvents.postReported,
459
+ label: "Post reported",
460
+ category: "Discussion",
461
+ description: "a post was reported"
462
+ },
463
+ {
464
+ event: discussionEvents.chatCreated,
465
+ label: "Chat created",
466
+ category: "Discussion",
467
+ description: "a chat was created"
468
+ },
469
+ {
470
+ event: discussionEvents.chatUpdated,
471
+ label: "Chat updated",
472
+ category: "Discussion",
473
+ description: "a chat was updated"
474
+ },
475
+ {
476
+ event: discussionEvents.chatParticipantAdded,
477
+ label: "Chat participant added",
478
+ category: "Discussion",
479
+ description: "a person was added to a chat"
480
+ },
481
+ {
482
+ event: discussionEvents.messageSent,
483
+ label: "Message sent",
484
+ category: "Discussion",
485
+ description: "a message was sent"
486
+ },
487
+ {
488
+ event: discussionEvents.messageUpdated,
489
+ label: "Message updated",
490
+ category: "Discussion",
491
+ description: "a message was edited"
492
+ },
493
+ {
494
+ event: discussionEvents.messageReactionAdded,
495
+ label: "Message reaction added",
496
+ category: "Discussion",
497
+ description: "a person reacted to a message for the first time"
498
+ },
499
+ {
500
+ event: discussionEvents.messageDeleted,
501
+ label: "Message deleted",
502
+ category: "Discussion",
503
+ description: "a message was deleted"
504
+ },
505
+ {
506
+ event: discussionEvents.messageReported,
507
+ label: "Message reported",
508
+ category: "Discussion",
509
+ description: "a message was reported"
510
+ },
511
+ {
512
+ event: discussionEvents.digestDue,
513
+ label: "Digest due",
514
+ category: "Discussion",
515
+ description: "a community's digest came due on its schedule"
516
+ },
294
517
  {
295
518
  event: assetEvents.assetCreated,
296
519
  label: "Upload requested",
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","names":[],"sources":["../../src/automations/catalog.ts"],"sourcesContent":["// automations context — the code-owned catalogs `availableActions()` and\n// `availableTriggers()` serve: built-in action definitions and the domain\n// event types automations may react to.\nimport type { z } from 'zod';\nimport type { EmailTemplateId } from '../types/index.js';\nimport { assetEvents } from '../assets/index.js';\nimport { contentEvents } from '../content/index.js';\nimport { discussionEvents } from '../discussion/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport { identityEvents } from '../identity/index.js';\nimport { integrationEvents } from '../integrations/index.js';\nimport { organizationEvents } from '../organizations/index.js';\nimport { progressEvents } from '../progress/index.js';\nimport type { AvailableActions, AvailableTriggers } from './types.js';\n\n/** Every EmailTemplateId — a missing key here is a compile error, kept exhaustive by construction. */\nexport const ALL_EMAIL_TEMPLATE_IDS: Record<EmailTemplateId, true> = {\n magicLink: true,\n studentInvite: true,\n memberInvite: true,\n passwordReset: true,\n passwordChanged: true,\n emailVerification: true,\n accessGranted: true,\n accessRevoked: true,\n courseCompleted: true,\n};\n\nexport const DELIVER_WEBHOOK_ACTION = 'deliverWebhook';\n\nexport function catalogActions(): AvailableActions {\n return [\n {\n type: 'sendEmail',\n description: 'Send a transactional email using a built-in template.',\n inputSchema: {\n type: 'object',\n required: ['template'],\n properties: {\n template: { enum: Object.keys(ALL_EMAIL_TEMPLATE_IDS) },\n },\n },\n source: 'system',\n },\n ];\n}\n\ninterface CatalogTrigger {\n readonly event: { readonly type: string; readonly publicData: z.ZodType };\n readonly label: string;\n readonly category: string;\n readonly description: string;\n}\n\nconst TRIGGERS: CatalogTrigger[] = [\n {\n event: identityEvents.userCreated,\n label: 'User created',\n category: 'Users',\n description: 'a user was created',\n },\n {\n event: identityEvents.userUpdated,\n label: 'User updated',\n category: 'Users',\n description: 'a user was updated',\n },\n {\n event: organizationEvents.organizationCreated,\n label: 'Organization created',\n category: 'Organization',\n description: 'an organization was created',\n },\n {\n event: organizationEvents.organizationUpdated,\n label: 'Organization updated',\n category: 'Organization',\n description: 'an organization was updated',\n },\n {\n event: organizationEvents.organizationDeleted,\n label: 'Organization deleted',\n category: 'Organization',\n description: 'an organization was deleted',\n },\n {\n event: organizationEvents.orgUserLinked,\n label: 'Member joined',\n category: 'Organization',\n description: 'a user was linked to an organization',\n },\n {\n event: organizationEvents.orgUserDeleted,\n label: 'Member removed',\n category: 'Organization',\n description: 'a user was removed from an organization',\n },\n {\n event: organizationEvents.inviteCreated,\n label: 'Invite sent',\n category: 'Organization',\n description: 'an invite was created or re-issued',\n },\n {\n event: organizationEvents.inviteAccepted,\n label: 'Invite accepted',\n category: 'Organization',\n description: 'an invite was accepted',\n },\n {\n event: organizationEvents.studentCreated,\n label: 'Student created',\n category: 'Students',\n description: 'a student was created',\n },\n {\n event: organizationEvents.studentDeleted,\n label: 'Student deleted',\n category: 'Students',\n description: 'a student was deleted',\n },\n {\n event: organizationEvents.studentLinked,\n label: 'Student linked to account',\n category: 'Students',\n description: 'a pending student was linked to an auth account',\n },\n {\n event: contentEvents.courseCreated,\n label: 'Course created',\n category: 'Courses',\n description: 'a course was created',\n },\n {\n event: contentEvents.courseUpdated,\n label: 'Course updated',\n category: 'Courses',\n description: 'a course was updated',\n },\n {\n event: contentEvents.courseDeleted,\n label: 'Course deleted',\n category: 'Courses',\n description: 'a course was deleted',\n },\n {\n event: contentEvents.moduleCreated,\n label: 'Module created',\n category: 'Courses',\n description: 'a course module was created',\n },\n {\n event: contentEvents.moduleUpdated,\n label: 'Module updated',\n category: 'Courses',\n description: 'a course module was updated',\n },\n {\n event: contentEvents.moduleDeleted,\n label: 'Module deleted',\n category: 'Courses',\n description: 'a course module was deleted',\n },\n {\n event: contentEvents.modulesReordered,\n label: 'Modules reordered',\n category: 'Courses',\n description: 'course modules were reordered',\n },\n {\n event: contentEvents.activityCreated,\n label: 'Activity created',\n category: 'Courses',\n description: 'a course activity was created',\n },\n {\n event: contentEvents.activityUpdated,\n label: 'Activity updated',\n category: 'Courses',\n description: 'a course activity was updated',\n },\n {\n event: contentEvents.activityDeleted,\n label: 'Activity deleted',\n category: 'Courses',\n description: 'a course activity was deleted',\n },\n {\n event: contentEvents.activitiesReordered,\n label: 'Activities reordered',\n category: 'Courses',\n description: 'course activities were reordered',\n },\n {\n event: contentEvents.downloadCreated,\n label: 'Download created',\n category: 'Downloads',\n description: 'a download was created',\n },\n {\n event: contentEvents.downloadUpdated,\n label: 'Download updated',\n category: 'Downloads',\n description: 'a download was updated',\n },\n {\n event: contentEvents.downloadDeleted,\n label: 'Download deleted',\n category: 'Downloads',\n description: 'a download was deleted',\n },\n {\n event: contentEvents.downloadAssetAdded,\n label: 'Download file added',\n category: 'Downloads',\n description: 'a download asset was added',\n },\n {\n event: contentEvents.downloadAssetRemoved,\n label: 'Download file removed',\n category: 'Downloads',\n description: 'a download asset was removed',\n },\n {\n event: contentEvents.downloadAssetRenamed,\n label: 'Download file renamed',\n category: 'Downloads',\n description: 'a download asset was renamed',\n },\n {\n event: contentEvents.downloadAssetsReordered,\n label: 'Download files reordered',\n category: 'Downloads',\n description: 'download assets were reordered',\n },\n {\n event: entitlementEvents.entitlementCreated,\n label: 'Access granted',\n category: 'Access',\n description: 'a student was granted access to content',\n },\n {\n event: entitlementEvents.entitlementUpdated,\n label: 'Access updated',\n category: 'Access',\n description: \"an entitlement's status or expiry changed\",\n },\n {\n event: entitlementEvents.entitlementDeleted,\n label: 'Access revoked',\n category: 'Access',\n description: \"a student's access to content was revoked\",\n },\n {\n event: entitlementEvents.entitlementExpired,\n label: 'Access expired',\n category: 'Access',\n description: 'an entitlement passed its expiry',\n },\n {\n event: progressEvents.progressStarted,\n label: 'Progress started',\n category: 'Progress',\n description: 'a student started a progress record',\n },\n {\n event: progressEvents.progressCompleted,\n label: 'Progress completed',\n category: 'Progress',\n description: 'a student completed a progress record',\n },\n {\n event: integrationEvents.connectionCreated,\n label: 'Integration connected',\n category: 'Integrations',\n description: 'an integration connection was established',\n },\n {\n event: integrationEvents.connectionUpdated,\n label: 'Integration updated',\n category: 'Integrations',\n description: 'an integration connection changed',\n },\n {\n event: integrationEvents.connectionRemoved,\n label: 'Integration disconnected',\n category: 'Integrations',\n description: 'an integration connection was removed',\n },\n {\n event: discussionEvents.commentCreated,\n label: 'Comment created',\n category: 'Discussion',\n description: 'a comment was created',\n },\n {\n event: discussionEvents.commentPublished,\n label: 'Comment published',\n category: 'Discussion',\n description: 'a comment was published',\n },\n {\n event: discussionEvents.commentRemoved,\n label: 'Comment removed',\n category: 'Discussion',\n description: 'a comment was removed',\n },\n {\n event: discussionEvents.commentReported,\n label: 'Comment reported',\n category: 'Discussion',\n description: 'a comment was reported',\n },\n {\n event: assetEvents.assetCreated,\n label: 'Upload requested',\n category: 'Assets',\n description: 'an asset upload was requested',\n },\n {\n event: assetEvents.assetReady,\n label: 'Upload ready',\n category: 'Assets',\n description: 'an asset was confirmed ready',\n },\n {\n event: assetEvents.assetDeleted,\n label: 'Asset deleted',\n category: 'Assets',\n description: 'an asset was deleted',\n },\n];\n\nexport function catalogTriggers(): AvailableTriggers['triggers'] {\n return TRIGGERS.map(({ event, ...trigger }) => ({ type: event.type, ...trigger }));\n}\n\nexport function publicDataSchema(type: string): z.ZodType | undefined {\n return TRIGGERS.find((trigger) => trigger.event.type === type)?.event.publicData;\n}\n"],"mappings":";;;;;;;;;;AAgBA,MAAa,yBAAwD;CACnE,WAAW;CACX,eAAe;CACf,cAAc;CACd,eAAe;CACf,iBAAiB;CACjB,mBAAmB;CACnB,eAAe;CACf,eAAe;CACf,iBAAiB;AACnB;AAEA,MAAa,yBAAyB;AAEtC,SAAgB,iBAAmC;CACjD,OAAO,CACL;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,UAAU,CAAC,UAAU;GACrB,YAAY,EACV,UAAU,EAAE,MAAM,OAAO,KAAK,sBAAsB,EAAE,EACxD;EACF;EACA,QAAQ;CACV,CACF;AACF;AASA,MAAM,WAA6B;CACjC;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;AACF;AAEA,SAAgB,kBAAiD;CAC/D,OAAO,SAAS,KAAK,EAAE,OAAO,GAAG,eAAe;EAAE,MAAM,MAAM;EAAM,GAAG;CAAQ,EAAE;AACnF;AAEA,SAAgB,iBAAiB,MAAqC;CACpE,OAAO,SAAS,MAAM,YAAY,QAAQ,MAAM,SAAS,IAAI,CAAC,EAAE,MAAM;AACxE"}
1
+ {"version":3,"file":"catalog.js","names":[],"sources":["../../src/automations/catalog.ts"],"sourcesContent":["// automations context — the code-owned catalogs `availableActions()` and\n// `availableTriggers()` serve: built-in action definitions and the domain\n// event types automations may react to.\nimport type { z } from 'zod';\nimport type { EmailTemplateId } from '../types/index.js';\nimport { assetEvents } from '../assets/index.js';\nimport { contentEvents } from '../content/index.js';\nimport { discussionEvents } from '../discussion/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport { identityEvents } from '../identity/index.js';\nimport { integrationEvents } from '../integrations/index.js';\nimport { organizationEvents } from '../organizations/index.js';\nimport { progressEvents } from '../progress/index.js';\nimport type { AvailableActions, AvailableTriggers } from './types.js';\n\n/** Every EmailTemplateId — a missing key here is a compile error, kept exhaustive by construction. */\nexport const ALL_EMAIL_TEMPLATE_IDS: Record<EmailTemplateId, true> = {\n magicLink: true,\n studentInvite: true,\n memberInvite: true,\n passwordReset: true,\n passwordChanged: true,\n emailVerification: true,\n accessGranted: true,\n accessRevoked: true,\n courseCompleted: true,\n welcomeToCommunity: true,\n membershipEndingSoon: true,\n membershipEnded: true,\n newPostInSpace: true,\n yourPostWasPublished: true,\n yourPostWasRemoved: true,\n newCommentOnPost: true,\n replyToYourComment: true,\n yourCommentWasRemoved: true,\n requestApproved: true,\n requestDeclined: true,\n invitedToSpace: true,\n messageRequest: true,\n newMessage: true,\n addedToGroupChat: true,\n youAreNowAModerator: true,\n digest: true,\n postAwaitingReview: true,\n joinRequest: true,\n somethingWasFlagged: true,\n messageWasFlagged: true,\n postReacted: true,\n commentReacted: true,\n mention: true,\n messageReacted: true,\n courseActivityAdded: true,\n activityCommentCreated: true,\n activityCommentRemoved: true,\n activityCommentReacted: true,\n activityCommentFlagged: true,\n activityMention: true,\n};\n\nexport const DELIVER_WEBHOOK_ACTION = 'deliverWebhook';\n\nexport function catalogActions(): AvailableActions {\n return [\n {\n type: 'sendEmail',\n description: 'Send a transactional email using a built-in template.',\n inputSchema: {\n type: 'object',\n required: ['template'],\n properties: {\n template: { enum: Object.keys(ALL_EMAIL_TEMPLATE_IDS) },\n },\n },\n source: 'system',\n },\n {\n type: 'grantAccess',\n description: 'Grant a content item or bundle to the person on the event.',\n inputSchema: {\n type: 'object',\n properties: {\n contentId: { type: 'string' },\n bundleId: { type: 'string' },\n expiresInDays: { type: 'number' },\n },\n },\n source: 'system',\n },\n ];\n}\n\ninterface CatalogTrigger {\n readonly event: { readonly type: string; readonly publicData: z.ZodType };\n readonly label: string;\n readonly category: string;\n readonly description: string;\n}\n\nconst TRIGGERS: CatalogTrigger[] = [\n {\n event: identityEvents.userCreated,\n label: 'User created',\n category: 'Users',\n description: 'a user was created',\n },\n {\n event: identityEvents.userUpdated,\n label: 'User updated',\n category: 'Users',\n description: 'a user was updated',\n },\n {\n event: organizationEvents.organizationCreated,\n label: 'Organization created',\n category: 'Organization',\n description: 'an organization was created',\n },\n {\n event: organizationEvents.organizationUpdated,\n label: 'Organization updated',\n category: 'Organization',\n description: 'an organization was updated',\n },\n {\n event: organizationEvents.organizationDeleted,\n label: 'Organization deleted',\n category: 'Organization',\n description: 'an organization was deleted',\n },\n {\n event: organizationEvents.orgUserLinked,\n label: 'Member joined',\n category: 'Organization',\n description: 'a user was linked to an organization',\n },\n {\n event: organizationEvents.orgUserDeleted,\n label: 'Member removed',\n category: 'Organization',\n description: 'a user was removed from an organization',\n },\n {\n event: organizationEvents.orgUserUpdated,\n label: 'Member updated',\n category: 'Organization',\n description: 'an organization member was updated',\n },\n {\n event: organizationEvents.inviteCreated,\n label: 'Invite sent',\n category: 'Organization',\n description: 'an invite was created or re-issued',\n },\n {\n event: organizationEvents.inviteAccepted,\n label: 'Invite accepted',\n category: 'Organization',\n description: 'an invite was accepted',\n },\n {\n event: organizationEvents.studentCreated,\n label: 'Student created',\n category: 'Students',\n description: 'a student was created',\n },\n {\n event: organizationEvents.studentDeleted,\n label: 'Student deleted',\n category: 'Students',\n description: 'a student was deleted',\n },\n {\n event: organizationEvents.studentLinked,\n label: 'Student linked to account',\n category: 'Students',\n description: 'a pending student was linked to an auth account',\n },\n {\n event: contentEvents.courseCreated,\n label: 'Course created',\n category: 'Courses',\n description: 'a course was created',\n },\n {\n event: contentEvents.courseUpdated,\n label: 'Course updated',\n category: 'Courses',\n description: 'a course was updated',\n },\n {\n event: contentEvents.courseDeleted,\n label: 'Course deleted',\n category: 'Courses',\n description: 'a course was deleted',\n },\n {\n event: contentEvents.moduleCreated,\n label: 'Module created',\n category: 'Courses',\n description: 'a course module was created',\n },\n {\n event: contentEvents.moduleUpdated,\n label: 'Module updated',\n category: 'Courses',\n description: 'a course module was updated',\n },\n {\n event: contentEvents.moduleDeleted,\n label: 'Module deleted',\n category: 'Courses',\n description: 'a course module was deleted',\n },\n {\n event: contentEvents.modulesReordered,\n label: 'Modules reordered',\n category: 'Courses',\n description: 'course modules were reordered',\n },\n {\n event: contentEvents.activityCreated,\n label: 'Activity created',\n category: 'Courses',\n description: 'a course activity was created',\n },\n {\n event: contentEvents.activityUpdated,\n label: 'Activity updated',\n category: 'Courses',\n description: 'a course activity was updated',\n },\n {\n event: contentEvents.activityDeleted,\n label: 'Activity deleted',\n category: 'Courses',\n description: 'a course activity was deleted',\n },\n {\n event: contentEvents.activityPublished,\n label: 'Activity published',\n category: 'Courses',\n description: 'an activity of a published course was published',\n },\n {\n event: contentEvents.activitiesReordered,\n label: 'Activities reordered',\n category: 'Courses',\n description: 'course activities were reordered',\n },\n {\n event: contentEvents.downloadCreated,\n label: 'Download created',\n category: 'Downloads',\n description: 'a download was created',\n },\n {\n event: contentEvents.downloadUpdated,\n label: 'Download updated',\n category: 'Downloads',\n description: 'a download was updated',\n },\n {\n event: contentEvents.downloadDeleted,\n label: 'Download deleted',\n category: 'Downloads',\n description: 'a download was deleted',\n },\n {\n event: contentEvents.downloadAssetAdded,\n label: 'Download file added',\n category: 'Downloads',\n description: 'a download asset was added',\n },\n {\n event: contentEvents.downloadAssetRemoved,\n label: 'Download file removed',\n category: 'Downloads',\n description: 'a download asset was removed',\n },\n {\n event: contentEvents.downloadAssetRenamed,\n label: 'Download file renamed',\n category: 'Downloads',\n description: 'a download asset was renamed',\n },\n {\n event: contentEvents.downloadAssetsReordered,\n label: 'Download files reordered',\n category: 'Downloads',\n description: 'download assets were reordered',\n },\n {\n event: contentEvents.communityCreated,\n label: 'Community created',\n category: 'Communities',\n description: 'a community was created',\n },\n {\n event: contentEvents.communityUpdated,\n label: 'Community updated',\n category: 'Communities',\n description: 'a community was updated',\n },\n {\n event: contentEvents.communityDeleted,\n label: 'Community deleted',\n category: 'Communities',\n description: 'a community was deleted',\n },\n {\n event: contentEvents.spaceCreated,\n label: 'Space created',\n category: 'Communities',\n description: 'a space was created',\n },\n {\n event: contentEvents.spaceUpdated,\n label: 'Space updated',\n category: 'Communities',\n description: 'a space was updated',\n },\n {\n event: contentEvents.spaceDeleted,\n label: 'Space deleted',\n category: 'Communities',\n description: 'a space was deleted',\n },\n {\n event: contentEvents.spacesReordered,\n label: 'Spaces reordered',\n category: 'Communities',\n description: 'spaces were reordered',\n },\n {\n event: entitlementEvents.entitlementCreated,\n label: 'Access granted',\n category: 'Access',\n description: 'a student was granted access to content',\n },\n {\n event: entitlementEvents.entitlementUpdated,\n label: 'Access updated',\n category: 'Access',\n description: \"an entitlement's status or expiry changed\",\n },\n {\n event: entitlementEvents.entitlementDeleted,\n label: 'Access revoked',\n category: 'Access',\n description: \"a student's access to content was revoked\",\n },\n {\n event: entitlementEvents.entitlementExpired,\n label: 'Access expired',\n category: 'Access',\n description: 'an entitlement passed its expiry',\n },\n {\n event: entitlementEvents.entitlementEndingSoon,\n label: 'Access ending soon',\n category: 'Access',\n description: 'an entitlement expires within a week',\n },\n {\n event: entitlementEvents.spaceMemberCreated,\n label: 'Space member created',\n category: 'Access',\n description: 'a person was added to a space',\n },\n {\n event: entitlementEvents.spaceMemberUpdated,\n label: 'Space member updated',\n category: 'Access',\n description: 'a space membership changed',\n },\n {\n event: entitlementEvents.spaceMemberDeleted,\n label: 'Space member removed',\n category: 'Access',\n description: 'a space membership was removed',\n },\n {\n event: progressEvents.progressStarted,\n label: 'Progress started',\n category: 'Progress',\n description: 'a student started a progress record',\n },\n {\n event: progressEvents.progressCompleted,\n label: 'Progress completed',\n category: 'Progress',\n description: 'a student completed a progress record',\n },\n {\n event: integrationEvents.connectionCreated,\n label: 'Integration connected',\n category: 'Integrations',\n description: 'an integration connection was established',\n },\n {\n event: integrationEvents.connectionUpdated,\n label: 'Integration updated',\n category: 'Integrations',\n description: 'an integration connection changed',\n },\n {\n event: integrationEvents.connectionRemoved,\n label: 'Integration disconnected',\n category: 'Integrations',\n description: 'an integration connection was removed',\n },\n {\n event: discussionEvents.commentCreated,\n label: 'Comment created',\n category: 'Discussion',\n description: 'a comment was created',\n },\n {\n event: discussionEvents.commentPublished,\n label: 'Comment published',\n category: 'Discussion',\n description: 'a comment was published',\n },\n {\n event: discussionEvents.commentUpdated,\n label: 'Comment updated',\n category: 'Discussion',\n description: 'a comment was edited',\n },\n {\n event: discussionEvents.commentReactionAdded,\n label: 'Comment reaction added',\n category: 'Discussion',\n description: 'a person reacted to a comment for the first time',\n },\n {\n event: discussionEvents.commentRemoved,\n label: 'Comment removed',\n category: 'Discussion',\n description: 'a comment was removed',\n },\n {\n event: discussionEvents.commentReported,\n label: 'Comment reported',\n category: 'Discussion',\n description: 'a comment was reported',\n },\n {\n event: discussionEvents.postCreated,\n label: 'Post created',\n category: 'Discussion',\n description: 'a post was created',\n },\n {\n event: discussionEvents.postUpdated,\n label: 'Post updated',\n category: 'Discussion',\n description: 'a post was updated',\n },\n {\n event: discussionEvents.postPublished,\n label: 'Post published',\n category: 'Discussion',\n description: 'a post was published',\n },\n {\n event: discussionEvents.postReactionAdded,\n label: 'Post reaction added',\n category: 'Discussion',\n description: 'a person reacted to a post for the first time',\n },\n {\n event: discussionEvents.postRemoved,\n label: 'Post removed',\n category: 'Discussion',\n description: 'a post was removed',\n },\n {\n event: discussionEvents.postReported,\n label: 'Post reported',\n category: 'Discussion',\n description: 'a post was reported',\n },\n {\n event: discussionEvents.chatCreated,\n label: 'Chat created',\n category: 'Discussion',\n description: 'a chat was created',\n },\n {\n event: discussionEvents.chatUpdated,\n label: 'Chat updated',\n category: 'Discussion',\n description: 'a chat was updated',\n },\n {\n event: discussionEvents.chatParticipantAdded,\n label: 'Chat participant added',\n category: 'Discussion',\n description: 'a person was added to a chat',\n },\n {\n event: discussionEvents.messageSent,\n label: 'Message sent',\n category: 'Discussion',\n description: 'a message was sent',\n },\n {\n event: discussionEvents.messageUpdated,\n label: 'Message updated',\n category: 'Discussion',\n description: 'a message was edited',\n },\n {\n event: discussionEvents.messageReactionAdded,\n label: 'Message reaction added',\n category: 'Discussion',\n description: 'a person reacted to a message for the first time',\n },\n {\n event: discussionEvents.messageDeleted,\n label: 'Message deleted',\n category: 'Discussion',\n description: 'a message was deleted',\n },\n {\n event: discussionEvents.messageReported,\n label: 'Message reported',\n category: 'Discussion',\n description: 'a message was reported',\n },\n {\n event: discussionEvents.digestDue,\n label: 'Digest due',\n category: 'Discussion',\n description: \"a community's digest came due on its schedule\",\n },\n {\n event: assetEvents.assetCreated,\n label: 'Upload requested',\n category: 'Assets',\n description: 'an asset upload was requested',\n },\n {\n event: assetEvents.assetReady,\n label: 'Upload ready',\n category: 'Assets',\n description: 'an asset was confirmed ready',\n },\n {\n event: assetEvents.assetDeleted,\n label: 'Asset deleted',\n category: 'Assets',\n description: 'an asset was deleted',\n },\n];\n\nexport function catalogTriggers(): AvailableTriggers['triggers'] {\n return TRIGGERS.map(({ event, ...trigger }) => ({ type: event.type, ...trigger }));\n}\n\nexport function publicDataSchema(type: string): z.ZodType | undefined {\n return TRIGGERS.find((trigger) => trigger.event.type === type)?.event.publicData;\n}\n"],"mappings":";;;;;;;;;;AAgBA,MAAa,yBAAwD;CACnE,WAAW;CACX,eAAe;CACf,cAAc;CACd,eAAe;CACf,iBAAiB;CACjB,mBAAmB;CACnB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,oBAAoB;CACpB,sBAAsB;CACtB,iBAAiB;CACjB,gBAAgB;CAChB,sBAAsB;CACtB,oBAAoB;CACpB,kBAAkB;CAClB,oBAAoB;CACpB,uBAAuB;CACvB,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAChB,gBAAgB;CAChB,YAAY;CACZ,kBAAkB;CAClB,qBAAqB;CACrB,QAAQ;CACR,oBAAoB;CACpB,aAAa;CACb,qBAAqB;CACrB,mBAAmB;CACnB,aAAa;CACb,gBAAgB;CAChB,SAAS;CACT,gBAAgB;CAChB,qBAAqB;CACrB,wBAAwB;CACxB,wBAAwB;CACxB,wBAAwB;CACxB,wBAAwB;CACxB,iBAAiB;AACnB;AAEA,MAAa,yBAAyB;AAEtC,SAAgB,iBAAmC;CACjD,OAAO,CACL;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,UAAU,CAAC,UAAU;GACrB,YAAY,EACV,UAAU,EAAE,MAAM,OAAO,KAAK,sBAAsB,EAAE,EACxD;EACF;EACA,QAAQ;CACV,GACA;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,WAAW,EAAE,MAAM,SAAS;IAC5B,UAAU,EAAE,MAAM,SAAS;IAC3B,eAAe,EAAE,MAAM,SAAS;GAClC;EACF;EACA,QAAQ;CACV,CACF;AACF;AASA,MAAM,WAA6B;CACjC;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;AACF;AAEA,SAAgB,kBAAiD;CAC/D,OAAO,SAAS,KAAK,EAAE,OAAO,GAAG,eAAe;EAAE,MAAM,MAAM;EAAM,GAAG;CAAQ,EAAE;AACnF;AAEA,SAAgB,iBAAiB,MAAqC;CACpE,OAAO,SAAS,MAAM,YAAY,QAAQ,MAAM,SAAS,IAAI,CAAC,EAAE,MAAM;AACxE"}
@@ -0,0 +1,14 @@
1
+ import { DomainEvent } from "../types/shared.js";
2
+ import { EmailTemplateId } from "../types/email-templates.js";
3
+ import "../types/index.js";
4
+ import "../shared/ports.js";
5
+ import { ActionDeps, EmailRecipient } from "./community-mail.js";
6
+ //#region src/automations/community-derivations.d.ts
7
+ interface EmailDerivation<K extends EmailTemplateId> {
8
+ triggers: readonly string[];
9
+ derive(event: DomainEvent, deps: ActionDeps): Promise<EmailRecipient<K>[] | undefined>;
10
+ }
11
+ declare const COMMUNITY_DERIVATIONS: { [K in EmailTemplateId]?: EmailDerivation<K>; };
12
+ //#endregion
13
+ export { COMMUNITY_DERIVATIONS, EmailDerivation };
14
+ //# sourceMappingURL=community-derivations.d.ts.map