@headless-lms/server 0.3.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/app/community-mail.d.ts +6 -8
- package/dist/app/community-mail.js +13 -17
- package/dist/app/community-mail.js.map +1 -1
- package/dist/app/container.d.ts +27 -10
- package/dist/app/container.js +178 -22
- package/dist/app/container.js.map +1 -1
- package/dist/app/notification-channels.d.ts +47 -0
- package/dist/app/notification-channels.js +174 -0
- package/dist/app/notification-channels.js.map +1 -0
- package/dist/app/notification-reads.d.ts +23 -0
- package/dist/app/notification-reads.js +95 -0
- package/dist/app/notification-reads.js.map +1 -0
- package/dist/http/errors.d.ts +1 -0
- package/dist/http/errors.js +16 -1
- package/dist/http/errors.js.map +1 -1
- package/dist/http/mcp/tools/communities.js +1 -1
- package/dist/http/mcp/tools/communities.js.map +1 -1
- package/dist/http/plugins/error-handler.js +3 -1
- package/dist/http/plugins/error-handler.js.map +1 -1
- package/dist/http/routes/automations.js +3 -3
- package/dist/http/routes/automations.js.map +1 -1
- package/dist/http/routes/communities.js +67 -7
- package/dist/http/routes/communities.js.map +1 -1
- package/dist/http/routes/member/actor.d.ts +1 -1
- package/dist/http/routes/member/chats.js +9 -30
- package/dist/http/routes/member/chats.js.map +1 -1
- package/dist/http/routes/member/community.js +25 -1
- package/dist/http/routes/member/community.js.map +1 -1
- package/dist/http/routes/member/devices.d.ts +7 -0
- package/dist/http/routes/member/devices.js +98 -0
- package/dist/http/routes/member/devices.js.map +1 -0
- package/dist/http/routes/member/index.js +4 -0
- package/dist/http/routes/member/index.js.map +1 -1
- package/dist/http/routes/member/notification-settings.d.ts +7 -0
- package/dist/http/routes/member/notification-settings.js +108 -0
- package/dist/http/routes/member/notification-settings.js.map +1 -0
- package/dist/http/routes/member/notifications.js +66 -42
- package/dist/http/routes/member/notifications.js.map +1 -1
- package/dist/http/routes/member/posts.js +33 -33
- package/dist/http/routes/member/posts.js.map +1 -1
- package/dist/http/routes/organizations.js +122 -1
- package/dist/http/routes/organizations.js.map +1 -1
- package/dist/http/schemas/assets.d.ts +6 -6
- package/dist/http/schemas/automations.d.ts +0 -4
- package/dist/http/schemas/chats.d.ts +34 -11
- package/dist/http/schemas/chats.js +4 -6
- package/dist/http/schemas/chats.js.map +1 -1
- package/dist/http/schemas/community.d.ts +77 -17
- package/dist/http/schemas/community.js +6 -3
- package/dist/http/schemas/community.js.map +1 -1
- package/dist/http/schemas/discussion.d.ts +23 -1
- package/dist/http/schemas/discussion.js +14 -2
- package/dist/http/schemas/discussion.js.map +1 -1
- package/dist/http/schemas/index.d.ts +6 -6
- package/dist/http/schemas/index.js +6 -6
- package/dist/http/schemas/integrations.d.ts +4 -4
- package/dist/http/schemas/members.d.ts +5 -5
- package/dist/http/schemas/notifications.d.ts +498 -175
- package/dist/http/schemas/notifications.js +148 -28
- package/dist/http/schemas/notifications.js.map +1 -1
- package/dist/http/schemas/posts.d.ts +37 -3
- package/dist/http/schemas/profile.d.ts +2 -2
- package/dist/http/schemas/shared.d.ts +10 -3
- package/dist/http/schemas/shared.js +3 -2
- package/dist/http/schemas/shared.js.map +1 -1
- package/dist/http/schemas/students.d.ts +3 -3
- package/dist/http/scope.d.ts +2 -1
- package/dist/http/scope.js +7 -1
- package/dist/http/scope.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js.map +1 -1
- package/dist/packages/server/package.js +1 -1
- package/package.json +5 -5
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
import { ContentService } from "@headless-lms/core/content";
|
|
2
2
|
import { EntitlementsService } from "@headless-lms/core/entitlements";
|
|
3
|
-
import { ChatService, DiscussionService, PostService } from "@headless-lms/core/discussion";
|
|
3
|
+
import { ChatService, DiscussionService, PostService, SubscriptionService } from "@headless-lms/core/discussion";
|
|
4
4
|
import { IdentityService } from "@headless-lms/core/identity";
|
|
5
5
|
import { OrganizationService } from "@headless-lms/core/organizations";
|
|
6
|
-
import {
|
|
7
|
-
import { CommunityMailReads, GrantWriter, ScheduledWork } from "@headless-lms/core/automations";
|
|
6
|
+
import { CommunityMailReads, GrantWriter } from "@headless-lms/core/automations";
|
|
8
7
|
//#region src/app/community-mail.d.ts
|
|
9
8
|
type CommunityMailDeps = {
|
|
10
9
|
content: Pick<ContentService, 'getCommunity' | 'getSpace' | 'listCommunitiesById'>;
|
|
11
|
-
entitlements: Pick<EntitlementsService, 'openSpacesFor' | 'communitiesOpenedBy' | 'communityMembersAmong' | 'spaceOpenersAmong' | 'spaceOpeners' | 'communityModeratorIds' | 'countActiveSpaceMembers' | 'communityIdsOpenedFor' | 'ensureGrant'
|
|
10
|
+
entitlements: Pick<EntitlementsService, 'openSpacesFor' | 'communitiesOpenedBy' | 'communityMembersAmong' | 'spaceOpenersAmong' | 'spaceOpeners' | 'communityModeratorIds' | 'countActiveSpaceMembers' | 'communityIdsOpenedFor' | 'ensureGrant'>;
|
|
12
11
|
organizations: Pick<OrganizationService, 'getOrgUserById' | 'staffOrgUserIds'>;
|
|
13
12
|
identity: Pick<IdentityService, 'displayName'>;
|
|
14
|
-
posts: Pick<PostService, '
|
|
15
|
-
|
|
13
|
+
posts: Pick<PostService, 'find'>;
|
|
14
|
+
subscriptions: Pick<SubscriptionService, 'followerIds' | 'itemSubscriptions'>;
|
|
15
|
+
discussion: Pick<DiscussionService, 'getComment'>;
|
|
16
16
|
chats: Pick<ChatService, 'chatSummary' | 'latestMessageBody' | 'isBlocked'>;
|
|
17
|
-
assets: Pick<AssetsService, 'removeUnattached' | 'hasUnattached'>;
|
|
18
17
|
};
|
|
19
18
|
declare function communityMail(deps: CommunityMailDeps): {
|
|
20
19
|
mail: Omit<CommunityMailReads, 'recentMessageRecipients'>;
|
|
21
20
|
grants: GrantWriter;
|
|
22
|
-
scheduledWork: ScheduledWork;
|
|
23
21
|
};
|
|
24
22
|
//#endregion
|
|
25
23
|
export { CommunityMailDeps, communityMail };
|
|
@@ -31,12 +31,14 @@ function communityMail(deps) {
|
|
|
31
31
|
const orgUser = await deps.organizations.getOrgUserById(orgId, orgUserId);
|
|
32
32
|
return deps.identity.displayName(orgUser?.userId ?? null);
|
|
33
33
|
},
|
|
34
|
-
followerIds: (orgId, postId) => deps.
|
|
34
|
+
followerIds: (orgId, postId) => deps.subscriptions.followerIds(orgId, postId),
|
|
35
35
|
async comment(orgId, commentId) {
|
|
36
36
|
const comment = await deps.discussion.getComment(orgId, commentId);
|
|
37
37
|
return comment ? {
|
|
38
38
|
orgUserId: comment.orgUserId,
|
|
39
39
|
postId: comment.postId,
|
|
40
|
+
activityId: comment.activityId,
|
|
41
|
+
parentId: comment.parentId,
|
|
40
42
|
body: comment.body
|
|
41
43
|
} : null;
|
|
42
44
|
},
|
|
@@ -52,18 +54,23 @@ function communityMail(deps) {
|
|
|
52
54
|
},
|
|
53
55
|
async chat(orgId, chatId) {
|
|
54
56
|
const summary = await deps.chats.chatSummary(orgId, chatId);
|
|
55
|
-
|
|
57
|
+
if (!summary) return null;
|
|
58
|
+
const mutes = new Map((await deps.subscriptions.itemSubscriptions(orgId, {
|
|
59
|
+
type: "chat",
|
|
60
|
+
id: chatId
|
|
61
|
+
})).filter((subscription) => subscription.state === "muted").map((subscription) => [subscription.orgUserId, subscription.mutedUntil]));
|
|
62
|
+
return {
|
|
56
63
|
communityId: summary.chat.communityId,
|
|
57
64
|
kind: summary.chat.kind,
|
|
58
65
|
status: summary.chat.status,
|
|
59
66
|
createdBy: summary.chat.createdBy,
|
|
60
67
|
participants: summary.participants.map((participant) => ({
|
|
61
68
|
orgUserId: participant.orgUserId,
|
|
62
|
-
muted: participant.
|
|
63
|
-
mutedUntil: participant.
|
|
69
|
+
muted: mutes.has(participant.orgUserId),
|
|
70
|
+
mutedUntil: mutes.get(participant.orgUserId) ?? null,
|
|
64
71
|
leftAt: participant.leftAt
|
|
65
72
|
}))
|
|
66
|
-
}
|
|
73
|
+
};
|
|
67
74
|
},
|
|
68
75
|
latestMessageBody: (orgId, chatId) => deps.chats.latestMessageBody(orgId, chatId),
|
|
69
76
|
pairBlocked: (orgId, communityId, a, b) => deps.chats.isBlocked(orgId, communityId, a, b),
|
|
@@ -76,18 +83,7 @@ function communityMail(deps) {
|
|
|
76
83
|
}));
|
|
77
84
|
}
|
|
78
85
|
},
|
|
79
|
-
grants: { grant: (orgId, input) => deps.entitlements.ensureGrant(orgId, input) }
|
|
80
|
-
scheduledWork: {
|
|
81
|
-
publishDuePosts: (orgId, now) => deps.posts.publishDue(orgId, now),
|
|
82
|
-
hasDuePosts: (orgId, now) => deps.posts.hasDue(orgId, now),
|
|
83
|
-
expireDueGrants: (orgId, now) => deps.entitlements.expireDue(orgId, now),
|
|
84
|
-
hasDueGrants: (orgId, now) => deps.entitlements.hasDueNotices(orgId, now),
|
|
85
|
-
sendDigest: (orgId, now) => deps.discussion.sendDigest(orgId, now),
|
|
86
|
-
removeUnattachedUploads: async (orgId, now) => {
|
|
87
|
-
await deps.assets.removeUnattached(orgId, now);
|
|
88
|
-
},
|
|
89
|
-
hasUnattachedUploads: (orgId, now) => deps.assets.hasUnattached(orgId, now)
|
|
90
|
-
}
|
|
86
|
+
grants: { grant: (orgId, input) => deps.entitlements.ensureGrant(orgId, input) }
|
|
91
87
|
};
|
|
92
88
|
}
|
|
93
89
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"community-mail.js","names":[],"sources":["../../src/app/community-mail.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"community-mail.js","names":[],"sources":["../../src/app/community-mail.ts"],"sourcesContent":["import type { CommunityMailReads, GrantWriter } from '@headless-lms/core/automations';\nimport type { ContentService } from '@headless-lms/core/content';\nimport type {\n ChatService,\n DiscussionService,\n PostService,\n SubscriptionService,\n} from '@headless-lms/core/discussion';\nimport type { EntitlementsService } from '@headless-lms/core/entitlements';\nimport type { IdentityService } from '@headless-lms/core/identity';\nimport type { OrganizationService } from '@headless-lms/core/organizations';\n\nexport type CommunityMailDeps = {\n content: Pick<ContentService, 'getCommunity' | 'getSpace' | 'listCommunitiesById'>;\n entitlements: Pick<\n EntitlementsService,\n | 'openSpacesFor'\n | 'communitiesOpenedBy'\n | 'communityMembersAmong'\n | 'spaceOpenersAmong'\n | 'spaceOpeners'\n | 'communityModeratorIds'\n | 'countActiveSpaceMembers'\n | 'communityIdsOpenedFor'\n | 'ensureGrant'\n >;\n organizations: Pick<OrganizationService, 'getOrgUserById' | 'staffOrgUserIds'>;\n identity: Pick<IdentityService, 'displayName'>;\n posts: Pick<PostService, 'find'>;\n subscriptions: Pick<SubscriptionService, 'followerIds' | 'itemSubscriptions'>;\n discussion: Pick<DiscussionService, 'getComment'>;\n chats: Pick<ChatService, 'chatSummary' | 'latestMessageBody' | 'isBlocked'>;\n};\n\nexport function communityMail(deps: CommunityMailDeps): {\n mail: Omit<CommunityMailReads, 'recentMessageRecipients'>;\n grants: GrantWriter;\n} {\n const mail: Omit<CommunityMailReads, 'recentMessageRecipients'> = {\n async communityTitle(orgId, communityId) {\n return (await deps.content.getCommunity(orgId, communityId))?.title ?? null;\n },\n async space(orgId, spaceId) {\n const space = await deps.content.getSpace(orgId, spaceId);\n return space\n ? { name: space.name, communityId: space.communityId, capacity: space.capacity }\n : null;\n },\n async openSpaceNames(orgId, orgUserId, communityId) {\n const orgUser = await deps.organizations.getOrgUserById(orgId, orgUserId);\n if (!orgUser) {\n return [];\n }\n const spaces = await deps.entitlements.openSpacesFor(\n orgId,\n { id: orgUser.id, role: orgUser.role },\n communityId,\n );\n return spaces.map((space) => space.name);\n },\n communitiesOpenedBy: (orgId, grant) => deps.entitlements.communitiesOpenedBy(orgId, grant),\n communityMembersAmong: (orgId, communityId, ids) =>\n deps.entitlements.communityMembersAmong(orgId, communityId, ids),\n spaceOpenersAmong: (orgId, spaceId, ids) =>\n deps.entitlements.spaceOpenersAmong(orgId, spaceId, ids),\n spaceOpeners: (orgId, spaceId) => deps.entitlements.spaceOpeners(orgId, spaceId),\n moderationAudience: (orgId, communityId) =>\n deps.entitlements.communityModeratorIds(orgId, communityId),\n staffIds: (orgId) => deps.organizations.staffOrgUserIds(orgId),\n async displayName(orgId, orgUserId) {\n const orgUser = await deps.organizations.getOrgUserById(orgId, orgUserId);\n return deps.identity.displayName(orgUser?.userId ?? null);\n },\n followerIds: (orgId, postId) => deps.subscriptions.followerIds(orgId, postId),\n async comment(orgId, commentId) {\n const comment = await deps.discussion.getComment(orgId, commentId);\n return comment\n ? {\n orgUserId: comment.orgUserId,\n postId: comment.postId,\n activityId: comment.activityId,\n parentId: comment.parentId,\n body: comment.body,\n }\n : null;\n },\n async post(orgId, postId) {\n const post = await deps.posts.find(orgId, postId);\n return post\n ? {\n title: post.title,\n body: post.body,\n spaceId: post.spaceId,\n orgUserId: post.orgUserId,\n communityId: post.communityId,\n }\n : null;\n },\n async chat(orgId, chatId) {\n const summary = await deps.chats.chatSummary(orgId, chatId);\n if (!summary) {\n return null;\n }\n const mutes = new Map(\n (await deps.subscriptions.itemSubscriptions(orgId, { type: 'chat', id: chatId }))\n .filter((subscription) => subscription.state === 'muted')\n .map((subscription) => [subscription.orgUserId, subscription.mutedUntil]),\n );\n return {\n communityId: summary.chat.communityId,\n kind: summary.chat.kind,\n status: summary.chat.status,\n createdBy: summary.chat.createdBy,\n participants: summary.participants.map((participant) => ({\n orgUserId: participant.orgUserId,\n muted: mutes.has(participant.orgUserId),\n mutedUntil: mutes.get(participant.orgUserId) ?? null,\n leftAt: participant.leftAt,\n })),\n };\n },\n latestMessageBody: (orgId, chatId) => deps.chats.latestMessageBody(orgId, chatId),\n pairBlocked: (orgId, communityId, a, b) => deps.chats.isBlocked(orgId, communityId, a, b),\n activeMemberCount: (orgId, spaceId) =>\n deps.entitlements.countActiveSpaceMembers(orgId, spaceId),\n async memberCommunityTitles(orgId, orgUserId) {\n const ids = await deps.entitlements.communityIdsOpenedFor(orgId, orgUserId);\n const communities = await deps.content.listCommunitiesById(orgId, ids);\n return communities.map((community) => ({ id: community.id, title: community.title }));\n },\n };\n return {\n mail,\n grants: {\n grant: (orgId, input) => deps.entitlements.ensureGrant(orgId, input),\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/app/container.d.ts
CHANGED
|
@@ -2,21 +2,21 @@ import { McpEndpoints } from "./mcp-endpoints.js";
|
|
|
2
2
|
import { PollingOutboxRelayConfig } from "@headless-lms/adapter-defaults/events/outbox-relay";
|
|
3
3
|
import { LogLevel, PinoInstance, RequestLogContext } from "@headless-lms/adapter-defaults/logging";
|
|
4
4
|
import { BetterAuth } from "@headless-lms/adapter-auth";
|
|
5
|
-
import { ContentService } from "@headless-lms/core/content";
|
|
5
|
+
import { CommunityNotificationCategories, ContentService } from "@headless-lms/core/content";
|
|
6
6
|
import { EntitlementsServiceImpl } from "@headless-lms/core/entitlements";
|
|
7
7
|
import { ProgressServiceImpl } from "@headless-lms/core/progress";
|
|
8
|
-
import { ChatServiceImpl, DiscussionServiceImpl, PostServiceImpl } from "@headless-lms/core/discussion";
|
|
9
|
-
import { IdentityServiceImpl,
|
|
10
|
-
import { OrgAdmin, OrganizationServiceImpl } from "@headless-lms/core/organizations";
|
|
8
|
+
import { ChatServiceImpl, DiscussionServiceImpl, PostServiceImpl, SubscriptionServiceImpl } from "@headless-lms/core/discussion";
|
|
9
|
+
import { DevicesServiceImpl, IdentityServiceImpl, NotificationSettingsServiceImpl, SessionAdmin } from "@headless-lms/core/identity";
|
|
10
|
+
import { OrgAdmin, OrgNotificationCategories, OrganizationServiceImpl } from "@headless-lms/core/organizations";
|
|
11
11
|
import { AssetsServiceImpl } from "@headless-lms/core/assets";
|
|
12
12
|
import { IntegrationsServiceImpl } from "@headless-lms/core/integrations";
|
|
13
|
-
import { AutomationsServiceImpl } from "@headless-lms/core/automations";
|
|
13
|
+
import { AutomationsServiceImpl, NotificationCategories, NotificationsServiceImpl } from "@headless-lms/core/automations";
|
|
14
|
+
import { Mailer } from "@headless-lms/core/shared/mailer";
|
|
14
15
|
import { AdminReportServiceImpl } from "@headless-lms/core/reporting/admin";
|
|
15
16
|
import { MemberReportServiceImpl } from "@headless-lms/core/reporting/member";
|
|
16
|
-
import { Mailer } from "@headless-lms/core/shared/mailer";
|
|
17
17
|
import { SettingsService } from "@headless-lms/core/shared/settings";
|
|
18
|
-
import { AutomationEngine, WebhookSender } from "@headless-lms/core/types";
|
|
19
|
-
import { CredentialStore, EmailSender, Logger, ObjectStorage, OutboxRelay, TemplateContext, TemplateRenderer } from "@headless-lms/core/shared/ports";
|
|
18
|
+
import { AutomationEngine, PushConfig, WebhookSender } from "@headless-lms/core/types";
|
|
19
|
+
import { ChannelRegistry, CredentialStore, EmailSender, Logger, NotificationChannel, NotificationTypeRegistry, ObjectStorage, OutboxRelay, PushSender, Scheduler, TemplateContext, TemplateRenderer } from "@headless-lms/core/shared/ports";
|
|
20
20
|
//#region src/app/container.d.ts
|
|
21
21
|
/** Installation-supplied ports; an absent slot falls back to a fail-loudly stub. */
|
|
22
22
|
interface AdapterOverrides {
|
|
@@ -25,9 +25,14 @@ interface AdapterOverrides {
|
|
|
25
25
|
/** Resolves email templates to rendered content. Absent → fail-loudly stub. */
|
|
26
26
|
templates?: TemplateRenderer;
|
|
27
27
|
/** Durable automation engine, or a factory given the automations logger. Absent → InlineAutomationEngine (in-process, one attempt per action). */
|
|
28
|
-
workflows?: AutomationEngine | ((logger: Logger) => AutomationEngine);
|
|
28
|
+
workflows?: (AutomationEngine & Scheduler) | ((logger: Logger) => AutomationEngine & Scheduler);
|
|
29
29
|
/** Outbound HTTP for webhook deliveries. Absent → FetchWebhookSender (public addresses only, 10s timeout). */
|
|
30
30
|
webhooks?: WebhookSender;
|
|
31
|
+
/** Notification channels beyond in-app, email and push; each key must be new. */
|
|
32
|
+
notificationChannels?: NotificationChannel[];
|
|
33
|
+
/** Push credentials per provider. Absent → no provider is configured and devices cannot register. */
|
|
34
|
+
push?: PushConfig;
|
|
35
|
+
pushSender?: PushSender;
|
|
31
36
|
}
|
|
32
37
|
interface BuildContainerOptions {
|
|
33
38
|
/** Installation's plugins folder, scanned by loadIntegrations. Absent → no integrations. */
|
|
@@ -72,6 +77,7 @@ interface OutboxConfig {
|
|
|
72
77
|
pollIntervalMs?: number;
|
|
73
78
|
/** Max rows fetched/dispatched per tick. Default 100. */
|
|
74
79
|
batchSize?: number;
|
|
80
|
+
concurrency?: number;
|
|
75
81
|
}
|
|
76
82
|
declare const OUTBOX_DEFAULTS: PollingOutboxRelayConfig;
|
|
77
83
|
declare function resolveOutboxConfig(config?: OutboxConfig): PollingOutboxRelayConfig;
|
|
@@ -87,7 +93,6 @@ interface Container {
|
|
|
87
93
|
mcp: McpEndpoints;
|
|
88
94
|
orgProvider: OrgAdmin;
|
|
89
95
|
identity: IdentityServiceImpl;
|
|
90
|
-
notifications: NotificationServiceImpl;
|
|
91
96
|
organizations: OrganizationServiceImpl;
|
|
92
97
|
content: ContentService;
|
|
93
98
|
entitlements: EntitlementsServiceImpl;
|
|
@@ -95,9 +100,20 @@ interface Container {
|
|
|
95
100
|
discussion: DiscussionServiceImpl;
|
|
96
101
|
posts: PostServiceImpl;
|
|
97
102
|
chats: ChatServiceImpl;
|
|
103
|
+
subscriptions: SubscriptionServiceImpl;
|
|
98
104
|
assets: AssetsServiceImpl;
|
|
99
105
|
integrations: IntegrationsServiceImpl;
|
|
100
106
|
automations: AutomationsServiceImpl;
|
|
107
|
+
notificationTypes: NotificationTypeRegistry;
|
|
108
|
+
notificationChannels: ChannelRegistry;
|
|
109
|
+
notificationCategories: {
|
|
110
|
+
community: CommunityNotificationCategories;
|
|
111
|
+
org: OrgNotificationCategories;
|
|
112
|
+
};
|
|
113
|
+
notificationCategoryLists: NotificationCategories;
|
|
114
|
+
notificationSettings: NotificationSettingsServiceImpl;
|
|
115
|
+
devices: DevicesServiceImpl;
|
|
116
|
+
notificationList: NotificationsServiceImpl;
|
|
101
117
|
/** Cross-cutting settings store. Not a context — a leaf every context may use;
|
|
102
118
|
* inject `settings.for('<namespace>')` into a service, never the service itself. */
|
|
103
119
|
settings: SettingsService;
|
|
@@ -117,6 +133,7 @@ interface Container {
|
|
|
117
133
|
* the installation's entry point starts it after listen (gen-openapi must
|
|
118
134
|
* not run a worker). buildServer stops it onClose. */
|
|
119
135
|
automationEngine: AutomationEngine;
|
|
136
|
+
scheduler: Scheduler;
|
|
120
137
|
/** Root logger port — components receive children bound with { name }. */
|
|
121
138
|
logger: Logger;
|
|
122
139
|
/** The raw pino root; buildServer hands it to Fastify so HTTP shares the stream. */
|
package/dist/app/container.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { buildNotificationRegistries, configuredPushSender } from "./notification-channels.js";
|
|
1
2
|
import { loadIntegrations } from "./integrations.js";
|
|
2
3
|
import { mcpEndpoints } from "./mcp-endpoints.js";
|
|
3
4
|
import { communityMail } from "./community-mail.js";
|
|
4
|
-
import {
|
|
5
|
+
import { notificationReads } from "./notification-reads.js";
|
|
6
|
+
import { DrizzleAdminRepository, DrizzleAssetsRepository, DrizzleAutomationRunsRepository, DrizzleAutomationsRepository, DrizzleChatRepository, DrizzleConnectionsRepository, DrizzleContentRepository, DrizzleCredentialStore, DrizzleDevicesRepository, DrizzleDigestRunRepository, DrizzleDiscussionRepository, DrizzleEntitlementsRepository, DrizzleIdentityRepository, DrizzleMemberRepository, DrizzleMembersRepository, DrizzleMentionsRepository, DrizzleNotificationSettingsRepository, DrizzleNotificationsRepository, DrizzleOrganizationsRepository, DrizzleOutboxAppender, DrizzleOutboxStore, DrizzlePostRepository, DrizzleProgressRepository, DrizzleSettingsRepository, DrizzleSubscriptionsRepository, DrizzleUnitOfWork, createDb } from "@headless-lms/adapter-db";
|
|
5
7
|
import { InMemoryEventBus } from "@headless-lms/adapter-defaults/events";
|
|
6
8
|
import { PollingOutboxRelay } from "@headless-lms/adapter-defaults/events/outbox-relay";
|
|
7
9
|
import { InlineAutomationEngine } from "@headless-lms/adapter-defaults/workflows";
|
|
@@ -10,24 +12,25 @@ import { EmailAdapter, StubTemplateRenderer } from "@headless-lms/adapter-defaul
|
|
|
10
12
|
import { createRootLogger, requestLogContext } from "@headless-lms/adapter-defaults/logging";
|
|
11
13
|
import { StorageAdapter } from "@headless-lms/adapter-defaults/storage";
|
|
12
14
|
import { BetterAuth } from "@headless-lms/adapter-auth";
|
|
13
|
-
import { ContentService } from "@headless-lms/core/content";
|
|
14
|
-
import { EntitlementsServiceImpl } from "@headless-lms/core/entitlements";
|
|
15
|
+
import { CommunityNotificationCategories, ContentItemTitles, ContentService } from "@headless-lms/core/content";
|
|
16
|
+
import { EntitlementsServiceImpl, entitlementsJobs, entitlementsRecurringJobs } from "@headless-lms/core/entitlements";
|
|
15
17
|
import { ProgressServiceImpl } from "@headless-lms/core/progress";
|
|
16
|
-
import { ChatServiceImpl, DiscussionServiceImpl, PostServiceImpl } from "@headless-lms/core/discussion";
|
|
17
|
-
import { IdentityServiceImpl,
|
|
18
|
-
import { OrganizationServiceImpl, parseRole } from "@headless-lms/core/organizations";
|
|
19
|
-
import { AssetsServiceImpl, createFileUrls } from "@headless-lms/core/assets";
|
|
18
|
+
import { ChatServiceImpl, DigestServiceImpl, DiscussionItemTitles, DiscussionServiceImpl, PostServiceImpl, SubscriptionServiceImpl, discussionJobs, discussionRecurringJobs } from "@headless-lms/core/discussion";
|
|
19
|
+
import { DevicesServiceImpl, IdentityServiceImpl, NotificationSettingsServiceImpl } from "@headless-lms/core/identity";
|
|
20
|
+
import { OrgNotificationCategories, OrganizationServiceImpl, parseRole } from "@headless-lms/core/organizations";
|
|
21
|
+
import { AssetsServiceImpl, assetsJobs, assetsRecurringJobs, createFileUrls } from "@headless-lms/core/assets";
|
|
20
22
|
import { IntegrationsServiceImpl } from "@headless-lms/core/integrations";
|
|
21
|
-
import { AutomationsServiceImpl } from "@headless-lms/core/automations";
|
|
23
|
+
import { AutomationsServiceImpl, DEFAULT_COMMUNITY_CATEGORIES, DEFAULT_ORG_CATEGORIES, NOTIFICATION_TYPES, NotificationDelivery, NotificationProcessor, NotificationsServiceImpl, RECIPIENT_RULES, SchedulerChatDebounce, notificationJobs } from "@headless-lms/core/automations";
|
|
24
|
+
import { Mailer } from "@headless-lms/core/shared/mailer";
|
|
22
25
|
import { AdminReportServiceImpl } from "@headless-lms/core/reporting/admin";
|
|
23
26
|
import { MemberReportServiceImpl } from "@headless-lms/core/reporting/member";
|
|
24
|
-
import { Mailer } from "@headless-lms/core/shared/mailer";
|
|
25
27
|
import { SettingsService } from "@headless-lms/core/shared/settings";
|
|
26
28
|
//#region src/app/container.ts
|
|
27
29
|
const OUTBOX_DEFAULTS = {
|
|
28
30
|
enabled: true,
|
|
29
31
|
pollIntervalMs: 1e3,
|
|
30
|
-
batchSize: 100
|
|
32
|
+
batchSize: 100,
|
|
33
|
+
concurrency: 16
|
|
31
34
|
};
|
|
32
35
|
function resolveOutboxConfig(config = {}) {
|
|
33
36
|
const overrides = Object.fromEntries(Object.entries(config).filter(([, value]) => value !== void 0));
|
|
@@ -89,10 +92,6 @@ async function buildContainer(config, options) {
|
|
|
89
92
|
images: assets,
|
|
90
93
|
fileUrls
|
|
91
94
|
});
|
|
92
|
-
const notifications = new NotificationServiceImpl({
|
|
93
|
-
repo: new DrizzleNotificationsRepository(db),
|
|
94
|
-
logger: logger.child({ name: "notifications" })
|
|
95
|
-
});
|
|
96
95
|
const organizationsRepo = new DrizzleOrganizationsRepository(db, logger.child({ name: "org" }));
|
|
97
96
|
const organizationsUow = new DrizzleUnitOfWork(db, (tx) => ({
|
|
98
97
|
organizations: new DrizzleOrganizationsRepository(tx, logger.child({ name: "org" })),
|
|
@@ -128,6 +127,38 @@ async function buildContainer(config, options) {
|
|
|
128
127
|
fileUrls,
|
|
129
128
|
logger: contentLogger
|
|
130
129
|
});
|
|
130
|
+
const pushConfig = options?.adapters?.push ?? {};
|
|
131
|
+
const pushSender = configuredPushSender(pushConfig, options?.adapters?.pushSender);
|
|
132
|
+
const notificationRegistries = buildNotificationRegistries({
|
|
133
|
+
declarations: NOTIFICATION_TYPES,
|
|
134
|
+
defaults: {
|
|
135
|
+
community: DEFAULT_COMMUNITY_CATEGORIES,
|
|
136
|
+
org: DEFAULT_ORG_CATEGORIES
|
|
137
|
+
},
|
|
138
|
+
mailer: options?.adapters?.email ? mailer : null,
|
|
139
|
+
emailOf: async (_orgId, userId) => (await identity.getUserById(userId))?.email ?? null,
|
|
140
|
+
push: pushSender ? {
|
|
141
|
+
sender: pushSender,
|
|
142
|
+
activeDevices: (orgId, userId, since) => devices.activeDevices(orgId, userId, since)
|
|
143
|
+
} : null,
|
|
144
|
+
channels: options?.adapters?.notificationChannels ?? []
|
|
145
|
+
});
|
|
146
|
+
const notificationCategories = {
|
|
147
|
+
community: new CommunityNotificationCategories({
|
|
148
|
+
communities: new DrizzleContentRepository(db, contentLogger),
|
|
149
|
+
settings,
|
|
150
|
+
types: notificationRegistries.types,
|
|
151
|
+
channels: notificationRegistries.channels,
|
|
152
|
+
logger: contentLogger
|
|
153
|
+
}),
|
|
154
|
+
org: new OrgNotificationCategories({
|
|
155
|
+
settings,
|
|
156
|
+
types: notificationRegistries.types,
|
|
157
|
+
channels: notificationRegistries.channels,
|
|
158
|
+
logger: logger.child({ name: "org" })
|
|
159
|
+
})
|
|
160
|
+
};
|
|
161
|
+
const notificationCategoryLists = { listFor: async (orgId, communityId) => (communityId ? await notificationCategories.community.get(orgId, communityId) : await notificationCategories.org.get(orgId, orgId)).categories };
|
|
131
162
|
const entitlementsUow = new DrizzleUnitOfWork(db, (tx) => ({
|
|
132
163
|
entitlements: new DrizzleEntitlementsRepository(tx, entitlementsLogger),
|
|
133
164
|
spaces: new DrizzleContentRepository(tx, contentLogger),
|
|
@@ -148,6 +179,22 @@ async function buildContainer(config, options) {
|
|
|
148
179
|
uow: entitlementsUow,
|
|
149
180
|
logger: entitlementsLogger
|
|
150
181
|
});
|
|
182
|
+
const identityLogger = logger.child({ name: "identity" });
|
|
183
|
+
const notificationSettings = new NotificationSettingsServiceImpl({
|
|
184
|
+
repo: new DrizzleNotificationSettingsRepository(db, identityLogger),
|
|
185
|
+
categories: {
|
|
186
|
+
communityList: async (orgId, communityId) => (await notificationCategories.community.get(orgId, communityId)).categories,
|
|
187
|
+
orgList: async (orgId) => (await notificationCategories.org.get(orgId, orgId)).categories
|
|
188
|
+
},
|
|
189
|
+
access: { canOpen: (orgId, actor, communityId) => entitlements.isCommunityMember(orgId, actor, communityId) },
|
|
190
|
+
channels: notificationRegistries.channels,
|
|
191
|
+
logger: identityLogger
|
|
192
|
+
});
|
|
193
|
+
const devices = new DevicesServiceImpl({
|
|
194
|
+
repo: new DrizzleDevicesRepository(db, identityLogger),
|
|
195
|
+
push: pushConfig,
|
|
196
|
+
logger: identityLogger
|
|
197
|
+
});
|
|
151
198
|
const progressUow = new DrizzleUnitOfWork(db, (tx) => ({
|
|
152
199
|
progress: new DrizzleProgressRepository(tx, progressLogger),
|
|
153
200
|
outbox: new DrizzleOutboxAppender(tx, outboxLogger)
|
|
@@ -162,6 +209,8 @@ async function buildContainer(config, options) {
|
|
|
162
209
|
const postReads = new DrizzlePostRepository(db, discussionLogger);
|
|
163
210
|
const discussionReads = new DrizzleDiscussionRepository(db, discussionLogger);
|
|
164
211
|
const chatReads = new DrizzleChatRepository(db, discussionLogger);
|
|
212
|
+
const subscriptionReads = new DrizzleSubscriptionsRepository(db, discussionLogger);
|
|
213
|
+
const mentionReads = new DrizzleMentionsRepository(db, discussionLogger);
|
|
165
214
|
const posts = new PostServiceImpl({
|
|
166
215
|
repo: postReads,
|
|
167
216
|
access: entitlements,
|
|
@@ -169,12 +218,16 @@ async function buildContainer(config, options) {
|
|
|
169
218
|
authors,
|
|
170
219
|
profiles: discussionReads,
|
|
171
220
|
comments: discussionReads,
|
|
221
|
+
subscriptions: subscriptionReads,
|
|
222
|
+
mentions: mentionReads,
|
|
172
223
|
images: assets,
|
|
173
224
|
fileUrls,
|
|
174
225
|
uow: new DrizzleUnitOfWork(db, (tx) => ({
|
|
175
226
|
posts: new DrizzlePostRepository(tx, discussionLogger),
|
|
227
|
+
mentions: new DrizzleMentionsRepository(tx, discussionLogger),
|
|
176
228
|
outbox: new DrizzleOutboxAppender(tx, outboxLogger)
|
|
177
229
|
})),
|
|
230
|
+
scheduler: automationEngine,
|
|
178
231
|
logger: discussionLogger
|
|
179
232
|
});
|
|
180
233
|
const chats = new ChatServiceImpl({
|
|
@@ -183,10 +236,13 @@ async function buildContainer(config, options) {
|
|
|
183
236
|
content,
|
|
184
237
|
authors,
|
|
185
238
|
profiles: discussionReads,
|
|
239
|
+
subscriptions: subscriptionReads,
|
|
240
|
+
mentions: mentionReads,
|
|
186
241
|
images: assets,
|
|
187
242
|
fileUrls,
|
|
188
243
|
uow: new DrizzleUnitOfWork(db, (tx) => ({
|
|
189
244
|
chats: new DrizzleChatRepository(tx, discussionLogger),
|
|
245
|
+
mentions: new DrizzleMentionsRepository(tx, discussionLogger),
|
|
190
246
|
outbox: new DrizzleOutboxAppender(tx, outboxLogger)
|
|
191
247
|
})),
|
|
192
248
|
logger: discussionLogger
|
|
@@ -196,15 +252,53 @@ async function buildContainer(config, options) {
|
|
|
196
252
|
access: entitlements,
|
|
197
253
|
content,
|
|
198
254
|
posts,
|
|
199
|
-
|
|
255
|
+
spaces: entitlements,
|
|
256
|
+
mentions: mentionReads,
|
|
200
257
|
fileUrls,
|
|
201
258
|
uow: new DrizzleUnitOfWork(db, (tx) => ({
|
|
202
259
|
discussion: new DrizzleDiscussionRepository(tx, discussionLogger),
|
|
260
|
+
mentions: new DrizzleMentionsRepository(tx, discussionLogger),
|
|
203
261
|
outbox: new DrizzleOutboxAppender(tx, outboxLogger)
|
|
204
262
|
})),
|
|
205
263
|
settings,
|
|
206
264
|
logger: discussionLogger
|
|
207
265
|
});
|
|
266
|
+
const subscriptions = new SubscriptionServiceImpl({
|
|
267
|
+
repo: subscriptionReads,
|
|
268
|
+
access: entitlements,
|
|
269
|
+
posts,
|
|
270
|
+
chats,
|
|
271
|
+
logger: discussionLogger
|
|
272
|
+
});
|
|
273
|
+
const digests = new DigestServiceImpl({
|
|
274
|
+
schedules: { communitiesWithDigest: () => content.communitiesWithDigest() },
|
|
275
|
+
runs: new DrizzleDigestRunRepository(db, discussionLogger),
|
|
276
|
+
uow: new DrizzleUnitOfWork(db, (tx) => ({
|
|
277
|
+
digests: new DrizzleDigestRunRepository(tx, discussionLogger),
|
|
278
|
+
outbox: new DrizzleOutboxAppender(tx, outboxLogger)
|
|
279
|
+
})),
|
|
280
|
+
logger: discussionLogger
|
|
281
|
+
});
|
|
282
|
+
const notificationsRepo = new DrizzleNotificationsRepository(db);
|
|
283
|
+
const notificationList = new NotificationsServiceImpl({
|
|
284
|
+
repo: notificationsRepo,
|
|
285
|
+
logger: automationsLogger
|
|
286
|
+
});
|
|
287
|
+
const itemTitles = {
|
|
288
|
+
discussion: new DiscussionItemTitles({
|
|
289
|
+
posts,
|
|
290
|
+
chats,
|
|
291
|
+
comments: discussionReads,
|
|
292
|
+
messages: chatReads,
|
|
293
|
+
profiles: discussionReads,
|
|
294
|
+
activities: content,
|
|
295
|
+
access: entitlements
|
|
296
|
+
}),
|
|
297
|
+
content: new ContentItemTitles({
|
|
298
|
+
content,
|
|
299
|
+
access: entitlements
|
|
300
|
+
})
|
|
301
|
+
};
|
|
208
302
|
const reporting = {
|
|
209
303
|
admin: new AdminReportServiceImpl({ repo: new DrizzleAdminRepository(db, reportingLogger) }),
|
|
210
304
|
member: new MemberReportServiceImpl({
|
|
@@ -214,9 +308,12 @@ async function buildContainer(config, options) {
|
|
|
214
308
|
files: assets,
|
|
215
309
|
fileUrls,
|
|
216
310
|
access: entitlements,
|
|
217
|
-
notifications,
|
|
218
|
-
|
|
219
|
-
|
|
311
|
+
notifications: notificationList,
|
|
312
|
+
titles: itemTitles,
|
|
313
|
+
subscriptions,
|
|
314
|
+
notificationCategories,
|
|
315
|
+
notificationSettings,
|
|
316
|
+
channels: notificationRegistries.channels
|
|
220
317
|
})
|
|
221
318
|
};
|
|
222
319
|
const credentialStore = new DrizzleCredentialStore(db, config.credentialStoreKey, integrationsLogger);
|
|
@@ -276,9 +373,33 @@ async function buildContainer(config, options) {
|
|
|
276
373
|
organizations,
|
|
277
374
|
identity,
|
|
278
375
|
posts,
|
|
376
|
+
subscriptions,
|
|
377
|
+
discussion,
|
|
378
|
+
chats
|
|
379
|
+
});
|
|
380
|
+
const recipientReads = notificationReads({
|
|
381
|
+
content,
|
|
382
|
+
entitlements,
|
|
383
|
+
organizations,
|
|
384
|
+
identity,
|
|
385
|
+
posts,
|
|
386
|
+
subscriptions,
|
|
279
387
|
discussion,
|
|
280
388
|
chats,
|
|
281
|
-
|
|
389
|
+
settings: notificationSettings
|
|
390
|
+
});
|
|
391
|
+
const notificationProcessor = new NotificationProcessor({
|
|
392
|
+
rules: RECIPIENT_RULES,
|
|
393
|
+
reads: recipientReads,
|
|
394
|
+
types: notificationRegistries.types,
|
|
395
|
+
channels: notificationRegistries.channels,
|
|
396
|
+
categories: notificationCategoryLists,
|
|
397
|
+
settings: notificationSettings,
|
|
398
|
+
devices,
|
|
399
|
+
repo: notificationsRepo,
|
|
400
|
+
engine: automationEngine,
|
|
401
|
+
debounce: new SchedulerChatDebounce(automationEngine),
|
|
402
|
+
logger: automationsLogger
|
|
282
403
|
});
|
|
283
404
|
const automations = new AutomationsServiceImpl({
|
|
284
405
|
repo: new DrizzleAutomationsRepository(db, automationsLogger),
|
|
@@ -292,11 +413,38 @@ async function buildContainer(config, options) {
|
|
|
292
413
|
webhooks: options?.adapters?.webhooks ?? new FetchWebhookSender({ allowPrivateNetwork: config.webhookAllowPrivateNetwork }),
|
|
293
414
|
mail: wired.mail,
|
|
294
415
|
grants: wired.grants,
|
|
295
|
-
|
|
296
|
-
|
|
416
|
+
delivery: new NotificationDelivery({
|
|
417
|
+
repo: notificationsRepo,
|
|
418
|
+
channels: notificationRegistries.channels,
|
|
419
|
+
devices,
|
|
420
|
+
logger: automationsLogger
|
|
421
|
+
}),
|
|
422
|
+
processor: notificationProcessor,
|
|
297
423
|
logger: automationsLogger
|
|
298
424
|
});
|
|
299
425
|
automationEngine.register(automations);
|
|
426
|
+
automationEngine.registerJobs([
|
|
427
|
+
...discussionJobs({
|
|
428
|
+
posts,
|
|
429
|
+
digests,
|
|
430
|
+
logger: discussionLogger
|
|
431
|
+
}),
|
|
432
|
+
...entitlementsJobs({ grants: entitlements }),
|
|
433
|
+
...assetsJobs({
|
|
434
|
+
assets,
|
|
435
|
+
orgs: organizations,
|
|
436
|
+
logger: assetsLogger
|
|
437
|
+
}),
|
|
438
|
+
...notificationJobs({
|
|
439
|
+
processor: notificationProcessor,
|
|
440
|
+
reads: recipientReads,
|
|
441
|
+
logger: automationsLogger
|
|
442
|
+
})
|
|
443
|
+
], [
|
|
444
|
+
...discussionRecurringJobs,
|
|
445
|
+
...entitlementsRecurringJobs,
|
|
446
|
+
...assetsRecurringJobs
|
|
447
|
+
]);
|
|
300
448
|
const eventBus = new InMemoryEventBus();
|
|
301
449
|
eventBus.subscribeAll((event) => automations.handle(event));
|
|
302
450
|
const outboxConfig = resolveOutboxConfig(config.outbox);
|
|
@@ -405,7 +553,6 @@ async function buildContainer(config, options) {
|
|
|
405
553
|
auth,
|
|
406
554
|
mcp,
|
|
407
555
|
identity,
|
|
408
|
-
notifications,
|
|
409
556
|
organizations,
|
|
410
557
|
orgProvider: auth,
|
|
411
558
|
content,
|
|
@@ -414,9 +561,17 @@ async function buildContainer(config, options) {
|
|
|
414
561
|
discussion,
|
|
415
562
|
posts,
|
|
416
563
|
chats,
|
|
564
|
+
subscriptions,
|
|
417
565
|
assets,
|
|
418
566
|
integrations,
|
|
419
567
|
automations,
|
|
568
|
+
notificationTypes: notificationRegistries.types,
|
|
569
|
+
notificationChannels: notificationRegistries.channels,
|
|
570
|
+
notificationCategories,
|
|
571
|
+
notificationCategoryLists,
|
|
572
|
+
notificationSettings,
|
|
573
|
+
devices,
|
|
574
|
+
notificationList,
|
|
420
575
|
settings,
|
|
421
576
|
reporting,
|
|
422
577
|
storage,
|
|
@@ -424,6 +579,7 @@ async function buildContainer(config, options) {
|
|
|
424
579
|
credentials: credentialStore,
|
|
425
580
|
outboxRelay,
|
|
426
581
|
automationEngine,
|
|
582
|
+
scheduler: automationEngine,
|
|
427
583
|
logger,
|
|
428
584
|
loggerInstance,
|
|
429
585
|
requestContext: requestLogContext,
|