@headless-lms/core 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/dist/assets/events.d.ts +27 -21
  2. package/dist/assets/file-urls.d.ts +11 -7
  3. package/dist/assets/file-urls.js +14 -4
  4. package/dist/assets/file-urls.js.map +1 -1
  5. package/dist/assets/index.d.ts +4 -4
  6. package/dist/assets/index.js +3 -3
  7. package/dist/assets/ports.d.ts +34 -15
  8. package/dist/assets/service.d.ts +30 -14
  9. package/dist/assets/service.js +230 -56
  10. package/dist/assets/service.js.map +1 -1
  11. package/dist/automations/actions.js.map +1 -1
  12. package/dist/automations/catalog.js +69 -4
  13. package/dist/automations/catalog.js.map +1 -1
  14. package/dist/automations/community-derivations.js +16 -16
  15. package/dist/automations/community-derivations.js.map +1 -1
  16. package/dist/automations/community-mail.d.ts +34 -4
  17. package/dist/automations/community-mail.js +32 -4
  18. package/dist/automations/community-mail.js.map +1 -1
  19. package/dist/automations/event-permissions.d.ts +12 -0
  20. package/dist/automations/event-permissions.js +38 -0
  21. package/dist/automations/event-permissions.js.map +1 -0
  22. package/dist/automations/index.d.ts +2 -1
  23. package/dist/automations/index.js +2 -1
  24. package/dist/automations/notifications/applicable.d.ts +8 -0
  25. package/dist/automations/notifications/applicable.js +12 -0
  26. package/dist/automations/notifications/applicable.js.map +1 -0
  27. package/dist/automations/notifications/debounce.js +1 -1
  28. package/dist/automations/notifications/debounce.js.map +1 -1
  29. package/dist/automations/notifications/defaults.js +33 -3
  30. package/dist/automations/notifications/defaults.js.map +1 -1
  31. package/dist/automations/notifications/processor.js +3 -3
  32. package/dist/automations/notifications/processor.js.map +1 -1
  33. package/dist/automations/notifications/rules/content.js +60 -3
  34. package/dist/automations/notifications/rules/content.js.map +1 -1
  35. package/dist/automations/notifications/rules/discussion.js +29 -29
  36. package/dist/automations/notifications/rules/discussion.js.map +1 -1
  37. package/dist/automations/notifications/rules/entitlements.js +36 -9
  38. package/dist/automations/notifications/rules/entitlements.js.map +1 -1
  39. package/dist/automations/notifications/rules/events.d.ts +9 -0
  40. package/dist/automations/notifications/rules/events.js +27 -0
  41. package/dist/automations/notifications/rules/events.js.map +1 -0
  42. package/dist/automations/notifications/rules/organizations.js +17 -10
  43. package/dist/automations/notifications/rules/organizations.js.map +1 -1
  44. package/dist/automations/notifications/rules/recipients.js +0 -1
  45. package/dist/automations/notifications/rules/recipients.js.map +1 -1
  46. package/dist/automations/notifications/service.d.ts +8 -6
  47. package/dist/automations/notifications/service.js +13 -13
  48. package/dist/automations/notifications/service.js.map +1 -1
  49. package/dist/automations/notifications/types.js +94 -7
  50. package/dist/automations/notifications/types.js.map +1 -1
  51. package/dist/automations/ports.d.ts +30 -31
  52. package/dist/automations/service.d.ts +20 -17
  53. package/dist/automations/service.js +91 -62
  54. package/dist/automations/service.js.map +1 -1
  55. package/dist/content/event-sight.d.ts +11 -0
  56. package/dist/content/event-sight.js +11 -0
  57. package/dist/content/event-sight.js.map +1 -0
  58. package/dist/content/events.d.ts +413 -72
  59. package/dist/content/events.js +34 -1
  60. package/dist/content/events.js.map +1 -1
  61. package/dist/content/index.d.ts +6 -4
  62. package/dist/content/index.js +3 -1
  63. package/dist/content/jobs.d.ts +16 -0
  64. package/dist/content/jobs.js +37 -0
  65. package/dist/content/jobs.js.map +1 -0
  66. package/dist/content/model.d.ts +2 -2
  67. package/dist/content/notification-categories.d.ts +5 -4
  68. package/dist/content/notification-categories.js +15 -6
  69. package/dist/content/notification-categories.js.map +1 -1
  70. package/dist/content/ports.d.ts +113 -68
  71. package/dist/content/service.d.ts +99 -67
  72. package/dist/content/service.js +680 -139
  73. package/dist/content/service.js.map +1 -1
  74. package/dist/content/titles.d.ts +6 -3
  75. package/dist/content/titles.js +37 -24
  76. package/dist/content/titles.js.map +1 -1
  77. package/dist/content/types.d.ts +2 -2
  78. package/dist/discussion/authors.d.ts +4 -2
  79. package/dist/discussion/authors.js +9 -5
  80. package/dist/discussion/authors.js.map +1 -1
  81. package/dist/discussion/chats.d.ts +56 -37
  82. package/dist/discussion/chats.js +393 -161
  83. package/dist/discussion/chats.js.map +1 -1
  84. package/dist/discussion/events.d.ts +77 -39
  85. package/dist/discussion/events.js +41 -3
  86. package/dist/discussion/events.js.map +1 -1
  87. package/dist/discussion/index.d.ts +8 -5
  88. package/dist/discussion/index.js +5 -3
  89. package/dist/discussion/live.d.ts +106 -0
  90. package/dist/discussion/live.js +642 -0
  91. package/dist/discussion/live.js.map +1 -0
  92. package/dist/discussion/mentions.js +2 -2
  93. package/dist/discussion/mentions.js.map +1 -1
  94. package/dist/discussion/ports.d.ts +182 -100
  95. package/dist/discussion/ports.js.map +1 -1
  96. package/dist/discussion/posts.d.ts +45 -39
  97. package/dist/discussion/posts.js +268 -154
  98. package/dist/discussion/posts.js.map +1 -1
  99. package/dist/discussion/rules.d.ts +18 -0
  100. package/dist/discussion/rules.js +22 -0
  101. package/dist/discussion/rules.js.map +1 -0
  102. package/dist/discussion/service.d.ts +37 -31
  103. package/dist/discussion/service.js +252 -188
  104. package/dist/discussion/service.js.map +1 -1
  105. package/dist/discussion/subscriptions.d.ts +8 -8
  106. package/dist/discussion/subscriptions.js +29 -13
  107. package/dist/discussion/subscriptions.js.map +1 -1
  108. package/dist/discussion/titles.d.ts +4 -2
  109. package/dist/discussion/titles.js +27 -13
  110. package/dist/discussion/titles.js.map +1 -1
  111. package/dist/entitlements/events.d.ts +20 -20
  112. package/dist/entitlements/index.d.ts +4 -4
  113. package/dist/entitlements/index.js +2 -2
  114. package/dist/entitlements/model.d.ts +2 -2
  115. package/dist/entitlements/ports.d.ts +65 -39
  116. package/dist/entitlements/rules.d.ts +3 -6
  117. package/dist/entitlements/rules.js +5 -10
  118. package/dist/entitlements/rules.js.map +1 -1
  119. package/dist/entitlements/service.d.ts +40 -28
  120. package/dist/entitlements/service.js +370 -163
  121. package/dist/entitlements/service.js.map +1 -1
  122. package/dist/identity/devices.d.ts +3 -3
  123. package/dist/identity/devices.js +7 -5
  124. package/dist/identity/devices.js.map +1 -1
  125. package/dist/identity/events.d.ts +2 -2
  126. package/dist/identity/index.d.ts +2 -2
  127. package/dist/identity/index.js +2 -2
  128. package/dist/identity/notification-settings.d.ts +1 -1
  129. package/dist/identity/notification-settings.js +3 -2
  130. package/dist/identity/notification-settings.js.map +1 -1
  131. package/dist/identity/ports.d.ts +7 -7
  132. package/dist/identity/service.d.ts +8 -7
  133. package/dist/identity/service.js +17 -13
  134. package/dist/identity/service.js.map +1 -1
  135. package/dist/integrations/events.d.ts +3 -3
  136. package/dist/integrations/ports.d.ts +9 -8
  137. package/dist/integrations/service.d.ts +9 -8
  138. package/dist/integrations/service.js +33 -16
  139. package/dist/integrations/service.js.map +1 -1
  140. package/dist/organizations/default-roles.d.ts +22 -0
  141. package/dist/organizations/default-roles.js +89 -0
  142. package/dist/organizations/default-roles.js.map +1 -0
  143. package/dist/organizations/effective-permissions.d.ts +45 -0
  144. package/dist/organizations/effective-permissions.js +113 -0
  145. package/dist/organizations/effective-permissions.js.map +1 -0
  146. package/dist/organizations/events.d.ts +320 -181
  147. package/dist/organizations/events.js +90 -18
  148. package/dist/organizations/events.js.map +1 -1
  149. package/dist/organizations/index.d.ts +14 -10
  150. package/dist/organizations/index.js +7 -3
  151. package/dist/organizations/members.d.ts +66 -8
  152. package/dist/organizations/members.js.map +1 -1
  153. package/dist/organizations/notification-catalog.d.ts +31 -0
  154. package/dist/organizations/notification-catalog.js +32 -0
  155. package/dist/organizations/notification-catalog.js.map +1 -0
  156. package/dist/organizations/notification-categories.d.ts +6 -4
  157. package/dist/organizations/notification-categories.js +25 -10
  158. package/dist/organizations/notification-categories.js.map +1 -1
  159. package/dist/organizations/org-roles.d.ts +33 -0
  160. package/dist/organizations/org-roles.js +49 -0
  161. package/dist/organizations/org-roles.js.map +1 -0
  162. package/dist/organizations/permissions.d.ts +311 -0
  163. package/dist/organizations/permissions.js +327 -0
  164. package/dist/organizations/permissions.js.map +1 -0
  165. package/dist/organizations/ports.d.ts +184 -65
  166. package/dist/organizations/service.d.ts +102 -35
  167. package/dist/organizations/service.js +1245 -328
  168. package/dist/organizations/service.js.map +1 -1
  169. package/dist/organizations/testing.d.ts +18 -0
  170. package/dist/organizations/testing.js +37 -0
  171. package/dist/organizations/testing.js.map +1 -0
  172. package/dist/organizations/types.d.ts +5 -16
  173. package/dist/progress/events.d.ts +14 -14
  174. package/dist/progress/index.d.ts +2 -2
  175. package/dist/progress/ports.d.ts +11 -3
  176. package/dist/progress/service.d.ts +6 -5
  177. package/dist/progress/service.js +23 -8
  178. package/dist/progress/service.js.map +1 -1
  179. package/dist/reporting/admin/index.d.ts +6 -4
  180. package/dist/reporting/admin/model.d.ts +36 -3
  181. package/dist/reporting/admin/ports.d.ts +39 -14
  182. package/dist/reporting/admin/service.d.ts +32 -11
  183. package/dist/reporting/admin/service.js +102 -18
  184. package/dist/reporting/admin/service.js.map +1 -1
  185. package/dist/reporting/events/index.d.ts +27 -0
  186. package/dist/reporting/events/index.js +20 -0
  187. package/dist/reporting/events/index.js.map +1 -0
  188. package/dist/reporting/member/calendar.d.ts +11 -0
  189. package/dist/reporting/member/calendar.js +75 -0
  190. package/dist/reporting/member/calendar.js.map +1 -0
  191. package/dist/reporting/member/index.d.ts +3 -2
  192. package/dist/reporting/member/model.d.ts +26 -5
  193. package/dist/reporting/member/ports.d.ts +48 -29
  194. package/dist/reporting/member/service.d.ts +56 -29
  195. package/dist/reporting/member/service.js +328 -113
  196. package/dist/reporting/member/service.js.map +1 -1
  197. package/dist/shared/actor.d.ts +22 -3
  198. package/dist/shared/errors.d.ts +2 -1
  199. package/dist/shared/errors.js +3 -1
  200. package/dist/shared/errors.js.map +1 -1
  201. package/dist/shared/id.d.ts +4 -0
  202. package/dist/shared/id.js +4 -0
  203. package/dist/shared/id.js.map +1 -1
  204. package/dist/shared/logger.d.ts +2 -1
  205. package/dist/shared/logger.js +10 -1
  206. package/dist/shared/logger.js.map +1 -1
  207. package/dist/shared/ports.d.ts +25 -5
  208. package/dist/types/content.d.ts +2 -2
  209. package/dist/types/discussion.d.ts +4 -5
  210. package/dist/types/email-templates.d.ts +22 -3
  211. package/dist/types/entitlements.d.ts +2 -2
  212. package/dist/types/identity.d.ts +13 -16
  213. package/dist/types/index.d.ts +9 -9
  214. package/dist/types/index.js +2 -1
  215. package/dist/types/notifications.d.ts +4 -4
  216. package/dist/types/organizations.d.ts +3 -2
  217. package/dist/types/ports.d.ts +8 -1
  218. package/dist/types/ports.js +7 -1
  219. package/dist/types/ports.js.map +1 -0
  220. package/dist/types/schemas/assets.d.ts +5 -5
  221. package/dist/types/schemas/assets.js +4 -3
  222. package/dist/types/schemas/assets.js.map +1 -1
  223. package/dist/types/schemas/content.d.ts +537 -13
  224. package/dist/types/schemas/content.js +201 -7
  225. package/dist/types/schemas/content.js.map +1 -1
  226. package/dist/types/schemas/discussion.d.ts +282 -59
  227. package/dist/types/schemas/discussion.js +77 -3
  228. package/dist/types/schemas/discussion.js.map +1 -1
  229. package/dist/types/schemas/entitlements.d.ts +14 -1
  230. package/dist/types/schemas/entitlements.js +11 -4
  231. package/dist/types/schemas/entitlements.js.map +1 -1
  232. package/dist/types/schemas/index.d.ts +5 -5
  233. package/dist/types/schemas/index.js +5 -5
  234. package/dist/types/schemas/notifications.d.ts +13 -12
  235. package/dist/types/schemas/notifications.js +3 -2
  236. package/dist/types/schemas/notifications.js.map +1 -1
  237. package/dist/types/schemas/organizations.d.ts +96 -60
  238. package/dist/types/schemas/organizations.js +78 -27
  239. package/dist/types/schemas/organizations.js.map +1 -1
  240. package/dist/types/schemas/progress.d.ts +3 -4
  241. package/dist/types/schemas/progress.js +0 -1
  242. package/dist/types/schemas/progress.js.map +1 -1
  243. package/package.json +1 -1
  244. package/dist/organizations/access-scopes.d.ts +0 -19
  245. package/dist/organizations/access-scopes.js +0 -89
  246. package/dist/organizations/access-scopes.js.map +0 -1
  247. package/dist/organizations/roles.d.ts +0 -19
  248. package/dist/organizations/roles.js +0 -82
  249. package/dist/organizations/roles.js.map +0 -1
