@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,18 +1,134 @@
1
1
  import { DomainEvent, Page } from "../types/shared.js";
2
2
  import { Automation, AutomationKind, AutomationRun, AutomationRunsQuery, AutomationsQuery, AvailableActions, AvailableTriggers, CreateAutomationInput, CreateWebhookInput, CreatedWebhook, UpdateAutomationInput, UpdateWebhookInput, Webhook, WebhookSecret } from "../types/schemas/automations.js";
3
- import { AutomationDispatch, AutomationEngine, AutomationExecutor, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
3
+ import { AutomationDispatch, AutomationEngine, AutomationExecutor, DeliveryDispatch, ScheduledAutomation, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
4
+ import { Delivery, NotificationCategory, NotificationFilter, RecipientList, StoredNotification, SubjectRef } from "../types/notifications.js";
4
5
  import "../types/index.js";
5
6
  import { CredentialStore, OutboxAppender, UnitOfWork } from "../shared/ports.js";
6
7
  import "./model.js";
7
8
  import "./types.js";
9
+ import { CommunityMailReads } from "./community-mail.js";
8
10
  //#region src/automations/ports.d.ts
9
11
  type NewAutomation = CreateAutomationInput & {
10
12
  kind: AutomationKind;
11
13
  };
14
+ interface NotificationCategories {
15
+ listFor(orgId: string, communityId: string | null): Promise<NotificationCategory[]>;
16
+ }
17
+ interface NotificationReads extends Omit<CommunityMailReads, 'recentMessageRecipients'> {
18
+ threadParticipants(orgId: string, item: SubjectRef): Promise<string[]>;
19
+ mutedAmong(orgId: string, item: SubjectRef, orgUserIds: string[], at: Date): Promise<string[]>;
20
+ communityMembers(orgId: string, communityId: string): Promise<string[]>;
21
+ switchedOn(orgId: string, communityId: string, category: string, spaceId: string | null): Promise<string[]>;
22
+ courseHolders(orgId: string, courseId: string): Promise<string[]>;
23
+ contentLostBy(orgId: string, grant: {
24
+ orgUserId: string;
25
+ contentId: string | null;
26
+ bundleId: string | null;
27
+ }): Promise<string[]>;
28
+ activity(orgId: string, activityId: string): Promise<{
29
+ title: string;
30
+ moduleTitle: string;
31
+ courseId: string;
32
+ courseTitle: string;
33
+ } | null>;
34
+ userIdsOf(orgId: string, orgUserIds: string[]): Promise<Record<string, string>>;
35
+ emailOf(orgId: string, userId: string): Promise<string | null>;
36
+ contentInfo(orgId: string, item: {
37
+ contentId: string;
38
+ } | {
39
+ bundleId: string;
40
+ }): Promise<{
41
+ title: string;
42
+ type: string;
43
+ } | null>;
44
+ message(orgId: string, messageId: string): Promise<{
45
+ orgUserId: string;
46
+ chatId: string;
47
+ body: string;
48
+ } | null>;
49
+ postsPublished(orgId: string, communityId: string, from: Date, to: Date): Promise<{
50
+ postId: string;
51
+ spaceId: string;
52
+ title: string;
53
+ authorName: string;
54
+ spaceName: string;
55
+ commentCount: number;
56
+ }[]>;
57
+ unreadInChat(orgId: string, chatId: string, orgUserId: string): Promise<{
58
+ count: number;
59
+ latest: {
60
+ messageId: string;
61
+ senderOrgUserId: string;
62
+ body: string;
63
+ } | null;
64
+ }>;
65
+ }
66
+ type RecipientRule = (event: DomainEvent, reads: NotificationReads) => Promise<RecipientList[]>;
67
+ interface ChatDebounce {
68
+ arm(orgId: string, list: RecipientList, occurredAt: Date): Promise<void>;
69
+ mentioned(orgId: string, userId: string, chatId: string): Promise<void>;
70
+ }
71
+ interface NewNotification extends Omit<StoredNotification, 'orgId'> {
72
+ sourceEventId: string | null;
73
+ inApp: boolean;
74
+ }
75
+ interface NewDelivery {
76
+ id: string;
77
+ notificationId: string;
78
+ channel: string;
79
+ }
80
+ type ListedNotification = StoredNotification & {
81
+ readAt: Date | null;
82
+ };
83
+ interface NotificationPage {
84
+ items: ListedNotification[];
85
+ total: number;
86
+ unreadCount: number;
87
+ }
88
+ interface UnreadCounts {
89
+ org: number;
90
+ communities: {
91
+ communityId: string;
92
+ unread: number;
93
+ }[];
94
+ }
95
+ interface NotificationsService {
96
+ list(orgId: string, userId: string, filter: NotificationFilter, page: {
97
+ page: number;
98
+ pageSize: number;
99
+ }): Promise<NotificationPage>;
100
+ get(orgId: string, userId: string, notificationId: string): Promise<ListedNotification | null>;
101
+ unreadCounts(orgId: string, userId: string, communityIds: string[]): Promise<UnreadCounts>;
102
+ markRead(orgId: string, userId: string, notificationId: string): Promise<void>;
103
+ markAllRead(orgId: string, userId: string, filter: NotificationFilter): Promise<{
104
+ marked: number;
105
+ }>;
106
+ }
107
+ interface NotificationsRepository {
108
+ insert(orgId: string, rows: NewNotification[], deliveries: NewDelivery[]): Promise<void>;
109
+ pendingDeliveriesForEvent(orgId: string, sourceEventId: string): Promise<{
110
+ id: string;
111
+ }[]>;
112
+ findDelivery(orgId: string, deliveryId: string): Promise<{
113
+ delivery: Delivery;
114
+ notification: StoredNotification;
115
+ } | null>;
116
+ markSent(orgId: string, deliveryId: string, at: Date): Promise<void>;
117
+ recordError(orgId: string, deliveryId: string, error: string): Promise<void>;
118
+ markFailed(orgId: string, deliveryId: string, error: string): Promise<void>;
119
+ page(orgId: string, userId: string, filter: NotificationFilter, page: {
120
+ page: number;
121
+ pageSize: number;
122
+ }): Promise<NotificationPage>;
123
+ find(orgId: string, userId: string, notificationId: string): Promise<ListedNotification | null>;
124
+ unreadCounts(orgId: string, userId: string, communityIds: string[]): Promise<UnreadCounts>;
125
+ markRead(orgId: string, userId: string, notificationId: string, at: Date): Promise<boolean>;
126
+ markAllRead(orgId: string, userId: string, filter: NotificationFilter, at: Date): Promise<number>;
127
+ }
12
128
  /** A run row before persistence assigns its id and event_id. */
13
129
  type NewAutomationRun = Omit<AutomationRun, 'id' | 'eventId'>;
14
130
  interface AutomationsService {
15
- /** Matches `event` against enabled automations and dispatches a run per match; never throws. */
131
+ /** Dispatches a run per enabled automation the event matches, then runs the notification process; throws only when the notification process fails, so the outbox redelivers. */
16
132
  handle(event: DomainEvent): Promise<void>;
17
133
  /** Built-in action types plus every loaded integration's declared actions. */
18
134
  availableActions(): AvailableActions;
@@ -42,6 +158,7 @@ interface AutomationsRepository {
42
158
  listByOrg(orgId: string, kind?: AutomationKind): Promise<Automation[]>;
43
159
  /** All rows whose triggers include `trigger`, enabled and disabled alike — the service filters to `enabled`. */
44
160
  listByTrigger(orgId: string, trigger: string): Promise<Automation[]>;
161
+ listSchedules(): Promise<ScheduledAutomation[]>;
45
162
  }
46
163
  interface AutomationRunsRepository {
47
164
  /** Keyed by (orgId, automationId, event.id); returns `null` if this event was already run for this automation (duplicate). */
@@ -55,6 +172,7 @@ interface AutomationRunsRepository {
55
172
  finishedAt: Date;
56
173
  }): Promise<AutomationRun | null>;
57
174
  list(orgId: string, automationId: string, query: AutomationRunsQuery): Promise<Page<AutomationRun>>;
175
+ recentRecipients(orgId: string, automationId: string, chatId: string, since: Date): Promise<string[]>;
58
176
  }
59
177
  /** Tx-scoped port bundle for this context's mutating use cases — every member
60
178
  * is bound to the UnitOfWork's transaction, so the write(s) and the event
@@ -67,5 +185,5 @@ interface AutomationsTxScope {
67
185
  }
68
186
  type AutomationsUnitOfWork = UnitOfWork<AutomationsTxScope>;
69
187
  //#endregion
70
- export { type AutomationDispatch, type AutomationEngine, type AutomationExecutor, AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsTxScope, AutomationsUnitOfWork, NewAutomation, NewAutomationRun, type WebhookRequest, type WebhookResponse, type WebhookSender };
188
+ export { type AutomationDispatch, type AutomationEngine, type AutomationExecutor, AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsTxScope, AutomationsUnitOfWork, ChatDebounce, type DeliveryDispatch, ListedNotification, NewAutomation, NewAutomationRun, NewDelivery, NewNotification, NotificationCategories, NotificationPage, NotificationReads, NotificationsRepository, NotificationsService, RecipientRule, UnreadCounts, type WebhookRequest, type WebhookResponse, type WebhookSender };
71
189
  //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1,6 @@
1
+ //#region src/automations/schedule.d.ts
2
+ declare function cronMatches(expression: string, at: Date): boolean;
3
+ declare function cronSupported(expression: string): boolean;
4
+ //#endregion
5
+ export { cronMatches, cronSupported };
6
+ //# sourceMappingURL=schedule.d.ts.map
@@ -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"}
@@ -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, DeliveryDispatch, 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 { Mailer, MailerLookups } from "../shared/mailer.js";
8
9
  import "./types.js";
9
10
  import { AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsUnitOfWork } from "./ports.js";
11
+ import { CommunityMailReads, GrantWriter } from "./community-mail.js";
12
+ import { NotificationDelivery } from "./notifications/delivery.js";
13
+ import { NotificationProcessor } from "./notifications/processor.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
+ delivery: Pick<NotificationDelivery, 'run'>;
32
+ processor: Pick<NotificationProcessor, 'process'>;
25
33
  logger?: Logger;
26
34
  };
27
35
  declare class AutomationsServiceImpl implements AutomationsService, AutomationExecutor {
@@ -34,17 +42,26 @@ 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 delivery;
48
+ private readonly processor;
37
49
  private readonly logger;
38
50
  constructor(params: AutomationsServiceParams);
39
51
  handle(event: DomainEvent): Promise<void>;
52
+ private reconcileSchedules;
40
53
  private safeListByTrigger;
41
54
  private dispatchOne;
42
55
  private openRun;
43
56
  private dispatchFor;
44
- /** Best-effort: logs and never rethrows — `handle` must never throw. */
57
+ /** Best-effort: logs and never rethrows, so an org automation never fails `handle`. */
45
58
  private recordFailure;
46
59
  runAction(d: AutomationDispatch, index: number): Promise<AutomationActionResult>;
60
+ runDelivery(d: DeliveryDispatch, lastAttempt: boolean): Promise<void>;
61
+ listSchedules(): Promise<ScheduledAutomation[]>;
62
+ fireSchedule(orgId: string, automationId: string, at: Date): Promise<void>;
47
63
  finalize(d: AutomationDispatch, results: AutomationActionResult[]): Promise<void>;
64
+ private logOutcome;
48
65
  create(orgId: string, input: CreateAutomationInput): Promise<Automation>;
49
66
  update(orgId: string, id: string, input: UpdateAutomationInput): Promise<Automation | null>;
50
67
  delete(orgId: string, id: string): Promise<boolean>;
@@ -60,7 +77,6 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
60
77
  revealWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
61
78
  rotateWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
62
79
  private findWebhook;
63
- private assertSubscribableEvents;
64
80
  availableActions(): AvailableActions;
65
81
  availableTriggers(): AvailableTriggers;
66
82
  }