{"id":22192518,"url":"https://github.com/3sidedcube/notification","last_synced_at":"2025-03-24T20:45:42.121Z","repository":{"id":232215556,"uuid":"474114328","full_name":"3sidedcube/notification","owner":"3sidedcube","description":"NestJS Notification Package","archived":false,"fork":false,"pushed_at":"2024-08-31T01:18:27.000Z","size":3098,"stargazers_count":0,"open_issues_count":11,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-30T01:22:29.263Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/3sidedcube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-25T17:58:51.000Z","updated_at":"2024-04-08T13:26:29.000Z","dependencies_parsed_at":"2024-04-17T15:03:30.823Z","dependency_job_id":null,"html_url":"https://github.com/3sidedcube/notification","commit_stats":null,"previous_names":["3sidedcube/notification"],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3sidedcube%2Fnotification","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3sidedcube%2Fnotification/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3sidedcube%2Fnotification/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3sidedcube%2Fnotification/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/3sidedcube","download_url":"https://codeload.github.com/3sidedcube/notification/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245351757,"owners_count":20601090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-02T12:25:43.346Z","updated_at":"2025-03-24T20:45:42.096Z","avatar_url":"https://github.com/3sidedcube.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Notification\n\nSend email, SMS and push\\* notifications to users on Chelsea Apps projects.\n\n\u003e Push notifications are not yet implemented\n\n### Installation\n\nThe project is hosted on our private npm registry, so to install simply run\n\n##### npm\n\n```bash\nnpm i @chelseaapps/notification\n```\n\n##### yarn\n\n```bash\nyarn add @chelseaapps/notification\n```\n\n### Requirements\n\nThe Email, SMS and Push methods are all sent using a separate process, via Redis. You must have a Redis server running locally on the default host \u0026 port (for now, will add Redis config parameters to the options in the future).\n\n### Configuration\n\nThe module can be imported either globally or restricted to a single module scope. The default option is global, as this allows the module to be used across multiple modules without having to configure it multiple times.\n\n#### Config options\n\n| Option                      | Description                                                | Example                             |\n| --------------------------- | ---------------------------------------------------------- | ----------------------------------- |\n| isGlobal                    | Register the module globally across all modules in the app | true                                |\n| email \u003e host                | SMTP email host                                            | email-smtp.eu-west-2.amazonaws.com  |\n| email \u003e port                | SMTP email port                                            | 465                                 |\n| email \u003e user                | SMTP user                                                  | AKIAZQJAQWWNH7QEHL4O                |\n| email \u003e password            | SMTP password                                              | \\*\\*\\*\\*                            |\n| email \u003e from                | 'From' details for email headers                           | \"Chelsea Apps\" ben@chelsea-apps.com |\n| sms \u003e aws \u003e region          | AWS region used for SNS                                    | eu-west-2                           |\n| sms \u003e aws \u003e accessKeyId     | AWS access key ID with SNS IAM privileges                  | AKIAZQJAQWWNEGDK5YGP                |\n| sms \u003e aws \u003e secretAccessKey | Corresponding AWS secret key                               | \\*\\*\\*\\*                            |\n| sms \u003e sender                | SMS sender ID (max 12 characters)                          | FExchange                           |\n| sms \u003e messageType           | Type of message being sent (Transactional or Promotional)  | Transactional                       |\n\nThe module can be configured in two ways:\n\n-   Regular\n-   Asynchronous\n\n#### Regular config\n\nImport the module into the module in which you wish to register, and call the static `register` function.\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { NotificationModule } from '@chelseaapps/notification';\n\n@Module({\n\timports: [\n        ... other imports here\n\t\tNotificationModule.register({\n\t\t\tisGlobal: true,\n            email: {\n                host: \"\",\n                port: 465,\n                user: \"\",\n                password: \"\",\n                from: \"\",\n            },\n            sms: {\n                aws: {\n                    region: \"\",\n                    accessKeyId: \"\",\n                    secretAccessKey: \"\",\n                },\n                sender: \"\",\n                messageType: \"\",\n            },\n\t\t}),\n\t],\n\tcontrollers: [],\n\tproviders: [],\n})\nexport class AppModule {}\n```\n\n#### Asynchronous config\n\nThe module can also be registered asynchronously to create the module dynamically, fetching configuration details from an external source (such as an environment variable).\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { NotificationModule } from '@chelseaapps/notification';\n\n@Module({\n    imports: [\n        NotificationModule.registerAsync({\n            isGlobal: true,\n            imports: [ConfigModule],\n            useFactory: (configService: ConfigService) =\u003e ({\n                email: {\n                    host: configService.get('EMAIL_HOST')!,\n                    port: configService.get('EMAIL_PORT')!,\n                    user: configService.get('EMAIL_USER')!,\n                    password: configService.get('EMAIL_PASSWORD')!,\n                    from: configService.get('EMAIL_FROM')!,\n                },\n                sms: {\n                    aws: {\n                        region: configService.get('AWS_REGION')!,\n                        accessKeyId: configService.get('AWS_ACCESS_KEY_ID')!,\n                        secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY')!,\n                    },\n                    sender: configService.get('SMS_SENDER')!,\n                    messageType: configService.get('SMS_MESSAGE_TYPE')!,\n                },\n            }),\n            inject: [ConfigService],\n        }),\n    ],\n    controllers: [],\n    providers: [],\n})\nexport class AppModule {}\n```\n\n### Usage\n\nImport the NotificationService into a module using the Nest depedency injection mechanism.\n\n```typescript\nimport { NotificationService} from \"@chelseaapps/notification\"\n\n@Injectable()\nexport class UserService {\n\tconstructor(\n\t\tprivate notificationService: NotificationService,\n\t) {}\n\n    ...\n    async test() {\n        await this.notificationService.send(new TestNotification())\n    }\n}\n```\n\nWhere `TestNotification` is a class extending the `INotification` interface (see below).\n\n```typescript\nimport { INotification, NotificationMethod } from '@chelseaapps/notification';\n\nclass TestNotification implements INotification {\n    // MJML or raw HTML email template here\n    private template = `\n        \u003cmjml\u003e\u003c/mjml\u003e\n    `;\n\n    // Array of notification methods (email, SMS, push)\n    methods = [NotificationMethod.Email];\n\n    // Email subject\n    subject = 'Welcome to Uplevyl (Alpha)!';\n\n    // Single user or list of multiple users as recipients\n    to: User | User[];\n\n    // Override default email sender\n    from: string = 'Chelsea Apps \u003cben@chelsea-apps.com\u003e';\n\n    // Body for all notifcations (see below to override for each method)\n    body: string;\n\n    // Email specific body (overrides the body field)\n    emailBody: string;\n\n    // SMS specific body (overrides the body field)\n    smsBody: string;\n\n    constructor(user: User) {\n        // Configure details and compile MJML (if using)\n        const renderedTemplate = this.render(this.template, user.firstName);\n        const { html } = this.complile(renderedTemplate);\n\n        if (!html) throw new Error('Unable to compile email to HTTP');\n\n        this.to = user;\n        this.emailBody = html;\n    }\n\n    // Render using mustache\n    private render(template: string, name: string) {\n        return mustache.render(template, {\n            name,\n        });\n    }\n\n    // Compile MJML to HTML\n    private complile(template: string) {\n        return mjml2html(template);\n    }\n}\n```\n\n#### Mustache \u0026 MJML\n\nNormally we use Mustache to template emails and MJML to compile to HTML. This makes it easier to send personalised, responsive emails. However these are not required.\nThe `NotificationService` expects the `body` or `emailBody` parameters to be plain text or HTML, so any templating and email markup libraries can be used (provided they compile to HTML).\n\n#### Custom Notification Handlers\n\nCustom handlers can be registered to listen for notifications with the `NotificationMethod.Custom` capability registered.\nThese handlers will receieve the whole notification payload and any custom data to handle in any way they want.\n\n**Example Notification**\n\n```typescript\nimport { INotification, INotificationUser, NotificationMethod } from '@chelsea-apps/notification';\n\nexport class TestNotification implements INotification {\n    methods: NotificationMethod[] = [NotificationMethod.Custom];\n\n    to: INotificationUser[] = [\n        {\n            email: 'ben@chelsea-apps.com',\n        },\n    ];\n\n    subject = 'Subject';\n    subtitle = 'Subtitle';\n    body = 'Body';\n    pushPayload?: Record\u003cstring, any\u003e = { push: 'payload' };\n    data?: Record\u003cstring, any\u003e = {\n        data: 'any',\n    };\n}\n```\n\nTo register a custom handler, use the `@CustomNotificationProcessor()` decorator to create a _Consumer_ class.\n\n**Example class to send to Onesignal**\n\n```typescript\nimport { CustomNotificationProcessor, ICustomPayload, INotificationUser } from '@chelsea-apps/notification';\nimport { OnesignalService } from '@chelsea-apps/onesignal';\nimport { Process } from '@nestjs/bull';\nimport { Job } from 'bull';\n\n@CustomNotificationProcessor()\nexport class OnesignalConsumer {\n    constructor(private readonly onesignalService: OnesignalService) {}\n\n    @Process()\n    async send({ data }: Job\u003cICustomPayload\u003e) {\n        const ids = data.data?.to\n            ?.filter((to: INotificationUser) =\u003e to.id)\n            .map((to: INotificationUser) =\u003e to.id) as string[];\n\n        if (ids.length === 0) return;\n        if (!data.push) return;\n\n        await this.onesignalService.send(ids, {\n            title: data.push.alert.title ?? '',\n            subtitle: data.push.alert.subtitle,\n            message: data.push.alert.body,\n            payload: data.push.payload,\n            threadId: data.data?.threadId,\n            url: data.data?.url,\n        });\n    }\n}\n```\n\n### Documentation\n\nDetailed documentation of the methods can be found in the `documentation` folder. They can be hosted locally by running\n\n```bash\nnpx serve\n```\n\nfrom the `documentation` folder, and are also hosted on the [Chelsea Apps Gitbook](https://docs.chelsea-apps.com/libraries/notification).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3sidedcube%2Fnotification","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F3sidedcube%2Fnotification","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3sidedcube%2Fnotification/lists"}