@develit-services/notification 0.0.3 → 0.0.4

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.
Files changed (62) hide show
  1. package/dist/src.cjs +636 -0
  2. package/dist/src.d.cts +491 -0
  3. package/dist/src.d.mts +489 -0
  4. package/dist/src.d.ts +491 -0
  5. package/dist/src.mjs +625 -0
  6. package/package.json +6 -1
  7. package/@types/consts/audit-log.consts.ts +0 -7
  8. package/@types/consts/index.ts +0 -1
  9. package/@types/database/audit-log.types.ts +0 -7
  10. package/@types/database/index.ts +0 -1
  11. package/@types/email/IEmail.connector.ts +0 -21
  12. package/@types/email/IEmail.types.ts +0 -25
  13. package/@types/email/ecomail/ecomail.connector.ts +0 -139
  14. package/@types/email/ecomail/ecomail.types.ts +0 -27
  15. package/@types/email/ecomail/index.ts +0 -2
  16. package/@types/email/index.ts +0 -3
  17. package/@types/index.ts +0 -9
  18. package/@types/io/index.ts +0 -3
  19. package/@types/io/sendEmail.ts +0 -18
  20. package/@types/io/sendSlack.ts +0 -19
  21. package/@types/io/sendSms.ts +0 -20
  22. package/@types/pushNotification/IPushNotification.ts +0 -1
  23. package/@types/pushNotification/index.ts +0 -1
  24. package/@types/queue.ts +0 -19
  25. package/@types/service.ts +0 -30
  26. package/@types/slack/ISlack.types.ts +0 -3
  27. package/@types/slack/index.ts +0 -1
  28. package/@types/slack/slack.connector.ts +0 -27
  29. package/@types/sms/ISms.connector.ts +0 -22
  30. package/@types/sms/ISms.types.ts +0 -4
  31. package/@types/sms/index.ts +0 -3
  32. package/@types/sms/twilio/index.ts +0 -1
  33. package/@types/sms/twilio/twilio.connector.ts +0 -35
  34. package/CHANGELOG.md +0 -32
  35. package/build.config.ts +0 -29
  36. package/drizzle.config.ts +0 -3
  37. package/src/database/drizzle.ts +0 -6
  38. package/src/database/migrations/0000_funny_beast.sql +0 -12
  39. package/src/database/migrations/meta/0000_snapshot.json +0 -101
  40. package/src/database/migrations/meta/_journal.json +0 -13
  41. package/src/database/schema/audit-log.schema.ts +0 -13
  42. package/src/database/schema/index.ts +0 -1
  43. package/src/defineNotificationService.ts +0 -328
  44. package/src/defineNotificationWrangler.ts +0 -78
  45. package/src/index.ts +0 -12
  46. package/src/utils/connectors.ts +0 -1
  47. package/src/utils/database/command/create-audit-log.command.ts +0 -34
  48. package/src/utils/database/command/index.ts +0 -1
  49. package/src/utils/database/index.ts +0 -1
  50. package/src/utils/email.ts +0 -25
  51. package/src/utils/index.ts +0 -3
  52. package/src/utils/sms.ts +0 -25
  53. package/test/env.d.ts +0 -7
  54. package/test/integration/sendEmail.test.ts +0 -88
  55. package/test/setup/migrations.ts +0 -3
  56. package/test/unit/connectors/ecomail.connector.ts +0 -715
  57. package/test/unit/email.test.ts +0 -55
  58. package/tsconfig.json +0 -3
  59. package/vitest.config.ts +0 -31
  60. package/worker-configuration.d.ts +0 -25
  61. package/wrangler.jsonc +0 -209
  62. package/wrangler.ts +0 -106