@@ -1,11 +1,16 @@
1
1
  import { DomainEvent, Page } from "../types/shared.js";
2
+ import { Event } from "../types/schemas/content.js";
2
3
  import { Automation, AutomationKind, AutomationRun, AutomationRunsQuery, AutomationsQuery, AvailableActions, AvailableTriggers, CreateAutomationInput, CreateWebhookInput, CreatedWebhook, UpdateAutomationInput, UpdateWebhookInput, Webhook, WebhookSecret } from "../types/schemas/automations.js";
3
4
  import { AutomationDispatch, AutomationEngine, AutomationExecutor, DeliveryDispatch, ScheduledAutomation, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
4
5
  import { Delivery, NotificationCategory, NotificationFilter, RecipientList, StoredNotification, SubjectRef } from "../types/notifications.js";
5
6
  import "../types/index.js";
7
+ import { Actor } from "../shared/actor.js";
6
8
  import { CredentialStore, OutboxAppender, UnitOfWork } from "../shared/ports.js";
7
9
  import "./model.js";
10
+ import "../content/index.js";
8
11
  import "./types.js";
12
+ import { MemberActor } from "../identity/ports.js";
13
+ import "../identity/index.js";
9
14
  import { CommunityMailReads } from "./community-mail.js";
10
15
  //#region src/automations/ports.d.ts
11
16
  type NewAutomation = CreateAutomationInput & {
@@ -19,7 +24,9 @@ interface NotificationReads extends Omit<CommunityMailReads, 'recentMessageRecip
19
24
  mutedAmong(orgId: string, item: SubjectRef, orgUserIds: string[], at: Date): Promise<string[]>;
20
25
  communityMembers(orgId: string, communityId: string): Promise<string[]>;
21
26
  switchedOn(orgId: string, communityId: string, category: string, spaceId: string | null): Promise<string[]>;
22
- courseHolders(orgId: string, courseId: string): Promise<string[]>;
27
+ courseMembers(orgId: string, courseId: string): Promise<string[]>;
28
+ event(orgId: string, eventId: string): Promise<Event | null>;
29
+ eventAttendees(orgId: string, eventId: string): Promise<string[]>;
23
30
  contentLostBy(orgId: string, grant: {
24
31
  orgUserId: string;
25
32
  contentId: string | null;
@@ -33,14 +40,6 @@ interface NotificationReads extends Omit<CommunityMailReads, 'recentMessageRecip
33
40
  } | null>;
34
41
  userIdsOf(orgId: string, orgUserIds: string[]): Promise<Record<string, string>>;
35
42
  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
43
  message(orgId: string, messageId: string): Promise<{
45
44
  orgUserId: string;
46
45
  chatId: string;
@@ -93,14 +92,14 @@ interface UnreadCounts {
93
92
  }[];
94
93
  }
95
94
  interface NotificationsService {
96
- list(orgId: string, userId: string, filter: NotificationFilter, page: {
95
+ list(filter: NotificationFilter, page: {
97
96
  page: number;
98
97
  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<{
98
+ }, actor: MemberActor): Promise<NotificationPage>;
99
+ get(notificationId: string, actor: MemberActor): Promise<ListedNotification | null>;
100
+ unreadCounts(communityIds: string[], actor: MemberActor): Promise<UnreadCounts>;
101
+ markRead(notificationId: string, actor: MemberActor): Promise<void>;
102
+ markAllRead(filter: NotificationFilter, actor: MemberActor): Promise<{
104
103
  marked: number;
105
104
  }>;
106
105
  }
@@ -131,23 +130,23 @@ interface AutomationsService {
131
130
  /** 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. */
132
131
  handle(event: DomainEvent): Promise<void>;
133
132
  /** Built-in action types plus every loaded integration's declared actions. */
134
- availableActions(): AvailableActions;
133
+ availableActions(actor: Actor): AvailableActions;
135
134
  /** The domain event types an automation may react to. */
136
- availableTriggers(): AvailableTriggers;
137
- list(orgId: string, query?: AutomationsQuery): Promise<Automation[]>;
138
- get(orgId: string, id: string): Promise<Automation | null>;
139
- create(orgId: string, input: CreateAutomationInput): Promise<Automation>;
140
- update(orgId: string, id: string, input: UpdateAutomationInput): Promise<Automation | null>;
141
- delete(orgId: string, id: string): Promise<boolean>;
142
- listRuns(orgId: string, automationId: string, query: AutomationRunsQuery): Promise<Page<AutomationRun>>;
143
- rerun(orgId: string, automationId: string, runId: string): Promise<AutomationRun>;
144
- listWebhooks(orgId: string): Promise<Webhook[]>;
145
- getWebhook(orgId: string, id: string): Promise<Webhook | null>;
146
- createWebhook(orgId: string, input: CreateWebhookInput): Promise<CreatedWebhook>;
147
- updateWebhook(orgId: string, id: string, input: UpdateWebhookInput): Promise<Webhook | null>;
148
- deleteWebhook(orgId: string, id: string): Promise<boolean>;
149
- revealWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
150
- rotateWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
135
+ availableTriggers(actor: Actor): AvailableTriggers;
136
+ list(query: AutomationsQuery | undefined, actor: Actor): Promise<Automation[]>;
137
+ get(id: string, actor: Actor): Promise<Automation>;
138
+ create(input: CreateAutomationInput, actor: Actor): Promise<Automation>;
139
+ update(id: string, input: UpdateAutomationInput, actor: Actor): Promise<Automation>;
140
+ delete(id: string, actor: Actor): Promise<void>;
141
+ listRuns(automationId: string, query: AutomationRunsQuery, actor: Actor): Promise<Page<AutomationRun>>;
142
+ rerun(automationId: string, runId: string, actor: Actor): Promise<AutomationRun>;
143
+ listWebhooks(actor: Actor): Promise<Webhook[]>;
144
+ getWebhook(id: string, actor: Actor): Promise<Webhook>;
145
+ createWebhook(input: CreateWebhookInput, actor: Actor): Promise<CreatedWebhook>;
146
+ updateWebhook(id: string, input: UpdateWebhookInput, actor: Actor): Promise<Webhook>;
147
+ deleteWebhook(id: string, actor: Actor): Promise<void>;
148
+ revealWebhookSecret(id: string, actor: Actor): Promise<WebhookSecret>;
149
+ rotateWebhookSecret(id: string, actor: Actor): Promise<WebhookSecret>;
151
150
  }
152
151
  interface AutomationsRepository {
153
152
  insert(orgId: string, input: NewAutomation): Promise<Automation>;
@@ -3,6 +3,7 @@ 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
4
  import { AutomationDispatch, AutomationEngine, AutomationExecutor, DeliveryDispatch, ScheduledAutomation, WebhookSender } from "../types/automations.js";
5
5
  import "../types/index.js";
6
+ import { Actor } from "../shared/actor.js";
6
7
  import { CredentialStore } from "../shared/ports.js";
7
8
  import "./model.js";
8
9
  import { Mailer, MailerLookups } from "../shared/mailer.js";
@@ -24,6 +25,7 @@ type AutomationsServiceParams = {
24
25
  mailer: Pick<Mailer, 'send'>;
25
26
  lookups: MailerLookups;
26
27
  integrations: Pick<IntegrationsService, 'available'>;
28
+ systemActor: (orgId: string) => Actor;
27
29
  credentials: CredentialStore;
28
30
  webhooks: WebhookSender;
29
31
  mail: Omit<CommunityMailReads, 'recentMessageRecipients'>;
@@ -40,6 +42,7 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
40
42
  private readonly mailer;
41
43
  private readonly lookups;
42
44
  private readonly integrations;
45
+ private readonly systemActor;
43
46
  private readonly credentials;
44
47
  private readonly webhooks;
45
48
  private readonly mail;
@@ -62,23 +65,23 @@ declare class AutomationsServiceImpl implements AutomationsService, AutomationEx
62
65
  fireSchedule(orgId: string, automationId: string, at: Date): Promise<void>;
63
66
  finalize(d: AutomationDispatch, results: AutomationActionResult[]): Promise<void>;
64
67
  private logOutcome;
65
- create(orgId: string, input: CreateAutomationInput): Promise<Automation>;
66
- update(orgId: string, id: string, input: UpdateAutomationInput): Promise<Automation | null>;
67
- delete(orgId: string, id: string): Promise<boolean>;
68
- list(orgId: string, query?: AutomationsQuery): Promise<Automation[]>;
69
- get(orgId: string, id: string): Promise<Automation | null>;
70
- listRuns(orgId: string, automationId: string, query: AutomationRunsQuery): Promise<Page<AutomationRun>>;
71
- rerun(orgId: string, automationId: string, runId: string): Promise<AutomationRun>;
72
- listWebhooks(orgId: string): Promise<Webhook[]>;
73
- getWebhook(orgId: string, id: string): Promise<Webhook | null>;
74
- createWebhook(orgId: string, input: CreateWebhookInput): Promise<CreatedWebhook>;
75
- updateWebhook(orgId: string, id: string, input: UpdateWebhookInput): Promise<Webhook | null>;
76
- deleteWebhook(orgId: string, id: string): Promise<boolean>;
77
- revealWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
78
- rotateWebhookSecret(orgId: string, id: string): Promise<WebhookSecret | null>;
79
- private findWebhook;
80
- availableActions(): AvailableActions;
81
- availableTriggers(): AvailableTriggers;
68
+ create(input: CreateAutomationInput, actor: Actor): Promise<Automation>;
69
+ update(id: string, input: UpdateAutomationInput, actor: Actor): Promise<Automation>;
70
+ delete(id: string, actor: Actor): Promise<void>;
71
+ list(query: AutomationsQuery | undefined, actor: Actor): Promise<Automation[]>;
72
+ get(id: string, actor: Actor): Promise<Automation>;
73
+ listRuns(automationId: string, query: AutomationRunsQuery, actor: Actor): Promise<Page<AutomationRun>>;
74
+ rerun(automationId: string, runId: string, actor: Actor): Promise<AutomationRun>;
75
+ listWebhooks(actor: Actor): Promise<Webhook[]>;
76
+ getWebhook(id: string, actor: Actor): Promise<Webhook>;
77
+ createWebhook(input: CreateWebhookInput, actor: Actor): Promise<CreatedWebhook>;
78
+ updateWebhook(id: string, input: UpdateWebhookInput, actor: Actor): Promise<Webhook>;
79
+ deleteWebhook(id: string, actor: Actor): Promise<void>;
80
+ revealWebhookSecret(id: string, actor: Actor): Promise<WebhookSecret>;
81
+ rotateWebhookSecret(id: string, actor: Actor): Promise<WebhookSecret>;
82
+ private requireWebhook;
83
+ availableActions(actor: Actor): AvailableActions;
84
+ availableTriggers(actor: Actor): AvailableTriggers;
82
85
  }
83
86
  //#endregion
84
87
  export { AutomationsServiceImpl, AutomationsServiceParams };
@@ -1,10 +1,11 @@
1
1
  import { deliverWebhookInputSchema } from "../types/schemas/automations.js";
2
- import { ConflictError, InvalidInputError, NotFoundError } from "../shared/errors.js";
3
2
  import { noopLogger } from "../shared/logger.js";
3
+ import { ConflictError, InvalidInputError, NotFoundError } from "../shared/errors.js";
4
4
  import { ActionFailedError, AutomationKindMismatchError, InvalidTriggerError, ReservedActionError } from "./model.js";
5
5
  import { DELIVER_WEBHOOK_ACTION, catalogActions, catalogTriggers, publicDataSchema } from "./catalog.js";
6
6
  import { generateWebhookSecret } from "./webhook-signing.js";
7
7
  import { executeAction } from "./actions.js";
8
+ import { assertGrantsAllowed, assertReadsEvents } from "./event-permissions.js";
8
9
  import { automationEvents } from "./events.js";
9
10
  import { cronSupported } from "./schedule.js";
10
11
  //#region src/automations/service.ts
@@ -128,6 +129,7 @@ var AutomationsServiceImpl = class {
128
129
  mailer;
129
130
  lookups;
130
131
  integrations;
132
+ systemActor;
131
133
  credentials;
132
134
  webhooks;
133
135
  mail;
@@ -143,6 +145,7 @@ var AutomationsServiceImpl = class {
143
145
  this.mailer = params.mailer;
144
146
  this.lookups = params.lookups;
145
147
  this.integrations = params.integrations;
148
+ this.systemActor = params.systemActor;
146
149
  this.credentials = params.credentials;
147
150
  this.webhooks = params.webhooks;
148
151
  this.mail = {
@@ -396,9 +399,12 @@ var AutomationsServiceImpl = class {
396
399
  }))
397
400
  });
398
401
  }
399
- async create(orgId, input) {
402
+ async create(input, actor) {
403
+ actor.permissions.require("automations:write");
404
+ const orgId = actor.orgId;
400
405
  assertCatalogTriggers(input.triggers, true);
401
406
  assertAuthorableActions(input.actions);
407
+ assertGrantsAllowed(actor, input.actions);
402
408
  const automation = await this.uow.run(async ({ automations, outbox }) => {
403
409
  const created = await automations.insert(orgId, {
404
410
  ...input,
@@ -413,16 +419,22 @@ var AutomationsServiceImpl = class {
413
419
  });
414
420
  this.logger.info("automation created", {
415
421
  orgId,
416
- automationId: automation.id
422
+ automationId: automation.id,
423
+ actorId: actor.id
417
424
  });
418
425
  await this.reconcileSchedules(orgId);
419
426
  return automation;
420
427
  }
421
- async update(orgId, id, input) {
428
+ async update(id, input, actor) {
429
+ actor.permissions.require("automations:write");
430
+ const orgId = actor.orgId;
422
431
  if (input.triggers !== void 0) assertCatalogTriggers(input.triggers, true);
423
- if (input.actions !== void 0) assertAuthorableActions(input.actions);
432
+ if (input.actions !== void 0) {
433
+ assertAuthorableActions(input.actions);
434
+ assertGrantsAllowed(actor, input.actions);
435
+ }
424
436
  const existing = await this.repo.findById(orgId, id);
425
- if (!existing) return null;
437
+ if (!existing) throw new NotFoundError("Automation", id);
426
438
  if (existing.kind !== "workflow") throw new AutomationKindMismatchError(id, existing.kind);
427
439
  const patch = input.triggers === void 0 ? input : {
428
440
  ...input,
@@ -434,20 +446,21 @@ var AutomationsServiceImpl = class {
434
446
  await outbox.append([updateEvent(orgId, input, updated)]);
435
447
  return updated;
436
448
  });
437
- if (automation) {
438
- this.logger.info("automation updated", {
439
- orgId,
440
- automationId: id
441
- });
442
- await this.reconcileSchedules(orgId);
443
- }
449
+ if (!automation) throw new NotFoundError("Automation", id);
450
+ this.logger.info("automation updated", {
451
+ orgId,
452
+ automationId: id
453
+ });
454
+ await this.reconcileSchedules(orgId);
444
455
  return automation;
445
456
  }
446
- async delete(orgId, id) {
457
+ async delete(id, actor) {
458
+ actor.permissions.require("automations:delete");
459
+ const orgId = actor.orgId;
447
460
  const existing = await this.repo.findById(orgId, id);
448
- if (!existing) return false;
461
+ if (!existing) throw new NotFoundError("Automation", id);
449
462
  if (existing.kind !== "workflow") throw new AutomationKindMismatchError(id, existing.kind);
450
- const deleted = await this.uow.run(async ({ automations, outbox }) => {
463
+ if (!await this.uow.run(async ({ automations, outbox }) => {
451
464
  const removed = await automations.delete(orgId, id);
452
465
  if (!removed) return null;
453
466
  await outbox.append([automationEvents.automationDeleted.make({
@@ -455,35 +468,39 @@ var AutomationsServiceImpl = class {
455
468
  data: removed
456
469
  })]);
457
470
  return removed;
471
+ })) throw new NotFoundError("Automation", id);
472
+ this.logger.info("automation deleted", {
473
+ orgId,
474
+ automationId: id
458
475
  });
459
- if (deleted) {
460
- this.logger.info("automation deleted", {
461
- orgId,
462
- automationId: id
463
- });
464
- await this.reconcileSchedules(orgId);
465
- }
466
- return deleted !== null;
476
+ await this.reconcileSchedules(orgId);
467
477
  }
468
- async list(orgId, query) {
469
- return (await this.repo.listByOrg(orgId, query?.kind)).map(toAutomationView);
478
+ async list(query, actor) {
479
+ actor.permissions.require("automations:read");
480
+ return (await this.repo.listByOrg(actor.orgId, query?.kind)).map(toAutomationView);
470
481
  }
471
- async get(orgId, id) {
472
- const automation = await this.repo.findById(orgId, id);
473
- return automation ? toAutomationView(automation) : null;
482
+ async get(id, actor) {
483
+ actor.permissions.require("automations:read");
484
+ const automation = await this.repo.findById(actor.orgId, id);
485
+ if (!automation) throw new NotFoundError("Automation", id);
486
+ return toAutomationView(automation);
474
487
  }
475
- async listRuns(orgId, automationId, query) {
476
- const page = await this.runsRepo.list(orgId, automationId, query);
488
+ async listRuns(automationId, query, actor) {
489
+ actor.permissions.require("automations:read");
490
+ const page = await this.runsRepo.list(actor.orgId, automationId, query);
477
491
  return {
478
492
  ...page,
479
493
  rows: page.rows.map(toRunView)
480
494
  };
481
495
  }
482
- async rerun(orgId, automationId, runId) {
496
+ async rerun(automationId, runId, actor) {
497
+ actor.permissions.require("automations:write");
498
+ const orgId = actor.orgId;
483
499
  const existing = await this.runsRepo.findById(orgId, runId);
484
500
  if (!existing || existing.automationId !== automationId) throw new NotFoundError("Automation run", runId);
485
501
  const automation = await this.repo.findById(orgId, automationId);
486
502
  if (!automation) throw new NotFoundError("Automation", automationId);
503
+ assertGrantsAllowed(actor, automation.actions);
487
504
  const run = await this.uow.run(async ({ runs, outbox }) => {
488
505
  const restarted = await runs.restart(orgId, runId, /* @__PURE__ */ new Date());
489
506
  if (!restarted) return null;
@@ -513,16 +530,20 @@ var AutomationsServiceImpl = class {
513
530
  });
514
531
  return toRunView(run);
515
532
  }
516
- async listWebhooks(orgId) {
517
- return (await this.repo.listByOrg(orgId, "webhook")).map(toWebhook);
533
+ async listWebhooks(actor) {
534
+ actor.permissions.require("automations:read");
535
+ return (await this.repo.listByOrg(actor.orgId, "webhook")).map(toWebhook);
518
536
  }
519
- async getWebhook(orgId, id) {
520
- const automation = await this.findWebhook(orgId, id);
521
- return automation ? toWebhook(automation) : null;
537
+ async getWebhook(id, actor) {
538
+ actor.permissions.require("automations:read");
539
+ return toWebhook(await this.requireWebhook(actor.orgId, id));
522
540
  }
523
- async createWebhook(orgId, input) {
541
+ async createWebhook(input, actor) {
542
+ actor.permissions.require("automations:write");
543
+ const orgId = actor.orgId;
524
544
  const events = unique(input.events);
525
545
  assertCatalogTriggers(events, false);
546
+ assertReadsEvents(actor, events);
526
547
  const secret = generateWebhookSecret();
527
548
  const automation = await this.uow.run(async ({ automations, credentials, outbox }) => {
528
549
  const secretRef = await credentials.store(orgId, { secret });
@@ -554,11 +575,15 @@ var AutomationsServiceImpl = class {
554
575
  secret
555
576
  };
556
577
  }
557
- async updateWebhook(orgId, id, input) {
558
- const existing = await this.findWebhook(orgId, id);
559
- if (!existing) return null;
578
+ async updateWebhook(id, input, actor) {
579
+ actor.permissions.require("automations:write");
580
+ const orgId = actor.orgId;
581
+ const existing = await this.requireWebhook(orgId, id);
560
582
  const events = input.events === void 0 ? void 0 : unique(input.events);
561
- if (events) assertCatalogTriggers(events, false);
583
+ if (events) {
584
+ assertCatalogTriggers(events, false);
585
+ assertReadsEvents(actor, events);
586
+ }
562
587
  const { secretRef } = webhookTarget(existing);
563
588
  const patch = {
564
589
  name: input.url,
@@ -579,18 +604,18 @@ var AutomationsServiceImpl = class {
579
604
  await outbox.append([updateEvent(orgId, input, row)]);
580
605
  return row;
581
606
  });
582
- if (!updated) return null;
607
+ if (!updated) throw new NotFoundError("Webhook", id);
583
608
  this.logger.info("webhook updated", {
584
609
  orgId,
585
610
  automationId: id
586
611
  });
587
612
  return toWebhook(updated);
588
613
  }
589
- async deleteWebhook(orgId, id) {
590
- const existing = await this.findWebhook(orgId, id);
591
- if (!existing) return false;
592
- const { secretRef } = webhookTarget(existing);
593
- const deleted = await this.uow.run(async ({ automations, credentials, outbox }) => {
614
+ async deleteWebhook(id, actor) {
615
+ actor.permissions.require("automations:delete");
616
+ const orgId = actor.orgId;
617
+ const { secretRef } = webhookTarget(await this.requireWebhook(orgId, id));
618
+ if (!await this.uow.run(async ({ automations, credentials, outbox }) => {
594
619
  const removed = await automations.delete(orgId, id);
595
620
  if (!removed) return null;
596
621
  await credentials.destroy(orgId, secretRef);
@@ -599,23 +624,24 @@ var AutomationsServiceImpl = class {
599
624
  data: removed
600
625
  })]);
601
626
  return removed;
602
- });
603
- if (deleted) this.logger.info("webhook deleted", {
627
+ })) throw new NotFoundError("Webhook", id);
628
+ this.logger.info("webhook deleted", {
604
629
  orgId,
605
630
  automationId: id
606
631
  });
607
- return deleted !== null;
608
632
  }
609
- async revealWebhookSecret(orgId, id) {
610
- const existing = await this.findWebhook(orgId, id);
611
- if (!existing) return null;
633
+ async revealWebhookSecret(id, actor) {
634
+ actor.permissions.require("automations:write");
635
+ const orgId = actor.orgId;
636
+ const existing = await this.requireWebhook(orgId, id);
612
637
  const secret = (await this.credentials.reveal(orgId, webhookTarget(existing).secretRef))?.["secret"];
613
638
  if (typeof secret !== "string") throw new Error(`webhook ${id}: signing secret is missing`);
614
639
  return { secret };
615
640
  }
616
- async rotateWebhookSecret(orgId, id) {
617
- const existing = await this.findWebhook(orgId, id);
618
- if (!existing) return null;
641
+ async rotateWebhookSecret(id, actor) {
642
+ actor.permissions.require("automations:write");
643
+ const orgId = actor.orgId;
644
+ const existing = await this.requireWebhook(orgId, id);
619
645
  const secret = generateWebhookSecret();
620
646
  await this.credentials.update(orgId, webhookTarget(existing).secretRef, { secret });
621
647
  this.logger.info("webhook secret rotated", {
@@ -624,19 +650,22 @@ var AutomationsServiceImpl = class {
624
650
  });
625
651
  return { secret };
626
652
  }
627
- async findWebhook(orgId, id) {
653
+ async requireWebhook(orgId, id) {
628
654
  const automation = await this.repo.findById(orgId, id);
629
- return automation?.kind === "webhook" ? automation : null;
655
+ if (automation?.kind !== "webhook") throw new NotFoundError("Webhook", id);
656
+ return automation;
630
657
  }
631
- availableActions() {
632
- return [...catalogActions(), ...this.integrations.available().flatMap((integration) => integration.actions.map((action) => ({
658
+ availableActions(actor) {
659
+ actor.permissions.require("automations:read");
660
+ return [...catalogActions(), ...this.integrations.available(this.systemActor(actor.orgId)).flatMap((integration) => integration.actions.map((action) => ({
633
661
  type: `${integration.id}.${action.id}`,
634
662
  description: action.description,
635
663
  inputSchema: action.inputSchema,
636
664
  source: integration.id
637
665
  })))];
638
666
  }
639
- availableTriggers() {
667
+ availableTriggers(actor) {
668
+ actor.permissions.require("automations:read");
640
669
  return { triggers: catalogTriggers() };
641
670
  }
642
671
  };