@headless-lms/core 0.2.0 → 0.3.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 (225) hide show
  1. package/dist/assets/events.d.ts +39 -21
  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 +5 -4
  8. package/dist/assets/index.js +3 -2
  9. package/dist/assets/model.d.ts +2 -2
  10. package/dist/assets/ports.d.ts +45 -15
  11. package/dist/assets/service.d.ts +39 -7
  12. package/dist/assets/service.js +291 -38
  13. package/dist/assets/service.js.map +1 -1
  14. package/dist/automations/actions.d.ts +13 -24
  15. package/dist/automations/actions.js +168 -43
  16. package/dist/automations/actions.js.map +1 -1
  17. package/dist/automations/catalog.d.ts +2 -1
  18. package/dist/automations/catalog.js +229 -13
  19. package/dist/automations/catalog.js.map +1 -1
  20. package/dist/automations/community-derivations.d.ts +14 -0
  21. package/dist/automations/community-derivations.js +439 -0
  22. package/dist/automations/community-derivations.js.map +1 -0
  23. package/dist/automations/community-mail.d.ts +112 -0
  24. package/dist/automations/community-mail.js +90 -0
  25. package/dist/automations/community-mail.js.map +1 -0
  26. package/dist/automations/community-notifications.d.ts +16 -0
  27. package/dist/automations/community-notifications.js +84 -0
  28. package/dist/automations/community-notifications.js.map +1 -0
  29. package/dist/automations/events.d.ts +28 -0
  30. package/dist/automations/index.d.ts +4 -2
  31. package/dist/automations/index.js +3 -2
  32. package/dist/automations/model.d.ts +10 -3
  33. package/dist/automations/model.js +15 -2
  34. package/dist/automations/model.js.map +1 -1
  35. package/dist/automations/ports.d.ts +5 -1
  36. package/dist/automations/schedule.d.ts +6 -0
  37. package/dist/automations/schedule.js +41 -0
  38. package/dist/automations/schedule.js.map +1 -0
  39. package/dist/automations/seeds.d.ts +17 -0
  40. package/dist/automations/seeds.js +235 -0
  41. package/dist/automations/seeds.js.map +1 -0
  42. package/dist/automations/service.d.ts +22 -3
  43. package/dist/automations/service.js +306 -43
  44. package/dist/automations/service.js.map +1 -1
  45. package/dist/content/events.d.ts +631 -19
  46. package/dist/content/events.js +44 -1
  47. package/dist/content/events.js.map +1 -1
  48. package/dist/content/index.d.ts +4 -4
  49. package/dist/content/model.d.ts +2 -2
  50. package/dist/content/ports.d.ts +71 -18
  51. package/dist/content/service.d.ts +57 -18
  52. package/dist/content/service.js +502 -23
  53. package/dist/content/service.js.map +1 -1
  54. package/dist/content/types.d.ts +2 -2
  55. package/dist/discussion/authors.d.ts +10 -0
  56. package/dist/discussion/authors.js +23 -0
  57. package/dist/discussion/authors.js.map +1 -0
  58. package/dist/discussion/chats.d.ts +104 -0
  59. package/dist/discussion/chats.js +798 -0
  60. package/dist/discussion/chats.js.map +1 -0
  61. package/dist/discussion/events.d.ts +619 -56
  62. package/dist/discussion/events.js +106 -3
  63. package/dist/discussion/events.js.map +1 -1
  64. package/dist/discussion/index.d.ts +7 -3
  65. package/dist/discussion/index.js +4 -1
  66. package/dist/discussion/ports.d.ts +288 -27
  67. package/dist/discussion/ports.js +6 -1
  68. package/dist/discussion/ports.js.map +1 -0
  69. package/dist/discussion/posts.d.ts +103 -0
  70. package/dist/discussion/posts.js +723 -0
  71. package/dist/discussion/posts.js.map +1 -0
  72. package/dist/discussion/service.d.ts +32 -10
  73. package/dist/discussion/service.js +293 -78
  74. package/dist/discussion/service.js.map +1 -1
  75. package/dist/entitlements/events.d.ts +178 -11
  76. package/dist/entitlements/events.js +28 -1
  77. package/dist/entitlements/events.js.map +1 -1
  78. package/dist/entitlements/index.d.ts +5 -4
  79. package/dist/entitlements/index.js +2 -1
  80. package/dist/entitlements/model.d.ts +3 -2
  81. package/dist/entitlements/ports.d.ts +124 -11
  82. package/dist/entitlements/rules.d.ts +12 -0
  83. package/dist/entitlements/rules.js +17 -0
  84. package/dist/entitlements/rules.js.map +1 -0
  85. package/dist/entitlements/service.d.ts +54 -3
  86. package/dist/entitlements/service.js +472 -2
  87. package/dist/entitlements/service.js.map +1 -1
  88. package/dist/identity/access.d.ts +6 -0
  89. package/dist/identity/access.js +7 -0
  90. package/dist/identity/access.js.map +1 -0
  91. package/dist/identity/index.d.ts +6 -4
  92. package/dist/identity/index.js +3 -1
  93. package/dist/identity/model.d.ts +2 -1
  94. package/dist/identity/notifications.d.ts +27 -0
  95. package/dist/identity/notifications.js +101 -0
  96. package/dist/identity/notifications.js.map +1 -0
  97. package/dist/identity/ports.d.ts +73 -3
  98. package/dist/identity/service.d.ts +14 -3
  99. package/dist/identity/service.js +62 -5
  100. package/dist/identity/service.js.map +1 -1
  101. package/dist/integrations/model.js +1 -1
  102. package/dist/integrations/model.js.map +1 -1
  103. package/dist/integrations/service.js +2 -2
  104. package/dist/integrations/service.js.map +1 -1
  105. package/dist/organizations/access-scopes.d.ts +19 -0
  106. package/dist/organizations/access-scopes.js +89 -0
  107. package/dist/organizations/access-scopes.js.map +1 -0
  108. package/dist/organizations/events.d.ts +74 -32
  109. package/dist/organizations/events.js +6 -0
  110. package/dist/organizations/events.js.map +1 -1
  111. package/dist/organizations/index.d.ts +7 -6
  112. package/dist/organizations/index.js +4 -3
  113. package/dist/organizations/members.d.ts +8 -5
  114. package/dist/organizations/members.js.map +1 -1
  115. package/dist/organizations/ports.d.ts +14 -11
  116. package/dist/organizations/roles.d.ts +6 -10
  117. package/dist/organizations/roles.js +19 -7
  118. package/dist/organizations/roles.js.map +1 -1
  119. package/dist/organizations/service.d.ts +20 -11
  120. package/dist/organizations/service.js +157 -47
  121. package/dist/organizations/service.js.map +1 -1
  122. package/dist/organizations/types.d.ts +1 -10
  123. package/dist/progress/index.d.ts +2 -2
  124. package/dist/progress/ports.d.ts +6 -1
  125. package/dist/progress/service.d.ts +3 -1
  126. package/dist/progress/service.js +6 -2
  127. package/dist/progress/service.js.map +1 -1
  128. package/dist/reporting/admin/index.d.ts +4 -0
  129. package/dist/reporting/admin/index.js +2 -0
  130. package/dist/reporting/admin/model.d.ts +108 -0
  131. package/dist/reporting/admin/ports.d.ts +27 -0
  132. package/dist/reporting/admin/service.d.ts +22 -0
  133. package/dist/reporting/admin/service.js +38 -0
  134. package/dist/reporting/admin/service.js.map +1 -0
  135. package/dist/reporting/member/index.d.ts +5 -0
  136. package/dist/reporting/member/index.js +2 -0
  137. package/dist/reporting/member/model.d.ts +124 -0
  138. package/dist/reporting/member/ports.d.ts +45 -0
  139. package/dist/reporting/member/service.d.ts +73 -0
  140. package/dist/reporting/member/service.js +286 -0
  141. package/dist/reporting/member/service.js.map +1 -0
  142. package/dist/shared/actor.d.ts +9 -0
  143. package/dist/shared/errors.d.ts +7 -1
  144. package/dist/shared/errors.js +10 -1
  145. package/dist/shared/errors.js.map +1 -1
  146. package/dist/shared/id.d.ts +11 -0
  147. package/dist/shared/id.js +12 -1
  148. package/dist/shared/id.js.map +1 -1
  149. package/dist/shared/mailer.d.ts +4 -1
  150. package/dist/shared/mailer.js.map +1 -1
  151. package/dist/shared/network.d.ts +10 -0
  152. package/dist/shared/network.js +211 -0
  153. package/dist/shared/network.js.map +1 -0
  154. package/dist/types/assets.d.ts +2 -2
  155. package/dist/types/automations.d.ts +10 -2
  156. package/dist/types/content.d.ts +2 -2
  157. package/dist/types/discussion.d.ts +11 -3
  158. package/dist/types/email-templates.d.ts +121 -0
  159. package/dist/types/entitlements.d.ts +2 -2
  160. package/dist/types/identity.d.ts +48 -2
  161. package/dist/types/index.d.ts +9 -9
  162. package/dist/types/ports.d.ts +6 -0
  163. package/dist/types/schemas/assets.d.ts +65 -37
  164. package/dist/types/schemas/assets.js +17 -12
  165. package/dist/types/schemas/assets.js.map +1 -1
  166. package/dist/types/schemas/automations.d.ts +18 -1
  167. package/dist/types/schemas/automations.js +15 -6
  168. package/dist/types/schemas/automations.js.map +1 -1
  169. package/dist/types/schemas/content.d.ts +335 -3
  170. package/dist/types/schemas/content.js +139 -3
  171. package/dist/types/schemas/content.js.map +1 -1
  172. package/dist/types/schemas/discussion.d.ts +370 -3
  173. package/dist/types/schemas/discussion.js +199 -4
  174. package/dist/types/schemas/discussion.js.map +1 -1
  175. package/dist/types/schemas/entitlements.d.ts +36 -2
  176. package/dist/types/schemas/entitlements.js +23 -1
  177. package/dist/types/schemas/entitlements.js.map +1 -1
  178. package/dist/types/schemas/identity.d.ts +111 -1
  179. package/dist/types/schemas/identity.js +55 -2
  180. package/dist/types/schemas/identity.js.map +1 -1
  181. package/dist/types/schemas/index.d.ts +8 -8
  182. package/dist/types/schemas/index.js +8 -8
  183. package/dist/types/schemas/organizations.d.ts +8 -0
  184. package/dist/types/schemas/organizations.js +2 -0
  185. package/dist/types/schemas/organizations.js.map +1 -1
  186. package/dist/types/schemas/shared.d.ts +3 -1
  187. package/dist/types/schemas/shared.js +5 -1
  188. package/dist/types/schemas/shared.js.map +1 -1
  189. package/package.json +2 -2
  190. package/dist/reporting/courses/index.d.ts +0 -4
  191. package/dist/reporting/courses/index.js +0 -2
  192. package/dist/reporting/courses/model.d.ts +0 -24
  193. package/dist/reporting/courses/ports.d.ts +0 -13
  194. package/dist/reporting/courses/service.d.ts +0 -19
  195. package/dist/reporting/courses/service.js +0 -20
  196. package/dist/reporting/courses/service.js.map +0 -1
  197. package/dist/reporting/dashboard/index.d.ts +0 -4
  198. package/dist/reporting/dashboard/index.js +0 -2
  199. package/dist/reporting/dashboard/model.d.ts +0 -14
  200. package/dist/reporting/dashboard/ports.d.ts +0 -13
  201. package/dist/reporting/dashboard/service.d.ts +0 -19
  202. package/dist/reporting/dashboard/service.js +0 -20
  203. package/dist/reporting/dashboard/service.js.map +0 -1
  204. package/dist/reporting/learn/index.d.ts +0 -5
  205. package/dist/reporting/learn/index.js +0 -2
  206. package/dist/reporting/learn/model.d.ts +0 -23
  207. package/dist/reporting/learn/ports.d.ts +0 -43
  208. package/dist/reporting/learn/ports.js +0 -1
  209. package/dist/reporting/learn/service.d.ts +0 -49
  210. package/dist/reporting/learn/service.js +0 -116
  211. package/dist/reporting/learn/service.js.map +0 -1
  212. package/dist/reporting/students/index.d.ts +0 -4
  213. package/dist/reporting/students/index.js +0 -2
  214. package/dist/reporting/students/model.d.ts +0 -51
  215. package/dist/reporting/students/model.js +0 -1
  216. package/dist/reporting/students/ports.d.ts +0 -15
  217. package/dist/reporting/students/ports.js +0 -1
  218. package/dist/reporting/students/service.d.ts +0 -20
  219. package/dist/reporting/students/service.js +0 -23
  220. package/dist/reporting/students/service.js.map +0 -1
  221. /package/dist/reporting/{courses → admin}/model.js +0 -0
  222. /package/dist/reporting/{courses → admin}/ports.js +0 -0
  223. /package/dist/reporting/{dashboard → member}/model.js +0 -0
  224. /package/dist/reporting/{dashboard → member}/ports.js +0 -0
  225. /package/dist/{reporting/learn/model.js → shared/actor.js} +0 -0
