@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.
- package/dist/assets/events.d.ts +42 -24
- package/dist/assets/events.js +1 -1
- package/dist/assets/events.js.map +1 -1
- package/dist/assets/file-urls.d.ts +20 -0
- package/dist/assets/file-urls.js +25 -0
- package/dist/assets/file-urls.js.map +1 -0
- package/dist/assets/index.d.ts +6 -4
- package/dist/assets/index.js +4 -2
- 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/model.d.ts +2 -2
- package/dist/assets/ports.d.ts +46 -15
- package/dist/assets/service.d.ts +38 -7
- package/dist/assets/service.js +287 -38
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.d.ts +13 -24
- package/dist/automations/actions.js +106 -42
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.js +226 -3
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.d.ts +14 -0
- package/dist/automations/community-derivations.js +439 -0
- package/dist/automations/community-derivations.js.map +1 -0
- package/dist/automations/community-mail.d.ts +98 -0
- package/dist/automations/community-mail.js +70 -0
- package/dist/automations/community-mail.js.map +1 -0
- package/dist/automations/events.d.ts +18 -0
- package/dist/automations/index.d.ts +13 -4
- package/dist/automations/index.js +10 -2
- package/dist/automations/model.d.ts +10 -3
- package/dist/automations/model.js +15 -2
- package/dist/automations/model.js.map +1 -1
- 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 +316 -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 +39 -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 +249 -0
- package/dist/automations/notifications/rules/entitlements.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 +28 -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 +99 -0
- package/dist/automations/notifications/rules/recipients.js.map +1 -0
- package/dist/automations/notifications/service.d.ts +27 -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 +473 -0
- package/dist/automations/notifications/types.js.map +1 -0
- package/dist/automations/ports.d.ts +121 -3
- package/dist/automations/schedule.d.ts +6 -0
- package/dist/automations/schedule.js +41 -0
- package/dist/automations/schedule.js.map +1 -0
- package/dist/automations/service.d.ts +20 -4
- package/dist/automations/service.js +246 -45
- package/dist/automations/service.js.map +1 -1
- package/dist/content/events.d.ts +712 -50
- package/dist/content/events.js +55 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +6 -4
- package/dist/content/index.js +3 -1
- package/dist/content/model.d.ts +2 -2
- package/dist/content/notification-categories.d.ts +36 -0
- package/dist/content/notification-categories.js +64 -0
- package/dist/content/notification-categories.js.map +1 -0
- package/dist/content/ports.d.ts +90 -18
- package/dist/content/service.d.ts +57 -18
- package/dist/content/service.js +520 -25
- package/dist/content/service.js.map +1 -1
- package/dist/content/titles.d.ts +22 -0
- package/dist/content/titles.js +69 -0
- package/dist/content/titles.js.map +1 -0
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +10 -0
- package/dist/discussion/authors.js +23 -0
- package/dist/discussion/authors.js.map +1 -0
- package/dist/discussion/chats.d.ts +109 -0
- package/dist/discussion/chats.js +831 -0
- package/dist/discussion/chats.js.map +1 -0
- 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 +785 -56
- package/dist/discussion/events.js +165 -5
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +12 -3
- package/dist/discussion/index.js +9 -1
- 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/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 +372 -28
- package/dist/discussion/ports.js +6 -1
- package/dist/discussion/ports.js.map +1 -0
- package/dist/discussion/posts.d.ts +113 -0
- package/dist/discussion/posts.js +775 -0
- package/dist/discussion/posts.js.map +1 -0
- package/dist/discussion/service.d.ts +42 -11
- package/dist/discussion/service.js +364 -85
- package/dist/discussion/service.js.map +1 -1
- package/dist/discussion/subscriptions.d.ts +37 -0
- package/dist/discussion/subscriptions.js +99 -0
- package/dist/discussion/subscriptions.js.map +1 -0
- package/dist/discussion/titles.d.ts +26 -0
- package/dist/discussion/titles.js +84 -0
- package/dist/discussion/titles.js.map +1 -0
- package/dist/entitlements/events.d.ts +178 -11
- package/dist/entitlements/events.js +28 -1
- package/dist/entitlements/events.js.map +1 -1
- package/dist/entitlements/index.d.ts +6 -4
- package/dist/entitlements/index.js +3 -1
- 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 +3 -2
- package/dist/entitlements/ports.d.ts +128 -11
- package/dist/entitlements/rules.d.ts +12 -0
- package/dist/entitlements/rules.js +17 -0
- package/dist/entitlements/rules.js.map +1 -0
- package/dist/entitlements/service.d.ts +57 -3
- package/dist/entitlements/service.js +492 -2
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/access.d.ts +6 -0
- package/dist/identity/access.js +7 -0
- package/dist/identity/access.js.map +1 -0
- package/dist/identity/devices.d.ts +30 -0
- package/dist/identity/devices.js +107 -0
- package/dist/identity/devices.js.map +1 -0
- package/dist/identity/events.d.ts +2 -2
- package/dist/identity/index.d.ts +7 -4
- package/dist/identity/index.js +4 -1
- package/dist/identity/model.d.ts +2 -1
- package/dist/identity/notification-settings.d.ts +28 -0
- package/dist/identity/notification-settings.js +113 -0
- package/dist/identity/notification-settings.js.map +1 -0
- package/dist/identity/ports.d.ts +97 -3
- package/dist/identity/service.d.ts +14 -3
- package/dist/identity/service.js +62 -5
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/events.d.ts +3 -3
- package/dist/integrations/model.js +1 -1
- package/dist/integrations/model.js.map +1 -1
- package/dist/integrations/service.js +2 -2
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/access-scopes.d.ts +19 -0
- package/dist/organizations/access-scopes.js +89 -0
- package/dist/organizations/access-scopes.js.map +1 -0
- package/dist/organizations/events.d.ts +75 -33
- package/dist/organizations/events.js +6 -0
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +8 -6
- package/dist/organizations/index.js +5 -3
- package/dist/organizations/members.d.ts +8 -5
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/notification-categories.d.ts +32 -0
- package/dist/organizations/notification-categories.js +51 -0
- package/dist/organizations/notification-categories.js.map +1 -0
- package/dist/organizations/ports.d.ts +17 -11
- package/dist/organizations/roles.d.ts +6 -10
- package/dist/organizations/roles.js +19 -7
- package/dist/organizations/roles.js.map +1 -1
- package/dist/organizations/service.d.ts +22 -11
- package/dist/organizations/service.js +164 -47
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +1 -10
- package/dist/progress/events.d.ts +14 -14
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +6 -1
- package/dist/progress/service.d.ts +3 -1
- package/dist/progress/service.js +6 -2
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +4 -0
- package/dist/reporting/admin/index.js +2 -0
- package/dist/reporting/admin/model.d.ts +108 -0
- package/dist/reporting/admin/ports.d.ts +27 -0
- package/dist/reporting/admin/service.d.ts +22 -0
- package/dist/reporting/admin/service.js +38 -0
- package/dist/reporting/admin/service.js.map +1 -0
- package/dist/reporting/member/index.d.ts +5 -0
- package/dist/reporting/member/index.js +2 -0
- package/dist/reporting/member/model.d.ts +157 -0
- package/dist/reporting/member/ports.d.ts +48 -0
- package/dist/reporting/member/service.d.ts +92 -0
- package/dist/reporting/member/service.js +364 -0
- package/dist/reporting/member/service.js.map +1 -0
- package/dist/shared/actor.d.ts +9 -0
- package/dist/shared/errors.d.ts +19 -1
- package/dist/shared/errors.js +27 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +14 -0
- package/dist/shared/id.js +15 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/mailer.d.ts +15 -2
- package/dist/shared/mailer.js +32 -5
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/network.d.ts +10 -0
- package/dist/shared/network.js +211 -0
- package/dist/shared/network.js.map +1 -0
- 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 +48 -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/assets.d.ts +2 -2
- package/dist/types/automations.d.ts +15 -1
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +11 -3
- package/dist/types/email-templates.d.ts +216 -1
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +48 -2
- package/dist/types/index.d.ts +9 -8
- package/dist/types/notifications.d.ts +157 -0
- package/dist/types/ports.d.ts +6 -0
- package/dist/types/schemas/assets.d.ts +65 -37
- package/dist/types/schemas/assets.js +17 -12
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +9 -1
- package/dist/types/schemas/automations.js +13 -6
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +396 -3
- package/dist/types/schemas/content.js +161 -3
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +443 -3
- package/dist/types/schemas/discussion.js +233 -4
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +36 -2
- package/dist/types/schemas/entitlements.js +23 -1
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +27 -1
- package/dist/types/schemas/identity.js +14 -2
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +9 -8
- package/dist/types/schemas/index.js +9 -8
- package/dist/types/schemas/notifications.d.ts +95 -0
- package/dist/types/schemas/notifications.js +56 -0
- package/dist/types/schemas/notifications.js.map +1 -0
- package/dist/types/schemas/organizations.d.ts +8 -0
- package/dist/types/schemas/organizations.js +2 -0
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +3 -3
- package/dist/types/schemas/shared.d.ts +3 -1
- package/dist/types/schemas/shared.js +5 -1
- package/dist/types/schemas/shared.js.map +1 -1
- package/package.json +2 -2
- package/dist/reporting/courses/index.d.ts +0 -4
- package/dist/reporting/courses/index.js +0 -2
- package/dist/reporting/courses/model.d.ts +0 -24
- package/dist/reporting/courses/ports.d.ts +0 -13
- package/dist/reporting/courses/service.d.ts +0 -19
- package/dist/reporting/courses/service.js +0 -20
- package/dist/reporting/courses/service.js.map +0 -1
- package/dist/reporting/dashboard/index.d.ts +0 -4
- package/dist/reporting/dashboard/index.js +0 -2
- package/dist/reporting/dashboard/model.d.ts +0 -14
- package/dist/reporting/dashboard/ports.d.ts +0 -13
- package/dist/reporting/dashboard/service.d.ts +0 -19
- package/dist/reporting/dashboard/service.js +0 -20
- package/dist/reporting/dashboard/service.js.map +0 -1
- package/dist/reporting/learn/index.d.ts +0 -5
- package/dist/reporting/learn/index.js +0 -2
- package/dist/reporting/learn/model.d.ts +0 -23
- package/dist/reporting/learn/ports.d.ts +0 -43
- package/dist/reporting/learn/service.d.ts +0 -49
- package/dist/reporting/learn/service.js +0 -116
- package/dist/reporting/learn/service.js.map +0 -1
- package/dist/reporting/students/index.d.ts +0 -4
- package/dist/reporting/students/index.js +0 -2
- package/dist/reporting/students/model.d.ts +0 -51
- package/dist/reporting/students/model.js +0 -1
- package/dist/reporting/students/ports.d.ts +0 -15
- package/dist/reporting/students/ports.js +0 -1
- package/dist/reporting/students/service.d.ts +0 -20
- package/dist/reporting/students/service.js +0 -23
- package/dist/reporting/students/service.js.map +0 -1
- /package/dist/reporting/{courses → admin}/model.js +0 -0
- /package/dist/reporting/{courses → admin}/ports.js +0 -0
- /package/dist/reporting/{dashboard → member}/model.js +0 -0
- /package/dist/reporting/{dashboard → member}/ports.js +0 -0
- /package/dist/{reporting/learn/model.js → shared/actor.js} +0 -0
- /package/dist/{reporting/learn/ports.js → types/notifications.js} +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { noopLogger } from "../shared/logger.js";
|
|
2
|
+
//#region src/automations/community-mail.ts
|
|
3
|
+
const MESSAGE_EXCERPT = 140;
|
|
4
|
+
const POST_EXCERPT = 280;
|
|
5
|
+
const MESSAGE_BATCH_MS = 900 * 1e3;
|
|
6
|
+
const emptyCommunityMail = {
|
|
7
|
+
communityTitle: async () => null,
|
|
8
|
+
space: async () => null,
|
|
9
|
+
openSpaceNames: async () => [],
|
|
10
|
+
communitiesOpenedBy: async () => [],
|
|
11
|
+
communityMembersAmong: async () => [],
|
|
12
|
+
spaceOpenersAmong: async () => [],
|
|
13
|
+
spaceOpeners: async () => [],
|
|
14
|
+
moderationAudience: async () => [],
|
|
15
|
+
staffIds: async () => [],
|
|
16
|
+
displayName: async () => "A member",
|
|
17
|
+
followerIds: async () => [],
|
|
18
|
+
comment: async () => null,
|
|
19
|
+
post: async () => null,
|
|
20
|
+
chat: async () => null,
|
|
21
|
+
latestMessageBody: async () => null,
|
|
22
|
+
pairBlocked: async () => false,
|
|
23
|
+
activeMemberCount: async () => 0,
|
|
24
|
+
memberCommunityTitles: async () => [],
|
|
25
|
+
recentMessageRecipients: async () => []
|
|
26
|
+
};
|
|
27
|
+
function actorOf(event) {
|
|
28
|
+
const value = event.metadata?.actorOrgUserId;
|
|
29
|
+
return typeof value === "string" ? value : void 0;
|
|
30
|
+
}
|
|
31
|
+
function previousStatusOf(event) {
|
|
32
|
+
const value = event.metadata?.previousStatus;
|
|
33
|
+
return typeof value === "string" ? value : void 0;
|
|
34
|
+
}
|
|
35
|
+
function excerpt(value, max) {
|
|
36
|
+
const flat = value.replace(/\s+/g, " ").trim();
|
|
37
|
+
return flat.length <= max ? flat : flat.slice(0, max);
|
|
38
|
+
}
|
|
39
|
+
function seededCommunityId(deps) {
|
|
40
|
+
const id = deps.actionInput["communityId"];
|
|
41
|
+
return typeof id === "string" ? id : null;
|
|
42
|
+
}
|
|
43
|
+
async function address(deps, event, orgId, orgUserIds, params) {
|
|
44
|
+
const actor = actorOf(event);
|
|
45
|
+
const wanted = [...new Set(orgUserIds)].filter((id) => id !== actor);
|
|
46
|
+
if (wanted.length === 0) return [];
|
|
47
|
+
const recipients = [];
|
|
48
|
+
const logger = deps.logger ?? noopLogger;
|
|
49
|
+
for (const orgUserId of wanted) {
|
|
50
|
+
const person = await deps.lookups.orgUserPerson(orgId, orgUserId);
|
|
51
|
+
if (!person) {
|
|
52
|
+
logger.warn("email skipped: recipient has no address", {
|
|
53
|
+
orgId,
|
|
54
|
+
orgUserId
|
|
55
|
+
});
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
recipients.push({
|
|
59
|
+
to: person.email,
|
|
60
|
+
orgUserId,
|
|
61
|
+
userId: person.userId,
|
|
62
|
+
params
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return recipients;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { MESSAGE_BATCH_MS, MESSAGE_EXCERPT, POST_EXCERPT, actorOf, address, emptyCommunityMail, excerpt, previousStatusOf, seededCommunityId };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=community-mail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-mail.js","names":[],"sources":["../../src/automations/community-mail.ts"],"sourcesContent":["import type { GrantEntitlementInput } from '../entitlements/index.js';\nimport type {\n ChatStatus,\n EmailTemplateId,\n EmailTemplateParams,\n JsonValue,\n} from '../types/index.js';\nimport type { Mailer, MailerLookups } from '../shared/mailer.js';\nimport type { CredentialStore, DomainEvent, Logger } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport type { WebhookSender } from './ports.js';\n\nexport const MESSAGE_EXCERPT = 140;\nexport const POST_EXCERPT = 280;\nexport const MESSAGE_BATCH_MS = 15 * 60 * 1000;\n\nexport interface EmailRecipient<K extends EmailTemplateId = EmailTemplateId> {\n to: string;\n orgUserId: string;\n userId: string;\n params: EmailTemplateParams[K];\n}\n\nexport interface CommunityMailReads {\n communityTitle(orgId: string, communityId: string): Promise<string | null>;\n space(\n orgId: string,\n spaceId: string,\n ): Promise<{ name: string; communityId: string; capacity: number | null } | null>;\n openSpaceNames(orgId: string, orgUserId: string, communityId: string): Promise<string[]>;\n communitiesOpenedBy(\n orgId: string,\n grant: { contentId: string | null; bundleId: string | null },\n ): Promise<string[]>;\n communityMembersAmong(orgId: string, communityId: string, ids: string[]): Promise<string[]>;\n spaceOpenersAmong(orgId: string, spaceId: string, ids: string[]): Promise<string[]>;\n spaceOpeners(orgId: string, spaceId: string): Promise<string[]>;\n moderationAudience(orgId: string, communityId: string): Promise<string[]>;\n staffIds(orgId: string): Promise<string[]>;\n displayName(orgId: string, orgUserId: string): Promise<string>;\n followerIds(orgId: string, postId: string): Promise<string[]>;\n comment(\n orgId: string,\n commentId: string,\n ): Promise<{\n orgUserId: string;\n postId: string | null;\n activityId: string | null;\n parentId: string | null;\n body: string;\n } | null>;\n post(\n orgId: string,\n postId: string,\n ): Promise<{\n title: string;\n body: string;\n spaceId: string;\n orgUserId: string;\n communityId: string;\n } | null>;\n chat(\n orgId: string,\n chatId: string,\n ): Promise<{\n communityId: string;\n kind: 'direct' | 'group';\n status: ChatStatus;\n createdBy: string | null;\n participants: {\n orgUserId: string;\n muted: boolean;\n mutedUntil: Date | null;\n leftAt: Date | null;\n }[];\n } | null>;\n latestMessageBody(orgId: string, chatId: string): Promise<string | null>;\n pairBlocked(orgId: string, communityId: string, a: string, b: string): Promise<boolean>;\n activeMemberCount(orgId: string, spaceId: string): Promise<number>;\n memberCommunityTitles(orgId: string, orgUserId: string): Promise<{ id: string; title: string }[]>;\n recentMessageRecipients(\n orgId: string,\n automationId: string,\n chatId: string,\n since: Date,\n ): Promise<string[]>;\n}\n\nexport interface GrantWriter {\n grant(orgId: string, input: GrantEntitlementInput): Promise<unknown>;\n}\n\nexport interface ActionDeps {\n mailer: Pick<Mailer, 'send'>;\n lookups: MailerLookups;\n credentials: Pick<CredentialStore, 'reveal'>;\n webhooks: WebhookSender;\n mail: CommunityMailReads;\n grants: GrantWriter;\n automationId: string;\n actionInput: Record<string, JsonValue>;\n logger?: Logger;\n}\n\nexport const emptyCommunityMail: CommunityMailReads = {\n communityTitle: async () => null,\n space: async () => null,\n openSpaceNames: async () => [],\n communitiesOpenedBy: async () => [],\n communityMembersAmong: async () => [],\n spaceOpenersAmong: async () => [],\n spaceOpeners: async () => [],\n moderationAudience: async () => [],\n staffIds: async () => [],\n displayName: async () => 'A member',\n followerIds: async () => [],\n comment: async () => null,\n post: async () => null,\n chat: async () => null,\n latestMessageBody: async () => null,\n pairBlocked: async () => false,\n activeMemberCount: async () => 0,\n memberCommunityTitles: async () => [],\n recentMessageRecipients: async () => [],\n};\n\nexport function actorOf(event: DomainEvent): string | undefined {\n const value = event.metadata?.actorOrgUserId;\n return typeof value === 'string' ? value : undefined;\n}\n\nexport function previousStatusOf(event: DomainEvent): string | undefined {\n const value = event.metadata?.previousStatus;\n return typeof value === 'string' ? value : undefined;\n}\n\nexport function excerpt(value: string, max: number): string {\n const flat = value.replace(/\\s+/g, ' ').trim();\n return flat.length <= max ? flat : flat.slice(0, max);\n}\n\nexport function seededCommunityId(deps: ActionDeps): string | null {\n const id = deps.actionInput['communityId'];\n return typeof id === 'string' ? id : null;\n}\n\nexport async function address<K extends EmailTemplateId>(\n deps: ActionDeps,\n event: DomainEvent,\n orgId: string,\n orgUserIds: string[],\n params: EmailTemplateParams[K],\n): Promise<EmailRecipient<K>[] | undefined> {\n const actor = actorOf(event);\n const wanted = [...new Set(orgUserIds)].filter((id) => id !== actor);\n if (wanted.length === 0) {\n return [];\n }\n const recipients: EmailRecipient<K>[] = [];\n const logger = deps.logger ?? noopLogger;\n for (const orgUserId of wanted) {\n const person = await deps.lookups.orgUserPerson(orgId, orgUserId);\n if (!person) {\n logger.warn('email skipped: recipient has no address', { orgId, orgUserId });\n continue;\n }\n recipients.push({ to: person.email, orgUserId, userId: person.userId, params });\n }\n return recipients;\n}\n"],"mappings":";;AAYA,MAAa,kBAAkB;AAC/B,MAAa,eAAe;AAC5B,MAAa,mBAAmB,MAAU;AA0F1C,MAAa,qBAAyC;CACpD,gBAAgB,YAAY;CAC5B,OAAO,YAAY;CACnB,gBAAgB,YAAY,CAAC;CAC7B,qBAAqB,YAAY,CAAC;CAClC,uBAAuB,YAAY,CAAC;CACpC,mBAAmB,YAAY,CAAC;CAChC,cAAc,YAAY,CAAC;CAC3B,oBAAoB,YAAY,CAAC;CACjC,UAAU,YAAY,CAAC;CACvB,aAAa,YAAY;CACzB,aAAa,YAAY,CAAC;CAC1B,SAAS,YAAY;CACrB,MAAM,YAAY;CAClB,MAAM,YAAY;CAClB,mBAAmB,YAAY;CAC/B,aAAa,YAAY;CACzB,mBAAmB,YAAY;CAC/B,uBAAuB,YAAY,CAAC;CACpC,yBAAyB,YAAY,CAAC;AACxC;AAEA,SAAgB,QAAQ,OAAwC;CAC9D,MAAM,QAAQ,MAAM,UAAU;CAC9B,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,SAAgB,iBAAiB,OAAwC;CACvE,MAAM,QAAQ,MAAM,UAAU;CAC9B,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,SAAgB,QAAQ,OAAe,KAAqB;CAC1D,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;CAC7C,OAAO,KAAK,UAAU,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG;AACtD;AAEA,SAAgB,kBAAkB,MAAiC;CACjE,MAAM,KAAK,KAAK,YAAY;CAC5B,OAAO,OAAO,OAAO,WAAW,KAAK;AACvC;AAEA,eAAsB,QACpB,MACA,OACA,OACA,YACA,QAC0C;CAC1C,MAAM,QAAQ,QAAQ,KAAK;CAC3B,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,QAAQ,OAAO,OAAO,KAAK;CACnE,IAAI,OAAO,WAAW,GACpB,OAAO,CAAC;CAEV,MAAM,aAAkC,CAAC;CACzC,MAAM,SAAS,KAAK,UAAU;CAC9B,KAAK,MAAM,aAAa,QAAQ;EAC9B,MAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,OAAO,SAAS;EAChE,IAAI,CAAC,QAAQ;GACX,OAAO,KAAK,2CAA2C;IAAE;IAAO;GAAU,CAAC;GAC3E;EACF;EACA,WAAW,KAAK;GAAE,IAAI,OAAO;GAAO;GAAW,QAAQ,OAAO;GAAQ;EAAO,CAAC;CAChF;CACA,OAAO;AACT"}
|
|
@@ -15,6 +15,7 @@ declare const automationEvents: {
|
|
|
15
15
|
input: Record<string, JsonValue>;
|
|
16
16
|
}[];
|
|
17
17
|
enabled: boolean;
|
|
18
|
+
filter: Record<string, JsonValue> | null;
|
|
18
19
|
createdAt: Date;
|
|
19
20
|
updatedAt: Date;
|
|
20
21
|
}, "automation.created", 2>, {
|
|
@@ -29,6 +30,7 @@ declare const automationEvents: {
|
|
|
29
30
|
input: Record<string, unknown>;
|
|
30
31
|
}[];
|
|
31
32
|
enabled: boolean;
|
|
33
|
+
filter: Record<string, unknown> | null;
|
|
32
34
|
createdAt: unknown;
|
|
33
35
|
updatedAt: unknown;
|
|
34
36
|
}, undefined>;
|
|
@@ -44,6 +46,7 @@ declare const automationEvents: {
|
|
|
44
46
|
input: Record<string, JsonValue>;
|
|
45
47
|
}[];
|
|
46
48
|
enabled: boolean;
|
|
49
|
+
filter: Record<string, JsonValue> | null;
|
|
47
50
|
createdAt: Date;
|
|
48
51
|
updatedAt: Date;
|
|
49
52
|
}, "automation.updated", 2>, {
|
|
@@ -58,6 +61,7 @@ declare const automationEvents: {
|
|
|
58
61
|
input: Record<string, unknown>;
|
|
59
62
|
}[];
|
|
60
63
|
enabled: boolean;
|
|
64
|
+
filter: Record<string, unknown> | null;
|
|
61
65
|
createdAt: unknown;
|
|
62
66
|
updatedAt: unknown;
|
|
63
67
|
}, undefined>;
|
|
@@ -73,6 +77,7 @@ declare const automationEvents: {
|
|
|
73
77
|
input: Record<string, JsonValue>;
|
|
74
78
|
}[];
|
|
75
79
|
enabled: boolean;
|
|
80
|
+
filter: Record<string, JsonValue> | null;
|
|
76
81
|
createdAt: Date;
|
|
77
82
|
updatedAt: Date;
|
|
78
83
|
}, "automation.deleted", 2>, {
|
|
@@ -87,6 +92,7 @@ declare const automationEvents: {
|
|
|
87
92
|
input: Record<string, unknown>;
|
|
88
93
|
}[];
|
|
89
94
|
enabled: boolean;
|
|
95
|
+
filter: Record<string, unknown> | null;
|
|
90
96
|
createdAt: unknown;
|
|
91
97
|
updatedAt: unknown;
|
|
92
98
|
}, undefined>;
|
|
@@ -102,6 +108,7 @@ declare const automationEvents: {
|
|
|
102
108
|
input: Record<string, JsonValue>;
|
|
103
109
|
}[];
|
|
104
110
|
enabled: boolean;
|
|
111
|
+
filter: Record<string, JsonValue> | null;
|
|
105
112
|
createdAt: Date;
|
|
106
113
|
updatedAt: Date;
|
|
107
114
|
}, "automation.enabled", 2>, {
|
|
@@ -116,6 +123,7 @@ declare const automationEvents: {
|
|
|
116
123
|
input: Record<string, unknown>;
|
|
117
124
|
}[];
|
|
118
125
|
enabled: boolean;
|
|
126
|
+
filter: Record<string, unknown> | null;
|
|
119
127
|
createdAt: unknown;
|
|
120
128
|
updatedAt: unknown;
|
|
121
129
|
}, undefined>;
|
|
@@ -131,6 +139,7 @@ declare const automationEvents: {
|
|
|
131
139
|
input: Record<string, JsonValue>;
|
|
132
140
|
}[];
|
|
133
141
|
enabled: boolean;
|
|
142
|
+
filter: Record<string, JsonValue> | null;
|
|
134
143
|
createdAt: Date;
|
|
135
144
|
updatedAt: Date;
|
|
136
145
|
}, "automation.disabled", 2>, {
|
|
@@ -145,6 +154,7 @@ declare const automationEvents: {
|
|
|
145
154
|
input: Record<string, unknown>;
|
|
146
155
|
}[];
|
|
147
156
|
enabled: boolean;
|
|
157
|
+
filter: Record<string, unknown> | null;
|
|
148
158
|
createdAt: unknown;
|
|
149
159
|
updatedAt: unknown;
|
|
150
160
|
}, undefined>;
|
|
@@ -161,6 +171,7 @@ declare const automationEvents: {
|
|
|
161
171
|
type: string;
|
|
162
172
|
status: "completed" | "failed";
|
|
163
173
|
error?: string | undefined;
|
|
174
|
+
recipients?: string[] | undefined;
|
|
164
175
|
}[];
|
|
165
176
|
startedAt: Date;
|
|
166
177
|
finishedAt: Date | null;
|
|
@@ -179,6 +190,7 @@ declare const automationEvents: {
|
|
|
179
190
|
type: string;
|
|
180
191
|
status: "completed" | "failed";
|
|
181
192
|
error?: string | undefined;
|
|
193
|
+
recipients?: string[] | undefined;
|
|
182
194
|
}[];
|
|
183
195
|
startedAt: unknown;
|
|
184
196
|
finishedAt: unknown;
|
|
@@ -198,6 +210,7 @@ declare const automationEvents: {
|
|
|
198
210
|
type: string;
|
|
199
211
|
status: "completed" | "failed";
|
|
200
212
|
error?: string | undefined;
|
|
213
|
+
recipients?: string[] | undefined;
|
|
201
214
|
}[];
|
|
202
215
|
startedAt: Date;
|
|
203
216
|
finishedAt: Date | null;
|
|
@@ -216,6 +229,7 @@ declare const automationEvents: {
|
|
|
216
229
|
type: string;
|
|
217
230
|
status: "completed" | "failed";
|
|
218
231
|
error?: string | undefined;
|
|
232
|
+
recipients?: string[] | undefined;
|
|
219
233
|
}[];
|
|
220
234
|
startedAt: unknown;
|
|
221
235
|
finishedAt: unknown;
|
|
@@ -235,6 +249,7 @@ declare const automationEvents: {
|
|
|
235
249
|
type: string;
|
|
236
250
|
status: "completed" | "failed";
|
|
237
251
|
error?: string | undefined;
|
|
252
|
+
recipients?: string[] | undefined;
|
|
238
253
|
}[];
|
|
239
254
|
startedAt: Date;
|
|
240
255
|
finishedAt: Date | null;
|
|
@@ -253,6 +268,7 @@ declare const automationEvents: {
|
|
|
253
268
|
type: string;
|
|
254
269
|
status: "completed" | "failed";
|
|
255
270
|
error?: string | undefined;
|
|
271
|
+
recipients?: string[] | undefined;
|
|
256
272
|
}[];
|
|
257
273
|
startedAt: unknown;
|
|
258
274
|
finishedAt: unknown;
|
|
@@ -264,11 +280,13 @@ declare const automationEvents: {
|
|
|
264
280
|
type: string;
|
|
265
281
|
status: "completed" | "failed";
|
|
266
282
|
error?: string | undefined;
|
|
283
|
+
recipients?: string[] | undefined;
|
|
267
284
|
}, "automation.action.failed", 1>, {
|
|
268
285
|
index: number;
|
|
269
286
|
type: string;
|
|
270
287
|
status: "completed" | "failed";
|
|
271
288
|
error?: string | undefined;
|
|
289
|
+
recipients?: string[] | undefined;
|
|
272
290
|
}, undefined>;
|
|
273
291
|
};
|
|
274
292
|
type AutomationCreated = EventOf<typeof automationEvents.automationCreated>;
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { Page } from "../types/shared.js";
|
|
2
2
|
import { Automation, AutomationAction, AutomationActionResult, AutomationKind, AutomationRun, AutomationRunStatus, AutomationRunsQuery, AutomationTrigger, AutomationsQuery, AvailableAction, 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";
|
|
4
|
-
import { AutomationKindMismatchError, InvalidTriggerError, ReservedActionError } from "./model.js";
|
|
3
|
+
import { AutomationDispatch, AutomationEngine, AutomationExecutor, DeliveryDispatch, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
|
|
4
|
+
import { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, InvalidTriggerError, ReservedActionError, actionFailureMessage } from "./model.js";
|
|
5
5
|
import "./types.js";
|
|
6
|
-
import { AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsUnitOfWork, NewAutomation, NewAutomationRun } from "./ports.js";
|
|
6
|
+
import { AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsUnitOfWork, ChatDebounce, ListedNotification, NewAutomation, NewAutomationRun, NewDelivery, NewNotification, NotificationCategories, NotificationPage, NotificationReads, NotificationsRepository, NotificationsService, RecipientRule, UnreadCounts } from "./ports.js";
|
|
7
|
+
import { CommunityMailReads, GrantWriter } from "./community-mail.js";
|
|
7
8
|
import { AutomationActionFailed, AutomationCreated, AutomationDeleted, AutomationDisabled, AutomationEnabled, AutomationEvent, AutomationRunCompleted, AutomationRunFailed, AutomationRunStarted, AutomationUpdated, automationEvents } from "./events.js";
|
|
9
|
+
import { CHANNEL_NOT_CONFIGURED, NOT_ACCEPTED, NO_ADDRESS, NotificationDelivery } from "./notifications/delivery.js";
|
|
10
|
+
import { DEVICE_WINDOW_MS, IN_APP, MESSAGE_SENT, NotificationProcessor, PUSH } from "./notifications/processor.js";
|
|
8
11
|
import { AutomationsServiceImpl } from "./service.js";
|
|
9
|
-
|
|
12
|
+
import { cronMatches } from "./schedule.js";
|
|
13
|
+
import { NotificationsServiceImpl } from "./notifications/service.js";
|
|
14
|
+
import { CHAT_QUIET_MS, FLUSH_JOB, SchedulerChatDebounce, flushKey, notificationJobs } from "./notifications/debounce.js";
|
|
15
|
+
import { RECIPIENT_RULES } from "./notifications/rules/index.js";
|
|
16
|
+
import { NOTIFICATION_TYPES } from "./notifications/types.js";
|
|
17
|
+
import { DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES } from "./notifications/defaults.js";
|
|
18
|
+
export { ACTION_FAILED, ActionFailedError, type Automation, type AutomationAction, type AutomationActionFailed, type AutomationActionResult, type AutomationCreated, type AutomationDeleted, type AutomationDisabled, type AutomationDispatch, type AutomationEnabled, type AutomationEngine, type AutomationEvent, type AutomationExecutor, type AutomationKind, AutomationKindMismatchError, type AutomationRun, type AutomationRunCompleted, type AutomationRunFailed, type AutomationRunStarted, type AutomationRunStatus, type AutomationRunsQuery, type AutomationRunsRepository, type AutomationTrigger, type AutomationUpdated, type AutomationsQuery, type AutomationsRepository, type AutomationsService, AutomationsServiceImpl, type AutomationsUnitOfWork, type AvailableAction, type AvailableActions, type AvailableTriggers, CHANNEL_NOT_CONFIGURED, CHAT_QUIET_MS, type ChatDebounce, type CommunityMailReads, type CreateAutomationInput, type CreateWebhookInput, type CreatedWebhook, DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES, DEVICE_WINDOW_MS, type DeliveryDispatch, FLUSH_JOB, type GrantWriter, IN_APP, InvalidTriggerError, type ListedNotification, MESSAGE_SENT, NOTIFICATION_TYPES, NOT_ACCEPTED, NO_ADDRESS, type NewAutomation, type NewAutomationRun, type NewDelivery, type NewNotification, type NotificationCategories, NotificationDelivery, type NotificationPage, NotificationProcessor, type NotificationReads, type NotificationsRepository, type NotificationsService, NotificationsServiceImpl, PUSH, type Page, RECIPIENT_RULES, type RecipientRule, ReservedActionError, SchedulerChatDebounce, type UnreadCounts, type UpdateAutomationInput, type UpdateWebhookInput, type Webhook, type WebhookRequest, type WebhookResponse, type WebhookSecret, type WebhookSender, actionFailureMessage, automationEvents, cronMatches, flushKey, notificationJobs };
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
import { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, InvalidTriggerError, ReservedActionError, actionFailureMessage } from "./model.js";
|
|
1
2
|
import { automationEvents } from "./events.js";
|
|
2
|
-
import {
|
|
3
|
+
import { cronMatches } from "./schedule.js";
|
|
3
4
|
import { AutomationsServiceImpl } from "./service.js";
|
|
4
|
-
|
|
5
|
+
import { NotificationsServiceImpl } from "./notifications/service.js";
|
|
6
|
+
import { CHANNEL_NOT_CONFIGURED, NOT_ACCEPTED, NO_ADDRESS, NotificationDelivery } from "./notifications/delivery.js";
|
|
7
|
+
import { DEVICE_WINDOW_MS, IN_APP, MESSAGE_SENT, NotificationProcessor, PUSH } from "./notifications/processor.js";
|
|
8
|
+
import { CHAT_QUIET_MS, FLUSH_JOB, SchedulerChatDebounce, flushKey, notificationJobs } from "./notifications/debounce.js";
|
|
9
|
+
import { RECIPIENT_RULES } from "./notifications/rules/index.js";
|
|
10
|
+
import { NOTIFICATION_TYPES } from "./notifications/types.js";
|
|
11
|
+
import { DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES } from "./notifications/defaults.js";
|
|
12
|
+
export { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, AutomationsServiceImpl, CHANNEL_NOT_CONFIGURED, CHAT_QUIET_MS, DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES, DEVICE_WINDOW_MS, FLUSH_JOB, IN_APP, InvalidTriggerError, MESSAGE_SENT, NOTIFICATION_TYPES, NOT_ACCEPTED, NO_ADDRESS, NotificationDelivery, NotificationProcessor, NotificationsServiceImpl, PUSH, RECIPIENT_RULES, ReservedActionError, SchedulerChatDebounce, actionFailureMessage, automationEvents, cronMatches, flushKey, notificationJobs };
|
|
@@ -5,9 +5,16 @@ import "../types/index.js";
|
|
|
5
5
|
/** Rejected at authoring time: automation.* is reserved to avoid a self-triggering loop. */
|
|
6
6
|
declare class InvalidTriggerError extends Error {
|
|
7
7
|
readonly trigger: string;
|
|
8
|
-
readonly reason: 'reserved' | 'unknown';
|
|
9
|
-
constructor(trigger: string, reason?: 'reserved' | 'unknown');
|
|
8
|
+
readonly reason: 'reserved' | 'unknown' | 'schedule';
|
|
9
|
+
constructor(trigger: string, reason?: 'reserved' | 'unknown' | 'schedule');
|
|
10
10
|
}
|
|
11
|
+
declare const ACTION_FAILED = "The action failed";
|
|
12
|
+
/** An action failure whose message is safe to record on the run. */
|
|
13
|
+
declare class ActionFailedError extends Error {
|
|
14
|
+
constructor(message?: string);
|
|
15
|
+
}
|
|
16
|
+
/** The message a run records for an action that threw `err`. */
|
|
17
|
+
declare function actionFailureMessage(err: unknown): string;
|
|
11
18
|
declare class ReservedActionError extends Error {
|
|
12
19
|
readonly actionType: string;
|
|
13
20
|
constructor(actionType: string);
|
|
@@ -18,5 +25,5 @@ declare class AutomationKindMismatchError extends Error {
|
|
|
18
25
|
constructor(automationId: string, kind: AutomationKind);
|
|
19
26
|
}
|
|
20
27
|
//#endregion
|
|
21
|
-
export { type Automation, type AutomationAction, type AutomationActionResult, type AutomationKind, AutomationKindMismatchError, type AutomationRun, type AutomationRunStatus, type AutomationTrigger, type CreatedWebhook, type DeliverWebhookInput, InvalidTriggerError, type Page, ReservedActionError, type Webhook, type WebhookSecret };
|
|
28
|
+
export { ACTION_FAILED, ActionFailedError, type Automation, type AutomationAction, type AutomationActionResult, type AutomationKind, AutomationKindMismatchError, type AutomationRun, type AutomationRunStatus, type AutomationTrigger, type CreatedWebhook, type DeliverWebhookInput, InvalidTriggerError, type Page, ReservedActionError, type Webhook, type WebhookSecret, actionFailureMessage };
|
|
22
29
|
//# sourceMappingURL=model.d.ts.map
|
|
@@ -4,12 +4,25 @@ var InvalidTriggerError = class extends Error {
|
|
|
4
4
|
trigger;
|
|
5
5
|
reason;
|
|
6
6
|
constructor(trigger, reason = "reserved") {
|
|
7
|
-
|
|
7
|
+
const message = reason === "reserved" ? `trigger "${trigger}" is reserved: automations cannot trigger on automation.* events` : reason === "unknown" ? `trigger "${trigger}" is not an event the system emits` : `trigger "${trigger}" uses a schedule this system cannot match`;
|
|
8
|
+
super(message);
|
|
8
9
|
this.trigger = trigger;
|
|
9
10
|
this.reason = reason;
|
|
10
11
|
this.name = "InvalidTriggerError";
|
|
11
12
|
}
|
|
12
13
|
};
|
|
14
|
+
const ACTION_FAILED = "The action failed";
|
|
15
|
+
/** An action failure whose message is safe to record on the run. */
|
|
16
|
+
var ActionFailedError = class extends Error {
|
|
17
|
+
constructor(message = ACTION_FAILED) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "ActionFailedError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/** The message a run records for an action that threw `err`. */
|
|
23
|
+
function actionFailureMessage(err) {
|
|
24
|
+
return err instanceof ActionFailedError ? err.message : ACTION_FAILED;
|
|
25
|
+
}
|
|
13
26
|
var ReservedActionError = class extends Error {
|
|
14
27
|
actionType;
|
|
15
28
|
constructor(actionType) {
|
|
@@ -29,6 +42,6 @@ var AutomationKindMismatchError = class extends Error {
|
|
|
29
42
|
}
|
|
30
43
|
};
|
|
31
44
|
//#endregion
|
|
32
|
-
export { AutomationKindMismatchError, InvalidTriggerError, ReservedActionError };
|
|
45
|
+
export { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, InvalidTriggerError, ReservedActionError, actionFailureMessage };
|
|
33
46
|
|
|
34
47
|
//# sourceMappingURL=model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","names":[],"sources":["../../src/automations/model.ts"],"sourcesContent":["// automations context — domain entities, owned by @headless-lms/core/types; the\n// domain errors below are runtime code and stay in core.\nimport type { AutomationKind } from '../types/index.js';\n\nexport type {\n AutomationTrigger,\n AutomationAction,\n AutomationKind,\n Automation,\n AutomationRunStatus,\n AutomationActionResult,\n AutomationRun,\n Webhook,\n CreatedWebhook,\n WebhookSecret,\n DeliverWebhookInput,\n Page,\n} from '../types/index.js';\n\n/** Rejected at authoring time: automation.* is reserved to avoid a self-triggering loop. */\nexport class InvalidTriggerError extends Error {\n constructor(\n readonly trigger: string,\n readonly reason: 'reserved' | 'unknown' = 'reserved',\n ) {\n
|
|
1
|
+
{"version":3,"file":"model.js","names":[],"sources":["../../src/automations/model.ts"],"sourcesContent":["// automations context — domain entities, owned by @headless-lms/core/types; the\n// domain errors below are runtime code and stay in core.\nimport type { AutomationKind } from '../types/index.js';\n\nexport type {\n AutomationTrigger,\n AutomationAction,\n AutomationKind,\n Automation,\n AutomationRunStatus,\n AutomationActionResult,\n AutomationRun,\n Webhook,\n CreatedWebhook,\n WebhookSecret,\n DeliverWebhookInput,\n Page,\n} from '../types/index.js';\n\n/** Rejected at authoring time: automation.* is reserved to avoid a self-triggering loop. */\nexport class InvalidTriggerError extends Error {\n constructor(\n readonly trigger: string,\n readonly reason: 'reserved' | 'unknown' | 'schedule' = 'reserved',\n ) {\n const message =\n reason === 'reserved'\n ? `trigger \"${trigger}\" is reserved: automations cannot trigger on automation.* events`\n : reason === 'unknown'\n ? `trigger \"${trigger}\" is not an event the system emits`\n : `trigger \"${trigger}\" uses a schedule this system cannot match`;\n super(message);\n this.name = 'InvalidTriggerError';\n }\n}\n\nexport const ACTION_FAILED = 'The action failed';\n\n/** An action failure whose message is safe to record on the run. */\nexport class ActionFailedError extends Error {\n constructor(message: string = ACTION_FAILED) {\n super(message);\n this.name = 'ActionFailedError';\n }\n}\n\n/** The message a run records for an action that threw `err`. */\nexport function actionFailureMessage(err: unknown): string {\n return err instanceof ActionFailedError ? err.message : ACTION_FAILED;\n}\n\nexport class ReservedActionError extends Error {\n constructor(readonly actionType: string) {\n super(`action \"${actionType}\" is reserved to webhooks`);\n this.name = 'ReservedActionError';\n }\n}\n\nexport class AutomationKindMismatchError extends Error {\n constructor(\n readonly automationId: string,\n readonly kind: AutomationKind,\n ) {\n super(`automation \"${automationId}\" is a ${kind} and can't be changed through this operation`);\n this.name = 'AutomationKindMismatchError';\n }\n}\n"],"mappings":";;AAoBA,IAAa,sBAAb,cAAyC,MAAM;CAElC;CACA;CAFX,YACE,SACA,SAAuD,YACvD;EACA,MAAM,UACJ,WAAW,aACP,YAAY,QAAQ,oEACpB,WAAW,YACT,YAAY,QAAQ,sCACpB,YAAY,QAAQ;EAC5B,MAAM,OAAO;EATJ,KAAA,UAAA;EACA,KAAA,SAAA;EAST,KAAK,OAAO;CACd;AACF;AAEA,MAAa,gBAAgB;;AAG7B,IAAa,oBAAb,cAAuC,MAAM;CAC3C,YAAY,UAAkB,eAAe;EAC3C,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,qBAAqB,KAAsB;CACzD,OAAO,eAAe,oBAAoB,IAAI,UAAU;AAC1D;AAEA,IAAa,sBAAb,cAAyC,MAAM;CACxB;CAArB,YAAY,YAA6B;EACvC,MAAM,WAAW,WAAW,0BAA0B;EADnC,KAAA,aAAA;EAEnB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,8BAAb,cAAiD,MAAM;CAE1C;CACA;CAFX,YACE,cACA,MACA;EACA,MAAM,eAAe,aAAa,SAAS,KAAK,6CAA6C;EAHpF,KAAA,eAAA;EACA,KAAA,OAAA;EAGT,KAAK,OAAO;CACd;AACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Logger } from "../../types/ports.js";
|
|
2
|
+
import { RecipientList } from "../../types/notifications.js";
|
|
3
|
+
import "../../types/index.js";
|
|
4
|
+
import { ScheduledJob, Scheduler } from "../../shared/ports.js";
|
|
5
|
+
import { ChatDebounce, NotificationReads } from "../ports.js";
|
|
6
|
+
import { NotificationProcessor } from "./processor.js";
|
|
7
|
+
//#region src/automations/notifications/debounce.d.ts
|
|
8
|
+
declare const FLUSH_JOB = "automations.notifications.flush";
|
|
9
|
+
declare const CHAT_QUIET_MS: number;
|
|
10
|
+
declare function flushKey(userId: string, chatId: string): string;
|
|
11
|
+
declare class SchedulerChatDebounce implements ChatDebounce {
|
|
12
|
+
private readonly scheduler;
|
|
13
|
+
constructor(scheduler: Pick<Scheduler, 'at' | 'cancel'>);
|
|
14
|
+
arm(orgId: string, list: RecipientList, occurredAt: Date): Promise<void>;
|
|
15
|
+
mentioned(_orgId: string, userId: string, chatId: string): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
interface NotificationJobDeps {
|
|
18
|
+
processor: Pick<NotificationProcessor, 'file'>;
|
|
19
|
+
reads: NotificationReads;
|
|
20
|
+
logger?: Logger;
|
|
21
|
+
}
|
|
22
|
+
declare function notificationJobs(deps: NotificationJobDeps): ScheduledJob[];
|
|
23
|
+
//#endregion
|
|
24
|
+
export { CHAT_QUIET_MS, FLUSH_JOB, NotificationJobDeps, SchedulerChatDebounce, flushKey, notificationJobs };
|
|
25
|
+
//# sourceMappingURL=debounce.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { idSchema } from "../../types/schemas/shared.js";
|
|
2
|
+
import { noopLogger } from "../../shared/logger.js";
|
|
3
|
+
import "../community-mail.js";
|
|
4
|
+
import { chatOf } from "./processor.js";
|
|
5
|
+
import { Reasons, chatReach, chatTitle, recipientsOf, textExcerpt } from "./rules/recipients.js";
|
|
6
|
+
import { messageSummary } from "./rules/discussion.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/automations/notifications/debounce.ts
|
|
9
|
+
const FLUSH_JOB = "automations.notifications.flush";
|
|
10
|
+
const CHAT_QUIET_MS = 120 * 1e3;
|
|
11
|
+
const flushPayload = z.object({
|
|
12
|
+
orgId: idSchema,
|
|
13
|
+
userId: idSchema,
|
|
14
|
+
orgUserId: idSchema,
|
|
15
|
+
chatId: idSchema
|
|
16
|
+
}).strict();
|
|
17
|
+
function flushKey(userId, chatId) {
|
|
18
|
+
return `${userId}:${chatId}`;
|
|
19
|
+
}
|
|
20
|
+
var SchedulerChatDebounce = class {
|
|
21
|
+
scheduler;
|
|
22
|
+
constructor(scheduler) {
|
|
23
|
+
this.scheduler = scheduler;
|
|
24
|
+
}
|
|
25
|
+
async arm(orgId, list, occurredAt) {
|
|
26
|
+
const chatId = chatOf(list);
|
|
27
|
+
if (!chatId) return;
|
|
28
|
+
const runAt = new Date(occurredAt.getTime() + CHAT_QUIET_MS);
|
|
29
|
+
for (const recipient of list.recipients ?? []) await this.scheduler.at(FLUSH_JOB, runAt, flushKey(recipient.userId, chatId), {
|
|
30
|
+
orgId,
|
|
31
|
+
userId: recipient.userId,
|
|
32
|
+
orgUserId: recipient.orgUserId,
|
|
33
|
+
chatId
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async mentioned(_orgId, userId, chatId) {
|
|
37
|
+
await this.scheduler.cancel(FLUSH_JOB, flushKey(userId, chatId));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function notificationJobs(deps) {
|
|
41
|
+
const logger = deps.logger ?? noopLogger;
|
|
42
|
+
return [{
|
|
43
|
+
job: FLUSH_JOB,
|
|
44
|
+
async run(payload, fire) {
|
|
45
|
+
const parsed = flushPayload.safeParse(payload);
|
|
46
|
+
if (!parsed.success) {
|
|
47
|
+
logger.error("chat flush payload refused", {
|
|
48
|
+
job: FLUSH_JOB,
|
|
49
|
+
fireId: fire.id
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const { orgId, orgUserId, chatId } = parsed.data;
|
|
54
|
+
const unread = await deps.reads.unreadInChat(orgId, chatId, orgUserId);
|
|
55
|
+
if (unread.count === 0 || !unread.latest) return;
|
|
56
|
+
const chat = await deps.reads.chat(orgId, chatId);
|
|
57
|
+
if (!chat) return;
|
|
58
|
+
const latest = unread.latest;
|
|
59
|
+
const recipients = await recipientsOf(deps.reads, orgId, new Reasons().add([orgUserId], "participant"), chatReach(deps.reads, orgId, chat, chatId, latest.senderOrgUserId, fire.startedAt));
|
|
60
|
+
if (recipients.length === 0) return;
|
|
61
|
+
await deps.processor.file(orgId, `chat-flush:${chatId}:${latest.messageId}`, [{
|
|
62
|
+
type: "message.sent",
|
|
63
|
+
scope: "chat",
|
|
64
|
+
actorOrgUserId: latest.senderOrgUserId,
|
|
65
|
+
communityId: chat.communityId,
|
|
66
|
+
spaceId: null,
|
|
67
|
+
subject: {
|
|
68
|
+
type: "message",
|
|
69
|
+
id: latest.messageId
|
|
70
|
+
},
|
|
71
|
+
parent: {
|
|
72
|
+
type: "chat",
|
|
73
|
+
id: chatId
|
|
74
|
+
},
|
|
75
|
+
display: {
|
|
76
|
+
senderName: await deps.reads.displayName(orgId, latest.senderOrgUserId),
|
|
77
|
+
chatTitle: await chatTitle(deps.reads, orgId, chat, latest.senderOrgUserId),
|
|
78
|
+
excerpt: await textExcerpt(deps.reads, orgId, latest.body, 140),
|
|
79
|
+
count: String(unread.count),
|
|
80
|
+
summary: messageSummary(unread.count)
|
|
81
|
+
},
|
|
82
|
+
recipients
|
|
83
|
+
}], {
|
|
84
|
+
occurredAt: fire.startedAt,
|
|
85
|
+
debounce: false
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}];
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { CHAT_QUIET_MS, FLUSH_JOB, SchedulerChatDebounce, flushKey, notificationJobs };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=debounce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debounce.js","names":[],"sources":["../../../src/automations/notifications/debounce.ts"],"sourcesContent":["import { z } from 'zod';\nimport { idSchema } from '../../types/schemas/index.js';\nimport type { RecipientList } from '../../types/index.js';\nimport { noopLogger } from '../../shared/logger.js';\nimport type { Logger, ScheduledJob, Scheduler } from '../../shared/ports.js';\nimport { MESSAGE_EXCERPT } from '../community-mail.js';\nimport type { ChatDebounce, NotificationReads } from '../ports.js';\nimport { chatOf, type NotificationProcessor } from './processor.js';\nimport { messageSummary } from './rules/discussion.js';\nimport { chatReach, chatTitle, Reasons, recipientsOf, textExcerpt } from './rules/recipients.js';\n\nexport const FLUSH_JOB = 'automations.notifications.flush';\nexport const CHAT_QUIET_MS = 2 * 60 * 1000;\n\nconst flushPayload = z\n .object({ orgId: idSchema, userId: idSchema, orgUserId: idSchema, chatId: idSchema })\n .strict();\n\nexport function flushKey(userId: string, chatId: string): string {\n return `${userId}:${chatId}`;\n}\n\nexport class SchedulerChatDebounce implements ChatDebounce {\n constructor(private readonly scheduler: Pick<Scheduler, 'at' | 'cancel'>) {}\n\n async arm(orgId: string, list: RecipientList, occurredAt: Date): Promise<void> {\n const chatId = chatOf(list);\n if (!chatId) {\n return;\n }\n const runAt = new Date(occurredAt.getTime() + CHAT_QUIET_MS);\n for (const recipient of list.recipients ?? []) {\n await this.scheduler.at(FLUSH_JOB, runAt, flushKey(recipient.userId, chatId), {\n orgId,\n userId: recipient.userId,\n orgUserId: recipient.orgUserId,\n chatId,\n });\n }\n }\n\n async mentioned(_orgId: string, userId: string, chatId: string): Promise<void> {\n await this.scheduler.cancel(FLUSH_JOB, flushKey(userId, chatId));\n }\n}\n\nexport interface NotificationJobDeps {\n processor: Pick<NotificationProcessor, 'file'>;\n reads: NotificationReads;\n logger?: Logger;\n}\n\nexport function notificationJobs(deps: NotificationJobDeps): ScheduledJob[] {\n const logger = deps.logger ?? noopLogger;\n return [\n {\n job: FLUSH_JOB,\n async run(payload, fire) {\n const parsed = flushPayload.safeParse(payload);\n if (!parsed.success) {\n logger.error('chat flush payload refused', { job: FLUSH_JOB, fireId: fire.id });\n return;\n }\n const { orgId, orgUserId, chatId } = parsed.data;\n const unread = await deps.reads.unreadInChat(orgId, chatId, orgUserId);\n if (unread.count === 0 || !unread.latest) {\n return;\n }\n const chat = await deps.reads.chat(orgId, chatId);\n if (!chat) {\n return;\n }\n const latest = unread.latest;\n const recipients = await recipientsOf(\n deps.reads,\n orgId,\n new Reasons().add([orgUserId], 'participant'),\n chatReach(deps.reads, orgId, chat, chatId, latest.senderOrgUserId, fire.startedAt),\n );\n if (recipients.length === 0) {\n return;\n }\n await deps.processor.file(\n orgId,\n `chat-flush:${chatId}:${latest.messageId}`,\n [\n {\n type: 'message.sent',\n scope: 'chat',\n actorOrgUserId: latest.senderOrgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: latest.messageId },\n parent: { type: 'chat', id: chatId },\n display: {\n senderName: await deps.reads.displayName(orgId, latest.senderOrgUserId),\n chatTitle: await chatTitle(deps.reads, orgId, chat, latest.senderOrgUserId),\n excerpt: await textExcerpt(deps.reads, orgId, latest.body, MESSAGE_EXCERPT),\n count: String(unread.count),\n summary: messageSummary(unread.count),\n },\n recipients,\n },\n ],\n { occurredAt: fire.startedAt, debounce: false },\n );\n },\n },\n ];\n}\n"],"mappings":";;;;;;;;AAWA,MAAa,YAAY;AACzB,MAAa,gBAAgB,MAAS;AAEtC,MAAM,eAAe,EAClB,OAAO;CAAE,OAAO;CAAU,QAAQ;CAAU,WAAW;CAAU,QAAQ;AAAS,CAAC,CAAC,CACpF,OAAO;AAEV,SAAgB,SAAS,QAAgB,QAAwB;CAC/D,OAAO,GAAG,OAAO,GAAG;AACtB;AAEA,IAAa,wBAAb,MAA2D;CAC5B;CAA7B,YAAY,WAA8D;EAA7C,KAAA,YAAA;CAA8C;CAE3E,MAAM,IAAI,OAAe,MAAqB,YAAiC;EAC7E,MAAM,SAAS,OAAO,IAAI;EAC1B,IAAI,CAAC,QACH;EAEF,MAAM,QAAQ,IAAI,KAAK,WAAW,QAAQ,IAAI,aAAa;EAC3D,KAAK,MAAM,aAAa,KAAK,cAAc,CAAC,GAC1C,MAAM,KAAK,UAAU,GAAG,WAAW,OAAO,SAAS,UAAU,QAAQ,MAAM,GAAG;GAC5E;GACA,QAAQ,UAAU;GAClB,WAAW,UAAU;GACrB;EACF,CAAC;CAEL;CAEA,MAAM,UAAU,QAAgB,QAAgB,QAA+B;EAC7E,MAAM,KAAK,UAAU,OAAO,WAAW,SAAS,QAAQ,MAAM,CAAC;CACjE;AACF;AAQA,SAAgB,iBAAiB,MAA2C;CAC1E,MAAM,SAAS,KAAK,UAAU;CAC9B,OAAO,CACL;EACE,KAAK;EACL,MAAM,IAAI,SAAS,MAAM;GACvB,MAAM,SAAS,aAAa,UAAU,OAAO;GAC7C,IAAI,CAAC,OAAO,SAAS;IACnB,OAAO,MAAM,8BAA8B;KAAE,KAAK;KAAW,QAAQ,KAAK;IAAG,CAAC;IAC9E;GACF;GACA,MAAM,EAAE,OAAO,WAAW,WAAW,OAAO;GAC5C,MAAM,SAAS,MAAM,KAAK,MAAM,aAAa,OAAO,QAAQ,SAAS;GACrE,IAAI,OAAO,UAAU,KAAK,CAAC,OAAO,QAChC;GAEF,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,OAAO,MAAM;GAChD,IAAI,CAAC,MACH;GAEF,MAAM,SAAS,OAAO;GACtB,MAAM,aAAa,MAAM,aACvB,KAAK,OACL,OACA,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,aAAa,GAC5C,UAAU,KAAK,OAAO,OAAO,MAAM,QAAQ,OAAO,iBAAiB,KAAK,SAAS,CACnF;GACA,IAAI,WAAW,WAAW,GACxB;GAEF,MAAM,KAAK,UAAU,KACnB,OACA,cAAc,OAAO,GAAG,OAAO,aAC/B,CACE;IACE,MAAM;IACN,OAAO;IACP,gBAAgB,OAAO;IACvB,aAAa,KAAK;IAClB,SAAS;IACT,SAAS;KAAE,MAAM;KAAW,IAAI,OAAO;IAAU;IACjD,QAAQ;KAAE,MAAM;KAAQ,IAAI;IAAO;IACnC,SAAS;KACP,YAAY,MAAM,KAAK,MAAM,YAAY,OAAO,OAAO,eAAe;KACtE,WAAW,MAAM,UAAU,KAAK,OAAO,OAAO,MAAM,OAAO,eAAe;KAC1E,SAAS,MAAM,YAAY,KAAK,OAAO,OAAO,OAAO,MAAA,GAAqB;KAC1E,OAAO,OAAO,OAAO,KAAK;KAC1B,SAAS,eAAe,OAAO,KAAK;IACtC;IACA;GACF,CACF,GACA;IAAE,YAAY,KAAK;IAAW,UAAU;GAAM,CAChD;EACF;CACF,CACF;AACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NotificationCategory } from "../../types/notifications.js";
|
|
2
|
+
import "../../types/index.js";
|
|
3
|
+
//#region src/automations/notifications/defaults.d.ts
|
|
4
|
+
declare const DEFAULT_COMMUNITY_CATEGORIES: NotificationCategory[];
|
|
5
|
+
declare const DEFAULT_ORG_CATEGORIES: NotificationCategory[];
|
|
6
|
+
//#endregion
|
|
7
|
+
export { DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES };
|
|
8
|
+
//# sourceMappingURL=defaults.d.ts.map
|