@@ -1,139 +0,0 @@
1
- import { useResult } from '@develit-io/backend-sdk'
2
- import {
3
- type EMAttachment,
4
- type EMContact,
5
- type EMEmail,
6
- type IContact,
7
- type IEmail,
8
- IEmailConnector,
9
- } from '../../email'
10
-
11
- export class EcomailConnector extends IEmailConnector {
12
- static providerName = 'ecomail'
13
-
14
- constructor({
15
- API_KEY,
16
- SMTP_HOST,
17
- SENDER,
18
- }: { API_KEY: string; SMTP_HOST: string; SENDER: IContact }) {
19
- super({ API_KEY, SMTP_HOST, SENDER })
20
- }
21
-
22
- async sendEmail(email: IEmail): Promise<Response | null> {
23
- // This is needed only for ecomail connector because when template variables includes word 'localhost' it does not send email
24
- if (email.templateVariables) {
25
- for (const [key, value] of Object.entries(email.templateVariables)) {
26
- if (
27
- typeof value === 'string' &&
28
- String(value).includes('localhost') &&
29
- key in email.templateVariables
30
- ) {
31
- email.templateVariables[key as keyof typeof email.templateVariables] =
32
- String(value).replace('localhost', 'origin')
33
- }
34
- }
35
- }
36
-
37
- const emEmail: EMEmail = this.convertEmail(email)
38
- const uri = emEmail.message.template_id
39
- ? 'https://api2.ecomailapp.cz/transactional/send-template'
40
- : 'https://api2.ecomailapp.cz/transactional/send-message'
41
-
42
- const [data, error] = await useResult(
43
- fetch(uri, {
44
- method: 'POST',
45
- headers: {
46
- 'Content-Type': 'application/json',
47
- key: this.API_KEY,
48
- },
49
- body: JSON.stringify(emEmail),
50
- }),
51
- )
52
- if (error) throw error
53
-
54
- return data
55
- }
56
-
57
- protected convertEmail(email: IEmail): EMEmail {
58
- const toContacts: EMContact[] = this.convertContacts(email.to)
59
- const ccContacts: EMContact[] = email.cc
60
- ? this.convertContacts(email.cc)
61
- : []
62
- const bccContacts: EMContact[] = email.bcc
63
- ? this.convertContacts(email.bcc)
64
- : []
65
-
66
- const replyTo: EMContact | undefined = email.replyTo
67
- ? this.convertContacts(email.replyTo)[0]
68
- : undefined
69
-
70
- const from: EMContact = this.convertContact(email.from || this.SENDER)
71
- const subject: string = email.subject
72
-
73
- const textAttachments: EMAttachment[] = email.text
74
- ? [{ name: 'plain', type: 'text/plain', content: email.text }]
75
- : []
76
-
77
- const htmlAttachments: EMAttachment[] = email.html
78
- ? [{ type: 'text/html', content: email.html, name: 'email_body.html' }]
79
- : []
80
-
81
- const attachments: EMAttachment[] = [...textAttachments, ...htmlAttachments]
82
-
83
- const contacts: EMContact[] = toContacts.flatMap((to) => {
84
- const entries: EMContact[] = []
85
- if (ccContacts.length > 0) {
86
- ccContacts.forEach((cc) => {
87
- entries.push({ email: cc?.email, name: cc?.name, cc: cc?.email })
88
- })
89
- }
90
- if (bccContacts.length > 0) {
91
- bccContacts.forEach((bcc) => {
92
- entries.push({ email: bcc?.email, name: bcc?.name, bcc: bcc?.email })
93
- })
94
- }
95
- return entries.length > 0 ? entries : [to]
96
- })
97
-
98
- return {
99
- message: {
100
- from_email: from?.email,
101
- from_name: from.name || '',
102
- subject,
103
- attachments,
104
- to: contacts,
105
- text: email.text,
106
- html: email.html,
107
- reply_to: replyTo?.email,
108
- template_id: email.templateId,
109
- global_merge_vars: email.templateVariables
110
- ? Object.keys(email.templateVariables).map((key) => ({
111
- name: key,
112
- content:
113
- email.templateVariables![
114
- key as keyof typeof email.templateVariables
115
- ],
116
- }))
117
- : null,
118
- },
119
- }
120
- }
121
-
122
- protected convertContacts(contacts: IContact | IContact[]): EMContact[] {
123
- if (!contacts) {
124
- return []
125
- }
126
- const contactArray: IContact[] = Array.isArray(contacts)
127
- ? contacts
128
- : [contacts]
129
- return contactArray.map(this.convertContact)
130
- }
131
-
132
- protected convertContact(contact: IContact): EMContact {
133
- if (typeof contact === 'string') {
134
- return { email: contact, name: undefined }
135
- }
136
-
137
- return { email: contact?.email, name: contact?.name }
138
- }
139
- }
@@ -1,27 +0,0 @@
1
- export interface EMContact {
2
- email: string
3
- name?: string
4
- cc?: string
5
- bcc?: string
6
- }
7
-
8
- export interface EMAttachment {
9
- type: string
10
- name: string
11
- content: string
12
- }
13
-
14
- export interface EMEmail {
15
- message: {
16
- template_id?: number
17
- subject: string
18
- from_name: string
19
- from_email: string
20
- reply_to?: string
21
- to: EMContact[]
22
- attachments: EMAttachment[]
23
- text?: string
24
- html?: string
25
- global_merge_vars: object | null
26
- }
27
- }
@@ -1,2 +0,0 @@
1
- export * from './ecomail.connector'
2
- export * from './ecomail.types'
@@ -1,3 +0,0 @@
1
- export * from './IEmail.types'
2
- export * from './IEmail.connector'
3
- export * from './ecomail'
package/@types/index.ts DELETED
@@ -1,9 +0,0 @@
1
- export * from './email'
2
- export * from './io'
3
- export * from './pushNotification'
4
- export * from './queue'
5
- export * from './sms'
6
- export * from './slack'
7
- export * from './database'
8
- export * from './consts'
9
- export * from './service'
@@ -1,3 +0,0 @@
1
- export * from './sendEmail'
2
- export * from './sendSlack'
3
- export * from './sendSms'
@@ -1,18 +0,0 @@
1
- import { iEmailSchema } from '../'
2
- import z from 'zod'
3
-
4
- export const sendEmailInputSchema = z.object({
5
- email: iEmailSchema,
6
- metadata: z.object({
7
- userAgent: z.string().optional(),
8
- ip: z.ipv4().or(z.ipv6()).optional(),
9
- initiator: z.object({
10
- service: z.string(),
11
- userId: z.string().optional(),
12
- }),
13
- }),
14
- })
15
-
16
- export interface SendEmailInput extends z.infer<typeof sendEmailInputSchema> {}
17
-
18
- export interface SendEmailOutput {}
@@ -1,19 +0,0 @@
1
- import { z } from 'zod/v4'
2
-
3
- export const sendSlackInputSchema = z.object({
4
- slack: z.object({
5
- message: z.string(),
6
- }),
7
- metadata: z.object({
8
- userAgent: z.string().optional(),
9
- ip: z.ipv4().or(z.ipv6()).optional(),
10
- initiator: z.object({
11
- service: z.string(),
12
- userId: z.string().optional(),
13
- }),
14
- }),
15
- })
16
-
17
- export interface SendSlackInput extends z.infer<typeof sendSlackInputSchema> {}
18
-
19
- export interface SendSlackOutput {}
@@ -1,20 +0,0 @@
1
- import { z } from 'zod'
2
-
3
- export const sendSmsInputSchema = z.object({
4
- sms: z.object({
5
- message: z.string(),
6
- to: z.string(),
7
- }),
8
- metadata: z.object({
9
- userAgent: z.string().optional(),
10
- ip: z.ipv4().or(z.ipv6()).optional(),
11
- initiator: z.object({
12
- service: z.string(),
13
- userId: z.string().optional(),
14
- }),
15
- }),
16
- })
17
-
18
- export interface SendSmsInput extends z.infer<typeof sendSmsInputSchema> {}
19
-
20
- export interface SendSmsOutput {}
@@ -1 +0,0 @@
1
- export interface IPushNotification {}
@@ -1 +0,0 @@
1
- export * from './IPushNotification'
package/@types/queue.ts DELETED
@@ -1,19 +0,0 @@
1
- import type { IEmail, IPushNotification, ISlack, ISms } from './'
2
-
3
- export interface NotificationQueueMessage {
4
- type: 'email' | 'sms' | 'pushNotification' | 'slack'
5
- metadata: {
6
- userAgent?: string
7
- ip?: string
8
- initiator: {
9
- service: string
10
- userId?: string
11
- }
12
- }
13
- payload: {
14
- email?: IEmail
15
- sms?: ISms
16
- pushNotification?: IPushNotification
17
- slack?: ISlack
18
- }
19
- }
package/@types/service.ts DELETED
@@ -1,30 +0,0 @@
1
- export interface NotificationServiceEnvironmentConfig {
2
- queue?: {
3
- max_batch_size?: number
4
- max_batch_timeout?: number
5
- }
6
- d1: {
7
- id: string
8
- }
9
- vars: {
10
- EMAIL_PROVIDER: 'ecomail'
11
- EMAIL_SENDER: { name: string; email: string }
12
- EMAIL_SMTP_HOST: string
13
- EMAIL_API_KEY: string
14
- SMS_PROVIDER: 'twilio'
15
- SMS_ACCOUNT_ID: string
16
- SMS_AUTH_TOKEN: string
17
- SMS_SERVICE_ID: string | number
18
- SLACK_WEBHOOKS: [string]
19
- }
20
- }
21
-
22
- export interface NotificationServiceWranglerConfig {
23
- name: string
24
- envs: {
25
- local: NotificationServiceEnvironmentConfig
26
- [key: string]: NotificationServiceEnvironmentConfig
27
- }
28
- }
29
-
30
- export interface NotificationServiceEnv extends NotificationEnv {}
@@ -1,3 +0,0 @@
1
- export interface ISlack {
2
- message: string
3
- }
@@ -1 +0,0 @@
1
- export * from './ISlack.types'
@@ -1,27 +0,0 @@
1
- export class SlackConnector {
2
- private webhooks: string[]
3
-
4
- constructor(webhooks: string[]) {
5
- this.webhooks = webhooks
6
- }
7
-
8
- async sendNotificationToAllSlack(message: string) {
9
- const controller = new AbortController()
10
- const timeoutId = setTimeout(() => controller.abort(), 3000)
11
-
12
- for (const webhook of this.webhooks) {
13
- let response = await fetch(webhook, {
14
- method: 'POST',
15
- body: JSON.stringify({ text: message }),
16
- headers: { 'Content-Type': 'application/json' },
17
- signal: controller.signal,
18
- })
19
-
20
- clearTimeout(timeoutId)
21
-
22
- if (!response.ok) {
23
- throw new Error('Failed sending Slack notification to ' + message)
24
- }
25
- }
26
- }
27
- }
@@ -1,22 +0,0 @@
1
- import type { InternalError } from '@develit-io/backend-sdk'
2
- import type { ISms } from '../'
3
-
4
- export abstract class ISmsConnector {
5
- static providerName: string
6
-
7
- public ACCOUNT_ID: string
8
- public AUTH_TOKEN: string
9
- public SERVICE_ID: string
10
-
11
- protected constructor({
12
- ACCOUNT_ID,
13
- AUTH_TOKEN,
14
- SERVICE_ID,
15
- }: { ACCOUNT_ID: string; AUTH_TOKEN: string; SERVICE_ID: string }) {
16
- this.ACCOUNT_ID = ACCOUNT_ID
17
- this.AUTH_TOKEN = AUTH_TOKEN
18
- this.SERVICE_ID = SERVICE_ID
19
- }
20
-
21
- abstract sendSms(sms: ISms): Promise<InternalError | void>
22
- }
@@ -1,4 +0,0 @@
1
- export interface ISms {
2
- message: string
3
- to: string
4
- }
@@ -1,3 +0,0 @@
1
- export * from './ISms.types'
2
- export * from './ISms.connector'
3
- export * from './twilio'
@@ -1 +0,0 @@
1
- export * from './twilio.connector'
@@ -1,35 +0,0 @@
1
- import {
2
- type InternalError,
3
- createInternalError,
4
- } from '@develit-io/backend-sdk'
5
- import { type ISms, ISmsConnector } from '../'
6
- import twilio from 'twilio'
7
-
8
- export class TwilioConnector extends ISmsConnector {
9
- static providerName = 'twilio'
10
-
11
- readonly twilioClient: twilio.Twilio
12
-
13
- constructor({
14
- ACCOUNT_ID,
15
- AUTH_TOKEN,
16
- SERVICE_ID,
17
- }: { ACCOUNT_ID: string; AUTH_TOKEN: string; SERVICE_ID: string }) {
18
- super({ ACCOUNT_ID, AUTH_TOKEN, SERVICE_ID })
19
- this.twilioClient = twilio(ACCOUNT_ID, AUTH_TOKEN)
20
- }
21
-
22
- async sendSms(sms: ISms): Promise<InternalError | void> {
23
- const message = await this.twilioClient.messages.create({
24
- body: sms.message,
25
- messagingServiceSid: this.SERVICE_ID,
26
- to: sms.to,
27
- })
28
-
29
- if (message.errorMessage)
30
- return createInternalError(null, {
31
- message: message.errorMessage,
32
- status: message.errorCode,
33
- })
34
- }
35
- }
package/CHANGELOG.md DELETED
@@ -1,32 +0,0 @@
1
- # Changelog
2
-
3
-
4
- ## v0.0.3
5
-
6
- [compare changes](https://github.com/develit-io/develit-services/compare/v0.0.2...v0.0.3)
7
-
8
- ## v0.0.2
9
-
10
-
11
- ### 🚀 Enhancements
12
-
13
- - **notification:** Init codebase + notification service ([3fa7306](https://github.com/develit-io/develit-services/commit/3fa7306))
14
-
15
- ### 📦 Build
16
-
17
- - **notification:** Setup package build ([79fb543](https://github.com/develit-io/develit-services/commit/79fb543))
18
-
19
- ### ❤️ Contributors
20
-
21
- - Klein Petr ([@kleinpetr](https://github.com/kleinpetr))
22
-
23
- ## v0.0.1
24
-
25
-
26
- ### 🚀 Enhancements
27
-
28
- - **notification:** Init codebase + notification service ([3fa7306](https://github.com/develit-io/develit-services/commit/3fa7306))
29
-
30
- ### ❤️ Contributors
31
-
32
- - Klein Petr ([@kleinpetr](https://github.com/kleinpetr))
package/build.config.ts DELETED
@@ -1,29 +0,0 @@
1
- import { defineBuildConfig } from 'unbuild'
2
-
3
- export default defineBuildConfig({
4
- entries: ['./src'],
5
- outDir: 'dist',
6
- declaration: true,
7
- failOnWarn: false,
8
- rollup: {
9
- emitCJS: true,
10
- },
11
- externals: [
12
- 'cloudflare:workers',
13
- '@cloudflare/workers-types',
14
- '@develit-io/backend-sdk',
15
- '@cloudflare/vitest-pool-workers',
16
- 'cloudflare',
17
- 'drizzle-kit',
18
- 'drizzle-orm',
19
- 'drizzle-seed',
20
- 'wrangler',
21
- 'zod',
22
- '@types/node',
23
- 'cloudflare:workers',
24
- '@std/text',
25
- '@develit-services/notification/@types',
26
- '@develit-services/notification/src/database/drizzle',
27
- '@develit-services/notification/src/utils',
28
- ],
29
- })
package/drizzle.config.ts DELETED
@@ -1,3 +0,0 @@
1
- import { getDrizzleD1Config } from '@develit-io/backend-sdk'
2
-
3
- export default getDrizzleD1Config()
@@ -1,6 +0,0 @@
1
- import * as schema from './schema'
2
-
3
- export * from 'drizzle-orm'
4
- export { alias } from 'drizzle-orm/sqlite-core'
5
-
6
- export const tables = schema
@@ -1,12 +0,0 @@
1
- CREATE TABLE `audit_log` (
2
- `id` text PRIMARY KEY NOT NULL,
3
- `created_at` integer DEFAULT (unixepoch('subsec') * 1000),
4
- `updated_at` integer DEFAULT (unixepoch('subsec') * 1000),
5
- `deleted_at` integer DEFAULT null,
6
- `event` text NOT NULL,
7
- `ip` text,
8
- `user_agent` text,
9
- `description` text,
10
- `initiator_service` text NOT NULL,
11
- `initiator_user_id` text
12
- );
@@ -1,101 +0,0 @@
1
- {
2
- "version": "6",
3
- "dialect": "sqlite",
4
- "id": "a975fc44-2981-453f-abe4-53763432eb34",
5
- "prevId": "00000000-0000-0000-0000-000000000000",
6
- "tables": {
7
- "audit_log": {
8
- "name": "audit_log",
9
- "columns": {
10
- "id": {
11
- "name": "id",
12
- "type": "text",
13
- "primaryKey": true,
14
- "notNull": true,
15
- "autoincrement": false
16
- },
17
- "created_at": {
18
- "name": "created_at",
19
- "type": "integer",
20
- "primaryKey": false,
21
- "notNull": false,
22
- "autoincrement": false,
23
- "default": "(unixepoch('subsec') * 1000)"
24
- },
25
- "updated_at": {
26
- "name": "updated_at",
27
- "type": "integer",
28
- "primaryKey": false,
29
- "notNull": false,
30
- "autoincrement": false,
31
- "default": "(unixepoch('subsec') * 1000)"
32
- },
33
- "deleted_at": {
34
- "name": "deleted_at",
35
- "type": "integer",
36
- "primaryKey": false,
37
- "notNull": false,
38
- "autoincrement": false,
39
- "default": "null"
40
- },
41
- "event": {
42
- "name": "event",
43
- "type": "text",
44
- "primaryKey": false,
45
- "notNull": true,
46
- "autoincrement": false
47
- },
48
- "ip": {
49
- "name": "ip",
50
- "type": "text",
51
- "primaryKey": false,
52
- "notNull": false,
53
- "autoincrement": false
54
- },
55
- "user_agent": {
56
- "name": "user_agent",
57
- "type": "text",
58
- "primaryKey": false,
59
- "notNull": false,
60
- "autoincrement": false
61
- },
62
- "description": {
63
- "name": "description",
64
- "type": "text",
65
- "primaryKey": false,
66
- "notNull": false,
67
- "autoincrement": false
68
- },
69
- "initiator_service": {
70
- "name": "initiator_service",
71
- "type": "text",
72
- "primaryKey": false,
73
- "notNull": true,
74
- "autoincrement": false
75
- },
76
- "initiator_user_id": {
77
- "name": "initiator_user_id",
78
- "type": "text",
79
- "primaryKey": false,
80
- "notNull": false,
81
- "autoincrement": false
82
- }
83
- },
84
- "indexes": {},
85
- "foreignKeys": {},
86
- "compositePrimaryKeys": {},
87
- "uniqueConstraints": {},
88
- "checkConstraints": {}
89
- }
90
- },
91
- "views": {},
92
- "enums": {},
93
- "_meta": {
94
- "schemas": {},
95
- "tables": {},
96
- "columns": {}
97
- },
98
- "internal": {
99
- "indexes": {}
100
- }
101
- }
@@ -1,13 +0,0 @@
1
- {
2
- "version": "7",
3
- "dialect": "sqlite",
4
- "entries": [
5
- {
6
- "idx": 0,
7
- "version": "6",
8
- "when": 1757619388118,
9
- "tag": "0000_funny_beast",
10
- "breakpoints": true
11
- }
12
- ]
13
- }
@@ -1,13 +0,0 @@
1
- import { base } from '@develit-io/backend-sdk'
2
- import type { AuditLogEventType } from '../../../@types'
3
- import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
4
-
5
- export const auditLog = sqliteTable('audit_log', {
6
- ...base,
7
- event: text('event').$type<AuditLogEventType>().notNull(),
8
- ip: text('ip'),
9
- userAgent: text('user_agent'),
10
- description: text('description'),
11
- initiatorService: text('initiator_service').notNull(),
12
- initiatorUserId: text('initiator_user_id'),
13
- })
@@ -1 +0,0 @@
1
- export * from './audit-log.schema'