@@ -0,0 +1,41 @@
1
+ //#region src/automations/schedule.ts
2
+ const FIELD_RANGES = [
3
+ [0, 59],
4
+ [0, 23],
5
+ [1, 31],
6
+ [1, 12],
7
+ [0, 6]
8
+ ];
9
+ function cronMatches(expression, at) {
10
+ const fields = expression.trim().split(/\s+/);
11
+ if (fields.length !== 5) return false;
12
+ const parts = [
13
+ at.getUTCMinutes(),
14
+ at.getUTCHours(),
15
+ at.getUTCDate(),
16
+ at.getUTCMonth() + 1,
17
+ at.getUTCDay()
18
+ ];
19
+ const [minute, hour, dayOfMonth, month, dayOfWeek] = fields.map((field, index) => field === "*" || field.split(",").some((piece) => Number(piece) === parts[index]));
20
+ const day = fields[2] !== "*" && fields[4] !== "*" ? dayOfMonth || dayOfWeek : dayOfMonth && dayOfWeek;
21
+ return Boolean(minute && hour && month && day);
22
+ }
23
+ function cronSupported(expression) {
24
+ const fields = expression.trim().split(/\s+/);
25
+ if (fields.length !== 5) return false;
26
+ return fields.every((field, index) => fieldSupported(field, FIELD_RANGES[index]));
27
+ }
28
+ function fieldSupported(field, range) {
29
+ if (field === "*") return true;
30
+ const pieces = field.split(",");
31
+ const [min, max] = range;
32
+ return pieces.length > 0 && pieces.every((piece) => {
33
+ if (!/^\d+$/.test(piece)) return false;
34
+ const value = Number(piece);
35
+ return value >= min && value <= max;
36
+ });
37
+ }
38
+ //#endregion
39
+ export { cronMatches, cronSupported };
40
+
41
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","names":[],"sources":["../../src/automations/schedule.ts"],"sourcesContent":["const FIELD_RANGES = [\n [0, 59],\n [0, 23],\n [1, 31],\n [1, 12],\n [0, 6],\n] as const;\n\nexport function cronMatches(expression: string, at: Date): boolean {\n const fields = expression.trim().split(/\\s+/);\n if (fields.length !== 5) {\n return false;\n }\n const parts = [\n at.getUTCMinutes(),\n at.getUTCHours(),\n at.getUTCDate(),\n at.getUTCMonth() + 1,\n at.getUTCDay(),\n ];\n const matches = fields.map(\n (field, index) =>\n field === '*' || field.split(',').some((piece) => Number(piece) === parts[index]),\n );\n const [minute, hour, dayOfMonth, month, dayOfWeek] = matches;\n const day =\n fields[2] !== '*' && fields[4] !== '*' ? dayOfMonth || dayOfWeek : dayOfMonth && dayOfWeek;\n return Boolean(minute && hour && month && day);\n}\n\nexport function cronSupported(expression: string): boolean {\n const fields = expression.trim().split(/\\s+/);\n if (fields.length !== 5) {\n return false;\n }\n return fields.every((field, index) => fieldSupported(field, FIELD_RANGES[index]!));\n}\n\nfunction fieldSupported(field: string, range: readonly [number, number]): boolean {\n if (field === '*') {\n return true;\n }\n const pieces = field.split(',');\n const [min, max] = range;\n return (\n pieces.length > 0 &&\n pieces.every((piece) => {\n if (!/^\\d+$/.test(piece)) {\n return false;\n }\n const value = Number(piece);\n return value >= min && value <= max;\n })\n );\n}\n"],"mappings":";AAAA,MAAM,eAAe;CACnB,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,CAAC;AACP;AAEA,SAAgB,YAAY,YAAoB,IAAmB;CACjE,MAAM,SAAS,WAAW,KAAK,CAAC,CAAC,MAAM,KAAK;CAC5C,IAAI,OAAO,WAAW,GACpB,OAAO;CAET,MAAM,QAAQ;EACZ,GAAG,cAAc;EACjB,GAAG,YAAY;EACf,GAAG,WAAW;EACd,GAAG,YAAY,IAAI;EACnB,GAAG,UAAU;CACf;CAKA,MAAM,CAAC,QAAQ,MAAM,YAAY,OAAO,aAJxB,OAAO,KACpB,OAAO,UACN,UAAU,OAAO,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,UAAU,OAAO,KAAK,MAAM,MAAM,MAAM,CAEzB;CAC3D,MAAM,MACJ,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,cAAc,YAAY,cAAc;CACnF,OAAO,QAAQ,UAAU,QAAQ,SAAS,GAAG;AAC/C;AAEA,SAAgB,cAAc,YAA6B;CACzD,MAAM,SAAS,WAAW,KAAK,CAAC,CAAC,MAAM,KAAK;CAC5C,IAAI,OAAO,WAAW,GACpB,OAAO;CAET,OAAO,OAAO,OAAO,OAAO,UAAU,eAAe,OAAO,aAAa,MAAO,CAAC;AACnF;AAEA,SAAS,eAAe,OAAe,OAA2C;CAChF,IAAI,UAAU,KACZ,OAAO;CAET,MAAM,SAAS,MAAM,MAAM,GAAG;CAC9B,MAAM,CAAC,KAAK,OAAO;CACnB,OACE,OAAO,SAAS,KAChB,OAAO,OAAO,UAAU;EACtB,IAAI,CAAC,QAAQ,KAAK,KAAK,GACrB,OAAO;EAET,MAAM,QAAQ,OAAO,KAAK;EAC1B,OAAO,SAAS,OAAO,SAAS;CAClC,CAAC;AAEL"}
@@ -0,0 +1,17 @@
1
+ import { JsonValue } from "../types/shared.js";
2
+ import { AutomationAction } from "../types/schemas/automations.js";
3
+ import "../types/index.js";
4
+ import "./model.js";
5
+ //#region src/automations/seeds.d.ts
6
+ interface SeedAutomation {
7
+ name: string;
8
+ description: string;
9
+ triggers: string[];
10
+ actions: AutomationAction[];
11
+ filter: Record<string, JsonValue> | null;
12
+ }
13
+ declare function orgSeeds(): SeedAutomation[];
14
+ declare function communitySeeds(communityId: string): SeedAutomation[];
15
+ //#endregion
16
+ export { SeedAutomation, communitySeeds, orgSeeds };
17
+ //# sourceMappingURL=seeds.d.ts.map
@@ -0,0 +1,235 @@
1
+ //#region src/automations/seeds.ts
2
+ function email(template, communityId) {
3
+ return {
4
+ type: "sendEmail",
5
+ input: communityId === void 0 ? { template } : {
6
+ template,
7
+ communityId
8
+ }
9
+ };
10
+ }
11
+ function notify(kind, communityId) {
12
+ return {
13
+ type: "notify",
14
+ input: communityId === void 0 ? { kind } : {
15
+ kind,
16
+ communityId
17
+ }
18
+ };
19
+ }
20
+ function orgSeeds() {
21
+ return [
22
+ {
23
+ name: "Access granted",
24
+ description: "Email the person when they are granted a content item.",
25
+ triggers: ["entitlement.created"],
26
+ actions: [email("accessGranted")],
27
+ filter: null
28
+ },
29
+ {
30
+ name: "Access revoked",
31
+ description: "Email the person when a content grant is deleted.",
32
+ triggers: ["entitlement.deleted"],
33
+ actions: [email("accessRevoked")],
34
+ filter: null
35
+ },
36
+ {
37
+ name: "You are now a moderator",
38
+ description: "Notify the person when they are given the moderator role.",
39
+ triggers: ["organization.user.updated"],
40
+ actions: [notify("youAreNowAModerator")],
41
+ filter: null
42
+ },
43
+ {
44
+ name: "Publish due posts",
45
+ description: "Submit scheduled posts whose time has passed.",
46
+ triggers: ["schedule:* * * * *"],
47
+ actions: [{
48
+ type: "publishDuePosts",
49
+ input: {}
50
+ }],
51
+ filter: null
52
+ },
53
+ {
54
+ name: "Expire due grants",
55
+ description: "Expire grants whose time has passed and remind those ending within a week.",
56
+ triggers: ["schedule:0 * * * *"],
57
+ actions: [{
58
+ type: "expireDueGrants",
59
+ input: {}
60
+ }],
61
+ filter: null
62
+ },
63
+ {
64
+ name: "Send digest",
65
+ description: "Open the daily digest for every community.",
66
+ triggers: ["schedule:0 7 * * *"],
67
+ actions: [{
68
+ type: "sendDigest",
69
+ input: {}
70
+ }],
71
+ filter: null
72
+ },
73
+ {
74
+ name: "Remove unattached uploads",
75
+ description: "Remove member uploads older than an hour that nothing references.",
76
+ triggers: ["schedule:0 * * * *"],
77
+ actions: [{
78
+ type: "removeUnattachedUploads",
79
+ input: {}
80
+ }],
81
+ filter: null
82
+ },
83
+ {
84
+ name: "Welcome to the community",
85
+ description: "Notify a person when a grant opens a community.",
86
+ triggers: ["entitlement.created"],
87
+ actions: [notify("welcomeToCommunity")],
88
+ filter: null
89
+ },
90
+ {
91
+ name: "Membership ended",
92
+ description: "Email a person when a grant that opened a community ends.",
93
+ triggers: ["entitlement.expired", "entitlement.deleted"],
94
+ actions: [email("membershipEnded")],
95
+ filter: null
96
+ }
97
+ ];
98
+ }
99
+ function communitySeeds(communityId) {
100
+ const filter = { communityId };
101
+ const scoped = (template) => email(template, communityId);
102
+ const told = (kind) => notify(kind, communityId);
103
+ return [
104
+ {
105
+ name: "Membership ending soon",
106
+ description: "Notify a member a week before this community grant ends.",
107
+ triggers: ["entitlement.ending_soon"],
108
+ actions: [told("membershipEndingSoon")],
109
+ filter: { communityId }
110
+ },
111
+ {
112
+ name: "New post in a space",
113
+ description: "Notify members who can open the space.",
114
+ triggers: ["discussion.post.published"],
115
+ actions: [told("newPostInSpace")],
116
+ filter
117
+ },
118
+ {
119
+ name: "Your post was published",
120
+ description: "Notify the author when a pending post is published.",
121
+ triggers: ["discussion.post.published"],
122
+ actions: [told("yourPostWasPublished")],
123
+ filter
124
+ },
125
+ {
126
+ name: "Your post was removed",
127
+ description: "Notify the author when someone else removes their post.",
128
+ triggers: ["discussion.post.removed"],
129
+ actions: [told("yourPostWasRemoved")],
130
+ filter
131
+ },
132
+ {
133
+ name: "New comment on a post you follow",
134
+ description: "Notify the author and followers when a comment is published.",
135
+ triggers: ["discussion.comment.created"],
136
+ actions: [told("newCommentOnPost")],
137
+ filter
138
+ },
139
+ {
140
+ name: "Reply to your comment",
141
+ description: "Notify the parent author when a reply is published.",
142
+ triggers: ["discussion.comment.created"],
143
+ actions: [told("replyToYourComment")],
144
+ filter
145
+ },
146
+ {
147
+ name: "Your comment was removed",
148
+ description: "Notify the author when someone else removes their comment.",
149
+ triggers: ["discussion.comment.removed"],
150
+ actions: [told("yourCommentWasRemoved")],
151
+ filter
152
+ },
153
+ {
154
+ name: "Post awaiting review",
155
+ description: "Notify staff and moderators when a post enters review.",
156
+ triggers: ["discussion.post.created", "discussion.post.updated"],
157
+ actions: [told("postAwaitingReview")],
158
+ filter
159
+ },
160
+ {
161
+ name: "Join request",
162
+ description: "Notify staff and moderators when someone requests a space.",
163
+ triggers: ["entitlement.space_member.created"],
164
+ actions: [told("joinRequest")],
165
+ filter
166
+ },
167
+ {
168
+ name: "Request approved",
169
+ description: "Notify the member when their request is approved.",
170
+ triggers: ["entitlement.space_member.updated"],
171
+ actions: [told("requestApproved")],
172
+ filter
173
+ },
174
+ {
175
+ name: "Request declined",
176
+ description: "Notify the person when their request is declined.",
177
+ triggers: ["entitlement.space_member.deleted"],
178
+ actions: [told("requestDeclined")],
179
+ filter
180
+ },
181
+ {
182
+ name: "Invited to a space",
183
+ description: "Notify the person when they are invited to a space.",
184
+ triggers: ["entitlement.space_member.created"],
185
+ actions: [told("invitedToSpace")],
186
+ filter
187
+ },
188
+ {
189
+ name: "New message",
190
+ description: "Notify participants who are not muted, at most once per chat per 15 minutes.",
191
+ triggers: ["discussion.message.sent"],
192
+ actions: [told("newMessage")],
193
+ filter
194
+ },
195
+ {
196
+ name: "Message request",
197
+ description: "Notify the recipient when a direct chat starts as a request.",
198
+ triggers: ["discussion.chat.created"],
199
+ actions: [told("messageRequest")],
200
+ filter
201
+ },
202
+ {
203
+ name: "Added to a group chat",
204
+ description: "Notify the person added to a group chat.",
205
+ triggers: ["discussion.chat.participant.added"],
206
+ actions: [told("addedToGroupChat")],
207
+ filter
208
+ },
209
+ {
210
+ name: "Something was flagged",
211
+ description: "Notify staff and moderators when a post or comment is flagged.",
212
+ triggers: ["discussion.post.reported", "discussion.comment.reported"],
213
+ actions: [told("somethingWasFlagged")],
214
+ filter
215
+ },
216
+ {
217
+ name: "A message was flagged",
218
+ description: "Notify staff when a message is flagged.",
219
+ triggers: ["discussion.message.reported"],
220
+ actions: [told("messageWasFlagged")],
221
+ filter
222
+ },
223
+ {
224
+ name: "Digest",
225
+ description: "Email members their unread activity. Not sent until email preferences exist.",
226
+ triggers: ["discussion.digest.due"],
227
+ actions: [scoped("digest")],
228
+ filter
229
+ }
230
+ ];
231
+ }
232
+ //#endregion
233
+ export { communitySeeds, orgSeeds };
234
+
235
+ //# sourceMappingURL=seeds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeds.js","names":[],"sources":["../../src/automations/seeds.ts"],"sourcesContent":["import type { JsonValue } from '../types/index.js';\nimport type { AutomationAction } from './model.js';\n\nexport interface SeedAutomation {\n name: string;\n description: string;\n triggers: string[];\n actions: AutomationAction[];\n filter: Record<string, JsonValue> | null;\n}\n\nfunction email(template: string, communityId?: string): AutomationAction {\n return {\n type: 'sendEmail',\n input: communityId === undefined ? { template } : { template, communityId },\n };\n}\n\nfunction notify(kind: string, communityId?: string): AutomationAction {\n return {\n type: 'notify',\n input: communityId === undefined ? { kind } : { kind, communityId },\n };\n}\n\nexport function orgSeeds(): SeedAutomation[] {\n return [\n {\n name: 'Access granted',\n description: 'Email the person when they are granted a content item.',\n triggers: ['entitlement.created'],\n actions: [email('accessGranted')],\n filter: null,\n },\n {\n name: 'Access revoked',\n description: 'Email the person when a content grant is deleted.',\n triggers: ['entitlement.deleted'],\n actions: [email('accessRevoked')],\n filter: null,\n },\n {\n name: 'You are now a moderator',\n description: 'Notify the person when they are given the moderator role.',\n triggers: ['organization.user.updated'],\n actions: [notify('youAreNowAModerator')],\n filter: null,\n },\n {\n name: 'Publish due posts',\n description: 'Submit scheduled posts whose time has passed.',\n triggers: ['schedule:* * * * *'],\n actions: [{ type: 'publishDuePosts', input: {} }],\n filter: null,\n },\n {\n name: 'Expire due grants',\n description: 'Expire grants whose time has passed and remind those ending within a week.',\n triggers: ['schedule:0 * * * *'],\n actions: [{ type: 'expireDueGrants', input: {} }],\n filter: null,\n },\n {\n name: 'Send digest',\n description: 'Open the daily digest for every community.',\n triggers: ['schedule:0 7 * * *'],\n actions: [{ type: 'sendDigest', input: {} }],\n filter: null,\n },\n {\n name: 'Remove unattached uploads',\n description: 'Remove member uploads older than an hour that nothing references.',\n triggers: ['schedule:0 * * * *'],\n actions: [{ type: 'removeUnattachedUploads', input: {} }],\n filter: null,\n },\n {\n name: 'Welcome to the community',\n description: 'Notify a person when a grant opens a community.',\n triggers: ['entitlement.created'],\n actions: [notify('welcomeToCommunity')],\n filter: null,\n },\n {\n name: 'Membership ended',\n description: 'Email a person when a grant that opened a community ends.',\n triggers: ['entitlement.expired', 'entitlement.deleted'],\n actions: [email('membershipEnded')],\n filter: null,\n },\n ];\n}\n\nexport function communitySeeds(communityId: string): SeedAutomation[] {\n const filter = { communityId };\n const scoped = (template: string): AutomationAction => email(template, communityId);\n const told = (kind: string): AutomationAction => notify(kind, communityId);\n return [\n {\n name: 'Membership ending soon',\n description: 'Notify a member a week before this community grant ends.',\n triggers: ['entitlement.ending_soon'],\n actions: [told('membershipEndingSoon')],\n filter: { communityId },\n },\n {\n name: 'New post in a space',\n description: 'Notify members who can open the space.',\n triggers: ['discussion.post.published'],\n actions: [told('newPostInSpace')],\n filter,\n },\n {\n name: 'Your post was published',\n description: 'Notify the author when a pending post is published.',\n triggers: ['discussion.post.published'],\n actions: [told('yourPostWasPublished')],\n filter,\n },\n {\n name: 'Your post was removed',\n description: 'Notify the author when someone else removes their post.',\n triggers: ['discussion.post.removed'],\n actions: [told('yourPostWasRemoved')],\n filter,\n },\n {\n name: 'New comment on a post you follow',\n description: 'Notify the author and followers when a comment is published.',\n triggers: ['discussion.comment.created'],\n actions: [told('newCommentOnPost')],\n filter,\n },\n {\n name: 'Reply to your comment',\n description: 'Notify the parent author when a reply is published.',\n triggers: ['discussion.comment.created'],\n actions: [told('replyToYourComment')],\n filter,\n },\n {\n name: 'Your comment was removed',\n description: 'Notify the author when someone else removes their comment.',\n triggers: ['discussion.comment.removed'],\n actions: [told('yourCommentWasRemoved')],\n filter,\n },\n {\n name: 'Post awaiting review',\n description: 'Notify staff and moderators when a post enters review.',\n triggers: ['discussion.post.created', 'discussion.post.updated'],\n actions: [told('postAwaitingReview')],\n filter,\n },\n {\n name: 'Join request',\n description: 'Notify staff and moderators when someone requests a space.',\n triggers: ['entitlement.space_member.created'],\n actions: [told('joinRequest')],\n filter,\n },\n {\n name: 'Request approved',\n description: 'Notify the member when their request is approved.',\n triggers: ['entitlement.space_member.updated'],\n actions: [told('requestApproved')],\n filter,\n },\n {\n name: 'Request declined',\n description: 'Notify the person when their request is declined.',\n triggers: ['entitlement.space_member.deleted'],\n actions: [told('requestDeclined')],\n filter,\n },\n {\n name: 'Invited to a space',\n description: 'Notify the person when they are invited to a space.',\n triggers: ['entitlement.space_member.created'],\n actions: [told('invitedToSpace')],\n filter,\n },\n {\n name: 'New message',\n description: 'Notify participants who are not muted, at most once per chat per 15 minutes.',\n triggers: ['discussion.message.sent'],\n actions: [told('newMessage')],\n filter,\n },\n {\n name: 'Message request',\n description: 'Notify the recipient when a direct chat starts as a request.',\n triggers: ['discussion.chat.created'],\n actions: [told('messageRequest')],\n filter,\n },\n {\n name: 'Added to a group chat',\n description: 'Notify the person added to a group chat.',\n triggers: ['discussion.chat.participant.added'],\n actions: [told('addedToGroupChat')],\n filter,\n },\n {\n name: 'Something was flagged',\n description: 'Notify staff and moderators when a post or comment is flagged.',\n triggers: ['discussion.post.reported', 'discussion.comment.reported'],\n actions: [told('somethingWasFlagged')],\n filter,\n },\n {\n name: 'A message was flagged',\n description: 'Notify staff when a message is flagged.',\n triggers: ['discussion.message.reported'],\n actions: [told('messageWasFlagged')],\n filter,\n },\n {\n name: 'Digest',\n description: 'Email members their unread activity. Not sent until email preferences exist.',\n triggers: ['discussion.digest.due'],\n actions: [scoped('digest')],\n filter,\n },\n ];\n}\n"],"mappings":"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"}
@@ -1,12 +1,16 @@
1
1
  import { DomainEvent, Page } from "../types/shared.js";
