@headless-lms/core 0.3.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.
- package/dist/assets/events.d.ts +24 -18
- package/dist/assets/file-urls.d.ts +11 -7
- package/dist/assets/file-urls.js +14 -4
- package/dist/assets/file-urls.js.map +1 -1
- package/dist/assets/index.d.ts +5 -4
- package/dist/assets/index.js +4 -3
- package/dist/assets/jobs.d.ts +15 -0
- package/dist/assets/jobs.js +30 -0
- package/dist/assets/jobs.js.map +1 -0
- package/dist/assets/ports.d.ts +37 -17
- package/dist/assets/service.d.ts +30 -15
- package/dist/assets/service.js +229 -59
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.js +2 -63
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +1 -2
- package/dist/automations/catalog.js +137 -65
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.js +20 -20
- package/dist/automations/community-derivations.js.map +1 -1
- package/dist/automations/community-mail.d.ts +36 -20
- package/dist/automations/community-mail.js +32 -24
- package/dist/automations/community-mail.js.map +1 -1
- package/dist/automations/event-permissions.d.ts +12 -0
- package/dist/automations/event-permissions.js +38 -0
- package/dist/automations/event-permissions.js.map +1 -0
- package/dist/automations/events.d.ts +0 -10
- package/dist/automations/index.d.ts +12 -4
- package/dist/automations/index.js +9 -1
- package/dist/automations/notifications/applicable.d.ts +8 -0
- package/dist/automations/notifications/applicable.js +12 -0
- package/dist/automations/notifications/applicable.js.map +1 -0
- package/dist/automations/notifications/debounce.d.ts +25 -0
- package/dist/automations/notifications/debounce.js +93 -0
- package/dist/automations/notifications/debounce.js.map +1 -0
- package/dist/automations/notifications/defaults.d.ts +8 -0
- package/dist/automations/notifications/defaults.js +346 -0
- package/dist/automations/notifications/defaults.js.map +1 -0
- package/dist/automations/notifications/delivery.d.ts +28 -0
- package/dist/automations/notifications/delivery.js +88 -0
- package/dist/automations/notifications/delivery.js.map +1 -0
- package/dist/automations/notifications/processor.d.ts +64 -0
- package/dist/automations/notifications/processor.js +270 -0
- package/dist/automations/notifications/processor.js.map +1 -0
- package/dist/automations/notifications/rules/content.d.ts +6 -0
- package/dist/automations/notifications/rules/content.js +96 -0
- package/dist/automations/notifications/rules/content.js.map +1 -0
- package/dist/automations/notifications/rules/discussion.d.ts +7 -0
- package/dist/automations/notifications/rules/discussion.js +678 -0
- package/dist/automations/notifications/rules/discussion.js.map +1 -0
- package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
- package/dist/automations/notifications/rules/entitlements.js +276 -0
- package/dist/automations/notifications/rules/entitlements.js.map +1 -0
- package/dist/automations/notifications/rules/events.d.ts +9 -0
- package/dist/automations/notifications/rules/events.js +27 -0
- package/dist/automations/notifications/rules/events.js.map +1 -0
- package/dist/automations/notifications/rules/index.d.ts +6 -0
- package/dist/automations/notifications/rules/index.js +15 -0
- package/dist/automations/notifications/rules/index.js.map +1 -0
- package/dist/automations/notifications/rules/organizations.d.ts +6 -0
- package/dist/automations/notifications/rules/organizations.js +35 -0
- package/dist/automations/notifications/rules/organizations.js.map +1 -0
- package/dist/automations/notifications/rules/recipients.d.ts +32 -0
- package/dist/automations/notifications/rules/recipients.js +98 -0
- package/dist/automations/notifications/rules/recipients.js.map +1 -0
- package/dist/automations/notifications/service.d.ts +29 -0
- package/dist/automations/notifications/service.js +45 -0
- package/dist/automations/notifications/service.js.map +1 -0
- package/dist/automations/notifications/types.d.ts +7 -0
- package/dist/automations/notifications/types.js +560 -0
- package/dist/automations/notifications/types.js.map +1 -0
- package/dist/automations/ports.d.ts +134 -21
- package/dist/automations/service.d.ts +30 -30
- package/dist/automations/service.js +111 -144
- package/dist/automations/service.js.map +1 -1
- package/dist/content/event-sight.d.ts +11 -0
- package/dist/content/event-sight.js +11 -0
- package/dist/content/event-sight.js.map +1 -0
- package/dist/content/events.d.ts +437 -46
- package/dist/content/events.js +45 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +8 -4
- package/dist/content/index.js +5 -1
- package/dist/content/jobs.d.ts +16 -0
- package/dist/content/jobs.js +37 -0
- package/dist/content/jobs.js.map +1 -0
- package/dist/content/model.d.ts +2 -2
- package/dist/content/notification-categories.d.ts +37 -0
- package/dist/content/notification-categories.js +73 -0
- package/dist/content/notification-categories.js.map +1 -0
- package/dist/content/ports.d.ts +132 -68
- package/dist/content/service.d.ts +100 -68
- package/dist/content/service.js +703 -146
- package/dist/content/service.js.map +1 -1
- package/dist/content/titles.d.ts +25 -0
- package/dist/content/titles.js +82 -0
- package/dist/content/titles.js.map +1 -0
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +4 -2
- package/dist/discussion/authors.js +9 -5
- package/dist/discussion/authors.js.map +1 -1
- package/dist/discussion/chats.d.ts +63 -39
- package/dist/discussion/chats.js +455 -190
- package/dist/discussion/chats.js.map +1 -1
- package/dist/discussion/digests.d.ts +24 -0
- package/dist/discussion/digests.js +104 -0
- package/dist/discussion/digests.js.map +1 -0
- package/dist/discussion/events.d.ts +227 -23
- package/dist/discussion/events.js +114 -19
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +12 -4
- package/dist/discussion/index.js +9 -2
- package/dist/discussion/jobs.d.ts +16 -0
- package/dist/discussion/jobs.js +40 -0
- package/dist/discussion/jobs.js.map +1 -0
- package/dist/discussion/live.d.ts +106 -0
- package/dist/discussion/live.js +642 -0
- package/dist/discussion/live.js.map +1 -0
- package/dist/discussion/mentions.d.ts +11 -0
- package/dist/discussion/mentions.js +35 -0
- package/dist/discussion/mentions.js.map +1 -0
- package/dist/discussion/ports.d.ts +279 -114
- package/dist/discussion/ports.js.map +1 -1
- package/dist/discussion/posts.d.ts +60 -44
- package/dist/discussion/posts.js +453 -287
- package/dist/discussion/posts.js.map +1 -1
- package/dist/discussion/rules.d.ts +18 -0
- package/dist/discussion/rules.js +22 -0
- package/dist/discussion/rules.js.map +1 -0
- package/dist/discussion/service.d.ts +50 -35
- package/dist/discussion/service.js +333 -205
- package/dist/discussion/service.js.map +1 -1
- package/dist/discussion/subscriptions.d.ts +37 -0
- package/dist/discussion/subscriptions.js +115 -0
- package/dist/discussion/subscriptions.js.map +1 -0
- package/dist/discussion/titles.d.ts +28 -0
- package/dist/discussion/titles.js +98 -0
- package/dist/discussion/titles.js.map +1 -0
- package/dist/entitlements/events.d.ts +20 -20
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +3 -2
- package/dist/entitlements/jobs.d.ts +12 -0
- package/dist/entitlements/jobs.js +18 -0
- package/dist/entitlements/jobs.js.map +1 -0
- package/dist/entitlements/model.d.ts +2 -2
- package/dist/entitlements/ports.d.ts +68 -38
- package/dist/entitlements/rules.d.ts +3 -6
- package/dist/entitlements/rules.js +5 -10
- package/dist/entitlements/rules.js.map +1 -1
- package/dist/entitlements/service.d.ts +43 -28
- package/dist/entitlements/service.js +387 -160
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/devices.d.ts +30 -0
- package/dist/identity/devices.js +109 -0
- package/dist/identity/devices.js.map +1 -0
- package/dist/identity/index.d.ts +6 -5
- package/dist/identity/index.js +4 -3
- package/dist/identity/model.d.ts +2 -2
- package/dist/identity/notification-settings.d.ts +28 -0
- package/dist/identity/notification-settings.js +114 -0
- package/dist/identity/notification-settings.js.map +1 -0
- package/dist/identity/ports.d.ts +80 -56
- package/dist/identity/service.d.ts +8 -7
- package/dist/identity/service.js +17 -13
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/ports.d.ts +9 -8
- package/dist/integrations/service.d.ts +9 -8
- package/dist/integrations/service.js +33 -16
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/default-roles.d.ts +22 -0
- package/dist/organizations/default-roles.js +89 -0
- package/dist/organizations/default-roles.js.map +1 -0
- package/dist/organizations/effective-permissions.d.ts +45 -0
- package/dist/organizations/effective-permissions.js +113 -0
- package/dist/organizations/effective-permissions.js.map +1 -0
- package/dist/organizations/events.d.ts +320 -181
- package/dist/organizations/events.js +90 -18
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +15 -10
- package/dist/organizations/index.js +8 -3
- package/dist/organizations/members.d.ts +66 -8
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/notification-catalog.d.ts +31 -0
- package/dist/organizations/notification-catalog.js +32 -0
- package/dist/organizations/notification-catalog.js.map +1 -0
- package/dist/organizations/notification-categories.d.ts +34 -0
- package/dist/organizations/notification-categories.js +66 -0
- package/dist/organizations/notification-categories.js.map +1 -0
- package/dist/organizations/org-roles.d.ts +33 -0
- package/dist/organizations/org-roles.js +49 -0
- package/dist/organizations/org-roles.js.map +1 -0
- package/dist/organizations/permissions.d.ts +311 -0
- package/dist/organizations/permissions.js +327 -0
- package/dist/organizations/permissions.js.map +1 -0
- package/dist/organizations/ports.d.ts +187 -65
- package/dist/organizations/service.d.ts +104 -35
- package/dist/organizations/service.js +1247 -323
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/testing.d.ts +18 -0
- package/dist/organizations/testing.js +37 -0
- package/dist/organizations/testing.js.map +1 -0
- package/dist/organizations/types.d.ts +5 -16
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +11 -3
- package/dist/progress/service.d.ts +6 -5
- package/dist/progress/service.js +23 -8
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +6 -4
- package/dist/reporting/admin/model.d.ts +36 -3
- package/dist/reporting/admin/ports.d.ts +39 -14
- package/dist/reporting/admin/service.d.ts +32 -11
- package/dist/reporting/admin/service.js +102 -18
- package/dist/reporting/admin/service.js.map +1 -1
- package/dist/reporting/events/index.d.ts +27 -0
- package/dist/reporting/events/index.js +20 -0
- package/dist/reporting/events/index.js.map +1 -0
- package/dist/reporting/member/calendar.d.ts +11 -0
- package/dist/reporting/member/calendar.js +75 -0
- package/dist/reporting/member/calendar.js.map +1 -0
- package/dist/reporting/member/index.d.ts +3 -2
- package/dist/reporting/member/model.d.ts +80 -26
- package/dist/reporting/member/ports.d.ts +50 -28
- package/dist/reporting/member/service.d.ts +81 -35
- package/dist/reporting/member/service.js +438 -145
- package/dist/reporting/member/service.js.map +1 -1
- package/dist/shared/actor.d.ts +22 -3
- package/dist/shared/errors.d.ts +15 -2
- package/dist/shared/errors.js +21 -2
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +7 -0
- package/dist/shared/id.js +8 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/logger.d.ts +2 -1
- package/dist/shared/logger.js +10 -1
- package/dist/shared/logger.js.map +1 -1
- package/dist/shared/mailer.d.ts +11 -1
- package/dist/shared/mailer.js +32 -5
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/notification-categories.d.ts +16 -0
- package/dist/shared/notification-categories.js +94 -0
- package/dist/shared/notification-categories.js.map +1 -0
- package/dist/shared/notification-settings.d.ts +14 -0
- package/dist/shared/notification-settings.js +61 -0
- package/dist/shared/notification-settings.js.map +1 -0
- package/dist/shared/ports.d.ts +68 -2
- package/dist/shared/settings.d.ts +2 -1
- package/dist/shared/settings.js +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/automations.d.ts +8 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +4 -5
- package/dist/types/email-templates.d.ts +119 -6
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +14 -17
- package/dist/types/index.d.ts +13 -12
- package/dist/types/index.js +2 -1
- package/dist/types/notifications.d.ts +157 -0
- package/dist/types/notifications.js +1 -0
- package/dist/types/organizations.d.ts +3 -2
- package/dist/types/ports.d.ts +8 -1
- package/dist/types/ports.js +7 -1
- package/dist/types/ports.js.map +1 -0
- package/dist/types/schemas/assets.d.ts +5 -5
- package/dist/types/schemas/assets.js +4 -3
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +1 -10
- package/dist/types/schemas/automations.js +1 -3
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +596 -11
- package/dist/types/schemas/content.js +225 -9
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +362 -66
- package/dist/types/schemas/discussion.js +123 -15
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +14 -1
- package/dist/types/schemas/entitlements.js +11 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +1 -85
- package/dist/types/schemas/identity.js +1 -42
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +8 -7
- package/dist/types/schemas/index.js +8 -7
- package/dist/types/schemas/notifications.d.ts +96 -0
- package/dist/types/schemas/notifications.js +57 -0
- package/dist/types/schemas/notifications.js.map +1 -0
- package/dist/types/schemas/organizations.d.ts +96 -60
- package/dist/types/schemas/organizations.js +78 -27
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +0 -1
- package/dist/types/schemas/progress.js +0 -1
- package/dist/types/schemas/progress.js.map +1 -1
- package/package.json +1 -1
- package/dist/automations/community-notifications.d.ts +0 -16
- package/dist/automations/community-notifications.js +0 -84
- package/dist/automations/community-notifications.js.map +0 -1
- package/dist/automations/seeds.d.ts +0 -17
- package/dist/automations/seeds.js +0 -235
- package/dist/automations/seeds.js.map +0 -1
- package/dist/identity/notifications.d.ts +0 -27
- package/dist/identity/notifications.js +0 -101
- package/dist/identity/notifications.js.map +0 -1
- package/dist/organizations/access-scopes.d.ts +0 -19
- package/dist/organizations/access-scopes.js +0 -89
- package/dist/organizations/access-scopes.js.map +0 -1
- package/dist/organizations/roles.d.ts +0 -19
- package/dist/organizations/roles.js +0 -82
- package/dist/organizations/roles.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { deliverWebhookInputSchema } from "../types/schemas/automations.js";
|
|
2
|
-
import { ConflictError, 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
|
-
import { communitySeeds, orgSeeds } from "./seeds.js";
|
|
10
10
|
import { cronSupported } from "./schedule.js";
|
|
11
11
|
//#region src/automations/service.ts
|
|
12
12
|
/** True only when `input` sets `enabled` and nothing else — emits automation.enabled|disabled instead of automation.updated. */
|
|
@@ -23,11 +23,6 @@ function floorMinute(at) {
|
|
|
23
23
|
function unique(values) {
|
|
24
24
|
return [...new Set(values)];
|
|
25
25
|
}
|
|
26
|
-
function recordString(value, key) {
|
|
27
|
-
if (typeof value !== "object" || value === null || !(key in value)) return null;
|
|
28
|
-
const found = value[key];
|
|
29
|
-
return typeof found === "string" ? found : null;
|
|
30
|
-
}
|
|
31
26
|
function filterMatches(filter, data) {
|
|
32
27
|
if (filter == null) return true;
|
|
33
28
|
if (typeof data !== "object" || data === null || Array.isArray(data)) return false;
|
|
@@ -48,8 +43,18 @@ function assertCatalogTriggers(triggers, schedules) {
|
|
|
48
43
|
const known = new Set(catalogTriggers().map((t) => t.type));
|
|
49
44
|
for (const trigger of triggers) if (!(schedules && trigger.startsWith("schedule:")) && !known.has(trigger)) throw new InvalidTriggerError(trigger, "unknown");
|
|
50
45
|
}
|
|
46
|
+
const REMOVED_ACTIONS = /* @__PURE__ */ new Set([
|
|
47
|
+
"notify",
|
|
48
|
+
"publishDuePosts",
|
|
49
|
+
"expireDueGrants",
|
|
50
|
+
"sendDigest",
|
|
51
|
+
"removeUnattachedUploads"
|
|
52
|
+
]);
|
|
51
53
|
function assertAuthorableActions(actions) {
|
|
52
|
-
for (const action of actions)
|
|
54
|
+
for (const action of actions) {
|
|
55
|
+
if (action.type === "deliverWebhook") throw new ReservedActionError(action.type);
|
|
56
|
+
if (REMOVED_ACTIONS.has(action.type)) throw new InvalidInputError(`The action "${action.type}" is no longer available`);
|
|
57
|
+
}
|
|
53
58
|
}
|
|
54
59
|
const SCHEDULE_FIRED = "automation.schedule.fired";
|
|
55
60
|
function publicEventData(event) {
|
|
@@ -124,12 +129,13 @@ var AutomationsServiceImpl = class {
|
|
|
124
129
|
mailer;
|
|
125
130
|
lookups;
|
|
126
131
|
integrations;
|
|
132
|
+
systemActor;
|
|
127
133
|
credentials;
|
|
128
134
|
webhooks;
|
|
129
135
|
mail;
|
|
130
136
|
grants;
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
delivery;
|
|
138
|
+
processor;
|
|
133
139
|
logger;
|
|
134
140
|
constructor(params) {
|
|
135
141
|
this.repo = params.repo;
|
|
@@ -139,6 +145,7 @@ var AutomationsServiceImpl = class {
|
|
|
139
145
|
this.mailer = params.mailer;
|
|
140
146
|
this.lookups = params.lookups;
|
|
141
147
|
this.integrations = params.integrations;
|
|
148
|
+
this.systemActor = params.systemActor;
|
|
142
149
|
this.credentials = params.credentials;
|
|
143
150
|
this.webhooks = params.webhooks;
|
|
144
151
|
this.mail = {
|
|
@@ -146,13 +153,12 @@ var AutomationsServiceImpl = class {
|
|
|
146
153
|
recentMessageRecipients: (orgId, automationId, chatId, since) => this.runsRepo.recentRecipients(orgId, automationId, chatId, since)
|
|
147
154
|
};
|
|
148
155
|
this.grants = params.grants;
|
|
149
|
-
this.
|
|
150
|
-
this.
|
|
156
|
+
this.delivery = params.delivery;
|
|
157
|
+
this.processor = params.processor;
|
|
151
158
|
this.logger = params.logger ?? noopLogger;
|
|
152
159
|
}
|
|
153
160
|
async handle(event) {
|
|
154
161
|
if (event.type.startsWith("automation.")) return;
|
|
155
|
-
await this.seedFor(event);
|
|
156
162
|
const automations = await this.safeListByTrigger(event);
|
|
157
163
|
for (const automation of automations) {
|
|
158
164
|
const matches = filterMatches(automation.filter, event.data);
|
|
@@ -166,50 +172,7 @@ var AutomationsServiceImpl = class {
|
|
|
166
172
|
}
|
|
167
173
|
await this.dispatchOne(automation, event);
|
|
168
174
|
}
|
|
169
|
-
|
|
170
|
-
seedsFor(event) {
|
|
171
|
-
if (event.type === "organization.created") return orgSeeds();
|
|
172
|
-
if (event.type !== "content.community.created") return null;
|
|
173
|
-
const communityId = recordString(event.data, "id");
|
|
174
|
-
if (!communityId) {
|
|
175
|
-
this.logger.error("community seed missing id", {
|
|
176
|
-
orgId: event.orgId,
|
|
177
|
-
eventId: event.id
|
|
178
|
-
});
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
return communitySeeds(communityId);
|
|
182
|
-
}
|
|
183
|
-
async seedFor(event) {
|
|
184
|
-
const rows = this.seedsFor(event);
|
|
185
|
-
if (!rows) return;
|
|
186
|
-
if (await this.uow.run(async ({ automations, outbox }) => {
|
|
187
|
-
const created = [];
|
|
188
|
-
for (const row of rows) {
|
|
189
|
-
const inserted = await automations.insertSeed(event.orgId, {
|
|
190
|
-
name: row.name,
|
|
191
|
-
description: row.description,
|
|
192
|
-
triggers: row.triggers,
|
|
193
|
-
actions: row.actions,
|
|
194
|
-
filter: row.filter,
|
|
195
|
-
kind: "workflow",
|
|
196
|
-
source: "system"
|
|
197
|
-
});
|
|
198
|
-
if (inserted) created.push(automationEvents.automationCreated.make({
|
|
199
|
-
orgId: event.orgId,
|
|
200
|
-
data: inserted
|
|
201
|
-
}));
|
|
202
|
-
}
|
|
203
|
-
if (created.length > 0) {
|
|
204
|
-
await outbox.append(created);
|
|
205
|
-
this.logger.info("system automations seeded", {
|
|
206
|
-
orgId: event.orgId,
|
|
207
|
-
trigger: event.type,
|
|
208
|
-
count: created.length
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return created.length;
|
|
212
|
-
}) > 0) await this.reconcileSchedules(event.orgId);
|
|
175
|
+
await this.processor.process(event);
|
|
213
176
|
}
|
|
214
177
|
async reconcileSchedules(orgId) {
|
|
215
178
|
try {
|
|
@@ -283,7 +246,7 @@ var AutomationsServiceImpl = class {
|
|
|
283
246
|
event
|
|
284
247
|
};
|
|
285
248
|
}
|
|
286
|
-
/** Best-effort: logs and never rethrows
|
|
249
|
+
/** Best-effort: logs and never rethrows, so an org automation never fails `handle`. */
|
|
287
250
|
async recordFailure(run, error) {
|
|
288
251
|
try {
|
|
289
252
|
return await this.uow.run(async ({ runs, outbox }) => {
|
|
@@ -321,8 +284,6 @@ var AutomationsServiceImpl = class {
|
|
|
321
284
|
webhooks: this.webhooks,
|
|
322
285
|
mail: this.mail,
|
|
323
286
|
grants: this.grants,
|
|
324
|
-
desk: this.desk,
|
|
325
|
-
scheduledWork: this.scheduledWork,
|
|
326
287
|
automationId: d.automationId,
|
|
327
288
|
actionInput: action.input,
|
|
328
289
|
logger: this.logger
|
|
@@ -356,6 +317,9 @@ var AutomationsServiceImpl = class {
|
|
|
356
317
|
...failed.length > 0 ? { error: `delivery failed for ${failed.length} recipients: ${failed.join(", ")}` } : {}
|
|
357
318
|
};
|
|
358
319
|
}
|
|
320
|
+
runDelivery(d, lastAttempt) {
|
|
321
|
+
return this.delivery.run(d, lastAttempt);
|
|
322
|
+
}
|
|
359
323
|
async listSchedules() {
|
|
360
324
|
return this.repo.listSchedules();
|
|
361
325
|
}
|
|
@@ -369,13 +333,6 @@ var AutomationsServiceImpl = class {
|
|
|
369
333
|
});
|
|
370
334
|
return;
|
|
371
335
|
}
|
|
372
|
-
if (!await this.scheduleHasWork(orgId, automation, firedAt)) {
|
|
373
|
-
this.logger.debug("schedule idle", {
|
|
374
|
-
orgId,
|
|
375
|
-
automationId
|
|
376
|
-
});
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
336
|
const event = {
|
|
380
337
|
type: SCHEDULE_FIRED,
|
|
381
338
|
id: `schedule_${automationId}_${firedAt.toISOString()}`,
|
|
@@ -389,21 +346,6 @@ var AutomationsServiceImpl = class {
|
|
|
389
346
|
};
|
|
390
347
|
await this.dispatchOne(automation, event);
|
|
391
348
|
}
|
|
392
|
-
async scheduleHasWork(orgId, automation, firedAt) {
|
|
393
|
-
const checks = automation.actions.map((action) => this.pendingWork(action.type));
|
|
394
|
-
const known = checks.filter((check) => check !== null);
|
|
395
|
-
if (checks.length === 0 || known.length < checks.length) return true;
|
|
396
|
-
for (const check of known) if (await check(orgId, firedAt)) return true;
|
|
397
|
-
return false;
|
|
398
|
-
}
|
|
399
|
-
pendingWork(type) {
|
|
400
|
-
switch (type) {
|
|
401
|
-
case "publishDuePosts": return (orgId, now) => this.scheduledWork.hasDuePosts(orgId, now);
|
|
402
|
-
case "expireDueGrants": return (orgId, now) => this.scheduledWork.hasDueGrants(orgId, now);
|
|
403
|
-
case "removeUnattachedUploads": return (orgId, now) => this.scheduledWork.hasUnattachedUploads(orgId, now);
|
|
404
|
-
default: return null;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
349
|
async finalize(d, results) {
|
|
408
350
|
const status = results.length === d.actions.length && results.every((r) => r.status === "completed") ? "completed" : "failed";
|
|
409
351
|
await this.uow.run(async ({ runs, outbox }) => {
|
|
@@ -457,9 +399,12 @@ var AutomationsServiceImpl = class {
|
|
|
457
399
|
}))
|
|
458
400
|
});
|
|
459
401
|
}
|
|
460
|
-
async create(
|
|
402
|
+
async create(input, actor) {
|
|
403
|
+
actor.permissions.require("automations:write");
|
|
404
|
+
const orgId = actor.orgId;
|
|
461
405
|
assertCatalogTriggers(input.triggers, true);
|
|
462
406
|
assertAuthorableActions(input.actions);
|
|
407
|
+
assertGrantsAllowed(actor, input.actions);
|
|
463
408
|
const automation = await this.uow.run(async ({ automations, outbox }) => {
|
|
464
409
|
const created = await automations.insert(orgId, {
|
|
465
410
|
...input,
|
|
@@ -474,16 +419,22 @@ var AutomationsServiceImpl = class {
|
|
|
474
419
|
});
|
|
475
420
|
this.logger.info("automation created", {
|
|
476
421
|
orgId,
|
|
477
|
-
automationId: automation.id
|
|
422
|
+
automationId: automation.id,
|
|
423
|
+
actorId: actor.id
|
|
478
424
|
});
|
|
479
425
|
await this.reconcileSchedules(orgId);
|
|
480
426
|
return automation;
|
|
481
427
|
}
|
|
482
|
-
async update(
|
|
428
|
+
async update(id, input, actor) {
|
|
429
|
+
actor.permissions.require("automations:write");
|
|
430
|
+
const orgId = actor.orgId;
|
|
483
431
|
if (input.triggers !== void 0) assertCatalogTriggers(input.triggers, true);
|
|
484
|
-
if (input.actions !== void 0)
|
|
432
|
+
if (input.actions !== void 0) {
|
|
433
|
+
assertAuthorableActions(input.actions);
|
|
434
|
+
assertGrantsAllowed(actor, input.actions);
|
|
435
|
+
}
|
|
485
436
|
const existing = await this.repo.findById(orgId, id);
|
|
486
|
-
if (!existing)
|
|
437
|
+
if (!existing) throw new NotFoundError("Automation", id);
|
|
487
438
|
if (existing.kind !== "workflow") throw new AutomationKindMismatchError(id, existing.kind);
|
|
488
439
|
const patch = input.triggers === void 0 ? input : {
|
|
489
440
|
...input,
|
|
@@ -495,21 +446,21 @@ var AutomationsServiceImpl = class {
|
|
|
495
446
|
await outbox.append([updateEvent(orgId, input, updated)]);
|
|
496
447
|
return updated;
|
|
497
448
|
});
|
|
498
|
-
if (automation)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
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);
|
|
505
455
|
return automation;
|
|
506
456
|
}
|
|
507
|
-
async delete(
|
|
457
|
+
async delete(id, actor) {
|
|
458
|
+
actor.permissions.require("automations:delete");
|
|
459
|
+
const orgId = actor.orgId;
|
|
508
460
|
const existing = await this.repo.findById(orgId, id);
|
|
509
|
-
if (!existing)
|
|
461
|
+
if (!existing) throw new NotFoundError("Automation", id);
|
|
510
462
|
if (existing.kind !== "workflow") throw new AutomationKindMismatchError(id, existing.kind);
|
|
511
|
-
if (
|
|
512
|
-
const deleted = await this.uow.run(async ({ automations, outbox }) => {
|
|
463
|
+
if (!await this.uow.run(async ({ automations, outbox }) => {
|
|
513
464
|
const removed = await automations.delete(orgId, id);
|
|
514
465
|
if (!removed) return null;
|
|
515
466
|
await outbox.append([automationEvents.automationDeleted.make({
|
|
@@ -517,35 +468,39 @@ var AutomationsServiceImpl = class {
|
|
|
517
468
|
data: removed
|
|
518
469
|
})]);
|
|
519
470
|
return removed;
|
|
471
|
+
})) throw new NotFoundError("Automation", id);
|
|
472
|
+
this.logger.info("automation deleted", {
|
|
473
|
+
orgId,
|
|
474
|
+
automationId: id
|
|
520
475
|
});
|
|
521
|
-
|
|
522
|
-
this.logger.info("automation deleted", {
|
|
523
|
-
orgId,
|
|
524
|
-
automationId: id
|
|
525
|
-
});
|
|
526
|
-
await this.reconcileSchedules(orgId);
|
|
527
|
-
}
|
|
528
|
-
return deleted !== null;
|
|
476
|
+
await this.reconcileSchedules(orgId);
|
|
529
477
|
}
|
|
530
|
-
async list(
|
|
531
|
-
|
|
478
|
+
async list(query, actor) {
|
|
479
|
+
actor.permissions.require("automations:read");
|
|
480
|
+
return (await this.repo.listByOrg(actor.orgId, query?.kind)).map(toAutomationView);
|
|
532
481
|
}
|
|
533
|
-
async get(
|
|
534
|
-
|
|
535
|
-
|
|
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);
|
|
536
487
|
}
|
|
537
|
-
async listRuns(
|
|
538
|
-
|
|
488
|
+
async listRuns(automationId, query, actor) {
|
|
489
|
+
actor.permissions.require("automations:read");
|
|
490
|
+
const page = await this.runsRepo.list(actor.orgId, automationId, query);
|
|
539
491
|
return {
|
|
540
492
|
...page,
|
|
541
493
|
rows: page.rows.map(toRunView)
|
|
542
494
|
};
|
|
543
495
|
}
|
|
544
|
-
async rerun(
|
|
496
|
+
async rerun(automationId, runId, actor) {
|
|
497
|
+
actor.permissions.require("automations:write");
|
|
498
|
+
const orgId = actor.orgId;
|
|
545
499
|
const existing = await this.runsRepo.findById(orgId, runId);
|
|
546
500
|
if (!existing || existing.automationId !== automationId) throw new NotFoundError("Automation run", runId);
|
|
547
501
|
const automation = await this.repo.findById(orgId, automationId);
|
|
548
502
|
if (!automation) throw new NotFoundError("Automation", automationId);
|
|
503
|
+
assertGrantsAllowed(actor, automation.actions);
|
|
549
504
|
const run = await this.uow.run(async ({ runs, outbox }) => {
|
|
550
505
|
const restarted = await runs.restart(orgId, runId, /* @__PURE__ */ new Date());
|
|
551
506
|
if (!restarted) return null;
|
|
@@ -575,16 +530,20 @@ var AutomationsServiceImpl = class {
|
|
|
575
530
|
});
|
|
576
531
|
return toRunView(run);
|
|
577
532
|
}
|
|
578
|
-
async listWebhooks(
|
|
579
|
-
|
|
533
|
+
async listWebhooks(actor) {
|
|
534
|
+
actor.permissions.require("automations:read");
|
|
535
|
+
return (await this.repo.listByOrg(actor.orgId, "webhook")).map(toWebhook);
|
|
580
536
|
}
|
|
581
|
-
async getWebhook(
|
|
582
|
-
|
|
583
|
-
return
|
|
537
|
+
async getWebhook(id, actor) {
|
|
538
|
+
actor.permissions.require("automations:read");
|
|
539
|
+
return toWebhook(await this.requireWebhook(actor.orgId, id));
|
|
584
540
|
}
|
|
585
|
-
async createWebhook(
|
|
541
|
+
async createWebhook(input, actor) {
|
|
542
|
+
actor.permissions.require("automations:write");
|
|
543
|
+
const orgId = actor.orgId;
|
|
586
544
|
const events = unique(input.events);
|
|
587
545
|
assertCatalogTriggers(events, false);
|
|
546
|
+
assertReadsEvents(actor, events);
|
|
588
547
|
const secret = generateWebhookSecret();
|
|
589
548
|
const automation = await this.uow.run(async ({ automations, credentials, outbox }) => {
|
|
590
549
|
const secretRef = await credentials.store(orgId, { secret });
|
|
@@ -616,11 +575,15 @@ var AutomationsServiceImpl = class {
|
|
|
616
575
|
secret
|
|
617
576
|
};
|
|
618
577
|
}
|
|
619
|
-
async updateWebhook(
|
|
620
|
-
|
|
621
|
-
|
|
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);
|
|
622
582
|
const events = input.events === void 0 ? void 0 : unique(input.events);
|
|
623
|
-
if (events)
|
|
583
|
+
if (events) {
|
|
584
|
+
assertCatalogTriggers(events, false);
|
|
585
|
+
assertReadsEvents(actor, events);
|
|
586
|
+
}
|
|
624
587
|
const { secretRef } = webhookTarget(existing);
|
|
625
588
|
const patch = {
|
|
626
589
|
name: input.url,
|
|
@@ -641,18 +604,18 @@ var AutomationsServiceImpl = class {
|
|
|
641
604
|
await outbox.append([updateEvent(orgId, input, row)]);
|
|
642
605
|
return row;
|
|
643
606
|
});
|
|
644
|
-
if (!updated)
|
|
607
|
+
if (!updated) throw new NotFoundError("Webhook", id);
|
|
645
608
|
this.logger.info("webhook updated", {
|
|
646
609
|
orgId,
|
|
647
610
|
automationId: id
|
|
648
611
|
});
|
|
649
612
|
return toWebhook(updated);
|
|
650
613
|
}
|
|
651
|
-
async deleteWebhook(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
const { secretRef } = webhookTarget(
|
|
655
|
-
|
|
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 }) => {
|
|
656
619
|
const removed = await automations.delete(orgId, id);
|
|
657
620
|
if (!removed) return null;
|
|
658
621
|
await credentials.destroy(orgId, secretRef);
|
|
@@ -661,23 +624,24 @@ var AutomationsServiceImpl = class {
|
|
|
661
624
|
data: removed
|
|
662
625
|
})]);
|
|
663
626
|
return removed;
|
|
664
|
-
});
|
|
665
|
-
|
|
627
|
+
})) throw new NotFoundError("Webhook", id);
|
|
628
|
+
this.logger.info("webhook deleted", {
|
|
666
629
|
orgId,
|
|
667
630
|
automationId: id
|
|
668
631
|
});
|
|
669
|
-
return deleted !== null;
|
|
670
632
|
}
|
|
671
|
-
async revealWebhookSecret(
|
|
672
|
-
|
|
673
|
-
|
|
633
|
+
async revealWebhookSecret(id, actor) {
|
|
634
|
+
actor.permissions.require("automations:write");
|
|
635
|
+
const orgId = actor.orgId;
|
|
636
|
+
const existing = await this.requireWebhook(orgId, id);
|
|
674
637
|
const secret = (await this.credentials.reveal(orgId, webhookTarget(existing).secretRef))?.["secret"];
|
|
675
638
|
if (typeof secret !== "string") throw new Error(`webhook ${id}: signing secret is missing`);
|
|
676
639
|
return { secret };
|
|
677
640
|
}
|
|
678
|
-
async rotateWebhookSecret(
|
|
679
|
-
|
|
680
|
-
|
|
641
|
+
async rotateWebhookSecret(id, actor) {
|
|
642
|
+
actor.permissions.require("automations:write");
|
|
643
|
+
const orgId = actor.orgId;
|
|
644
|
+
const existing = await this.requireWebhook(orgId, id);
|
|
681
645
|
const secret = generateWebhookSecret();
|
|
682
646
|
await this.credentials.update(orgId, webhookTarget(existing).secretRef, { secret });
|
|
683
647
|
this.logger.info("webhook secret rotated", {
|
|
@@ -686,19 +650,22 @@ var AutomationsServiceImpl = class {
|
|
|
686
650
|
});
|
|
687
651
|
return { secret };
|
|
688
652
|
}
|
|
689
|
-
async
|
|
653
|
+
async requireWebhook(orgId, id) {
|
|
690
654
|
const automation = await this.repo.findById(orgId, id);
|
|
691
|
-
|
|
655
|
+
if (automation?.kind !== "webhook") throw new NotFoundError("Webhook", id);
|
|
656
|
+
return automation;
|
|
692
657
|
}
|
|
693
|
-
availableActions() {
|
|
694
|
-
|
|
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) => ({
|
|
695
661
|
type: `${integration.id}.${action.id}`,
|
|
696
662
|
description: action.description,
|
|
697
663
|
inputSchema: action.inputSchema,
|
|
698
664
|
source: integration.id
|
|
699
665
|
})))];
|
|
700
666
|
}
|
|
701
|
-
availableTriggers() {
|
|
667
|
+
availableTriggers(actor) {
|
|
668
|
+
actor.permissions.require("automations:read");
|
|
702
669
|
return { triggers: catalogTriggers() };
|
|
703
670
|
}
|
|
704
671
|
};
|