@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","names":[],"sources":["../../src/automations/catalog.ts"],"sourcesContent":["// automations context — the code-owned catalogs `availableActions()` and\n// `availableTriggers()` serve: built-in action definitions and the domain\n// event types automations may react to.\nimport type { z } from 'zod';\nimport type { EmailTemplateId } from '../types/index.js';\nimport { assetEvents } from '../assets/index.js';\nimport { contentEvents } from '../content/index.js';\nimport { discussionEvents } from '../discussion/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport { identityEvents } from '../identity/index.js';\nimport { integrationEvents } from '../integrations/index.js';\nimport { organizationEvents } from '../organizations/index.js';\nimport { progressEvents } from '../progress/index.js';\nimport type { AvailableActions, AvailableTriggers } from './types.js';\n\n/** Every EmailTemplateId — a missing key here is a compile error, kept exhaustive by construction. */\nexport const ALL_EMAIL_TEMPLATE_IDS: Record<EmailTemplateId, true> = {\n magicLink: true,\n studentInvite: true,\n memberInvite: true,\n passwordReset: true,\n passwordChanged: true,\n emailVerification: true,\n accessGranted: true,\n accessRevoked: true,\n courseCompleted: true,\n};\n\nexport const DELIVER_WEBHOOK_ACTION = 'deliverWebhook';\n\nexport function catalogActions(): AvailableActions {\n return [\n {\n type: 'sendEmail',\n description: 'Send a transactional email using a built-in template.',\n inputSchema: {\n type: 'object',\n required: ['template'],\n properties: {\n template: { enum: Object.keys(ALL_EMAIL_TEMPLATE_IDS) },\n },\n },\n source: 'system',\n },\n ];\n}\n\ninterface CatalogTrigger {\n readonly event: { readonly type: string; readonly publicData: z.ZodType };\n readonly label: string;\n readonly category: string;\n readonly description: string;\n}\n\nconst TRIGGERS: CatalogTrigger[] = [\n {\n event: identityEvents.userCreated,\n label: 'User created',\n category: 'Users',\n description: 'a user was created',\n },\n {\n event: identityEvents.userUpdated,\n label: 'User updated',\n category: 'Users',\n description: 'a user was updated',\n },\n {\n event: organizationEvents.organizationCreated,\n label: 'Organization created',\n category: 'Organization',\n description: 'an organization was created',\n },\n {\n event: organizationEvents.organizationUpdated,\n label: 'Organization updated',\n category: 'Organization',\n description: 'an organization was updated',\n },\n {\n event: organizationEvents.organizationDeleted,\n label: 'Organization deleted',\n category: 'Organization',\n description: 'an organization was deleted',\n },\n {\n event: organizationEvents.orgUserLinked,\n label: 'Member joined',\n category: 'Organization',\n description: 'a user was linked to an organization',\n },\n {\n event: organizationEvents.orgUserDeleted,\n label: 'Member removed',\n category: 'Organization',\n description: 'a user was removed from an organization',\n },\n {\n event: organizationEvents.inviteCreated,\n label: 'Invite sent',\n category: 'Organization',\n description: 'an invite was created or re-issued',\n },\n {\n event: organizationEvents.inviteAccepted,\n label: 'Invite accepted',\n category: 'Organization',\n description: 'an invite was accepted',\n },\n {\n event: organizationEvents.studentCreated,\n label: 'Student created',\n category: 'Students',\n description: 'a student was created',\n },\n {\n event: organizationEvents.studentDeleted,\n label: 'Student deleted',\n category: 'Students',\n description: 'a student was deleted',\n },\n {\n event: organizationEvents.studentLinked,\n label: 'Student linked to account',\n category: 'Students',\n description: 'a pending student was linked to an auth account',\n },\n {\n event: contentEvents.courseCreated,\n label: 'Course created',\n category: 'Courses',\n description: 'a course was created',\n },\n {\n event: contentEvents.courseUpdated,\n label: 'Course updated',\n category: 'Courses',\n description: 'a course was updated',\n },\n {\n event: contentEvents.courseDeleted,\n label: 'Course deleted',\n category: 'Courses',\n description: 'a course was deleted',\n },\n {\n event: contentEvents.moduleCreated,\n label: 'Module created',\n category: 'Courses',\n description: 'a course module was created',\n },\n {\n event: contentEvents.moduleUpdated,\n label: 'Module updated',\n category: 'Courses',\n description: 'a course module was updated',\n },\n {\n event: contentEvents.moduleDeleted,\n label: 'Module deleted',\n category: 'Courses',\n description: 'a course module was deleted',\n },\n {\n event: contentEvents.modulesReordered,\n label: 'Modules reordered',\n category: 'Courses',\n description: 'course modules were reordered',\n },\n {\n event: contentEvents.activityCreated,\n label: 'Activity created',\n category: 'Courses',\n description: 'a course activity was created',\n },\n {\n event: contentEvents.activityUpdated,\n label: 'Activity updated',\n category: 'Courses',\n description: 'a course activity was updated',\n },\n {\n event: contentEvents.activityDeleted,\n label: 'Activity deleted',\n category: 'Courses',\n description: 'a course activity was deleted',\n },\n {\n event: contentEvents.activitiesReordered,\n label: 'Activities reordered',\n category: 'Courses',\n description: 'course activities were reordered',\n },\n {\n event: contentEvents.downloadCreated,\n label: 'Download created',\n category: 'Downloads',\n description: 'a download was created',\n },\n {\n event: contentEvents.downloadUpdated,\n label: 'Download updated',\n category: 'Downloads',\n description: 'a download was updated',\n },\n {\n event: contentEvents.downloadDeleted,\n label: 'Download deleted',\n category: 'Downloads',\n description: 'a download was deleted',\n },\n {\n event: contentEvents.downloadAssetAdded,\n label: 'Download file added',\n category: 'Downloads',\n description: 'a download asset was added',\n },\n {\n event: contentEvents.downloadAssetRemoved,\n label: 'Download file removed',\n category: 'Downloads',\n description: 'a download asset was removed',\n },\n {\n event: contentEvents.downloadAssetRenamed,\n label: 'Download file renamed',\n category: 'Downloads',\n description: 'a download asset was renamed',\n },\n {\n event: contentEvents.downloadAssetsReordered,\n label: 'Download files reordered',\n category: 'Downloads',\n description: 'download assets were reordered',\n },\n {\n event: entitlementEvents.entitlementCreated,\n label: 'Access granted',\n category: 'Access',\n description: 'a student was granted access to content',\n },\n {\n event: entitlementEvents.entitlementUpdated,\n label: 'Access updated',\n category: 'Access',\n description: \"an entitlement's status or expiry changed\",\n },\n {\n event: entitlementEvents.entitlementDeleted,\n label: 'Access revoked',\n category: 'Access',\n description: \"a student's access to content was revoked\",\n },\n {\n event: entitlementEvents.entitlementExpired,\n label: 'Access expired',\n category: 'Access',\n description: 'an entitlement passed its expiry',\n },\n {\n event: progressEvents.progressStarted,\n label: 'Progress started',\n category: 'Progress',\n description: 'a student started a progress record',\n },\n {\n event: progressEvents.progressCompleted,\n label: 'Progress completed',\n category: 'Progress',\n description: 'a student completed a progress record',\n },\n {\n event: integrationEvents.connectionCreated,\n label: 'Integration connected',\n category: 'Integrations',\n description: 'an integration connection was established',\n },\n {\n event: integrationEvents.connectionUpdated,\n label: 'Integration updated',\n category: 'Integrations',\n description: 'an integration connection changed',\n },\n {\n event: integrationEvents.connectionRemoved,\n label: 'Integration disconnected',\n category: 'Integrations',\n description: 'an integration connection was removed',\n },\n {\n event: discussionEvents.commentCreated,\n label: 'Comment created',\n category: 'Discussion',\n description: 'a comment was created',\n },\n {\n event: discussionEvents.commentPublished,\n label: 'Comment published',\n category: 'Discussion',\n description: 'a comment was published',\n },\n {\n event: discussionEvents.commentRemoved,\n label: 'Comment removed',\n category: 'Discussion',\n description: 'a comment was removed',\n },\n {\n event: discussionEvents.commentReported,\n label: 'Comment reported',\n category: 'Discussion',\n description: 'a comment was reported',\n },\n {\n event: assetEvents.assetCreated,\n label: 'Upload requested',\n category: 'Assets',\n description: 'an asset upload was requested',\n },\n {\n event: assetEvents.assetReady,\n label: 'Upload ready',\n category: 'Assets',\n description: 'an asset was confirmed ready',\n },\n {\n event: assetEvents.assetDeleted,\n label: 'Asset deleted',\n category: 'Assets',\n description: 'an asset was deleted',\n },\n];\n\nexport function catalogTriggers(): AvailableTriggers['triggers'] {\n return TRIGGERS.map(({ event, ...trigger }) => ({ type: event.type, ...trigger }));\n}\n\nexport function publicDataSchema(type: string): z.ZodType | undefined {\n return TRIGGERS.find((trigger) => trigger.event.type === type)?.event.publicData;\n}\n"],"mappings":";;;;;;;;;;AAgBA,MAAa,yBAAwD;CACnE,WAAW;CACX,eAAe;CACf,cAAc;CACd,eAAe;CACf,iBAAiB;CACjB,mBAAmB;CACnB,eAAe;CACf,eAAe;CACf,iBAAiB;AACnB;AAEA,MAAa,yBAAyB;AAEtC,SAAgB,iBAAmC;CACjD,OAAO,CACL;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,UAAU,CAAC,UAAU;GACrB,YAAY,EACV,UAAU,EAAE,MAAM,OAAO,KAAK,sBAAsB,EAAE,EACxD;EACF;EACA,QAAQ;CACV,CACF;AACF;AASA,MAAM,WAA6B;CACjC;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;AACF;AAEA,SAAgB,kBAAiD;CAC/D,OAAO,SAAS,KAAK,EAAE,OAAO,GAAG,eAAe;EAAE,MAAM,MAAM;EAAM,GAAG;CAAQ,EAAE;AACnF;AAEA,SAAgB,iBAAiB,MAAqC;CACpE,OAAO,SAAS,MAAM,YAAY,QAAQ,MAAM,SAAS,IAAI,CAAC,EAAE,MAAM;AACxE"}
|
|
1
|
+
{"version":3,"file":"catalog.js","names":[],"sources":["../../src/automations/catalog.ts"],"sourcesContent":["// automations context — the code-owned catalogs `availableActions()` and\n// `availableTriggers()` serve: built-in action definitions and the domain\n// event types automations may react to.\nimport type { z } from 'zod';\nimport type { EmailTemplateId } from '../types/index.js';\nimport { notificationKindSchema } from '../types/schemas/index.js';\nimport { assetEvents } from '../assets/index.js';\nimport { contentEvents } from '../content/index.js';\nimport { discussionEvents } from '../discussion/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport { identityEvents } from '../identity/index.js';\nimport { integrationEvents } from '../integrations/index.js';\nimport { organizationEvents } from '../organizations/index.js';\nimport { progressEvents } from '../progress/index.js';\nimport type { AvailableActions, AvailableTriggers } from './types.js';\n\n/** Every EmailTemplateId — a missing key here is a compile error, kept exhaustive by construction. */\nexport const ALL_EMAIL_TEMPLATE_IDS: Record<EmailTemplateId, true> = {\n magicLink: true,\n studentInvite: true,\n memberInvite: true,\n passwordReset: true,\n passwordChanged: true,\n emailVerification: true,\n accessGranted: true,\n accessRevoked: true,\n courseCompleted: true,\n welcomeToCommunity: true,\n membershipEndingSoon: true,\n membershipEnded: true,\n newPostInSpace: true,\n yourPostWasPublished: true,\n yourPostWasRemoved: true,\n newCommentOnPost: true,\n replyToYourComment: true,\n yourCommentWasRemoved: true,\n requestApproved: true,\n requestDeclined: true,\n invitedToSpace: true,\n messageRequest: true,\n newMessage: true,\n addedToGroupChat: true,\n youAreNowAModerator: true,\n digest: true,\n postAwaitingReview: true,\n joinRequest: true,\n somethingWasFlagged: true,\n messageWasFlagged: true,\n};\n\nexport const DELIVER_WEBHOOK_ACTION = 'deliverWebhook';\nexport const NOTIFY_ACTION = 'notify';\n\nexport function catalogActions(): AvailableActions {\n return [\n {\n type: 'sendEmail',\n description: 'Send a transactional email using a built-in template.',\n inputSchema: {\n type: 'object',\n required: ['template'],\n properties: {\n template: { enum: Object.keys(ALL_EMAIL_TEMPLATE_IDS) },\n },\n },\n source: 'system',\n },\n {\n type: NOTIFY_ACTION,\n description: 'Tell each person concerned, in the app and by email, as they chose.',\n inputSchema: {\n type: 'object',\n required: ['kind'],\n properties: {\n kind: { enum: [...notificationKindSchema.options] },\n },\n },\n source: 'system',\n },\n {\n type: 'grantAccess',\n description: 'Grant a content item or bundle to the person on the event.',\n inputSchema: {\n type: 'object',\n properties: {\n contentId: { type: 'string' },\n bundleId: { type: 'string' },\n expiresInDays: { type: 'number' },\n },\n },\n source: 'system',\n },\n {\n type: 'publishDuePosts',\n description: 'Submit scheduled posts whose time has passed.',\n inputSchema: { type: 'object' },\n source: 'system',\n },\n {\n type: 'expireDueGrants',\n description: 'Expire grants whose time has passed.',\n inputSchema: { type: 'object' },\n source: 'system',\n },\n {\n type: 'sendDigest',\n description: 'Open the daily digest for every community.',\n inputSchema: { type: 'object' },\n source: 'system',\n },\n {\n type: 'removeUnattachedUploads',\n description: 'Remove member uploads older than an hour that nothing references.',\n inputSchema: { type: 'object' },\n source: 'system',\n },\n ];\n}\n\ninterface CatalogTrigger {\n readonly event: { readonly type: string; readonly publicData: z.ZodType };\n readonly label: string;\n readonly category: string;\n readonly description: string;\n}\n\nconst TRIGGERS: CatalogTrigger[] = [\n {\n event: identityEvents.userCreated,\n label: 'User created',\n category: 'Users',\n description: 'a user was created',\n },\n {\n event: identityEvents.userUpdated,\n label: 'User updated',\n category: 'Users',\n description: 'a user was updated',\n },\n {\n event: organizationEvents.organizationCreated,\n label: 'Organization created',\n category: 'Organization',\n description: 'an organization was created',\n },\n {\n event: organizationEvents.organizationUpdated,\n label: 'Organization updated',\n category: 'Organization',\n description: 'an organization was updated',\n },\n {\n event: organizationEvents.organizationDeleted,\n label: 'Organization deleted',\n category: 'Organization',\n description: 'an organization was deleted',\n },\n {\n event: organizationEvents.orgUserLinked,\n label: 'Member joined',\n category: 'Organization',\n description: 'a user was linked to an organization',\n },\n {\n event: organizationEvents.orgUserDeleted,\n label: 'Member removed',\n category: 'Organization',\n description: 'a user was removed from an organization',\n },\n {\n event: organizationEvents.orgUserUpdated,\n label: 'Member updated',\n category: 'Organization',\n description: 'an organization member was updated',\n },\n {\n event: organizationEvents.inviteCreated,\n label: 'Invite sent',\n category: 'Organization',\n description: 'an invite was created or re-issued',\n },\n {\n event: organizationEvents.inviteAccepted,\n label: 'Invite accepted',\n category: 'Organization',\n description: 'an invite was accepted',\n },\n {\n event: organizationEvents.studentCreated,\n label: 'Student created',\n category: 'Students',\n description: 'a student was created',\n },\n {\n event: organizationEvents.studentDeleted,\n label: 'Student deleted',\n category: 'Students',\n description: 'a student was deleted',\n },\n {\n event: organizationEvents.studentLinked,\n label: 'Student linked to account',\n category: 'Students',\n description: 'a pending student was linked to an auth account',\n },\n {\n event: contentEvents.courseCreated,\n label: 'Course created',\n category: 'Courses',\n description: 'a course was created',\n },\n {\n event: contentEvents.courseUpdated,\n label: 'Course updated',\n category: 'Courses',\n description: 'a course was updated',\n },\n {\n event: contentEvents.courseDeleted,\n label: 'Course deleted',\n category: 'Courses',\n description: 'a course was deleted',\n },\n {\n event: contentEvents.moduleCreated,\n label: 'Module created',\n category: 'Courses',\n description: 'a course module was created',\n },\n {\n event: contentEvents.moduleUpdated,\n label: 'Module updated',\n category: 'Courses',\n description: 'a course module was updated',\n },\n {\n event: contentEvents.moduleDeleted,\n label: 'Module deleted',\n category: 'Courses',\n description: 'a course module was deleted',\n },\n {\n event: contentEvents.modulesReordered,\n label: 'Modules reordered',\n category: 'Courses',\n description: 'course modules were reordered',\n },\n {\n event: contentEvents.activityCreated,\n label: 'Activity created',\n category: 'Courses',\n description: 'a course activity was created',\n },\n {\n event: contentEvents.activityUpdated,\n label: 'Activity updated',\n category: 'Courses',\n description: 'a course activity was updated',\n },\n {\n event: contentEvents.activityDeleted,\n label: 'Activity deleted',\n category: 'Courses',\n description: 'a course activity was deleted',\n },\n {\n event: contentEvents.activitiesReordered,\n label: 'Activities reordered',\n category: 'Courses',\n description: 'course activities were reordered',\n },\n {\n event: contentEvents.downloadCreated,\n label: 'Download created',\n category: 'Downloads',\n description: 'a download was created',\n },\n {\n event: contentEvents.downloadUpdated,\n label: 'Download updated',\n category: 'Downloads',\n description: 'a download was updated',\n },\n {\n event: contentEvents.downloadDeleted,\n label: 'Download deleted',\n category: 'Downloads',\n description: 'a download was deleted',\n },\n {\n event: contentEvents.downloadAssetAdded,\n label: 'Download file added',\n category: 'Downloads',\n description: 'a download asset was added',\n },\n {\n event: contentEvents.downloadAssetRemoved,\n label: 'Download file removed',\n category: 'Downloads',\n description: 'a download asset was removed',\n },\n {\n event: contentEvents.downloadAssetRenamed,\n label: 'Download file renamed',\n category: 'Downloads',\n description: 'a download asset was renamed',\n },\n {\n event: contentEvents.downloadAssetsReordered,\n label: 'Download files reordered',\n category: 'Downloads',\n description: 'download assets were reordered',\n },\n {\n event: contentEvents.communityCreated,\n label: 'Community created',\n category: 'Communities',\n description: 'a community was created',\n },\n {\n event: contentEvents.communityUpdated,\n label: 'Community updated',\n category: 'Communities',\n description: 'a community was updated',\n },\n {\n event: contentEvents.communityDeleted,\n label: 'Community deleted',\n category: 'Communities',\n description: 'a community was deleted',\n },\n {\n event: contentEvents.spaceCreated,\n label: 'Space created',\n category: 'Communities',\n description: 'a space was created',\n },\n {\n event: contentEvents.spaceUpdated,\n label: 'Space updated',\n category: 'Communities',\n description: 'a space was updated',\n },\n {\n event: contentEvents.spaceDeleted,\n label: 'Space deleted',\n category: 'Communities',\n description: 'a space was deleted',\n },\n {\n event: contentEvents.spacesReordered,\n label: 'Spaces reordered',\n category: 'Communities',\n description: 'spaces were reordered',\n },\n {\n event: entitlementEvents.entitlementCreated,\n label: 'Access granted',\n category: 'Access',\n description: 'a student was granted access to content',\n },\n {\n event: entitlementEvents.entitlementUpdated,\n label: 'Access updated',\n category: 'Access',\n description: \"an entitlement's status or expiry changed\",\n },\n {\n event: entitlementEvents.entitlementDeleted,\n label: 'Access revoked',\n category: 'Access',\n description: \"a student's access to content was revoked\",\n },\n {\n event: entitlementEvents.entitlementExpired,\n label: 'Access expired',\n category: 'Access',\n description: 'an entitlement passed its expiry',\n },\n {\n event: entitlementEvents.entitlementEndingSoon,\n label: 'Access ending soon',\n category: 'Access',\n description: 'an entitlement expires within a week',\n },\n {\n event: entitlementEvents.spaceMemberCreated,\n label: 'Space member created',\n category: 'Access',\n description: 'a person was added to a space',\n },\n {\n event: entitlementEvents.spaceMemberUpdated,\n label: 'Space member updated',\n category: 'Access',\n description: 'a space membership changed',\n },\n {\n event: entitlementEvents.spaceMemberDeleted,\n label: 'Space member removed',\n category: 'Access',\n description: 'a space membership was removed',\n },\n {\n event: progressEvents.progressStarted,\n label: 'Progress started',\n category: 'Progress',\n description: 'a student started a progress record',\n },\n {\n event: progressEvents.progressCompleted,\n label: 'Progress completed',\n category: 'Progress',\n description: 'a student completed a progress record',\n },\n {\n event: integrationEvents.connectionCreated,\n label: 'Integration connected',\n category: 'Integrations',\n description: 'an integration connection was established',\n },\n {\n event: integrationEvents.connectionUpdated,\n label: 'Integration updated',\n category: 'Integrations',\n description: 'an integration connection changed',\n },\n {\n event: integrationEvents.connectionRemoved,\n label: 'Integration disconnected',\n category: 'Integrations',\n description: 'an integration connection was removed',\n },\n {\n event: discussionEvents.commentCreated,\n label: 'Comment created',\n category: 'Discussion',\n description: 'a comment was created',\n },\n {\n event: discussionEvents.commentPublished,\n label: 'Comment published',\n category: 'Discussion',\n description: 'a comment was published',\n },\n {\n event: discussionEvents.commentRemoved,\n label: 'Comment removed',\n category: 'Discussion',\n description: 'a comment was removed',\n },\n {\n event: discussionEvents.commentReported,\n label: 'Comment reported',\n category: 'Discussion',\n description: 'a comment was reported',\n },\n {\n event: discussionEvents.postCreated,\n label: 'Post created',\n category: 'Discussion',\n description: 'a post was created',\n },\n {\n event: discussionEvents.postUpdated,\n label: 'Post updated',\n category: 'Discussion',\n description: 'a post was updated',\n },\n {\n event: discussionEvents.postPublished,\n label: 'Post published',\n category: 'Discussion',\n description: 'a post was published',\n },\n {\n event: discussionEvents.postRemoved,\n label: 'Post removed',\n category: 'Discussion',\n description: 'a post was removed',\n },\n {\n event: discussionEvents.postReported,\n label: 'Post reported',\n category: 'Discussion',\n description: 'a post was reported',\n },\n {\n event: discussionEvents.chatCreated,\n label: 'Chat created',\n category: 'Discussion',\n description: 'a chat was created',\n },\n {\n event: discussionEvents.chatUpdated,\n label: 'Chat updated',\n category: 'Discussion',\n description: 'a chat was updated',\n },\n {\n event: discussionEvents.chatParticipantAdded,\n label: 'Chat participant added',\n category: 'Discussion',\n description: 'a person was added to a chat',\n },\n {\n event: discussionEvents.messageSent,\n label: 'Message sent',\n category: 'Discussion',\n description: 'a message was sent',\n },\n {\n event: discussionEvents.messageDeleted,\n label: 'Message deleted',\n category: 'Discussion',\n description: 'a message was deleted',\n },\n {\n event: discussionEvents.messageReported,\n label: 'Message reported',\n category: 'Discussion',\n description: 'a message was reported',\n },\n {\n event: discussionEvents.digestDue,\n label: 'Digest due',\n category: 'Discussion',\n description: 'a community digest period opened',\n },\n {\n event: assetEvents.assetCreated,\n label: 'Upload requested',\n category: 'Assets',\n description: 'an asset upload was requested',\n },\n {\n event: assetEvents.assetReady,\n label: 'Upload ready',\n category: 'Assets',\n description: 'an asset was confirmed ready',\n },\n {\n event: assetEvents.assetDeleted,\n label: 'Asset deleted',\n category: 'Assets',\n description: 'an asset was deleted',\n },\n];\n\nexport function catalogTriggers(): AvailableTriggers['triggers'] {\n return TRIGGERS.map(({ event, ...trigger }) => ({ type: event.type, ...trigger }));\n}\n\nexport function publicDataSchema(type: string): z.ZodType | undefined {\n return TRIGGERS.find((trigger) => trigger.event.type === type)?.event.publicData;\n}\n"],"mappings":";;;;;;;;;;;AAiBA,MAAa,yBAAwD;CACnE,WAAW;CACX,eAAe;CACf,cAAc;CACd,eAAe;CACf,iBAAiB;CACjB,mBAAmB;CACnB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,oBAAoB;CACpB,sBAAsB;CACtB,iBAAiB;CACjB,gBAAgB;CAChB,sBAAsB;CACtB,oBAAoB;CACpB,kBAAkB;CAClB,oBAAoB;CACpB,uBAAuB;CACvB,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAChB,gBAAgB;CAChB,YAAY;CACZ,kBAAkB;CAClB,qBAAqB;CACrB,QAAQ;CACR,oBAAoB;CACpB,aAAa;CACb,qBAAqB;CACrB,mBAAmB;AACrB;AAEA,MAAa,yBAAyB;AACtC,MAAa,gBAAgB;AAE7B,SAAgB,iBAAmC;CACjD,OAAO;EACL;GACE,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,UAAU,CAAC,UAAU;IACrB,YAAY,EACV,UAAU,EAAE,MAAM,OAAO,KAAK,sBAAsB,EAAE,EACxD;GACF;GACA,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,UAAU,CAAC,MAAM;IACjB,YAAY,EACV,MAAM,EAAE,MAAM,CAAC,GAAG,uBAAuB,OAAO,EAAE,EACpD;GACF;GACA,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,YAAY;KACV,WAAW,EAAE,MAAM,SAAS;KAC5B,UAAU,EAAE,MAAM,SAAS;KAC3B,eAAe,EAAE,MAAM,SAAS;IAClC;GACF;GACA,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa,EAAE,MAAM,SAAS;GAC9B,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa,EAAE,MAAM,SAAS;GAC9B,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa,EAAE,MAAM,SAAS;GAC9B,QAAQ;EACV;EACA;GACE,MAAM;GACN,aAAa;GACb,aAAa,EAAE,MAAM,SAAS;GAC9B,QAAQ;EACV;CACF;AACF;AASA,MAAM,WAA6B;CACjC;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,mBAAmB;EAC1B,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,cAAc;EACrB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,eAAe;EACtB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,kBAAkB;EACzB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,iBAAiB;EACxB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;CACA;EACE,OAAO,YAAY;EACnB,OAAO;EACP,UAAU;EACV,aAAa;CACf;AACF;AAEA,SAAgB,kBAAiD;CAC/D,OAAO,SAAS,KAAK,EAAE,OAAO,GAAG,eAAe;EAAE,MAAM,MAAM;EAAM,GAAG;CAAQ,EAAE;AACnF;AAEA,SAAgB,iBAAiB,MAAqC;CACpE,OAAO,SAAS,MAAM,YAAY,QAAQ,MAAM,SAAS,IAAI,CAAC,EAAE,MAAM;AACxE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DomainEvent } from "../types/shared.js";
|
|
2
|
+
import { EmailTemplateId } from "../types/email-templates.js";
|
|
3
|
+
import "../types/index.js";
|
|
4
|
+
import "../shared/ports.js";
|
|
5
|
+
import { ActionDeps, EmailRecipient } from "./community-mail.js";
|
|
6
|
+
//#region src/automations/community-derivations.d.ts
|
|
7
|
+
interface EmailDerivation<K extends EmailTemplateId> {
|
|
8
|
+
triggers: readonly string[];
|
|
9
|
+
derive(event: DomainEvent, deps: ActionDeps): Promise<EmailRecipient<K>[] | undefined>;
|
|
10
|
+
}
|
|
11
|
+
declare const COMMUNITY_DERIVATIONS: { [K in EmailTemplateId]?: EmailDerivation<K>; };
|
|
12
|
+
//#endregion
|
|
13
|
+
export { COMMUNITY_DERIVATIONS, EmailDerivation };
|
|
14
|
+
//# sourceMappingURL=community-derivations.d.ts.map
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { organizationEvents } from "../organizations/events.js";
|
|
2
|
+
import { entitlementEvents } from "../entitlements/events.js";
|
|
3
|
+
import { discussionEvents } from "../discussion/events.js";
|
|
4
|
+
import { MESSAGE_BATCH_MS, actorOf, address, excerpt, previousStatusOf } from "./community-mail.js";
|
|
5
|
+
//#region src/automations/community-derivations.ts
|
|
6
|
+
function silence(triggers) {
|
|
7
|
+
return {
|
|
8
|
+
triggers,
|
|
9
|
+
derive: async () => []
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function seatsLeft(capacity, active) {
|
|
13
|
+
if (capacity == null) return "No cap";
|
|
14
|
+
return String(Math.max(capacity - active, 0));
|
|
15
|
+
}
|
|
16
|
+
function muted(participant, at) {
|
|
17
|
+
return participant.muted && (participant.mutedUntil === null || participant.mutedUntil.getTime() > at.getTime());
|
|
18
|
+
}
|
|
19
|
+
function chatStatusOf(event) {
|
|
20
|
+
const value = event.metadata?.chatStatus;
|
|
21
|
+
return typeof value === "string" ? value : void 0;
|
|
22
|
+
}
|
|
23
|
+
async function communityTitle(deps, orgId, communityId) {
|
|
24
|
+
return deps.mail.communityTitle(orgId, communityId);
|
|
25
|
+
}
|
|
26
|
+
const COMMUNITY_DERIVATIONS = {
|
|
27
|
+
welcomeToCommunity: {
|
|
28
|
+
triggers: ["entitlement.created"],
|
|
29
|
+
derive: async (event, deps) => {
|
|
30
|
+
const parsed = entitlementEvents.entitlementCreated.safeParse(event);
|
|
31
|
+
if (!parsed.success) return;
|
|
32
|
+
const grant = parsed.data.data;
|
|
33
|
+
const communityIds = await deps.mail.communitiesOpenedBy(event.orgId, {
|
|
34
|
+
contentId: grant.contentId,
|
|
35
|
+
bundleId: grant.bundleId
|
|
36
|
+
});
|
|
37
|
+
const recipients = [];
|
|
38
|
+
for (const communityId of communityIds) {
|
|
39
|
+
const title = await communityTitle(deps, event.orgId, communityId);
|
|
40
|
+
if (!title) return;
|
|
41
|
+
const spaceNames = await deps.mail.openSpaceNames(event.orgId, grant.orgUserId, communityId);
|
|
42
|
+
const addressed = await address(deps, event, event.orgId, [grant.orgUserId], {
|
|
43
|
+
communityTitle: title,
|
|
44
|
+
communityId,
|
|
45
|
+
spaceNames
|
|
46
|
+
});
|
|
47
|
+
if (!addressed) return;
|
|
48
|
+
recipients.push(...addressed);
|
|
49
|
+
}
|
|
50
|
+
return recipients;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
membershipEndingSoon: {
|
|
54
|
+
triggers: ["entitlement.ending_soon"],
|
|
55
|
+
derive: async (event, deps) => {
|
|
56
|
+
const parsed = entitlementEvents.entitlementEndingSoon.safeParse(event);
|
|
57
|
+
if (!parsed.success) return;
|
|
58
|
+
const grant = parsed.data.data;
|
|
59
|
+
const communityId = grant.communityId;
|
|
60
|
+
const title = await communityTitle(deps, event.orgId, communityId);
|
|
61
|
+
if (!title) return;
|
|
62
|
+
return address(deps, event, event.orgId, [grant.orgUserId], {
|
|
63
|
+
communityTitle: title,
|
|
64
|
+
communityId,
|
|
65
|
+
expiresAt: grant.expiresAt ? grant.expiresAt.toISOString() : ""
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
membershipEnded: {
|
|
70
|
+
triggers: ["entitlement.expired", "entitlement.deleted"],
|
|
71
|
+
derive: async (event, deps) => {
|
|
72
|
+
const parsed = event.type === "entitlement.expired" ? entitlementEvents.entitlementExpired.safeParse(event) : entitlementEvents.entitlementDeleted.safeParse(event);
|
|
73
|
+
if (!parsed.success) return;
|
|
74
|
+
const grant = parsed.data.data;
|
|
75
|
+
const communityIds = await deps.mail.communitiesOpenedBy(event.orgId, {
|
|
76
|
+
contentId: grant.contentId,
|
|
77
|
+
bundleId: grant.bundleId
|
|
78
|
+
});
|
|
79
|
+
const recipients = [];
|
|
80
|
+
for (const communityId of communityIds) {
|
|
81
|
+
const title = await communityTitle(deps, event.orgId, communityId);
|
|
82
|
+
if (!title) return;
|
|
83
|
+
const addressed = await address(deps, event, event.orgId, [grant.orgUserId], {
|
|
84
|
+
communityTitle: title,
|
|
85
|
+
communityId
|
|
86
|
+
});
|
|
87
|
+
if (!addressed) return;
|
|
88
|
+
recipients.push(...addressed);
|
|
89
|
+
}
|
|
90
|
+
return recipients;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
newPostInSpace: {
|
|
94
|
+
triggers: ["discussion.post.published"],
|
|
95
|
+
derive: async (event, deps) => {
|
|
96
|
+
const parsed = discussionEvents.postPublished.safeParse(event);
|
|
97
|
+
if (!parsed.success) return;
|
|
98
|
+
const post = parsed.data.data;
|
|
99
|
+
const space = await deps.mail.space(event.orgId, post.spaceId);
|
|
100
|
+
if (!space) return;
|
|
101
|
+
const openers = await deps.mail.spaceOpeners(event.orgId, post.spaceId);
|
|
102
|
+
return address(deps, event, event.orgId, openers.filter((id) => id !== post.orgUserId), {
|
|
103
|
+
spaceName: space.name,
|
|
104
|
+
postTitle: post.title,
|
|
105
|
+
authorName: await deps.mail.displayName(event.orgId, post.orgUserId),
|
|
106
|
+
excerpt: excerpt(post.body || post.title, 280),
|
|
107
|
+
postId: post.id,
|
|
108
|
+
communityId: post.communityId
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
yourPostWasPublished: {
|
|
113
|
+
triggers: ["discussion.post.published"],
|
|
114
|
+
derive: async (event, deps) => {
|
|
115
|
+
if (previousStatusOf(event) !== "pending") return [];
|
|
116
|
+
const parsed = discussionEvents.postPublished.safeParse(event);
|
|
117
|
+
if (!parsed.success) return;
|
|
118
|
+
const post = parsed.data.data;
|
|
119
|
+
const space = await deps.mail.space(event.orgId, post.spaceId);
|
|
120
|
+
if (!space) return;
|
|
121
|
+
return address(deps, event, event.orgId, [post.orgUserId], {
|
|
122
|
+
postTitle: post.title,
|
|
123
|
+
spaceName: space.name,
|
|
124
|
+
postId: post.id,
|
|
125
|
+
communityId: post.communityId
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
yourPostWasRemoved: {
|
|
130
|
+
triggers: ["discussion.post.removed"],
|
|
131
|
+
derive: async (event, deps) => {
|
|
132
|
+
const parsed = discussionEvents.postRemoved.safeParse(event);
|
|
133
|
+
if (!parsed.success) return;
|
|
134
|
+
const post = parsed.data.data;
|
|
135
|
+
if (post.removedBy === post.orgUserId) return [];
|
|
136
|
+
const space = await deps.mail.space(event.orgId, post.spaceId);
|
|
137
|
+
if (!space) return;
|
|
138
|
+
return address(deps, event, event.orgId, [post.orgUserId], {
|
|
139
|
+
postTitle: post.title,
|
|
140
|
+
spaceName: space.name,
|
|
141
|
+
spaceId: post.spaceId,
|
|
142
|
+
communityId: post.communityId
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
newCommentOnPost: {
|
|
147
|
+
triggers: ["discussion.comment.created"],
|
|
148
|
+
derive: async (event, deps) => {
|
|
149
|
+
const parsed = discussionEvents.commentCreated.safeParse(event);
|
|
150
|
+
if (!parsed.success) return;
|
|
151
|
+
const comment = parsed.data.data;
|
|
152
|
+
if (!comment.postId || comment.status !== "published" || !comment.communityId) return [];
|
|
153
|
+
const post = await deps.mail.post(event.orgId, comment.postId);
|
|
154
|
+
if (!post) return;
|
|
155
|
+
const followers = await deps.mail.followerIds(event.orgId, comment.postId);
|
|
156
|
+
const ids = [.../* @__PURE__ */ new Set([...followers, post.orgUserId])].filter((id) => id !== comment.orgUserId);
|
|
157
|
+
const openers = await deps.mail.spaceOpenersAmong(event.orgId, post.spaceId, ids);
|
|
158
|
+
return address(deps, event, event.orgId, openers, {
|
|
159
|
+
postTitle: post.title,
|
|
160
|
+
commenterName: await deps.mail.displayName(event.orgId, comment.orgUserId),
|
|
161
|
+
excerpt: excerpt(comment.body, 280),
|
|
162
|
+
commentId: comment.id,
|
|
163
|
+
postId: comment.postId,
|
|
164
|
+
communityId: comment.communityId
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
replyToYourComment: {
|
|
169
|
+
triggers: ["discussion.comment.created"],
|
|
170
|
+
derive: async (event, deps) => {
|
|
171
|
+
const parsed = discussionEvents.commentCreated.safeParse(event);
|
|
172
|
+
if (!parsed.success) return;
|
|
173
|
+
const comment = parsed.data.data;
|
|
174
|
+
if (!comment.parentId || !comment.postId || comment.status !== "published") return [];
|
|
175
|
+
const parent = await deps.mail.comment(event.orgId, comment.parentId);
|
|
176
|
+
const post = await deps.mail.post(event.orgId, comment.postId);
|
|
177
|
+
if (!parent || !post || !comment.communityId) return parent && post ? [] : void 0;
|
|
178
|
+
if (parent.orgUserId === comment.orgUserId) return [];
|
|
179
|
+
const openers = await deps.mail.spaceOpenersAmong(event.orgId, post.spaceId, [parent.orgUserId]);
|
|
180
|
+
return address(deps, event, event.orgId, openers, {
|
|
181
|
+
postTitle: post.title,
|
|
182
|
+
commenterName: await deps.mail.displayName(event.orgId, comment.orgUserId),
|
|
183
|
+
excerpt: excerpt(comment.body, 280),
|
|
184
|
+
commentId: comment.id,
|
|
185
|
+
postId: comment.postId,
|
|
186
|
+
communityId: comment.communityId
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
yourCommentWasRemoved: {
|
|
191
|
+
triggers: ["discussion.comment.removed"],
|
|
192
|
+
derive: async (event, deps) => {
|
|
193
|
+
const parsed = discussionEvents.commentRemoved.safeParse(event);
|
|
194
|
+
if (!parsed.success) return;
|
|
195
|
+
const comment = parsed.data.data;
|
|
196
|
+
if (!comment.postId || !comment.communityId) return [];
|
|
197
|
+
if (comment.removedBy === comment.orgUserId) return [];
|
|
198
|
+
const post = await deps.mail.post(event.orgId, comment.postId);
|
|
199
|
+
if (!post) return;
|
|
200
|
+
return address(deps, event, event.orgId, [comment.orgUserId], {
|
|
201
|
+
postTitle: post.title,
|
|
202
|
+
postId: comment.postId,
|
|
203
|
+
communityId: comment.communityId
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
postAwaitingReview: {
|
|
208
|
+
triggers: ["discussion.post.created", "discussion.post.updated"],
|
|
209
|
+
derive: async (event, deps) => {
|
|
210
|
+
const parsed = event.type === "discussion.post.created" ? discussionEvents.postCreated.safeParse(event) : discussionEvents.postUpdated.safeParse(event);
|
|
211
|
+
if (!parsed.success) return;
|
|
212
|
+
const post = parsed.data.data;
|
|
213
|
+
if (post.status !== "pending" || previousStatusOf(event) === "pending") return [];
|
|
214
|
+
const space = await deps.mail.space(event.orgId, post.spaceId);
|
|
215
|
+
if (!space) return;
|
|
216
|
+
const audience = await deps.mail.moderationAudience(event.orgId, post.communityId);
|
|
217
|
+
return address(deps, event, event.orgId, audience, {
|
|
218
|
+
spaceName: space.name,
|
|
219
|
+
postTitle: post.title,
|
|
220
|
+
authorName: await deps.mail.displayName(event.orgId, post.orgUserId),
|
|
221
|
+
spaceId: post.spaceId,
|
|
222
|
+
communityId: post.communityId
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
joinRequest: {
|
|
227
|
+
triggers: ["entitlement.space_member.created"],
|
|
228
|
+
derive: async (event, deps) => {
|
|
229
|
+
const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);
|
|
230
|
+
if (!parsed.success) return;
|
|
231
|
+
const member = parsed.data.data;
|
|
232
|
+
if (member.status !== "requested") return [];
|
|
233
|
+
const space = await deps.mail.space(event.orgId, member.spaceId);
|
|
234
|
+
if (!space) return;
|
|
235
|
+
const active = await deps.mail.activeMemberCount(event.orgId, member.spaceId);
|
|
236
|
+
const audience = await deps.mail.moderationAudience(event.orgId, member.communityId);
|
|
237
|
+
return address(deps, event, event.orgId, audience, {
|
|
238
|
+
spaceName: space.name,
|
|
239
|
+
memberName: await deps.mail.displayName(event.orgId, member.orgUserId),
|
|
240
|
+
seatsLeft: seatsLeft(space.capacity, active),
|
|
241
|
+
spaceId: member.spaceId,
|
|
242
|
+
communityId: member.communityId
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
requestApproved: {
|
|
247
|
+
triggers: ["entitlement.space_member.updated"],
|
|
248
|
+
derive: async (event, deps) => {
|
|
249
|
+
const parsed = entitlementEvents.spaceMemberUpdated.safeParse(event);
|
|
250
|
+
if (!parsed.success) return;
|
|
251
|
+
const member = parsed.data.data;
|
|
252
|
+
if (member.status !== "active" || previousStatusOf(event) !== "requested") return [];
|
|
253
|
+
const space = await deps.mail.space(event.orgId, member.spaceId);
|
|
254
|
+
if (!space) return;
|
|
255
|
+
return address(deps, event, event.orgId, [member.orgUserId], {
|
|
256
|
+
spaceName: space.name,
|
|
257
|
+
spaceId: member.spaceId,
|
|
258
|
+
communityId: member.communityId
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
requestDeclined: {
|
|
263
|
+
triggers: ["entitlement.space_member.deleted"],
|
|
264
|
+
derive: async (event, deps) => {
|
|
265
|
+
if (previousStatusOf(event) !== "requested") return [];
|
|
266
|
+
const parsed = entitlementEvents.spaceMemberDeleted.safeParse(event);
|
|
267
|
+
if (!parsed.success) return;
|
|
268
|
+
const member = parsed.data.data;
|
|
269
|
+
const space = await deps.mail.space(event.orgId, member.spaceId);
|
|
270
|
+
if (!space) return;
|
|
271
|
+
return address(deps, event, event.orgId, [member.orgUserId], {
|
|
272
|
+
spaceName: space.name,
|
|
273
|
+
communityId: member.communityId
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
invitedToSpace: {
|
|
278
|
+
triggers: ["entitlement.space_member.created"],
|
|
279
|
+
derive: async (event, deps) => {
|
|
280
|
+
const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);
|
|
281
|
+
if (!parsed.success) return;
|
|
282
|
+
const member = parsed.data.data;
|
|
283
|
+
if (member.status !== "invited") return [];
|
|
284
|
+
const space = await deps.mail.space(event.orgId, member.spaceId);
|
|
285
|
+
if (!space) return;
|
|
286
|
+
const actor = actorOf(event);
|
|
287
|
+
return address(deps, event, event.orgId, [member.orgUserId], {
|
|
288
|
+
spaceName: space.name,
|
|
289
|
+
inviterName: actor ? await deps.mail.displayName(event.orgId, actor) : "A member",
|
|
290
|
+
spaceId: member.spaceId,
|
|
291
|
+
communityId: member.communityId
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
messageRequest: {
|
|
296
|
+
triggers: ["discussion.chat.created"],
|
|
297
|
+
derive: async (event, deps) => {
|
|
298
|
+
const parsed = discussionEvents.chatCreated.safeParse(event);
|
|
299
|
+
if (!parsed.success) return;
|
|
300
|
+
const chat = parsed.data.data;
|
|
301
|
+
if (chat.kind !== "direct" || chat.status !== "pending") return [];
|
|
302
|
+
const recipient = chat.participantIds.find((id) => id !== chat.createdBy);
|
|
303
|
+
if (!recipient) return [];
|
|
304
|
+
const members = await deps.mail.communityMembersAmong(event.orgId, chat.communityId, [recipient]);
|
|
305
|
+
const body = await deps.mail.latestMessageBody(event.orgId, chat.id);
|
|
306
|
+
return address(deps, event, event.orgId, members, {
|
|
307
|
+
senderName: chat.createdBy ? await deps.mail.displayName(event.orgId, chat.createdBy) : "A member",
|
|
308
|
+
excerpt: excerpt(body ?? "", 140),
|
|
309
|
+
chatId: chat.id,
|
|
310
|
+
communityId: chat.communityId
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
newMessage: {
|
|
315
|
+
triggers: ["discussion.message.sent"],
|
|
316
|
+
derive: async (event, deps) => {
|
|
317
|
+
const parsed = discussionEvents.messageSent.safeParse(event);
|
|
318
|
+
if (!parsed.success) return;
|
|
319
|
+
const message = parsed.data.data;
|
|
320
|
+
const chat = await deps.mail.chat(event.orgId, message.chatId);
|
|
321
|
+
if (!chat) return;
|
|
322
|
+
if (chatStatusOf(event) === "pending") return [];
|
|
323
|
+
const at = new Date(event.occurredAt);
|
|
324
|
+
const since = new Date(at.getTime() - MESSAGE_BATCH_MS);
|
|
325
|
+
const recent = new Set(await deps.mail.recentMessageRecipients(event.orgId, deps.automationId, message.chatId, since));
|
|
326
|
+
const ids = [];
|
|
327
|
+
for (const participant of chat.participants) {
|
|
328
|
+
if (participant.leftAt || participant.orgUserId === message.orgUserId) continue;
|
|
329
|
+
if (muted(participant, at) || recent.has(participant.orgUserId)) continue;
|
|
330
|
+
if (await deps.mail.pairBlocked(event.orgId, chat.communityId, message.orgUserId, participant.orgUserId)) continue;
|
|
331
|
+
ids.push(participant.orgUserId);
|
|
332
|
+
}
|
|
333
|
+
const members = await deps.mail.communityMembersAmong(event.orgId, chat.communityId, ids);
|
|
334
|
+
const title = chat.kind === "direct" ? await deps.mail.displayName(event.orgId, message.orgUserId) : await groupTitle(deps, event.orgId, chat.participants);
|
|
335
|
+
return address(deps, event, event.orgId, members, {
|
|
336
|
+
senderName: await deps.mail.displayName(event.orgId, message.orgUserId),
|
|
337
|
+
chatTitle: title,
|
|
338
|
+
excerpt: excerpt(message.body, 140),
|
|
339
|
+
chatId: message.chatId,
|
|
340
|
+
communityId: message.communityId
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
addedToGroupChat: {
|
|
345
|
+
triggers: ["discussion.chat.participant.added"],
|
|
346
|
+
derive: async (event, deps) => {
|
|
347
|
+
const parsed = discussionEvents.chatParticipantAdded.safeParse(event);
|
|
348
|
+
if (!parsed.success) return;
|
|
349
|
+
const added = parsed.data.data;
|
|
350
|
+
const chat = await deps.mail.chat(event.orgId, added.chatId);
|
|
351
|
+
if (!chat) return;
|
|
352
|
+
return address(deps, event, event.orgId, [added.orgUserId], {
|
|
353
|
+
adderName: await deps.mail.displayName(event.orgId, added.addedBy),
|
|
354
|
+
participantNames: await participantNames(deps, event.orgId, chat.participants),
|
|
355
|
+
chatId: added.chatId,
|
|
356
|
+
communityId: added.communityId
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
youAreNowAModerator: {
|
|
361
|
+
triggers: ["organization.user.updated"],
|
|
362
|
+
derive: async (event, deps) => {
|
|
363
|
+
const parsed = organizationEvents.orgUserUpdated.safeParse(event);
|
|
364
|
+
if (!parsed.success) return;
|
|
365
|
+
const orgUser = parsed.data.data;
|
|
366
|
+
if (orgUser.role !== "moderator") return [];
|
|
367
|
+
const communities = await deps.mail.memberCommunityTitles(event.orgId, orgUser.id);
|
|
368
|
+
return address(deps, event, event.orgId, [orgUser.id], { communityTitles: communities.map((community) => community.title) });
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
digest: silence(["discussion.digest.due"]),
|
|
372
|
+
somethingWasFlagged: {
|
|
373
|
+
triggers: ["discussion.post.reported", "discussion.comment.reported"],
|
|
374
|
+
derive: async (event, deps) => {
|
|
375
|
+
if (event.type === "discussion.post.reported") {
|
|
376
|
+
const parsed = discussionEvents.postReported.safeParse(event);
|
|
377
|
+
if (!parsed.success) return;
|
|
378
|
+
const flag = parsed.data.data;
|
|
379
|
+
const post = await deps.mail.post(event.orgId, flag.postId);
|
|
380
|
+
const space = post ? await deps.mail.space(event.orgId, post.spaceId) : null;
|
|
381
|
+
if (!post || !space) return;
|
|
382
|
+
const audience = await deps.mail.moderationAudience(event.orgId, flag.communityId);
|
|
383
|
+
return address(deps, event, event.orgId, audience, {
|
|
384
|
+
spaceName: space.name,
|
|
385
|
+
excerpt: excerpt(post.body || post.title, 280),
|
|
386
|
+
reason: flag.reason,
|
|
387
|
+
spaceId: post.spaceId,
|
|
388
|
+
communityId: flag.communityId
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
const parsed = discussionEvents.commentReported.safeParse(event);
|
|
392
|
+
if (!parsed.success) return;
|
|
393
|
+
const flag = parsed.data.data;
|
|
394
|
+
if (!flag.communityId) return [];
|
|
395
|
+
const comment = await deps.mail.comment(event.orgId, flag.commentId);
|
|
396
|
+
if (!comment?.postId) return comment ? [] : void 0;
|
|
397
|
+
const post = await deps.mail.post(event.orgId, comment.postId);
|
|
398
|
+
const space = post ? await deps.mail.space(event.orgId, post.spaceId) : null;
|
|
399
|
+
if (!post || !space) return;
|
|
400
|
+
const audience = await deps.mail.moderationAudience(event.orgId, flag.communityId);
|
|
401
|
+
return address(deps, event, event.orgId, audience, {
|
|
402
|
+
spaceName: space.name,
|
|
403
|
+
excerpt: excerpt(comment.body, 280),
|
|
404
|
+
reason: flag.reason,
|
|
405
|
+
spaceId: post.spaceId,
|
|
406
|
+
communityId: flag.communityId
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
messageWasFlagged: {
|
|
411
|
+
triggers: ["discussion.message.reported"],
|
|
412
|
+
derive: async (event, deps) => {
|
|
413
|
+
const parsed = discussionEvents.messageReported.safeParse(event);
|
|
414
|
+
if (!parsed.success) return;
|
|
415
|
+
const flag = parsed.data.data;
|
|
416
|
+
const audience = await deps.mail.staffIds(event.orgId);
|
|
417
|
+
return address(deps, event, event.orgId, audience, {
|
|
418
|
+
reason: flag.reason,
|
|
419
|
+
communityId: flag.communityId
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
async function participantNames(deps, orgId, participants) {
|
|
425
|
+
const names = [];
|
|
426
|
+
for (const participant of participants) {
|
|
427
|
+
if (participant.leftAt) continue;
|
|
428
|
+
names.push(await deps.mail.displayName(orgId, participant.orgUserId));
|
|
429
|
+
}
|
|
430
|
+
return names;
|
|
431
|
+
}
|
|
432
|
+
async function groupTitle(deps, orgId, participants) {
|
|
433
|
+
const names = await participantNames(deps, orgId, participants);
|
|
434
|
+
return names.length > 0 ? names.join(", ") : "Group chat";
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
437
|
+
export { COMMUNITY_DERIVATIONS };
|
|
438
|
+
|
|
439
|
+
//# sourceMappingURL=community-derivations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-derivations.js","names":[],"sources":["../../src/automations/community-derivations.ts"],"sourcesContent":["import { discussionEvents } from '../discussion/index.js';\nimport { entitlementEvents } from '../entitlements/index.js';\nimport { organizationEvents } from '../organizations/index.js';\nimport type { EmailTemplateId } from '../types/index.js';\nimport type { DomainEvent } from '../shared/ports.js';\nimport {\n actorOf,\n address,\n excerpt,\n MESSAGE_BATCH_MS,\n MESSAGE_EXCERPT,\n POST_EXCERPT,\n previousStatusOf,\n type ActionDeps,\n type EmailRecipient,\n} from './community-mail.js';\n\nexport interface EmailDerivation<K extends EmailTemplateId> {\n triggers: readonly string[];\n derive(event: DomainEvent, deps: ActionDeps): Promise<EmailRecipient<K>[] | undefined>;\n}\n\nfunction silence<K extends EmailTemplateId>(triggers: readonly string[]): EmailDerivation<K> {\n return { triggers, derive: async () => [] };\n}\n\nfunction seatsLeft(capacity: number | null, active: number): string {\n if (capacity == null) {\n return 'No cap';\n }\n return String(Math.max(capacity - active, 0));\n}\n\nfunction muted(participant: { muted: boolean; mutedUntil: Date | null }, at: Date): boolean {\n return (\n participant.muted &&\n (participant.mutedUntil === null || participant.mutedUntil.getTime() > at.getTime())\n );\n}\n\nfunction chatStatusOf(event: DomainEvent): string | undefined {\n const value = event.metadata?.chatStatus;\n return typeof value === 'string' ? value : undefined;\n}\n\nasync function communityTitle(deps: ActionDeps, orgId: string, communityId: string) {\n return deps.mail.communityTitle(orgId, communityId);\n}\n\nexport const COMMUNITY_DERIVATIONS: {\n [K in EmailTemplateId]?: EmailDerivation<K>;\n} = {\n welcomeToCommunity: {\n triggers: ['entitlement.created'],\n derive: async (event, deps) => {\n const parsed = entitlementEvents.entitlementCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const grant = parsed.data.data;\n const communityIds = await deps.mail.communitiesOpenedBy(event.orgId, {\n contentId: grant.contentId,\n bundleId: grant.bundleId,\n });\n const recipients: EmailRecipient<'welcomeToCommunity'>[] = [];\n for (const communityId of communityIds) {\n const title = await communityTitle(deps, event.orgId, communityId);\n if (!title) {\n return undefined;\n }\n const spaceNames = await deps.mail.openSpaceNames(\n event.orgId,\n grant.orgUserId,\n communityId,\n );\n const addressed = await address<'welcomeToCommunity'>(\n deps,\n event,\n event.orgId,\n [grant.orgUserId],\n { communityTitle: title, communityId, spaceNames },\n );\n if (!addressed) {\n return undefined;\n }\n recipients.push(...addressed);\n }\n return recipients;\n },\n },\n membershipEndingSoon: {\n triggers: ['entitlement.ending_soon'],\n derive: async (event, deps) => {\n const parsed = entitlementEvents.entitlementEndingSoon.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const grant = parsed.data.data;\n const communityId = grant.communityId;\n const title = await communityTitle(deps, event.orgId, communityId);\n if (!title) {\n return undefined;\n }\n return address(deps, event, event.orgId, [grant.orgUserId], {\n communityTitle: title,\n communityId,\n expiresAt: grant.expiresAt ? grant.expiresAt.toISOString() : '',\n });\n },\n },\n membershipEnded: {\n triggers: ['entitlement.expired', 'entitlement.deleted'],\n derive: async (event, deps) => {\n const parsed =\n event.type === 'entitlement.expired'\n ? entitlementEvents.entitlementExpired.safeParse(event)\n : entitlementEvents.entitlementDeleted.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const grant = parsed.data.data;\n const communityIds = await deps.mail.communitiesOpenedBy(event.orgId, {\n contentId: grant.contentId,\n bundleId: grant.bundleId,\n });\n const recipients: EmailRecipient<'membershipEnded'>[] = [];\n for (const communityId of communityIds) {\n const title = await communityTitle(deps, event.orgId, communityId);\n if (!title) {\n return undefined;\n }\n const addressed = await address<'membershipEnded'>(\n deps,\n event,\n event.orgId,\n [grant.orgUserId],\n { communityTitle: title, communityId },\n );\n if (!addressed) {\n return undefined;\n }\n recipients.push(...addressed);\n }\n return recipients;\n },\n },\n newPostInSpace: {\n triggers: ['discussion.post.published'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const post = parsed.data.data;\n const space = await deps.mail.space(event.orgId, post.spaceId);\n if (!space) {\n return undefined;\n }\n const openers = await deps.mail.spaceOpeners(event.orgId, post.spaceId);\n return address(\n deps,\n event,\n event.orgId,\n openers.filter((id) => id !== post.orgUserId),\n {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await deps.mail.displayName(event.orgId, post.orgUserId),\n excerpt: excerpt(post.body || post.title, POST_EXCERPT),\n postId: post.id,\n communityId: post.communityId,\n },\n );\n },\n },\n yourPostWasPublished: {\n triggers: ['discussion.post.published'],\n derive: async (event, deps) => {\n if (previousStatusOf(event) !== 'pending') {\n return [];\n }\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const post = parsed.data.data;\n const space = await deps.mail.space(event.orgId, post.spaceId);\n if (!space) {\n return undefined;\n }\n return address(deps, event, event.orgId, [post.orgUserId], {\n postTitle: post.title,\n spaceName: space.name,\n postId: post.id,\n communityId: post.communityId,\n });\n },\n },\n yourPostWasRemoved: {\n triggers: ['discussion.post.removed'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.postRemoved.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const post = parsed.data.data;\n if (post.removedBy === post.orgUserId) {\n return [];\n }\n const space = await deps.mail.space(event.orgId, post.spaceId);\n if (!space) {\n return undefined;\n }\n return address(deps, event, event.orgId, [post.orgUserId], {\n postTitle: post.title,\n spaceName: space.name,\n spaceId: post.spaceId,\n communityId: post.communityId,\n });\n },\n },\n newCommentOnPost: {\n triggers: ['discussion.comment.created'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const comment = parsed.data.data;\n if (!comment.postId || comment.status !== 'published' || !comment.communityId) {\n return [];\n }\n const post = await deps.mail.post(event.orgId, comment.postId);\n if (!post) {\n return undefined;\n }\n const followers = await deps.mail.followerIds(event.orgId, comment.postId);\n const ids = [...new Set([...followers, post.orgUserId])].filter(\n (id) => id !== comment.orgUserId,\n );\n const openers = await deps.mail.spaceOpenersAmong(event.orgId, post.spaceId, ids);\n return address(deps, event, event.orgId, openers, {\n postTitle: post.title,\n commenterName: await deps.mail.displayName(event.orgId, comment.orgUserId),\n excerpt: excerpt(comment.body, POST_EXCERPT),\n commentId: comment.id,\n postId: comment.postId,\n communityId: comment.communityId,\n });\n },\n },\n replyToYourComment: {\n triggers: ['discussion.comment.created'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const comment = parsed.data.data;\n if (!comment.parentId || !comment.postId || comment.status !== 'published') {\n return [];\n }\n const parent = await deps.mail.comment(event.orgId, comment.parentId);\n const post = await deps.mail.post(event.orgId, comment.postId);\n if (!parent || !post || !comment.communityId) {\n return parent && post ? [] : undefined;\n }\n if (parent.orgUserId === comment.orgUserId) {\n return [];\n }\n const openers = await deps.mail.spaceOpenersAmong(event.orgId, post.spaceId, [\n parent.orgUserId,\n ]);\n return address(deps, event, event.orgId, openers, {\n postTitle: post.title,\n commenterName: await deps.mail.displayName(event.orgId, comment.orgUserId),\n excerpt: excerpt(comment.body, POST_EXCERPT),\n commentId: comment.id,\n postId: comment.postId,\n communityId: comment.communityId,\n });\n },\n },\n yourCommentWasRemoved: {\n triggers: ['discussion.comment.removed'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.commentRemoved.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const comment = parsed.data.data;\n if (!comment.postId || !comment.communityId) {\n return [];\n }\n if (comment.removedBy === comment.orgUserId) {\n return [];\n }\n const post = await deps.mail.post(event.orgId, comment.postId);\n if (!post) {\n return undefined;\n }\n return address(deps, event, event.orgId, [comment.orgUserId], {\n postTitle: post.title,\n postId: comment.postId,\n communityId: comment.communityId,\n });\n },\n },\n postAwaitingReview: {\n triggers: ['discussion.post.created', 'discussion.post.updated'],\n derive: async (event, deps) => {\n const parsed =\n event.type === 'discussion.post.created'\n ? discussionEvents.postCreated.safeParse(event)\n : discussionEvents.postUpdated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const post = parsed.data.data;\n if (post.status !== 'pending' || previousStatusOf(event) === 'pending') {\n return [];\n }\n const space = await deps.mail.space(event.orgId, post.spaceId);\n if (!space) {\n return undefined;\n }\n const audience = await deps.mail.moderationAudience(event.orgId, post.communityId);\n return address(deps, event, event.orgId, audience, {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await deps.mail.displayName(event.orgId, post.orgUserId),\n spaceId: post.spaceId,\n communityId: post.communityId,\n });\n },\n },\n joinRequest: {\n triggers: ['entitlement.space_member.created'],\n derive: async (event, deps) => {\n const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const member = parsed.data.data;\n if (member.status !== 'requested') {\n return [];\n }\n const space = await deps.mail.space(event.orgId, member.spaceId);\n if (!space) {\n return undefined;\n }\n const active = await deps.mail.activeMemberCount(event.orgId, member.spaceId);\n const audience = await deps.mail.moderationAudience(event.orgId, member.communityId);\n return address(deps, event, event.orgId, audience, {\n spaceName: space.name,\n memberName: await deps.mail.displayName(event.orgId, member.orgUserId),\n seatsLeft: seatsLeft(space.capacity, active),\n spaceId: member.spaceId,\n communityId: member.communityId,\n });\n },\n },\n requestApproved: {\n triggers: ['entitlement.space_member.updated'],\n derive: async (event, deps) => {\n const parsed = entitlementEvents.spaceMemberUpdated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const member = parsed.data.data;\n if (member.status !== 'active' || previousStatusOf(event) !== 'requested') {\n return [];\n }\n const space = await deps.mail.space(event.orgId, member.spaceId);\n if (!space) {\n return undefined;\n }\n return address(deps, event, event.orgId, [member.orgUserId], {\n spaceName: space.name,\n spaceId: member.spaceId,\n communityId: member.communityId,\n });\n },\n },\n requestDeclined: {\n triggers: ['entitlement.space_member.deleted'],\n derive: async (event, deps) => {\n if (previousStatusOf(event) !== 'requested') {\n return [];\n }\n const parsed = entitlementEvents.spaceMemberDeleted.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const member = parsed.data.data;\n const space = await deps.mail.space(event.orgId, member.spaceId);\n if (!space) {\n return undefined;\n }\n return address(deps, event, event.orgId, [member.orgUserId], {\n spaceName: space.name,\n communityId: member.communityId,\n });\n },\n },\n invitedToSpace: {\n triggers: ['entitlement.space_member.created'],\n derive: async (event, deps) => {\n const parsed = entitlementEvents.spaceMemberCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const member = parsed.data.data;\n if (member.status !== 'invited') {\n return [];\n }\n const space = await deps.mail.space(event.orgId, member.spaceId);\n if (!space) {\n return undefined;\n }\n const actor = actorOf(event);\n return address(deps, event, event.orgId, [member.orgUserId], {\n spaceName: space.name,\n inviterName: actor ? await deps.mail.displayName(event.orgId, actor) : 'A member',\n spaceId: member.spaceId,\n communityId: member.communityId,\n });\n },\n },\n messageRequest: {\n triggers: ['discussion.chat.created'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.chatCreated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const chat = parsed.data.data;\n if (chat.kind !== 'direct' || chat.status !== 'pending') {\n return [];\n }\n const recipient = chat.participantIds.find((id) => id !== chat.createdBy);\n if (!recipient) {\n return [];\n }\n const members = await deps.mail.communityMembersAmong(event.orgId, chat.communityId, [\n recipient,\n ]);\n const body = await deps.mail.latestMessageBody(event.orgId, chat.id);\n return address(deps, event, event.orgId, members, {\n senderName: chat.createdBy\n ? await deps.mail.displayName(event.orgId, chat.createdBy)\n : 'A member',\n excerpt: excerpt(body ?? '', MESSAGE_EXCERPT),\n chatId: chat.id,\n communityId: chat.communityId,\n });\n },\n },\n newMessage: {\n triggers: ['discussion.message.sent'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.messageSent.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const message = parsed.data.data;\n const chat = await deps.mail.chat(event.orgId, message.chatId);\n if (!chat) {\n return undefined;\n }\n if (chatStatusOf(event) === 'pending') {\n return [];\n }\n const at = new Date(event.occurredAt);\n const since = new Date(at.getTime() - MESSAGE_BATCH_MS);\n const recent = new Set(\n await deps.mail.recentMessageRecipients(\n event.orgId,\n deps.automationId,\n message.chatId,\n since,\n ),\n );\n const ids: string[] = [];\n for (const participant of chat.participants) {\n if (participant.leftAt || participant.orgUserId === message.orgUserId) {\n continue;\n }\n if (muted(participant, at) || recent.has(participant.orgUserId)) {\n continue;\n }\n if (\n await deps.mail.pairBlocked(\n event.orgId,\n chat.communityId,\n message.orgUserId,\n participant.orgUserId,\n )\n ) {\n continue;\n }\n ids.push(participant.orgUserId);\n }\n const members = await deps.mail.communityMembersAmong(event.orgId, chat.communityId, ids);\n const title =\n chat.kind === 'direct'\n ? await deps.mail.displayName(event.orgId, message.orgUserId)\n : await groupTitle(deps, event.orgId, chat.participants);\n return address(deps, event, event.orgId, members, {\n senderName: await deps.mail.displayName(event.orgId, message.orgUserId),\n chatTitle: title,\n excerpt: excerpt(message.body, MESSAGE_EXCERPT),\n chatId: message.chatId,\n communityId: message.communityId,\n });\n },\n },\n addedToGroupChat: {\n triggers: ['discussion.chat.participant.added'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.chatParticipantAdded.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const added = parsed.data.data;\n const chat = await deps.mail.chat(event.orgId, added.chatId);\n if (!chat) {\n return undefined;\n }\n return address(deps, event, event.orgId, [added.orgUserId], {\n adderName: await deps.mail.displayName(event.orgId, added.addedBy),\n participantNames: await participantNames(deps, event.orgId, chat.participants),\n chatId: added.chatId,\n communityId: added.communityId,\n });\n },\n },\n youAreNowAModerator: {\n triggers: ['organization.user.updated'],\n derive: async (event, deps) => {\n const parsed = organizationEvents.orgUserUpdated.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const orgUser = parsed.data.data;\n if (orgUser.role !== 'moderator') {\n return [];\n }\n const communities = await deps.mail.memberCommunityTitles(event.orgId, orgUser.id);\n return address(deps, event, event.orgId, [orgUser.id], {\n communityTitles: communities.map((community) => community.title),\n });\n },\n },\n digest: silence(['discussion.digest.due']),\n somethingWasFlagged: {\n triggers: ['discussion.post.reported', 'discussion.comment.reported'],\n derive: async (event, deps) => {\n if (event.type === 'discussion.post.reported') {\n const parsed = discussionEvents.postReported.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const flag = parsed.data.data;\n const post = await deps.mail.post(event.orgId, flag.postId);\n const space = post ? await deps.mail.space(event.orgId, post.spaceId) : null;\n if (!post || !space) {\n return undefined;\n }\n const audience = await deps.mail.moderationAudience(event.orgId, flag.communityId);\n return address(deps, event, event.orgId, audience, {\n spaceName: space.name,\n excerpt: excerpt(post.body || post.title, POST_EXCERPT),\n reason: flag.reason,\n spaceId: post.spaceId,\n communityId: flag.communityId,\n });\n }\n const parsed = discussionEvents.commentReported.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const flag = parsed.data.data;\n if (!flag.communityId) {\n return [];\n }\n const comment = await deps.mail.comment(event.orgId, flag.commentId);\n if (!comment?.postId) {\n return comment ? [] : undefined;\n }\n const post = await deps.mail.post(event.orgId, comment.postId);\n const space = post ? await deps.mail.space(event.orgId, post.spaceId) : null;\n if (!post || !space) {\n return undefined;\n }\n const audience = await deps.mail.moderationAudience(event.orgId, flag.communityId);\n return address(deps, event, event.orgId, audience, {\n spaceName: space.name,\n excerpt: excerpt(comment.body, POST_EXCERPT),\n reason: flag.reason,\n spaceId: post.spaceId,\n communityId: flag.communityId,\n });\n },\n },\n messageWasFlagged: {\n triggers: ['discussion.message.reported'],\n derive: async (event, deps) => {\n const parsed = discussionEvents.messageReported.safeParse(event);\n if (!parsed.success) {\n return undefined;\n }\n const flag = parsed.data.data;\n const audience = await deps.mail.staffIds(event.orgId);\n return address(deps, event, event.orgId, audience, {\n reason: flag.reason,\n communityId: flag.communityId,\n });\n },\n },\n};\n\nasync function participantNames(\n deps: ActionDeps,\n orgId: string,\n participants: { orgUserId: string; leftAt: Date | null }[],\n): Promise<string[]> {\n const names: string[] = [];\n for (const participant of participants) {\n if (participant.leftAt) {\n continue;\n }\n names.push(await deps.mail.displayName(orgId, participant.orgUserId));\n }\n return names;\n}\n\nasync function groupTitle(\n deps: ActionDeps,\n orgId: string,\n participants: { orgUserId: string; leftAt: Date | null }[],\n): Promise<string> {\n const names = await participantNames(deps, orgId, participants);\n return names.length > 0 ? names.join(', ') : 'Group chat';\n}\n"],"mappings":"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"}
|