@headless-lms/core 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/events.d.ts +39 -21
- 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 +5 -4
- package/dist/assets/index.js +3 -2
- package/dist/assets/model.d.ts +2 -2
- package/dist/assets/ports.d.ts +45 -15
- package/dist/assets/service.d.ts +39 -7
- package/dist/assets/service.js +291 -38
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.d.ts +13 -24
- package/dist/automations/actions.js +168 -43
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +2 -1
- package/dist/automations/catalog.js +229 -13
- 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 +112 -0
- package/dist/automations/community-mail.js +90 -0
- package/dist/automations/community-mail.js.map +1 -0
- package/dist/automations/community-notifications.d.ts +16 -0
- package/dist/automations/community-notifications.js +84 -0
- package/dist/automations/community-notifications.js.map +1 -0
- package/dist/automations/events.d.ts +28 -0
- package/dist/automations/index.d.ts +4 -2
- package/dist/automations/index.js +3 -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/ports.d.ts +5 -1
- 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/seeds.d.ts +17 -0
- package/dist/automations/seeds.js +235 -0
- package/dist/automations/seeds.js.map +1 -0
- package/dist/automations/service.d.ts +22 -3
- package/dist/automations/service.js +306 -43
- package/dist/automations/service.js.map +1 -1
- package/dist/content/events.d.ts +631 -19
- package/dist/content/events.js +44 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +4 -4
- package/dist/content/model.d.ts +2 -2
- package/dist/content/ports.d.ts +71 -18
- package/dist/content/service.d.ts +57 -18
- package/dist/content/service.js +502 -23
- package/dist/content/service.js.map +1 -1
- 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 +104 -0
- package/dist/discussion/chats.js +798 -0
- package/dist/discussion/chats.js.map +1 -0
- package/dist/discussion/events.d.ts +619 -56
- package/dist/discussion/events.js +106 -3
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +7 -3
- package/dist/discussion/index.js +4 -1
- package/dist/discussion/ports.d.ts +288 -27
- package/dist/discussion/ports.js +6 -1
- package/dist/discussion/ports.js.map +1 -0
- package/dist/discussion/posts.d.ts +103 -0
- package/dist/discussion/posts.js +723 -0
- package/dist/discussion/posts.js.map +1 -0
- package/dist/discussion/service.d.ts +32 -10
- package/dist/discussion/service.js +293 -78
- package/dist/discussion/service.js.map +1 -1
- 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 +5 -4
- package/dist/entitlements/index.js +2 -1
- package/dist/entitlements/model.d.ts +3 -2
- package/dist/entitlements/ports.d.ts +124 -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 +54 -3
- package/dist/entitlements/service.js +472 -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/index.d.ts +6 -4
- package/dist/identity/index.js +3 -1
- package/dist/identity/model.d.ts +2 -1
- package/dist/identity/notifications.d.ts +27 -0
- package/dist/identity/notifications.js +101 -0
- package/dist/identity/notifications.js.map +1 -0
- package/dist/identity/ports.d.ts +73 -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/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 +74 -32
- package/dist/organizations/events.js +6 -0
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +7 -6
- package/dist/organizations/index.js +4 -3
- package/dist/organizations/members.d.ts +8 -5
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/ports.d.ts +14 -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 +20 -11
- package/dist/organizations/service.js +157 -47
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +1 -10
- 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 +124 -0
- package/dist/reporting/member/ports.d.ts +45 -0
- package/dist/reporting/member/service.d.ts +73 -0
- package/dist/reporting/member/service.js +286 -0
- package/dist/reporting/member/service.js.map +1 -0
- package/dist/shared/actor.d.ts +9 -0
- package/dist/shared/errors.d.ts +7 -1
- package/dist/shared/errors.js +10 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +11 -0
- package/dist/shared/id.js +12 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/mailer.d.ts +4 -1
- 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/types/assets.d.ts +2 -2
- package/dist/types/automations.d.ts +10 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +11 -3
- package/dist/types/email-templates.d.ts +121 -0
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +48 -2
- package/dist/types/index.d.ts +9 -9
- 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 +18 -1
- package/dist/types/schemas/automations.js +15 -6
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +335 -3
- package/dist/types/schemas/content.js +139 -3
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +370 -3
- package/dist/types/schemas/discussion.js +199 -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 +111 -1
- package/dist/types/schemas/identity.js +55 -2
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +8 -8
- package/dist/types/schemas/index.js +8 -8
- 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/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/ports.js +0 -1
- 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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { DomainEvent, JsonValue } from "../types/shared.js";
|
|
2
|
+
import { Logger } from "../types/ports.js";
|
|
3
|
+
import { EmailTemplateId, EmailTemplateParams } from "../types/email-templates.js";
|
|
4
|
+
import { GrantEntitlementInput } from "../types/schemas/entitlements.js";
|
|
5
|
+
import { WebhookSender } from "../types/automations.js";
|
|
6
|
+
import { ChatStatus } from "../types/schemas/discussion.js";
|
|
7
|
+
import "../types/index.js";
|
|
8
|
+
import { CredentialStore } from "../shared/ports.js";
|
|
9
|
+
import { NotificationDesk } from "../identity/ports.js";
|
|
10
|
+
import { Mailer, MailerLookups } from "../shared/mailer.js";
|
|
11
|
+
import "../identity/index.js";
|
|
12
|
+
import "../entitlements/index.js";
|
|
13
|
+
import "./ports.js";
|
|
14
|
+
//#region src/automations/community-mail.d.ts
|
|
15
|
+
declare const MESSAGE_EXCERPT = 140;
|
|
16
|
+
declare const POST_EXCERPT = 280;
|
|
17
|
+
declare const MESSAGE_BATCH_MS: number;
|
|
18
|
+
interface EmailRecipient<K extends EmailTemplateId = EmailTemplateId> {
|
|
19
|
+
to: string;
|
|
20
|
+
orgUserId: string;
|
|
21
|
+
userId: string;
|
|
22
|
+
params: EmailTemplateParams[K];
|
|
23
|
+
}
|
|
24
|
+
interface CommunityMailReads {
|
|
25
|
+
communityTitle(orgId: string, communityId: string): Promise<string | null>;
|
|
26
|
+
space(orgId: string, spaceId: string): Promise<{
|
|
27
|
+
name: string;
|
|
28
|
+
communityId: string;
|
|
29
|
+
capacity: number | null;
|
|
30
|
+
} | null>;
|
|
31
|
+
openSpaceNames(orgId: string, orgUserId: string, communityId: string): Promise<string[]>;
|
|
32
|
+
communitiesOpenedBy(orgId: string, grant: {
|
|
33
|
+
contentId: string | null;
|
|
34
|
+
bundleId: string | null;
|
|
35
|
+
}): Promise<string[]>;
|
|
36
|
+
communityMembersAmong(orgId: string, communityId: string, ids: string[]): Promise<string[]>;
|
|
37
|
+
spaceOpenersAmong(orgId: string, spaceId: string, ids: string[]): Promise<string[]>;
|
|
38
|
+
spaceOpeners(orgId: string, spaceId: string): Promise<string[]>;
|
|
39
|
+
moderationAudience(orgId: string, communityId: string): Promise<string[]>;
|
|
40
|
+
staffIds(orgId: string): Promise<string[]>;
|
|
41
|
+
displayName(orgId: string, orgUserId: string): Promise<string>;
|
|
42
|
+
followerIds(orgId: string, postId: string): Promise<string[]>;
|
|
43
|
+
comment(orgId: string, commentId: string): Promise<{
|
|
44
|
+
orgUserId: string;
|
|
45
|
+
postId: string | null;
|
|
46
|
+
body: string;
|
|
47
|
+
} | null>;
|
|
48
|
+
post(orgId: string, postId: string): Promise<{
|
|
49
|
+
title: string;
|
|
50
|
+
body: string;
|
|
51
|
+
spaceId: string;
|
|
52
|
+
orgUserId: string;
|
|
53
|
+
communityId: string;
|
|
54
|
+
} | null>;
|
|
55
|
+
chat(orgId: string, chatId: string): Promise<{
|
|
56
|
+
communityId: string;
|
|
57
|
+
kind: 'direct' | 'group';
|
|
58
|
+
status: ChatStatus;
|
|
59
|
+
createdBy: string | null;
|
|
60
|
+
participants: {
|
|
61
|
+
orgUserId: string;
|
|
62
|
+
muted: boolean;
|
|
63
|
+
mutedUntil: Date | null;
|
|
64
|
+
leftAt: Date | null;
|
|
65
|
+
}[];
|
|
66
|
+
} | null>;
|
|
67
|
+
latestMessageBody(orgId: string, chatId: string): Promise<string | null>;
|
|
68
|
+
pairBlocked(orgId: string, communityId: string, a: string, b: string): Promise<boolean>;
|
|
69
|
+
activeMemberCount(orgId: string, spaceId: string): Promise<number>;
|
|
70
|
+
memberCommunityTitles(orgId: string, orgUserId: string): Promise<{
|
|
71
|
+
id: string;
|
|
72
|
+
title: string;
|
|
73
|
+
}[]>;
|
|
74
|
+
recentMessageRecipients(orgId: string, automationId: string, chatId: string, since: Date): Promise<string[]>;
|
|
75
|
+
}
|
|
76
|
+
interface ScheduledWork {
|
|
77
|
+
publishDuePosts(orgId: string, now: Date): Promise<void>;
|
|
78
|
+
expireDueGrants(orgId: string, now: Date): Promise<void>;
|
|
79
|
+
sendDigest(orgId: string, now: Date): Promise<void>;
|
|
80
|
+
hasDuePosts(orgId: string, now: Date): Promise<boolean>;
|
|
81
|
+
hasDueGrants(orgId: string, now: Date): Promise<boolean>;
|
|
82
|
+
removeUnattachedUploads(orgId: string, now: Date): Promise<void>;
|
|
83
|
+
hasUnattachedUploads(orgId: string, now: Date): Promise<boolean>;
|
|
84
|
+
}
|
|
85
|
+
interface GrantWriter {
|
|
86
|
+
grant(orgId: string, input: GrantEntitlementInput): Promise<unknown>;
|
|
87
|
+
}
|
|
88
|
+
interface ActionDeps {
|
|
89
|
+
mailer: Pick<Mailer, 'send'>;
|
|
90
|
+
lookups: MailerLookups;
|
|
91
|
+
credentials: Pick<CredentialStore, 'reveal'>;
|
|
92
|
+
webhooks: WebhookSender;
|
|
93
|
+
mail: CommunityMailReads;
|
|
94
|
+
grants: GrantWriter;
|
|
95
|
+
desk: NotificationDesk;
|
|
96
|
+
scheduledWork: ScheduledWork;
|
|
97
|
+
automationId: string;
|
|
98
|
+
actionInput: Record<string, JsonValue>;
|
|
99
|
+
logger?: Logger;
|
|
100
|
+
}
|
|
101
|
+
declare const emptyCommunityMail: CommunityMailReads;
|
|
102
|
+
declare const emptyNotificationDesk: NotificationDesk;
|
|
103
|
+
declare const emptyScheduledWork: ScheduledWork;
|
|
104
|
+
declare function actorOf(event: DomainEvent): string | undefined;
|
|
105
|
+
declare function previousStatusOf(event: DomainEvent): string | undefined;
|
|
106
|
+
declare function excerpt(value: string, max: number): string;
|
|
107
|
+
declare function seededCommunityId(deps: ActionDeps): string | null;
|
|
108
|
+
declare function firedAtOf(event: DomainEvent): Date;
|
|
109
|
+
declare function address<K extends EmailTemplateId>(deps: ActionDeps, event: DomainEvent, orgId: string, orgUserIds: string[], params: EmailTemplateParams[K]): Promise<EmailRecipient<K>[] | undefined>;
|
|
110
|
+
//#endregion
|
|
111
|
+
export { ActionDeps, CommunityMailReads, EmailRecipient, GrantWriter, MESSAGE_BATCH_MS, MESSAGE_EXCERPT, POST_EXCERPT, ScheduledWork, actorOf, address, emptyCommunityMail, emptyNotificationDesk, emptyScheduledWork, excerpt, firedAtOf, previousStatusOf, seededCommunityId };
|
|
112
|
+
//# sourceMappingURL=community-mail.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
const emptyNotificationDesk = {
|
|
28
|
+
notify: async () => {},
|
|
29
|
+
preferencesFor: async () => ({})
|
|
30
|
+
};
|
|
31
|
+
const emptyScheduledWork = {
|
|
32
|
+
publishDuePosts: async () => {},
|
|
33
|
+
expireDueGrants: async () => {},
|
|
34
|
+
sendDigest: async () => {},
|
|
35
|
+
hasDuePosts: async () => false,
|
|
36
|
+
hasDueGrants: async () => false,
|
|
37
|
+
removeUnattachedUploads: async () => {},
|
|
38
|
+
hasUnattachedUploads: async () => false
|
|
39
|
+
};
|
|
40
|
+
function actorOf(event) {
|
|
41
|
+
const value = event.metadata?.actorOrgUserId;
|
|
42
|
+
return typeof value === "string" ? value : void 0;
|
|
43
|
+
}
|
|
44
|
+
function previousStatusOf(event) {
|
|
45
|
+
const value = event.metadata?.previousStatus;
|
|
46
|
+
return typeof value === "string" ? value : void 0;
|
|
47
|
+
}
|
|
48
|
+
function excerpt(value, max) {
|
|
49
|
+
const flat = value.replace(/\s+/g, " ").trim();
|
|
50
|
+
return flat.length <= max ? flat : flat.slice(0, max);
|
|
51
|
+
}
|
|
52
|
+
function seededCommunityId(deps) {
|
|
53
|
+
const id = deps.actionInput["communityId"];
|
|
54
|
+
return typeof id === "string" ? id : null;
|
|
55
|
+
}
|
|
56
|
+
function firedAtOf(event) {
|
|
57
|
+
if (typeof event.data === "object" && event.data !== null && "firedAt" in event.data) {
|
|
58
|
+
const firedAt = event.data.firedAt;
|
|
59
|
+
if (typeof firedAt === "string") return new Date(firedAt);
|
|
60
|
+
}
|
|
61
|
+
return new Date(event.occurredAt);
|
|
62
|
+
}
|
|
63
|
+
async function address(deps, event, orgId, orgUserIds, params) {
|
|
64
|
+
const actor = actorOf(event);
|
|
65
|
+
const wanted = [...new Set(orgUserIds)].filter((id) => id !== actor);
|
|
66
|
+
if (wanted.length === 0) return [];
|
|
67
|
+
const recipients = [];
|
|
68
|
+
const logger = deps.logger ?? noopLogger;
|
|
69
|
+
for (const orgUserId of wanted) {
|
|
70
|
+
const person = await deps.lookups.orgUserPerson(orgId, orgUserId);
|
|
71
|
+
if (!person) {
|
|
72
|
+
logger.warn("email skipped: recipient has no address", {
|
|
73
|
+
orgId,
|
|
74
|
+
orgUserId
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
recipients.push({
|
|
79
|
+
to: person.email,
|
|
80
|
+
orgUserId,
|
|
81
|
+
userId: person.userId,
|
|
82
|
+
params
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return recipients;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { MESSAGE_BATCH_MS, MESSAGE_EXCERPT, POST_EXCERPT, actorOf, address, emptyCommunityMail, emptyNotificationDesk, emptyScheduledWork, excerpt, firedAtOf, previousStatusOf, seededCommunityId };
|
|
89
|
+
|
|
90
|
+
//# 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 { NotificationDesk } from '../identity/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<{ orgUserId: string; postId: string | null; body: string } | 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 ScheduledWork {\n publishDuePosts(orgId: string, now: Date): Promise<void>;\n expireDueGrants(orgId: string, now: Date): Promise<void>;\n sendDigest(orgId: string, now: Date): Promise<void>;\n hasDuePosts(orgId: string, now: Date): Promise<boolean>;\n hasDueGrants(orgId: string, now: Date): Promise<boolean>;\n removeUnattachedUploads(orgId: string, now: Date): Promise<void>;\n hasUnattachedUploads(orgId: string, now: Date): Promise<boolean>;\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 desk: NotificationDesk;\n scheduledWork: ScheduledWork;\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 const emptyNotificationDesk: NotificationDesk = {\n notify: async () => {},\n preferencesFor: async () => ({}),\n};\n\nexport const emptyScheduledWork: ScheduledWork = {\n publishDuePosts: async () => {},\n expireDueGrants: async () => {},\n sendDigest: async () => {},\n hasDuePosts: async () => false,\n hasDueGrants: async () => false,\n removeUnattachedUploads: async () => {},\n hasUnattachedUploads: async () => false,\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 function firedAtOf(event: DomainEvent): Date {\n if (typeof event.data === 'object' && event.data !== null && 'firedAt' in event.data) {\n const firedAt = (event.data as { firedAt?: unknown }).firedAt;\n if (typeof firedAt === 'string') {\n return new Date(firedAt);\n }\n }\n return new Date(event.occurredAt);\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":";;AAaA,MAAa,kBAAkB;AAC/B,MAAa,eAAe;AAC5B,MAAa,mBAAmB,MAAU;AAgG1C,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,MAAa,wBAA0C;CACrD,QAAQ,YAAY,CAAC;CACrB,gBAAgB,aAAa,CAAC;AAChC;AAEA,MAAa,qBAAoC;CAC/C,iBAAiB,YAAY,CAAC;CAC9B,iBAAiB,YAAY,CAAC;CAC9B,YAAY,YAAY,CAAC;CACzB,aAAa,YAAY;CACzB,cAAc,YAAY;CAC1B,yBAAyB,YAAY,CAAC;CACtC,sBAAsB,YAAY;AACpC;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,SAAgB,UAAU,OAA0B;CAClD,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,SAAS,QAAQ,aAAa,MAAM,MAAM;EACpF,MAAM,UAAW,MAAM,KAA+B;EACtD,IAAI,OAAO,YAAY,UACrB,OAAO,IAAI,KAAK,OAAO;CAE3B;CACA,OAAO,IAAI,KAAK,MAAM,UAAU;AAClC;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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DomainEvent } from "../types/shared.js";
|
|
2
|
+
import { NotificationKind } from "../types/schemas/identity.js";
|
|
3
|
+
import "../types/index.js";
|
|
4
|
+
import "../shared/ports.js";
|
|
5
|
+
import { NewNotification } from "../identity/ports.js";
|
|
6
|
+
import "../identity/index.js";
|
|
7
|
+
import { ActionDeps, EmailRecipient } from "./community-mail.js";
|
|
8
|
+
//#region src/automations/community-notifications.d.ts
|
|
9
|
+
type Placement = Omit<NewNotification, 'userId' | 'kind'>;
|
|
10
|
+
interface NotificationPlacement<K extends NotificationKind> {
|
|
11
|
+
place(event: DomainEvent, recipient: EmailRecipient<K>, deps: ActionDeps): Promise<Placement[]>;
|
|
12
|
+
}
|
|
13
|
+
declare const NOTIFICATION_PLACEMENTS: { [K in NotificationKind]: NotificationPlacement<K>; };
|
|
14
|
+
//#endregion
|
|
15
|
+
export { NOTIFICATION_PLACEMENTS, NotificationPlacement };
|
|
16
|
+
//# sourceMappingURL=community-notifications.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { actorOf } from "./community-mail.js";
|
|
2
|
+
//#region src/automations/community-notifications.ts
|
|
3
|
+
function text(event, key) {
|
|
4
|
+
if (typeof event.data !== "object" || event.data === null) return null;
|
|
5
|
+
const value = event.data[key];
|
|
6
|
+
return typeof value === "string" ? value : null;
|
|
7
|
+
}
|
|
8
|
+
function at(communityId, actorOrgUserId, about) {
|
|
9
|
+
return [{
|
|
10
|
+
communityId,
|
|
11
|
+
actorOrgUserId,
|
|
12
|
+
spaceId: about.spaceId ?? null,
|
|
13
|
+
postId: about.postId ?? null,
|
|
14
|
+
commentId: about.commentId ?? null,
|
|
15
|
+
chatId: about.chatId ?? null,
|
|
16
|
+
messageId: about.messageId ?? null
|
|
17
|
+
}];
|
|
18
|
+
}
|
|
19
|
+
function actor(event) {
|
|
20
|
+
return actorOf(event) ?? null;
|
|
21
|
+
}
|
|
22
|
+
async function spaceOfPost(deps, event, postId) {
|
|
23
|
+
return postId ? (await deps.mail.post(event.orgId, postId))?.spaceId ?? null : null;
|
|
24
|
+
}
|
|
25
|
+
const NOTIFICATION_PLACEMENTS = {
|
|
26
|
+
newPostInSpace: { place: async (event, { params }) => at(params.communityId, text(event, "orgUserId"), {
|
|
27
|
+
postId: params.postId,
|
|
28
|
+
spaceId: text(event, "spaceId")
|
|
29
|
+
}) },
|
|
30
|
+
newCommentOnPost: { place: async (event, { params }, deps) => at(params.communityId, text(event, "orgUserId"), {
|
|
31
|
+
postId: params.postId,
|
|
32
|
+
commentId: params.commentId,
|
|
33
|
+
spaceId: await spaceOfPost(deps, event, params.postId)
|
|
34
|
+
}) },
|
|
35
|
+
replyToYourComment: { place: async (event, { params }, deps) => at(params.communityId, text(event, "orgUserId"), {
|
|
36
|
+
postId: params.postId,
|
|
37
|
+
commentId: params.commentId,
|
|
38
|
+
spaceId: await spaceOfPost(deps, event, params.postId)
|
|
39
|
+
}) },
|
|
40
|
+
yourPostWasPublished: { place: async (event, { params }) => at(params.communityId, actor(event), {
|
|
41
|
+
postId: params.postId,
|
|
42
|
+
spaceId: text(event, "spaceId")
|
|
43
|
+
}) },
|
|
44
|
+
yourPostWasRemoved: { place: async (event, { params }) => at(params.communityId, text(event, "removedBy"), {
|
|
45
|
+
postId: text(event, "id"),
|
|
46
|
+
spaceId: params.spaceId
|
|
47
|
+
}) },
|
|
48
|
+
yourCommentWasRemoved: { place: async (event, { params }, deps) => at(params.communityId, text(event, "removedBy"), {
|
|
49
|
+
postId: params.postId,
|
|
50
|
+
commentId: text(event, "id"),
|
|
51
|
+
spaceId: await spaceOfPost(deps, event, params.postId)
|
|
52
|
+
}) },
|
|
53
|
+
requestApproved: { place: async (event, { params }) => at(params.communityId, actor(event), { spaceId: params.spaceId }) },
|
|
54
|
+
requestDeclined: { place: async (event, { params }) => at(params.communityId, actor(event), { spaceId: text(event, "spaceId") }) },
|
|
55
|
+
invitedToSpace: { place: async (event, { params }) => at(params.communityId, actor(event), { spaceId: params.spaceId }) },
|
|
56
|
+
newMessage: { place: async (event, { params }) => at(params.communityId, text(event, "orgUserId"), {
|
|
57
|
+
chatId: params.chatId,
|
|
58
|
+
messageId: text(event, "id")
|
|
59
|
+
}) },
|
|
60
|
+
messageRequest: { place: async (event, { params }) => at(params.communityId, text(event, "createdBy"), { chatId: params.chatId }) },
|
|
61
|
+
addedToGroupChat: { place: async (event, { params }) => at(params.communityId, text(event, "addedBy"), { chatId: params.chatId }) },
|
|
62
|
+
youAreNowAModerator: { place: async (event) => at(null, actor(event), {}) },
|
|
63
|
+
membershipEndingSoon: { place: async (_event, { params }) => at(params.communityId, null, {}) },
|
|
64
|
+
welcomeToCommunity: { place: async (event, { params }) => at(params.communityId, actor(event), {}) },
|
|
65
|
+
postAwaitingReview: { place: async (event, { params }) => at(params.communityId, text(event, "orgUserId"), {
|
|
66
|
+
postId: text(event, "id"),
|
|
67
|
+
spaceId: params.spaceId
|
|
68
|
+
}) },
|
|
69
|
+
joinRequest: { place: async (event, { params }) => at(params.communityId, text(event, "orgUserId"), { spaceId: params.spaceId }) },
|
|
70
|
+
somethingWasFlagged: { place: async (event, { params }, deps) => {
|
|
71
|
+
const commentId = text(event, "commentId");
|
|
72
|
+
const postId = commentId ? (await deps.mail.comment(event.orgId, commentId))?.postId ?? null : text(event, "postId");
|
|
73
|
+
return at(params.communityId, text(event, "orgUserId"), {
|
|
74
|
+
spaceId: params.spaceId,
|
|
75
|
+
postId,
|
|
76
|
+
commentId
|
|
77
|
+
});
|
|
78
|
+
} },
|
|
79
|
+
messageWasFlagged: { place: async (event, { params }) => at(params.communityId, text(event, "orgUserId"), { messageId: text(event, "messageId") }) }
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
export { NOTIFICATION_PLACEMENTS };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=community-notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-notifications.js","names":[],"sources":["../../src/automations/community-notifications.ts"],"sourcesContent":["import type { NewNotification } from '../identity/index.js';\nimport type { NotificationKind } from '../types/index.js';\nimport type { DomainEvent } from '../shared/ports.js';\nimport { actorOf, type ActionDeps, type EmailRecipient } from './community-mail.js';\n\ntype Placement = Omit<NewNotification, 'userId' | 'kind'>;\n\nexport interface NotificationPlacement<K extends NotificationKind> {\n place(event: DomainEvent, recipient: EmailRecipient<K>, deps: ActionDeps): Promise<Placement[]>;\n}\n\ntype About = Partial<Pick<Placement, 'spaceId' | 'postId' | 'commentId' | 'chatId' | 'messageId'>>;\n\nfunction text(event: DomainEvent, key: string): string | null {\n if (typeof event.data !== 'object' || event.data === null) {\n return null;\n }\n const value = (event.data as Record<string, unknown>)[key];\n return typeof value === 'string' ? value : null;\n}\n\nfunction at(communityId: string | null, actorOrgUserId: string | null, about: About): Placement[] {\n return [\n {\n communityId,\n actorOrgUserId,\n spaceId: about.spaceId ?? null,\n postId: about.postId ?? null,\n commentId: about.commentId ?? null,\n chatId: about.chatId ?? null,\n messageId: about.messageId ?? null,\n },\n ];\n}\n\nfunction actor(event: DomainEvent): string | null {\n return actorOf(event) ?? null;\n}\n\nasync function spaceOfPost(\n deps: ActionDeps,\n event: DomainEvent,\n postId: string | null,\n): Promise<string | null> {\n return postId ? ((await deps.mail.post(event.orgId, postId))?.spaceId ?? null) : null;\n}\n\nexport const NOTIFICATION_PLACEMENTS: {\n [K in NotificationKind]: NotificationPlacement<K>;\n} = {\n newPostInSpace: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'orgUserId'), {\n postId: params.postId,\n spaceId: text(event, 'spaceId'),\n }),\n },\n newCommentOnPost: {\n place: async (event, { params }, deps) =>\n at(params.communityId, text(event, 'orgUserId'), {\n postId: params.postId,\n commentId: params.commentId,\n spaceId: await spaceOfPost(deps, event, params.postId),\n }),\n },\n replyToYourComment: {\n place: async (event, { params }, deps) =>\n at(params.communityId, text(event, 'orgUserId'), {\n postId: params.postId,\n commentId: params.commentId,\n spaceId: await spaceOfPost(deps, event, params.postId),\n }),\n },\n yourPostWasPublished: {\n place: async (event, { params }) =>\n at(params.communityId, actor(event), {\n postId: params.postId,\n spaceId: text(event, 'spaceId'),\n }),\n },\n yourPostWasRemoved: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'removedBy'), {\n postId: text(event, 'id'),\n spaceId: params.spaceId,\n }),\n },\n yourCommentWasRemoved: {\n place: async (event, { params }, deps) =>\n at(params.communityId, text(event, 'removedBy'), {\n postId: params.postId,\n commentId: text(event, 'id'),\n spaceId: await spaceOfPost(deps, event, params.postId),\n }),\n },\n requestApproved: {\n place: async (event, { params }) =>\n at(params.communityId, actor(event), { spaceId: params.spaceId }),\n },\n requestDeclined: {\n place: async (event, { params }) =>\n at(params.communityId, actor(event), { spaceId: text(event, 'spaceId') }),\n },\n invitedToSpace: {\n place: async (event, { params }) =>\n at(params.communityId, actor(event), { spaceId: params.spaceId }),\n },\n newMessage: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'orgUserId'), {\n chatId: params.chatId,\n messageId: text(event, 'id'),\n }),\n },\n messageRequest: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'createdBy'), { chatId: params.chatId }),\n },\n addedToGroupChat: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'addedBy'), { chatId: params.chatId }),\n },\n youAreNowAModerator: {\n place: async (event) => at(null, actor(event), {}),\n },\n membershipEndingSoon: {\n place: async (_event, { params }) => at(params.communityId, null, {}),\n },\n welcomeToCommunity: {\n place: async (event, { params }) => at(params.communityId, actor(event), {}),\n },\n postAwaitingReview: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'orgUserId'), {\n postId: text(event, 'id'),\n spaceId: params.spaceId,\n }),\n },\n joinRequest: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'orgUserId'), { spaceId: params.spaceId }),\n },\n somethingWasFlagged: {\n place: async (event, { params }, deps) => {\n const commentId = text(event, 'commentId');\n const postId = commentId\n ? ((await deps.mail.comment(event.orgId, commentId))?.postId ?? null)\n : text(event, 'postId');\n return at(params.communityId, text(event, 'orgUserId'), {\n spaceId: params.spaceId,\n postId,\n commentId,\n });\n },\n },\n messageWasFlagged: {\n place: async (event, { params }) =>\n at(params.communityId, text(event, 'orgUserId'), { messageId: text(event, 'messageId') }),\n },\n};\n"],"mappings":"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"}
|
|
@@ -15,6 +15,8 @@ declare const automationEvents: {
|
|
|
15
15
|
input: Record<string, JsonValue>;
|
|
16
16
|
}[];
|
|
17
17
|
enabled: boolean;
|
|
18
|
+
filter: Record<string, JsonValue> | null;
|
|
19
|
+
source: "system" | "user";
|
|
18
20
|
createdAt: Date;
|
|
19
21
|
updatedAt: Date;
|
|
20
22
|
}, "automation.created", 2>, {
|
|
@@ -29,6 +31,8 @@ declare const automationEvents: {
|
|
|
29
31
|
input: Record<string, unknown>;
|
|
30
32
|
}[];
|
|
31
33
|
enabled: boolean;
|
|
34
|
+
filter: Record<string, unknown> | null;
|
|
35
|
+
source: "system" | "user";
|
|
32
36
|
createdAt: unknown;
|
|
33
37
|
updatedAt: unknown;
|
|
34
38
|
}, undefined>;
|
|
@@ -44,6 +48,8 @@ declare const automationEvents: {
|
|
|
44
48
|
input: Record<string, JsonValue>;
|
|
45
49
|
}[];
|
|
46
50
|
enabled: boolean;
|
|
51
|
+
filter: Record<string, JsonValue> | null;
|
|
52
|
+
source: "system" | "user";
|
|
47
53
|
createdAt: Date;
|
|
48
54
|
updatedAt: Date;
|
|
49
55
|
}, "automation.updated", 2>, {
|
|
@@ -58,6 +64,8 @@ declare const automationEvents: {
|
|
|
58
64
|
input: Record<string, unknown>;
|
|
59
65
|
}[];
|
|
60
66
|
enabled: boolean;
|
|
67
|
+
filter: Record<string, unknown> | null;
|
|
68
|
+
source: "system" | "user";
|
|
61
69
|
createdAt: unknown;
|
|
62
70
|
updatedAt: unknown;
|
|
63
71
|
}, undefined>;
|
|
@@ -73,6 +81,8 @@ declare const automationEvents: {
|
|
|
73
81
|
input: Record<string, JsonValue>;
|
|
74
82
|
}[];
|
|
75
83
|
enabled: boolean;
|
|
84
|
+
filter: Record<string, JsonValue> | null;
|
|
85
|
+
source: "system" | "user";
|
|
76
86
|
createdAt: Date;
|
|
77
87
|
updatedAt: Date;
|
|
78
88
|
}, "automation.deleted", 2>, {
|
|
@@ -87,6 +97,8 @@ declare const automationEvents: {
|
|
|
87
97
|
input: Record<string, unknown>;
|
|
88
98
|
}[];
|
|
89
99
|
enabled: boolean;
|
|
100
|
+
filter: Record<string, unknown> | null;
|
|
101
|
+
source: "system" | "user";
|
|
90
102
|
createdAt: unknown;
|
|
91
103
|
updatedAt: unknown;
|
|
92
104
|
}, undefined>;
|
|
@@ -102,6 +114,8 @@ declare const automationEvents: {
|
|
|
102
114
|
input: Record<string, JsonValue>;
|
|
103
115
|
}[];
|
|
104
116
|
enabled: boolean;
|
|
117
|
+
filter: Record<string, JsonValue> | null;
|
|
118
|
+
source: "system" | "user";
|
|
105
119
|
createdAt: Date;
|
|
106
120
|
updatedAt: Date;
|
|
107
121
|
}, "automation.enabled", 2>, {
|
|
@@ -116,6 +130,8 @@ declare const automationEvents: {
|
|
|
116
130
|
input: Record<string, unknown>;
|
|
117
131
|
}[];
|
|
118
132
|
enabled: boolean;
|
|
133
|
+
filter: Record<string, unknown> | null;
|
|
134
|
+
source: "system" | "user";
|
|
119
135
|
createdAt: unknown;
|
|
120
136
|
updatedAt: unknown;
|
|
121
137
|
}, undefined>;
|
|
@@ -131,6 +147,8 @@ declare const automationEvents: {
|
|
|
131
147
|
input: Record<string, JsonValue>;
|
|
132
148
|
}[];
|
|
133
149
|
enabled: boolean;
|
|
150
|
+
filter: Record<string, JsonValue> | null;
|
|
151
|
+
source: "system" | "user";
|
|
134
152
|
createdAt: Date;
|
|
135
153
|
updatedAt: Date;
|
|
136
154
|
}, "automation.disabled", 2>, {
|
|
@@ -145,6 +163,8 @@ declare const automationEvents: {
|
|
|
145
163
|
input: Record<string, unknown>;
|
|
146
164
|
}[];
|
|
147
165
|
enabled: boolean;
|
|
166
|
+
filter: Record<string, unknown> | null;
|
|
167
|
+
source: "system" | "user";
|
|
148
168
|
createdAt: unknown;
|
|
149
169
|
updatedAt: unknown;
|
|
150
170
|
}, undefined>;
|
|
@@ -161,6 +181,7 @@ declare const automationEvents: {
|
|
|
161
181
|
type: string;
|
|
162
182
|
status: "completed" | "failed";
|
|
163
183
|
error?: string | undefined;
|
|
184
|
+
recipients?: string[] | undefined;
|
|
164
185
|
}[];
|
|
165
186
|
startedAt: Date;
|
|
166
187
|
finishedAt: Date | null;
|
|
@@ -179,6 +200,7 @@ declare const automationEvents: {
|
|
|
179
200
|
type: string;
|
|
180
201
|
status: "completed" | "failed";
|
|
181
202
|
error?: string | undefined;
|
|
203
|
+
recipients?: string[] | undefined;
|
|
182
204
|
}[];
|
|
183
205
|
startedAt: unknown;
|
|
184
206
|
finishedAt: unknown;
|
|
@@ -198,6 +220,7 @@ declare const automationEvents: {
|
|
|
198
220
|
type: string;
|
|
199
221
|
status: "completed" | "failed";
|
|
200
222
|
error?: string | undefined;
|
|
223
|
+
recipients?: string[] | undefined;
|
|
201
224
|
}[];
|
|
202
225
|
startedAt: Date;
|
|
203
226
|
finishedAt: Date | null;
|
|
@@ -216,6 +239,7 @@ declare const automationEvents: {
|
|
|
216
239
|
type: string;
|
|
217
240
|
status: "completed" | "failed";
|
|
218
241
|
error?: string | undefined;
|
|
242
|
+
recipients?: string[] | undefined;
|
|
219
243
|
}[];
|
|
220
244
|
startedAt: unknown;
|
|
221
245
|
finishedAt: unknown;
|
|
@@ -235,6 +259,7 @@ declare const automationEvents: {
|
|
|
235
259
|
type: string;
|
|
236
260
|
status: "completed" | "failed";
|
|
237
261
|
error?: string | undefined;
|
|
262
|
+
recipients?: string[] | undefined;
|
|
238
263
|
}[];
|
|
239
264
|
startedAt: Date;
|
|
240
265
|
finishedAt: Date | null;
|
|
@@ -253,6 +278,7 @@ declare const automationEvents: {
|
|
|
253
278
|
type: string;
|
|
254
279
|
status: "completed" | "failed";
|
|
255
280
|
error?: string | undefined;
|
|
281
|
+
recipients?: string[] | undefined;
|
|
256
282
|
}[];
|
|
257
283
|
startedAt: unknown;
|
|
258
284
|
finishedAt: unknown;
|
|
@@ -264,11 +290,13 @@ declare const automationEvents: {
|
|
|
264
290
|
type: string;
|
|
265
291
|
status: "completed" | "failed";
|
|
266
292
|
error?: string | undefined;
|
|
293
|
+
recipients?: string[] | undefined;
|
|
267
294
|
}, "automation.action.failed", 1>, {
|
|
268
295
|
index: number;
|
|
269
296
|
type: string;
|
|
270
297
|
status: "completed" | "failed";
|
|
271
298
|
error?: string | undefined;
|
|
299
|
+
recipients?: string[] | undefined;
|
|
272
300
|
}, undefined>;
|
|
273
301
|
};
|
|
274
302
|
type AutomationCreated = EventOf<typeof automationEvents.automationCreated>;
|
|
@@ -1,9 +1,11 @@
|
|
|
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
3
|
import { AutomationDispatch, AutomationEngine, AutomationExecutor, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
|
|
4
|
-
import { AutomationKindMismatchError, InvalidTriggerError, ReservedActionError } from "./model.js";
|
|
4
|
+
import { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, InvalidTriggerError, ReservedActionError, actionFailureMessage } from "./model.js";
|
|
5
5
|
import "./types.js";
|
|
6
6
|
import { AutomationRunsRepository, AutomationsRepository, AutomationsService, AutomationsUnitOfWork, NewAutomation, NewAutomationRun } from "./ports.js";
|
|
7
|
+
import { CommunityMailReads, GrantWriter, ScheduledWork } from "./community-mail.js";
|
|
7
8
|
import { AutomationActionFailed, AutomationCreated, AutomationDeleted, AutomationDisabled, AutomationEnabled, AutomationEvent, AutomationRunCompleted, AutomationRunFailed, AutomationRunStarted, AutomationUpdated, automationEvents } from "./events.js";
|
|
8
9
|
import { AutomationsServiceImpl } from "./service.js";
|
|
9
|
-
|
|
10
|
+
import { cronMatches } from "./schedule.js";
|
|
11
|
+
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, type CommunityMailReads, type CreateAutomationInput, type CreateWebhookInput, type CreatedWebhook, type GrantWriter, InvalidTriggerError, type NewAutomation, type NewAutomationRun, type Page, ReservedActionError, type ScheduledWork, type UpdateAutomationInput, type UpdateWebhookInput, type Webhook, type WebhookRequest, type WebhookResponse, type WebhookSecret, type WebhookSender, actionFailureMessage, automationEvents, cronMatches };
|
|
@@ -1,4 +1,5 @@
|
|
|
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
|
-
export { AutomationKindMismatchError, AutomationsServiceImpl, InvalidTriggerError, ReservedActionError, automationEvents };
|
|
5
|
+
export { ACTION_FAILED, ActionFailedError, AutomationKindMismatchError, AutomationsServiceImpl, InvalidTriggerError, ReservedActionError, actionFailureMessage, automationEvents, cronMatches };
|
|
@@ -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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DomainEvent, Page } from "../types/shared.js";
|
|
2
2
|
import { Automation, AutomationKind, AutomationRun, AutomationRunsQuery, AutomationsQuery, AvailableActions, AvailableTriggers, CreateAutomationInput, CreateWebhookInput, CreatedWebhook, UpdateAutomationInput, UpdateWebhookInput, Webhook, WebhookSecret } from "../types/schemas/automations.js";
|
|
3
|
-
import { AutomationDispatch, AutomationEngine, AutomationExecutor, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
|
|
3
|
+
import { AutomationDispatch, AutomationEngine, AutomationExecutor, ScheduledAutomation, WebhookRequest, WebhookResponse, WebhookSender } from "../types/automations.js";
|
|
4
4
|
import "../types/index.js";
|
|
5
5
|
import { CredentialStore, OutboxAppender, UnitOfWork } from "../shared/ports.js";
|
|
6
6
|
import "./model.js";
|
|
@@ -8,6 +8,7 @@ import "./types.js";
|
|
|
8
8
|
//#region src/automations/ports.d.ts
|
|
9
9
|
type NewAutomation = CreateAutomationInput & {
|
|
10
10
|
kind: AutomationKind;
|
|
11
|
+
source?: 'system' | 'user';
|
|
11
12
|
};
|
|
12
13
|
/** A run row before persistence assigns its id and event_id. */
|
|
13
14
|
type NewAutomationRun = Omit<AutomationRun, 'id' | 'eventId'>;
|
|
@@ -35,6 +36,7 @@ interface AutomationsService {
|
|
|
35
36
|
}
|
|
36
37
|
interface AutomationsRepository {
|
|
37
38
|
insert(orgId: string, input: NewAutomation): Promise<Automation>;
|
|
39
|
+
insertSeed(orgId: string, input: NewAutomation): Promise<Automation | null>;
|
|
38
40
|
update(orgId: string, id: string, patch: UpdateAutomationInput): Promise<Automation | null>;
|
|
39
41
|
/** Returns the deleted row (the event snapshot), or null if it didn't exist. */
|
|
40
42
|
delete(orgId: string, id: string): Promise<Automation | null>;
|
|
@@ -42,6 +44,7 @@ interface AutomationsRepository {
|
|
|
42
44
|
listByOrg(orgId: string, kind?: AutomationKind): Promise<Automation[]>;
|
|
43
45
|
/** All rows whose triggers include `trigger`, enabled and disabled alike — the service filters to `enabled`. */
|
|
44
46
|
listByTrigger(orgId: string, trigger: string): Promise<Automation[]>;
|
|
47
|
+
listSchedules(): Promise<ScheduledAutomation[]>;
|
|
45
48
|
}
|
|
46
49
|
interface AutomationRunsRepository {
|
|
47
50
|
/** Keyed by (orgId, automationId, event.id); returns `null` if this event was already run for this automation (duplicate). */
|
|
@@ -55,6 +58,7 @@ interface AutomationRunsRepository {
|
|
|
55
58
|
finishedAt: Date;
|
|
56
59
|
}): Promise<AutomationRun | null>;
|
|
57
60
|
list(orgId: string, automationId: string, query: AutomationRunsQuery): Promise<Page<AutomationRun>>;
|
|
61
|
+
recentRecipients(orgId: string, automationId: string, chatId: string, since: Date): Promise<string[]>;
|
|
58
62
|
}
|
|
59
63
|
/** Tx-scoped port bundle for this context's mutating use cases — every member
|
|
60
64
|
* is bound to the UnitOfWork's transaction, so the write(s) and the event
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/automations/schedule.d.ts
|
|
2
|
+
declare function cronMatches(expression: string, at: Date): boolean;
|
|
3
|
+
declare function cronSupported(expression: string): boolean;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { cronMatches, cronSupported };
|
|
6
|
+
//# sourceMappingURL=schedule.d.ts.map
|