2
2
  import { Logger } from "../types/ports.js";
3
3
  import { Automation, AutomationActionResult, AutomationRun, AutomationRunsQuery, AutomationsQuery, AvailableActions, AvailableTriggers, CreateAutomationInput, CreateWebhookInput, CreatedWebhook, UpdateAutomationInput, UpdateWebhookInput, Webhook, WebhookSecret } from "../types/schemas/automations.js";
4
- import { AutomationDispatch, AutomationEngine, AutomationExecutor, WebhookSender } from "../types/automations.js";
4
+ import { AutomationDispatch, AutomationEngine, AutomationExecutor, ScheduledAutomation, WebhookSender } from "../types/automations.js";
5
+ import "../types/index.js";
5
6
  import { CredentialStore } from "../shared/ports.js";
6
- import { Mailer, MailerLookups } from "../shared/mailer.js";
7
7
  import "./model.js";
8
+ import { NotificationDesk } from "../identity/ports.js";
9
+ import { Mailer, MailerLookups } from "../shared/mailer.js";
10
+ import "../identity/index.js";
8
11
  import "./types.js";
9
12
  import { AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsUnitOfWork } from "./ports.js";
13
+ import { CommunityMailReads, GrantWriter, ScheduledWork } from "./community-mail.js";
10
14
  import { IntegrationsService } from "../integrations/ports.js";
