@headless-lms/core 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/events.d.ts +24 -18
- package/dist/assets/file-urls.d.ts +11 -7
- package/dist/assets/file-urls.js +14 -4
- package/dist/assets/file-urls.js.map +1 -1
- package/dist/assets/index.d.ts +5 -4
- package/dist/assets/index.js +4 -3
- package/dist/assets/jobs.d.ts +15 -0
- package/dist/assets/jobs.js +30 -0
- package/dist/assets/jobs.js.map +1 -0
- package/dist/assets/ports.d.ts +37 -17
- package/dist/assets/service.d.ts +30 -15
- package/dist/assets/service.js +229 -59
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.js +2 -63
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +1 -2
- package/dist/automations/catalog.js +137 -65
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.js +20 -20
- package/dist/automations/community-derivations.js.map +1 -1
- package/dist/automations/community-mail.d.ts +36 -20
- package/dist/automations/community-mail.js +32 -24
- package/dist/automations/community-mail.js.map +1 -1
- package/dist/automations/event-permissions.d.ts +12 -0
- package/dist/automations/event-permissions.js +38 -0
- package/dist/automations/event-permissions.js.map +1 -0
- package/dist/automations/events.d.ts +0 -10
- package/dist/automations/index.d.ts +12 -4
- package/dist/automations/index.js +9 -1
- package/dist/automations/notifications/applicable.d.ts +8 -0
- package/dist/automations/notifications/applicable.js +12 -0
- package/dist/automations/notifications/applicable.js.map +1 -0
- package/dist/automations/notifications/debounce.d.ts +25 -0
- package/dist/automations/notifications/debounce.js +93 -0
- package/dist/automations/notifications/debounce.js.map +1 -0
- package/dist/automations/notifications/defaults.d.ts +8 -0
- package/dist/automations/notifications/defaults.js +346 -0
- package/dist/automations/notifications/defaults.js.map +1 -0
- package/dist/automations/notifications/delivery.d.ts +28 -0
- package/dist/automations/notifications/delivery.js +88 -0
- package/dist/automations/notifications/delivery.js.map +1 -0
- package/dist/automations/notifications/processor.d.ts +64 -0
- package/dist/automations/notifications/processor.js +270 -0
- package/dist/automations/notifications/processor.js.map +1 -0
- package/dist/automations/notifications/rules/content.d.ts +6 -0
- package/dist/automations/notifications/rules/content.js +96 -0
- package/dist/automations/notifications/rules/content.js.map +1 -0
- package/dist/automations/notifications/rules/discussion.d.ts +7 -0
- package/dist/automations/notifications/rules/discussion.js +678 -0
- package/dist/automations/notifications/rules/discussion.js.map +1 -0
- package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
- package/dist/automations/notifications/rules/entitlements.js +276 -0
- package/dist/automations/notifications/rules/entitlements.js.map +1 -0
- package/dist/automations/notifications/rules/events.d.ts +9 -0
- package/dist/automations/notifications/rules/events.js +27 -0
- package/dist/automations/notifications/rules/events.js.map +1 -0
- package/dist/automations/notifications/rules/index.d.ts +6 -0
- package/dist/automations/notifications/rules/index.js +15 -0
- package/dist/automations/notifications/rules/index.js.map +1 -0
- package/dist/automations/notifications/rules/organizations.d.ts +6 -0
- package/dist/automations/notifications/rules/organizations.js +35 -0
- package/dist/automations/notifications/rules/organizations.js.map +1 -0
- package/dist/automations/notifications/rules/recipients.d.ts +32 -0
- package/dist/automations/notifications/rules/recipients.js +98 -0
- package/dist/automations/notifications/rules/recipients.js.map +1 -0
- package/dist/automations/notifications/service.d.ts +29 -0
- package/dist/automations/notifications/service.js +45 -0
- package/dist/automations/notifications/service.js.map +1 -0
- package/dist/automations/notifications/types.d.ts +7 -0
- package/dist/automations/notifications/types.js +560 -0
- package/dist/automations/notifications/types.js.map +1 -0
- package/dist/automations/ports.d.ts +134 -21
- package/dist/automations/service.d.ts +30 -30
- package/dist/automations/service.js +111 -144
- package/dist/automations/service.js.map +1 -1
- package/dist/content/event-sight.d.ts +11 -0
- package/dist/content/event-sight.js +11 -0
- package/dist/content/event-sight.js.map +1 -0
- package/dist/content/events.d.ts +437 -46
- package/dist/content/events.js +45 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +8 -4
- package/dist/content/index.js +5 -1
- package/dist/content/jobs.d.ts +16 -0
- package/dist/content/jobs.js +37 -0
- package/dist/content/jobs.js.map +1 -0
- package/dist/content/model.d.ts +2 -2
- package/dist/content/notification-categories.d.ts +37 -0
- package/dist/content/notification-categories.js +73 -0
- package/dist/content/notification-categories.js.map +1 -0
- package/dist/content/ports.d.ts +132 -68
- package/dist/content/service.d.ts +100 -68
- package/dist/content/service.js +703 -146
- package/dist/content/service.js.map +1 -1
- package/dist/content/titles.d.ts +25 -0
- package/dist/content/titles.js +82 -0
- package/dist/content/titles.js.map +1 -0
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +4 -2
- package/dist/discussion/authors.js +9 -5
- package/dist/discussion/authors.js.map +1 -1
- package/dist/discussion/chats.d.ts +63 -39
- package/dist/discussion/chats.js +455 -190
- package/dist/discussion/chats.js.map +1 -1
- package/dist/discussion/digests.d.ts +24 -0
- package/dist/discussion/digests.js +104 -0
- package/dist/discussion/digests.js.map +1 -0
- package/dist/discussion/events.d.ts +227 -23
- package/dist/discussion/events.js +114 -19
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +12 -4
- package/dist/discussion/index.js +9 -2
- package/dist/discussion/jobs.d.ts +16 -0
- package/dist/discussion/jobs.js +40 -0
- package/dist/discussion/jobs.js.map +1 -0
- package/dist/discussion/live.d.ts +106 -0
- package/dist/discussion/live.js +642 -0
- package/dist/discussion/live.js.map +1 -0
- package/dist/discussion/mentions.d.ts +11 -0
- package/dist/discussion/mentions.js +35 -0
- package/dist/discussion/mentions.js.map +1 -0
- package/dist/discussion/ports.d.ts +279 -114
- package/dist/discussion/ports.js.map +1 -1
- package/dist/discussion/posts.d.ts +60 -44
- package/dist/discussion/posts.js +453 -287
- package/dist/discussion/posts.js.map +1 -1
- package/dist/discussion/rules.d.ts +18 -0
- package/dist/discussion/rules.js +22 -0
- package/dist/discussion/rules.js.map +1 -0
- package/dist/discussion/service.d.ts +50 -35
- package/dist/discussion/service.js +333 -205
- package/dist/discussion/service.js.map +1 -1
- package/dist/discussion/subscriptions.d.ts +37 -0
- package/dist/discussion/subscriptions.js +115 -0
- package/dist/discussion/subscriptions.js.map +1 -0
- package/dist/discussion/titles.d.ts +28 -0
- package/dist/discussion/titles.js +98 -0
- package/dist/discussion/titles.js.map +1 -0
- package/dist/entitlements/events.d.ts +20 -20
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +3 -2
- package/dist/entitlements/jobs.d.ts +12 -0
- package/dist/entitlements/jobs.js +18 -0
- package/dist/entitlements/jobs.js.map +1 -0
- package/dist/entitlements/model.d.ts +2 -2
- package/dist/entitlements/ports.d.ts +68 -38
- package/dist/entitlements/rules.d.ts +3 -6
- package/dist/entitlements/rules.js +5 -10
- package/dist/entitlements/rules.js.map +1 -1
- package/dist/entitlements/service.d.ts +43 -28
- package/dist/entitlements/service.js +387 -160
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/devices.d.ts +30 -0
- package/dist/identity/devices.js +109 -0
- package/dist/identity/devices.js.map +1 -0
- package/dist/identity/index.d.ts +6 -5
- package/dist/identity/index.js +4 -3
- package/dist/identity/model.d.ts +2 -2
- package/dist/identity/notification-settings.d.ts +28 -0
- package/dist/identity/notification-settings.js +114 -0
- package/dist/identity/notification-settings.js.map +1 -0
- package/dist/identity/ports.d.ts +80 -56
- package/dist/identity/service.d.ts +8 -7
- package/dist/identity/service.js +17 -13
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/ports.d.ts +9 -8
- package/dist/integrations/service.d.ts +9 -8
- package/dist/integrations/service.js +33 -16
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/default-roles.d.ts +22 -0
- package/dist/organizations/default-roles.js +89 -0
- package/dist/organizations/default-roles.js.map +1 -0
- package/dist/organizations/effective-permissions.d.ts +45 -0
- package/dist/organizations/effective-permissions.js +113 -0
- package/dist/organizations/effective-permissions.js.map +1 -0
- package/dist/organizations/events.d.ts +320 -181
- package/dist/organizations/events.js +90 -18
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +15 -10
- package/dist/organizations/index.js +8 -3
- package/dist/organizations/members.d.ts +66 -8
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/notification-catalog.d.ts +31 -0
- package/dist/organizations/notification-catalog.js +32 -0
- package/dist/organizations/notification-catalog.js.map +1 -0
- package/dist/organizations/notification-categories.d.ts +34 -0
- package/dist/organizations/notification-categories.js +66 -0
- package/dist/organizations/notification-categories.js.map +1 -0
- package/dist/organizations/org-roles.d.ts +33 -0
- package/dist/organizations/org-roles.js +49 -0
- package/dist/organizations/org-roles.js.map +1 -0
- package/dist/organizations/permissions.d.ts +311 -0
- package/dist/organizations/permissions.js +327 -0
- package/dist/organizations/permissions.js.map +1 -0
- package/dist/organizations/ports.d.ts +187 -65
- package/dist/organizations/service.d.ts +104 -35
- package/dist/organizations/service.js +1247 -323
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/testing.d.ts +18 -0
- package/dist/organizations/testing.js +37 -0
- package/dist/organizations/testing.js.map +1 -0
- package/dist/organizations/types.d.ts +5 -16
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +11 -3
- package/dist/progress/service.d.ts +6 -5
- package/dist/progress/service.js +23 -8
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +6 -4
- package/dist/reporting/admin/model.d.ts +36 -3
- package/dist/reporting/admin/ports.d.ts +39 -14
- package/dist/reporting/admin/service.d.ts +32 -11
- package/dist/reporting/admin/service.js +102 -18
- package/dist/reporting/admin/service.js.map +1 -1
- package/dist/reporting/events/index.d.ts +27 -0
- package/dist/reporting/events/index.js +20 -0
- package/dist/reporting/events/index.js.map +1 -0
- package/dist/reporting/member/calendar.d.ts +11 -0
- package/dist/reporting/member/calendar.js +75 -0
- package/dist/reporting/member/calendar.js.map +1 -0
- package/dist/reporting/member/index.d.ts +3 -2
- package/dist/reporting/member/model.d.ts +80 -26
- package/dist/reporting/member/ports.d.ts +50 -28
- package/dist/reporting/member/service.d.ts +81 -35
- package/dist/reporting/member/service.js +438 -145
- package/dist/reporting/member/service.js.map +1 -1
- package/dist/shared/actor.d.ts +22 -3
- package/dist/shared/errors.d.ts +15 -2
- package/dist/shared/errors.js +21 -2
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +7 -0
- package/dist/shared/id.js +8 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/logger.d.ts +2 -1
- package/dist/shared/logger.js +10 -1
- package/dist/shared/logger.js.map +1 -1
- package/dist/shared/mailer.d.ts +11 -1
- package/dist/shared/mailer.js +32 -5
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/notification-categories.d.ts +16 -0
- package/dist/shared/notification-categories.js +94 -0
- package/dist/shared/notification-categories.js.map +1 -0
- package/dist/shared/notification-settings.d.ts +14 -0
- package/dist/shared/notification-settings.js +61 -0
- package/dist/shared/notification-settings.js.map +1 -0
- package/dist/shared/ports.d.ts +68 -2
- package/dist/shared/settings.d.ts +2 -1
- package/dist/shared/settings.js +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/automations.d.ts +8 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +4 -5
- package/dist/types/email-templates.d.ts +119 -6
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +14 -17
- package/dist/types/index.d.ts +13 -12
- package/dist/types/index.js +2 -1
- package/dist/types/notifications.d.ts +157 -0
- package/dist/types/notifications.js +1 -0
- package/dist/types/organizations.d.ts +3 -2
- package/dist/types/ports.d.ts +8 -1
- package/dist/types/ports.js +7 -1
- package/dist/types/ports.js.map +1 -0
- package/dist/types/schemas/assets.d.ts +5 -5
- package/dist/types/schemas/assets.js +4 -3
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +1 -10
- package/dist/types/schemas/automations.js +1 -3
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +596 -11
- package/dist/types/schemas/content.js +225 -9
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +362 -66
- package/dist/types/schemas/discussion.js +123 -15
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +14 -1
- package/dist/types/schemas/entitlements.js +11 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +1 -85
- package/dist/types/schemas/identity.js +1 -42
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +8 -7
- package/dist/types/schemas/index.js +8 -7
- package/dist/types/schemas/notifications.d.ts +96 -0
- package/dist/types/schemas/notifications.js +57 -0
- package/dist/types/schemas/notifications.js.map +1 -0
- package/dist/types/schemas/organizations.d.ts +96 -60
- package/dist/types/schemas/organizations.js +78 -27
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +0 -1
- package/dist/types/schemas/progress.js +0 -1
- package/dist/types/schemas/progress.js.map +1 -1
- package/package.json +1 -1
- package/dist/automations/community-notifications.d.ts +0 -16
- package/dist/automations/community-notifications.js +0 -84
- package/dist/automations/community-notifications.js.map +0 -1
- package/dist/automations/seeds.d.ts +0 -17
- package/dist/automations/seeds.js +0 -235
- package/dist/automations/seeds.js.map +0 -1
- package/dist/identity/notifications.d.ts +0 -27
- package/dist/identity/notifications.js +0 -101
- package/dist/identity/notifications.js.map +0 -1
- package/dist/organizations/access-scopes.d.ts +0 -19
- package/dist/organizations/access-scopes.js +0 -89
- package/dist/organizations/access-scopes.js.map +0 -1
- package/dist/organizations/roles.d.ts +0 -19
- package/dist/organizations/roles.js +0 -82
- package/dist/organizations/roles.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","names":[],"sources":["../../src/discussion/live.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { DomainEvent, EventBus, JsonValue, Logger, PubSub } from '../shared/ports.js';\nimport { describeError, noopLogger } from '../shared/logger.js';\nimport type { Actor } from '../shared/actor.js';\nimport type { ChatLiveEvent } from '../types/index.js';\nimport { discussionEvents } from './events.js';\nimport type {\n ChatCreated,\n ChatMuted,\n ChatRead,\n ChatUpdated,\n MessageDeleted,\n MessageSent,\n MessageUpdated,\n} from './events.js';\nimport type { ChatLiveReads } from './ports.js';\n\nexport const CHAT_CHANNEL = 'discussion.chats';\nexport const TYPING = 'typing';\n\nconst HEARTBEAT_MS = 25_000;\nconst PUBLISH_TIMEOUT_MS = 2000;\nconst FLUSH_MS = 1000;\nconst CLOSE_TIMEOUT_MS = 2000;\nconst MAX_CHATS = 16;\nconst MAX_PENDING = 5000;\nconst STREAM_QUEUE = 256;\n\nconst SENT = discussionEvents.messageSent.type;\nconst UPDATED = discussionEvents.messageUpdated.type;\nconst DELETED = discussionEvents.messageDeleted.type;\nconst REACTIONS = discussionEvents.messageReactionsChanged.type;\nconst CREATED = discussionEvents.chatCreated.type;\nconst CHAT_UPDATED = discussionEvents.chatUpdated.type;\nconst ADDED = discussionEvents.chatParticipantAdded.type;\nconst READ = discussionEvents.chatRead.type;\nconst MUTED = discussionEvents.chatMuted.type;\n\nconst chatChangeSchema = z.object({\n event: z.string(),\n orgId: z.string(),\n communityId: z.string(),\n chatId: z.string(),\n messageId: z.string().optional(),\n orgUserId: z.string().optional(),\n members: z.array(z.string()).optional(),\n reaction: z.string().nullable().optional(),\n until: z.string().optional(),\n});\n\n/** One chat change on the `discussion.chats` channel. It never carries a body;\n * every instance reads current state itself. */\nexport type ChatChange = z.infer<typeof chatChangeSchema>;\n\n/** Publishes a change, logging and dropping it when the publish fails or has\n * not finished within 2 s. Never throws. */\nexport async function publishChange(\n pubsub: PubSub,\n change: ChatChange,\n logger: Logger,\n timeoutMs = PUBLISH_TIMEOUT_MS,\n): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n pubsub.publish(CHAT_CHANNEL, change as JsonValue),\n new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error('publish timed out')), timeoutMs);\n }),\n ]);\n } catch (error) {\n logger.warn('live publish failed', {\n orgId: change.orgId,\n chatId: change.chatId,\n event: change.event,\n error: describeError(error),\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction actorOf(event: DomainEvent): string[] {\n const actor = event.metadata?.actorId;\n return typeof actor === 'string' ? [actor] : [];\n}\n\nfunction union(...lists: string[][]): string[] {\n return [...new Set(lists.flat())].sort();\n}\n\nexport type ChatLiveForwarderParams = {\n pubsub: PubSub;\n logger?: Logger;\n timeoutMs?: number;\n};\n\n/** Publishes every chat change committed through the outbox to every instance. */\nexport class ChatLiveForwarder {\n private readonly pubsub: PubSub;\n private readonly logger: Logger;\n private readonly timeoutMs: number;\n\n constructor(params: ChatLiveForwarderParams) {\n this.pubsub = params.pubsub;\n this.logger = params.logger ?? noopLogger;\n this.timeoutMs = params.timeoutMs ?? PUBLISH_TIMEOUT_MS;\n }\n\n attach(bus: EventBus): void {\n const forward = (change: ChatChange) =>\n publishChange(this.pubsub, change, this.logger, this.timeoutMs);\n const chat = (event: ChatCreated | ChatUpdated) =>\n forward({\n event: event.type,\n orgId: event.orgId,\n communityId: event.data.communityId,\n chatId: event.data.id,\n members: union(event.data.participantIds, actorOf(event)),\n });\n const message = (event: MessageSent | MessageUpdated | MessageDeleted) =>\n forward({\n event: event.type,\n orgId: event.orgId,\n communityId: event.data.communityId,\n chatId: event.data.chatId,\n messageId: event.data.id,\n });\n const member = (event: ChatRead | ChatMuted) =>\n forward({\n event: event.type,\n orgId: event.orgId,\n communityId: event.data.communityId,\n chatId: event.data.chatId,\n orgUserId: event.data.orgUserId,\n });\n bus.subscribe(discussionEvents.chatCreated, chat);\n bus.subscribe(discussionEvents.chatUpdated, chat);\n bus.subscribe(discussionEvents.chatParticipantAdded, (event) =>\n forward({\n event: event.type,\n orgId: event.orgId,\n communityId: event.data.communityId,\n chatId: event.data.chatId,\n orgUserId: event.data.orgUserId,\n members: union([event.data.orgUserId], actorOf(event)),\n }),\n );\n bus.subscribe(discussionEvents.messageSent, message);\n bus.subscribe(discussionEvents.messageUpdated, message);\n bus.subscribe(discussionEvents.messageDeleted, message);\n bus.subscribe(discussionEvents.messageReactionsChanged, (event) =>\n forward({\n event: event.type,\n orgId: event.orgId,\n communityId: event.data.communityId,\n chatId: event.data.chatId,\n messageId: event.data.messageId,\n orgUserId: event.data.orgUserId,\n reaction: event.data.reaction,\n }),\n );\n bus.subscribe(discussionEvents.chatRead, member);\n bus.subscribe(discussionEvents.chatMuted, member);\n }\n}\n\nexport interface ChatHubOptions {\n flushMs?: number;\n closeTimeoutMs?: number;\n}\n\nexport type ChatHubParams = ChatHubOptions & {\n pubsub: PubSub;\n reads: ChatLiveReads;\n logger?: Logger;\n};\n\nexport interface LiveRegistration {\n communityId: string;\n actor: Actor;\n}\n\nclass LiveStream implements AsyncIterableIterator<ChatLiveEvent> {\n readonly done: Promise<void>;\n private queue: ChatLiveEvent[] = [];\n private waiter: ((result: IteratorResult<ChatLiveEvent>) => void) | null = null;\n private ending = false;\n private finished = false;\n private resolveDone!: () => void;\n\n constructor(\n readonly orgId: string,\n readonly communityId: string,\n readonly orgUserId: string,\n private readonly onEnd: (stream: LiveStream) => void,\n private readonly onOverflow: (stream: LiveStream) => void,\n ) {\n this.done = new Promise((resolve) => {\n this.resolveDone = resolve;\n });\n }\n\n get ended(): boolean {\n return this.ending;\n }\n\n push(event: ChatLiveEvent): void {\n if (this.ending) {\n return;\n }\n const waiter = this.waiter;\n if (waiter) {\n this.waiter = null;\n waiter({ value: event, done: false });\n return;\n }\n if (this.queue.length >= STREAM_QUEUE) {\n this.queue = [{ type: 'resync' }];\n this.onOverflow(this);\n return;\n }\n this.queue.push(event);\n }\n\n end(last?: ChatLiveEvent): void {\n if (this.ending) {\n return;\n }\n if (last) {\n this.push(last);\n }\n this.ending = true;\n this.onEnd(this);\n const waiter = this.waiter;\n if (waiter && this.queue.length === 0) {\n this.waiter = null;\n this.finish();\n waiter({ value: undefined, done: true });\n }\n }\n\n next(): Promise<IteratorResult<ChatLiveEvent>> {\n const event = this.queue.shift();\n if (event) {\n return Promise.resolve({ value: event, done: false });\n }\n if (this.ending) {\n this.finish();\n return Promise.resolve({ value: undefined, done: true });\n }\n return new Promise((resolve) => {\n this.waiter = resolve;\n });\n }\n\n return(): Promise<IteratorResult<ChatLiveEvent>> {\n this.queue = [];\n this.end();\n const waiter = this.waiter;\n if (waiter) {\n this.waiter = null;\n waiter({ value: undefined, done: true });\n }\n this.finish();\n return Promise.resolve({ value: undefined, done: true });\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<ChatLiveEvent> {\n return this;\n }\n\n private finish(): void {\n if (this.finished) {\n return;\n }\n this.finished = true;\n this.resolveDone();\n }\n}\n\ninterface ChatQueue {\n pending: ChatChange[];\n running: boolean;\n queued: boolean;\n}\n\ninterface DirtyGroup {\n orgId: string;\n communityId: string;\n members: Map<string, Set<string>>;\n}\n\nfunction coalesceKey(change: ChatChange): string | null {\n switch (change.event) {\n case SENT:\n case UPDATED:\n case DELETED:\n return `message:${change.messageId}`;\n case REACTIONS:\n return `reaction:${change.messageId}:${change.orgUserId}`;\n case CREATED:\n case CHAT_UPDATED:\n case ADDED:\n return 'chat';\n case READ:\n case MUTED:\n return `member:${change.orgUserId}`;\n default:\n return null;\n }\n}\n\nfunction merge(existing: ChatChange, next: ChatChange): ChatChange {\n switch (existing.event) {\n case SENT:\n case UPDATED:\n case DELETED: {\n const events = [existing.event, next.event];\n const event = events.includes(SENT) ? SENT : events.includes(DELETED) ? DELETED : UPDATED;\n return { ...next, event };\n }\n case CREATED:\n case CHAT_UPDATED:\n case ADDED:\n return { ...existing, members: union(existing.members ?? [], next.members ?? []) };\n case REACTIONS:\n return next;\n default:\n return existing;\n }\n}\n\nconst key = (orgId: string, id: string) => `${orgId}\\u0000${id}`;\n\n/** This process's open chat streams, and the live delivery of every chat\n * change to them. */\nexport class ChatHub {\n private readonly pubsub: PubSub;\n private readonly reads: ChatLiveReads;\n private readonly logger: Logger;\n private readonly flushMs: number;\n private readonly closeTimeoutMs: number;\n private readonly streams = new Set<LiveStream>();\n private readonly byMember = new Map<string, Set<LiveStream>>();\n private readonly byCommunity = new Map<string, Set<LiveStream>>();\n private readonly queues = new Map<string, ChatQueue>();\n private ready: string[] = [];\n private running = 0;\n private pending = 0;\n private dirty = new Map<string, DirtyGroup>();\n private flushing = false;\n private flushAgain = false;\n private closing = false;\n private unsubscribe: (() => void) | null = null;\n private flushTimer: NodeJS.Timeout | null = null;\n\n constructor(params: ChatHubParams) {\n this.pubsub = params.pubsub;\n this.reads = params.reads;\n this.logger = params.logger ?? noopLogger;\n this.flushMs = params.flushMs ?? FLUSH_MS;\n this.closeTimeoutMs = params.closeTimeoutMs ?? CLOSE_TIMEOUT_MS;\n }\n\n async start(): Promise<void> {\n if (this.unsubscribe || this.closing) {\n return;\n }\n this.unsubscribe = this.pubsub.subscribe(\n CHAT_CHANNEL,\n (message) => this.receive(message),\n () => this.reset(),\n );\n this.flushTimer = setInterval(() => {\n if (!this.flushing) {\n void this.flush();\n }\n }, this.flushMs);\n this.flushTimer.unref();\n this.logger.info('chat hub started');\n }\n\n /** Ends every stream with `closed { reason: 'shutdown' }` and waits, up to\n * 2 s in all, for each to be read to its end. */\n async close(): Promise<void> {\n if (this.closing) {\n return;\n }\n this.closing = true;\n this.unsubscribe?.();\n this.unsubscribe = null;\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n this.queues.clear();\n this.ready = [];\n this.pending = 0;\n const streams = [...this.streams];\n for (const stream of streams) {\n stream.end({ type: 'closed', reason: 'shutdown' });\n }\n let timer: NodeJS.Timeout | undefined;\n await Promise.race([\n Promise.all(streams.map((stream) => stream.done)),\n new Promise((resolve) => {\n timer = setTimeout(resolve, this.closeTimeoutMs);\n }),\n ]);\n clearTimeout(timer);\n this.logger.info('chat hub closed', { streams: streams.length });\n }\n\n /** Registers one stream. It starts with `ready`, then the member's unread. */\n open(registration: LiveRegistration): AsyncIterable<ChatLiveEvent> {\n const { actor, communityId } = registration;\n const stream = new LiveStream(\n actor.orgId,\n communityId,\n actor.id,\n (ended) => this.unregister(ended),\n (full) => this.markDirty(full.orgId, full.communityId, full.orgUserId),\n );\n if (this.closing) {\n stream.end({ type: 'closed', reason: 'shutdown' });\n return stream;\n }\n this.streams.add(stream);\n this.index(this.byMember, key(stream.orgId, stream.orgUserId), stream);\n this.index(this.byCommunity, key(stream.orgId, stream.communityId), stream);\n stream.push({ type: 'ready', heartbeatMs: HEARTBEAT_MS });\n this.markDirty(stream.orgId, stream.communityId, stream.orgUserId);\n void this.flush();\n this.logger.debug('chat stream opened', {\n orgId: stream.orgId,\n communityId,\n streams: this.streams.size,\n });\n return stream;\n }\n\n private index(map: Map<string, Set<LiveStream>>, at: string, stream: LiveStream): void {\n const set = map.get(at) ?? new Set<LiveStream>();\n set.add(stream);\n map.set(at, set);\n }\n\n private unindex(map: Map<string, Set<LiveStream>>, at: string, stream: LiveStream): void {\n const set = map.get(at);\n set?.delete(stream);\n if (set?.size === 0) {\n map.delete(at);\n }\n }\n\n private unregister(stream: LiveStream): void {\n if (!this.streams.delete(stream)) {\n return;\n }\n this.unindex(this.byMember, key(stream.orgId, stream.orgUserId), stream);\n this.unindex(this.byCommunity, key(stream.orgId, stream.communityId), stream);\n this.logger.debug('chat stream closed', {\n orgId: stream.orgId,\n communityId: stream.communityId,\n streams: this.streams.size,\n });\n }\n\n private streamsOf(orgId: string, communityId: string, orgUserId: string): LiveStream[] {\n return [...(this.byMember.get(key(orgId, orgUserId)) ?? [])].filter(\n (stream) => stream.communityId === communityId,\n );\n }\n\n private communityStreams(orgId: string, communityId: string): LiveStream[] {\n return [...(this.byCommunity.get(key(orgId, communityId)) ?? [])];\n }\n\n private receive(message: JsonValue): void {\n const parsed = chatChangeSchema.safeParse(message);\n if (!parsed.success) {\n this.logger.warn('chat change unreadable');\n return;\n }\n const change = parsed.data;\n if (this.closing || !this.byCommunity.has(key(change.orgId, change.communityId))) {\n return;\n }\n const at = key(change.orgId, change.chatId);\n const queue = this.queues.get(at) ?? { pending: [], running: false, queued: false };\n this.queues.set(at, queue);\n const coalesce = coalesceKey(change);\n const index =\n coalesce === null ? -1 : queue.pending.findIndex((other) => coalesceKey(other) === coalesce);\n if (index >= 0) {\n queue.pending[index] = merge(queue.pending[index]!, change);\n } else {\n if (this.pending >= MAX_PENDING) {\n this.overflow();\n return;\n }\n queue.pending.push(change);\n this.pending += 1;\n }\n if (!queue.running && !queue.queued) {\n queue.queued = true;\n this.ready.push(at);\n }\n this.pump();\n }\n\n private pump(): void {\n while (this.running < MAX_CHATS && this.ready.length > 0) {\n const at = this.ready.shift()!;\n const queue = this.queues.get(at);\n if (!queue) {\n continue;\n }\n queue.queued = false;\n const change = queue.pending.shift();\n if (!change) {\n this.queues.delete(at);\n continue;\n }\n this.pending -= 1;\n queue.running = true;\n this.running += 1;\n void this.handle(change).finally(() => {\n queue.running = false;\n this.running -= 1;\n if (this.queues.get(at) === queue) {\n if (queue.pending.length > 0) {\n queue.queued = true;\n this.ready.push(at);\n } else {\n this.queues.delete(at);\n }\n }\n this.pump();\n });\n }\n }\n\n private overflow(): void {\n this.logger.warn('chat hub queue full; dropping pending changes', { pending: this.pending });\n for (const [at, queue] of this.queues) {\n queue.pending = [];\n queue.queued = false;\n if (!queue.running) {\n this.queues.delete(at);\n }\n }\n this.ready = [];\n this.pending = 0;\n this.resync([...this.streams]);\n }\n\n private reset(): void {\n this.logger.info('chat hub reset', { streams: this.streams.size });\n this.resync([...this.streams]);\n }\n\n private resync(streams: LiveStream[]): void {\n for (const stream of streams) {\n stream.push({ type: 'resync' });\n this.markDirty(stream.orgId, stream.communityId, stream.orgUserId);\n }\n }\n\n private async handle(change: ChatChange): Promise<void> {\n try {\n switch (change.event) {\n case SENT:\n case UPDATED:\n case DELETED:\n await this.onMessage(change);\n return;\n case REACTIONS:\n await this.onReactions(change);\n return;\n case CREATED:\n case CHAT_UPDATED:\n case ADDED:\n await this.onChat(change);\n return;\n case READ:\n case MUTED:\n if (change.orgUserId) {\n this.markDirty(change.orgId, change.communityId, change.orgUserId, change.chatId);\n }\n return;\n case TYPING:\n await this.onTyping(change);\n return;\n default:\n this.logger.debug('chat change ignored', { event: change.event });\n }\n } catch (error) {\n this.logger.error('chat change read failed', {\n orgId: change.orgId,\n chatId: change.chatId,\n event: change.event,\n error: describeError(error),\n });\n this.resync(this.communityStreams(change.orgId, change.communityId));\n }\n }\n\n private async participantStreams(\n change: ChatChange,\n ): Promise<{ members: string[]; streams: LiveStream[] }> {\n const active = await this.reads.activeParticipants(change.orgId, change.chatId);\n const members: string[] = [];\n const streams: LiveStream[] = [];\n for (const orgUserId of active) {\n const local = this.streamsOf(change.orgId, change.communityId, orgUserId);\n if (local.length > 0) {\n members.push(orgUserId);\n streams.push(...local);\n }\n }\n return { members, streams };\n }\n\n private async onMessage(change: ChatChange): Promise<void> {\n const { members, streams } = await this.participantStreams(change);\n if (streams.length === 0 || !change.messageId) {\n return;\n }\n const [view] = await this.reads.messageViews(change.orgId, [change.messageId]);\n if (!view || view.chatId !== change.chatId) {\n return;\n }\n const event: ChatLiveEvent = view.deletedAt\n ? {\n type: 'message.deleted',\n chatId: change.chatId,\n messageId: view.id,\n deletedAt: view.deletedAt,\n }\n : {\n type: change.event === SENT ? 'message.created' : 'message.updated',\n chatId: change.chatId,\n message: view,\n };\n for (const stream of streams) {\n stream.push(event);\n }\n if (change.event !== UPDATED || view.deletedAt) {\n for (const orgUserId of members) {\n this.markDirty(change.orgId, change.communityId, orgUserId, change.chatId);\n }\n }\n }\n\n private async onReactions(change: ChatChange): Promise<void> {\n const { streams } = await this.participantStreams(change);\n if (streams.length === 0 || !change.messageId || !change.orgUserId) {\n return;\n }\n const reactions = await this.reads.messageReactions(change.orgId, change.messageId);\n for (const stream of streams) {\n stream.push({\n type: 'message.reactions',\n chatId: change.chatId,\n messageId: change.messageId,\n reactions,\n orgUserId: change.orgUserId,\n reaction: change.reaction ?? null,\n });\n }\n }\n\n private async onChat(change: ChatChange): Promise<void> {\n const live = await this.reads.liveChat(change.orgId, change.chatId);\n const active = new Set(live?.participantIds ?? []);\n if (live) {\n for (const orgUserId of active) {\n const streams = this.streamsOf(change.orgId, change.communityId, orgUserId);\n if (streams.length === 0) {\n continue;\n }\n for (const stream of streams) {\n stream.push({\n type: 'chat.updated',\n chatId: change.chatId,\n chat: live.chat,\n participants: live.participants,\n });\n }\n this.markDirty(change.orgId, change.communityId, orgUserId, change.chatId);\n }\n }\n for (const orgUserId of change.members ?? []) {\n if (active.has(orgUserId)) {\n continue;\n }\n const streams = this.streamsOf(change.orgId, change.communityId, orgUserId);\n if (streams.length === 0) {\n continue;\n }\n for (const stream of streams) {\n stream.push({ type: 'chat.removed', chatId: change.chatId });\n }\n this.markDirty(change.orgId, change.communityId, orgUserId);\n }\n }\n\n private async onTyping(change: ChatChange): Promise<void> {\n if (!change.orgUserId || !change.until) {\n return;\n }\n const { streams } = await this.participantStreams(change);\n const until = new Date(change.until);\n for (const stream of streams) {\n if (stream.orgUserId === change.orgUserId) {\n continue;\n }\n stream.push({\n type: 'typing',\n chatId: change.chatId,\n orgUserId: change.orgUserId,\n until,\n });\n }\n }\n\n private markDirty(orgId: string, communityId: string, orgUserId: string, chatId?: string): void {\n const at = key(orgId, communityId);\n const group = this.dirty.get(at) ?? { orgId, communityId, members: new Map() };\n this.dirty.set(at, group);\n const chats = group.members.get(orgUserId) ?? new Set<string>();\n group.members.set(orgUserId, chats);\n if (chatId) {\n chats.add(chatId);\n }\n }\n\n /** Pushes the `chat.state` of every dirty member and chat and the `unread`\n * of every dirty member, read now. One flush runs at a time. */\n private async flush(): Promise<void> {\n if (this.flushing) {\n this.flushAgain = true;\n return;\n }\n this.flushing = true;\n try {\n do {\n this.flushAgain = false;\n const groups = [...this.dirty.values()];\n this.dirty = new Map();\n await Promise.all(groups.map((group) => this.flushGroup(group)));\n } while (this.flushAgain && this.dirty.size > 0 && !this.closing);\n } finally {\n this.flushing = false;\n }\n }\n\n private async flushGroup(group: DirtyGroup): Promise<void> {\n const { orgId, communityId } = group;\n const members = [...group.members.keys()].filter(\n (orgUserId) => this.streamsOf(orgId, communityId, orgUserId).length > 0,\n );\n if (members.length === 0) {\n return;\n }\n let states: Awaited<ReturnType<ChatLiveReads['memberStates']>>;\n try {\n states = await this.reads.memberStates(orgId, communityId, members);\n } catch (error) {\n this.logger.error('chat member state read failed', {\n orgId,\n communityId,\n error: describeError(error),\n });\n for (const orgUserId of members) {\n const chats = group.members.get(orgUserId) ?? new Set<string>();\n this.markDirty(orgId, communityId, orgUserId);\n for (const chatId of chats) {\n this.markDirty(orgId, communityId, orgUserId, chatId);\n }\n }\n return;\n }\n for (const state of states) {\n const chats = group.members.get(state.orgUserId);\n const streams = this.streamsOf(orgId, communityId, state.orgUserId);\n if (!chats || streams.length === 0) {\n continue;\n }\n const events: ChatLiveEvent[] = state.chats\n .filter((chat) => chats.has(chat.chatId))\n .map((chat) => ({\n type: 'chat.state',\n chatId: chat.chatId,\n unread: chat.unread,\n lastReadMessageId: chat.lastReadMessageId,\n subscription: chat.subscription,\n }));\n events.push({ type: 'unread', ...state.unread });\n for (const stream of streams) {\n for (const event of events) {\n stream.push(event);\n }\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MentionItemType, MentionView } from "../types/schemas/discussion.js";
|
|
2
|
+
import "../types/index.js";
|
|
3
|
+
import { AuthorProfileReader, MentionsRepository } from "./ports.js";
|
|
4
|
+
//#region src/discussion/mentions.d.ts
|
|
5
|
+
declare function mentionTokens(...texts: string[]): string[];
|
|
6
|
+
declare function nameMentions(text: string, nameOf: (orgUserId: string) => Promise<string>): Promise<string>;
|
|
7
|
+
declare function keepAllowed(tokens: string[], allowed: string[]): string[];
|
|
8
|
+
declare function mentionViews(mentions: Pick<MentionsRepository, 'forItems'>, profiles: AuthorProfileReader, orgId: string, itemType: MentionItemType, itemIds: string[]): Promise<Record<string, MentionView[]>>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { keepAllowed, mentionTokens, mentionViews, nameMentions };
|
|
11
|
+
//# sourceMappingURL=mentions.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { authorName } from "./authors.js";
|
|
2
|
+
//#region src/discussion/mentions.ts
|
|
3
|
+
const TOKEN = /<@([A-Za-z0-9_-]+)>/g;
|
|
4
|
+
const UNNAMED = "A member";
|
|
5
|
+
function mentionTokens(...texts) {
|
|
6
|
+
const found = /* @__PURE__ */ new Set();
|
|
7
|
+
for (const text of texts) for (const match of text.matchAll(TOKEN)) found.add(match[1]);
|
|
8
|
+
return [...found];
|
|
9
|
+
}
|
|
10
|
+
async function nameMentions(text, nameOf) {
|
|
11
|
+
const names = /* @__PURE__ */ new Map();
|
|
12
|
+
for (const orgUserId of mentionTokens(text)) names.set(orgUserId, await nameOf(orgUserId));
|
|
13
|
+
return text.replace(TOKEN, (_token, orgUserId) => names.get(orgUserId) ?? UNNAMED);
|
|
14
|
+
}
|
|
15
|
+
function keepAllowed(tokens, allowed) {
|
|
16
|
+
const kept = new Set(allowed);
|
|
17
|
+
return tokens.filter((token) => kept.has(token));
|
|
18
|
+
}
|
|
19
|
+
async function mentionViews(mentions, profiles, orgId, itemType, itemIds) {
|
|
20
|
+
if (itemIds.length === 0) return {};
|
|
21
|
+
const byItem = await mentions.forItems(orgId, itemType, [...new Set(itemIds)]);
|
|
22
|
+
const people = [...new Set(Object.values(byItem).flat())];
|
|
23
|
+
const records = people.length > 0 ? await profiles.authorsOf(orgId, people) : {};
|
|
24
|
+
return Object.fromEntries(Object.entries(byItem).map(([itemId, orgUserIds]) => [itemId, orgUserIds.flatMap((orgUserId) => {
|
|
25
|
+
const record = records[orgUserId];
|
|
26
|
+
return record ? [{
|
|
27
|
+
orgUserId,
|
|
28
|
+
name: authorName(record) || UNNAMED
|
|
29
|
+
}] : [];
|
|
30
|
+
})]));
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { keepAllowed, mentionTokens, mentionViews, nameMentions };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=mentions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mentions.js","names":[],"sources":["../../src/discussion/mentions.ts"],"sourcesContent":["import type { MentionItemType, MentionView } from '../types/index.js';\nimport { authorName } from './authors.js';\nimport type { AuthorProfileReader, MentionsRepository } from './ports.js';\n\nconst TOKEN = /<@([A-Za-z0-9_-]+)>/g;\nconst UNNAMED = 'A member';\n\nexport function mentionTokens(...texts: string[]): string[] {\n const found = new Set<string>();\n for (const text of texts) {\n for (const match of text.matchAll(TOKEN)) {\n found.add(match[1]!);\n }\n }\n return [...found];\n}\n\nexport async function nameMentions(\n text: string,\n nameOf: (orgUserId: string) => Promise<string>,\n): Promise<string> {\n const names = new Map<string, string>();\n for (const orgUserId of mentionTokens(text)) {\n names.set(orgUserId, await nameOf(orgUserId));\n }\n return text.replace(TOKEN, (_token, orgUserId: string) => names.get(orgUserId) ?? UNNAMED);\n}\n\nexport function keepAllowed(tokens: string[], allowed: string[]): string[] {\n const kept = new Set(allowed);\n return tokens.filter((token) => kept.has(token));\n}\n\nexport async function mentionViews(\n mentions: Pick<MentionsRepository, 'forItems'>,\n profiles: AuthorProfileReader,\n orgId: string,\n itemType: MentionItemType,\n itemIds: string[],\n): Promise<Record<string, MentionView[]>> {\n if (itemIds.length === 0) {\n return {};\n }\n const byItem = await mentions.forItems(orgId, itemType, [...new Set(itemIds)]);\n const people = [...new Set(Object.values(byItem).flat())];\n const records = people.length > 0 ? await profiles.authorsOf(orgId, people) : {};\n return Object.fromEntries(\n Object.entries(byItem).map(([itemId, orgUserIds]) => [\n itemId,\n orgUserIds.flatMap((orgUserId) => {\n const record = records[orgUserId];\n return record ? [{ orgUserId, name: authorName(record) || UNNAMED }] : [];\n }),\n ]),\n );\n}\n"],"mappings":";;AAIA,MAAM,QAAQ;AACd,MAAM,UAAU;AAEhB,SAAgB,cAAc,GAAG,OAA2B;CAC1D,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,SAAS,KAAK,SAAS,KAAK,GACrC,MAAM,IAAI,MAAM,EAAG;CAGvB,OAAO,CAAC,GAAG,KAAK;AAClB;AAEA,eAAsB,aACpB,MACA,QACiB;CACjB,MAAM,wBAAQ,IAAI,IAAoB;CACtC,KAAK,MAAM,aAAa,cAAc,IAAI,GACxC,MAAM,IAAI,WAAW,MAAM,OAAO,SAAS,CAAC;CAE9C,OAAO,KAAK,QAAQ,QAAQ,QAAQ,cAAsB,MAAM,IAAI,SAAS,KAAK,OAAO;AAC3F;AAEA,SAAgB,YAAY,QAAkB,SAA6B;CACzE,MAAM,OAAO,IAAI,IAAI,OAAO;CAC5B,OAAO,OAAO,QAAQ,UAAU,KAAK,IAAI,KAAK,CAAC;AACjD;AAEA,eAAsB,aACpB,UACA,UACA,OACA,UACA,SACwC;CACxC,IAAI,QAAQ,WAAW,GACrB,OAAO,CAAC;CAEV,MAAM,SAAS,MAAM,SAAS,SAAS,OAAO,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC;CAC7E,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;CACxD,MAAM,UAAU,OAAO,SAAS,IAAI,MAAM,SAAS,UAAU,OAAO,MAAM,IAAI,CAAC;CAC/E,OAAO,OAAO,YACZ,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,gBAAgB,CACnD,QACA,WAAW,SAAS,cAAc;EAChC,MAAM,SAAS,QAAQ;EACvB,OAAO,SAAS,CAAC;GAAE;GAAW,MAAM,WAAW,MAAM,KAAK;EAAQ,CAAC,IAAI,CAAC;CAC1E,CAAC,CACH,CAAC,CACH;AACF"}
|