11
15
  import "../integrations/index.js";
12
16
  //#region src/automations/service.d.ts
@@ -22,6 +26,10 @@ type AutomationsServiceParams = {
22
26
  integrations: Pick<IntegrationsService, 'available'>;
23
27
  credentials: CredentialStore;
24
28
  webhooks: WebhookSender;
29
+ mail: Omit<CommunityMailReads, 'recentMessageRecipients'>;
30
+ grants: GrantWriter;
31
+ desk: NotificationDesk;
32
+ scheduledWork: ScheduledWork;
25
33
  logger?: Logger;
26
34
  };
27
35
  declare class AutomationsServiceImpl implements AutomationsService, AutomationExecutor {
@@ -34,9 +42,16 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
34
42
  private readonly integrations;
35
43
  private readonly credentials;
36
44
  private readonly webhooks;
45
+ private readonly mail;
46
+ private readonly grants;
47
+ private readonly desk;
48
+ private readonly scheduledWork;
37
49
  private readonly logger;
38
50
  constructor(params: AutomationsServiceParams);
39
51
  handle(event: DomainEvent): Promise<void>;
52
+ private seedsFor;
53
+ private seedFor;
54
+ private reconcileSchedules;
40
55
  private safeListByTrigger;
41
56
  private dispatchOne;
42
57
  private openRun;
@@ -44,7 +59,12 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
44
59
  /** Best-effort: logs and never rethrows — `handle` must never throw. */
45
60
  private recordFailure;
46
61
  runAction(d: AutomationDispatch, index: number): Promise<AutomationActionResult>;
62
+ listSchedules(): Promise<ScheduledAutomation[]>;
63
+ fireSchedule(orgId: string, automationId: string, at: Date): Promise<void>;
64
+ private scheduleHasWork;
65
+ private pendingWork;
47
66
  finalize(d: AutomationDispatch, results: AutomationActionResult[]): Promise<void>;
67
+ private logOutcome;
48
68
  create(orgId: string, input: CreateAutomationInput): Promise<Automation>;
49
69
  update(orgId: string, id: string, input: UpdateAutomationInput): Promise<Automation | null>;
50
70
  delete(orgId: string, id: string): Promise<boolean>;
@@ -60,7 +80,6 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
60
80
  revealWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
61
81
  rotateWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
62
82
  private findWebhook;
63
- private assertSubscribableEvents;
64
83
  availableActions(): AvailableActions;
65
84
  availableTriggers(): AvailableTriggers;
66
85
  }