vintasend 0.1.0 → 0.1.1

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 (23) hide show
  1. package/package.json +1 -1
  2. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/Dockerfile.notifications-worker +0 -14
  3. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/package-lock.json +254 -12
  4. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/package.json +5 -0
  5. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/src/app/api/auth/forgot-password/forgot-password-notification-context.ts +21 -21
  6. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/src/lib/services/notifications.ts +3 -3
  7. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/src/lib/services/temporal-queue-service.ts +2 -2
  8. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/src/workers/notifications/activities.ts +6 -5
  9. package/src/examples/nextjs-prisma-nodemailer-pug-temporal/src/workers/notifications/workflows.ts +5 -2
  10. package/src/implementations/vintasend-nodemailer/nodemailer-notification-adapter.ts +26 -12
  11. package/src/implementations/vintasend-nodemailer/package.json +2 -1
  12. package/src/implementations/vintasend-prisma/package.json +2 -1
  13. package/src/implementations/vintasend-prisma/prisma-notification-backend.ts +9 -8
  14. package/src/implementations/vintasend-pug/package.json +2 -1
  15. package/src/implementations/vintasend-pug/pug-email-template-renderer.ts +11 -7
  16. package/src/implementations/vintasend-winston/package.json +2 -1
  17. package/src/implementations/vintasend-winston/winston-logger.ts +1 -1
  18. package/src/services/notification-adapters/base-notification-adapter.ts +8 -2
  19. package/src/services/notification-backends/base-notification-backend.ts +21 -17
  20. package/src/services/notification-queue-service/base-notification-queue-service.ts +3 -3
  21. package/src/services/notification-service.ts +39 -32
  22. package/src/services/notification-template-renderers/base-email-template-renderer.ts +13 -4
  23. package/src/services/notification-template-renderers/base-notification-template-renderer.ts +11 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vintasend",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "scripts": {
5
5
  "lint": "biome check .",
6
6
  "format": "biome format .",
@@ -9,20 +9,6 @@ COPY package*.json ./
9
9
  # Install dependencies
10
10
  RUN npm install
11
11
 
12
- RUN mkdir -p src/vintasend-ts/services
13
- RUN mkdir -p src/vintasend-ts/types
14
- RUN mkdir -p src/vintasend-nodemailer
15
- RUN mkdir -p src/vintasend-prisma
16
- RUN mkdir -p src/vintasend-pug
17
- RUN mkdir -p src/vintasend-winston
18
-
19
- COPY ../../services ./src/vintasend-ts/services
20
- COPY ../../types ./src/vintasend-ts/types
21
- COPY ../../implementations/vintasend-nodemailer ./src/vintasend-nodemailer
22
- COPY ../../implementations/vintasend-prisma ./src/vintasend-prisma
23
- COPY ../../implementations/vintasend-pug ./src/vintasend-pug
24
- COPY ../../implementations/vintasend-winston ./src/vintasend-winston
25
-
26
12
  # Copy the rest of the application code
27
13
  COPY . .
28
14
 
@@ -29,6 +29,11 @@
29
29
  "react-hook-form": "^7.54.2",
30
30
  "tailwind-merge": "^3.0.1",
31
31
  "tailwindcss-animate": "^1.0.7",
32
+ "vintasend": "^0.1.0",
33
+ "vintasend-nodemailer": "^0.1.0",
34
+ "vintasend-prisma": "^0.1.0",
35
+ "vintasend-pug": "^0.1.0",
36
+ "vintasend-winston": "^0.1.0",
32
37
  "zod": "^3.24.1"
33
38
  },
34
39
  "devDependencies": {
@@ -101,6 +106,24 @@
101
106
  "node": ">=6.9.0"
102
107
  }
103
108
  },
109
+ "node_modules/@colors/colors": {
110
+ "version": "1.6.0",
111
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
112
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
113
+ "engines": {
114
+ "node": ">=0.1.90"
115
+ }
116
+ },
117
+ "node_modules/@dabh/diagnostics": {
118
+ "version": "2.0.3",
119
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
120
+ "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
121
+ "dependencies": {
122
+ "colorspace": "1.1.x",
123
+ "enabled": "2.0.x",
124
+ "kuler": "^2.0.0"
125
+ }
126
+ },
104
127
  "node_modules/@emnapi/runtime": {
105
128
  "version": "1.3.1",
106
129
  "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz",
@@ -1423,14 +1446,12 @@
1423
1446
  "node_modules/@prisma/debug": {
1424
1447
  "version": "6.3.1",
1425
1448
  "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.3.1.tgz",
1426
- "integrity": "sha512-RrEBkd+HLZx+ydfmYT0jUj7wjLiS95wfTOSQ+8FQbvb6vHh5AeKfEPt/XUQ5+Buljj8hltEfOslEW57/wQIVeA==",
1427
- "devOptional": true
1449
+ "integrity": "sha512-RrEBkd+HLZx+ydfmYT0jUj7wjLiS95wfTOSQ+8FQbvb6vHh5AeKfEPt/XUQ5+Buljj8hltEfOslEW57/wQIVeA=="
1428
1450
  },
1429
1451
  "node_modules/@prisma/engines": {
1430
1452
  "version": "6.3.1",
1431
1453
  "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.3.1.tgz",
1432
1454
  "integrity": "sha512-sXdqEVLyGAJ5/iUoG/Ea5AdHMN71m6PzMBWRQnLmhhOejzqAaEr8rUd623ql6OJpED4s/U4vIn4dg1qkF7vGag==",
1433
- "devOptional": true,
1434
1455
  "hasInstallScript": true,
1435
1456
  "dependencies": {
1436
1457
  "@prisma/debug": "6.3.1",
@@ -1442,14 +1463,12 @@
1442
1463
  "node_modules/@prisma/engines-version": {
1443
1464
  "version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0",
1444
1465
  "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0.tgz",
1445
- "integrity": "sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA==",
1446
- "devOptional": true
1466
+ "integrity": "sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA=="
1447
1467
  },
1448
1468
  "node_modules/@prisma/fetch-engine": {
1449
1469
  "version": "6.3.1",
1450
1470
  "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.3.1.tgz",
1451
1471
  "integrity": "sha512-HOf/0umOgt+/S2xtZze+FHKoxpVg4YpVxROr6g2YG09VsI3Ipyb+rGvD6QGbCqkq5NTWAAZoOGNL+oy7t+IhaQ==",
1452
- "devOptional": true,
1453
1472
  "dependencies": {
1454
1473
  "@prisma/debug": "6.3.1",
1455
1474
  "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0",
@@ -1460,7 +1479,6 @@
1460
1479
  "version": "6.3.1",
1461
1480
  "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.3.1.tgz",
1462
1481
  "integrity": "sha512-AYLq6Hk9xG73JdLWJ3Ip9Wg/vlP7xPvftGBalsPzKDOHr/ImhwJ09eS8xC2vNT12DlzGxhfk8BkL0ve2OriNhQ==",
1463
- "devOptional": true,
1464
1482
  "dependencies": {
1465
1483
  "@prisma/debug": "6.3.1"
1466
1484
  }
@@ -3334,6 +3352,11 @@
3334
3352
  "@types/react": "^19.0.0"
3335
3353
  }
3336
3354
  },
3355
+ "node_modules/@types/triple-beam": {
3356
+ "version": "1.3.5",
3357
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
3358
+ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
3359
+ },
3337
3360
  "node_modules/@typescript-eslint/eslint-plugin": {
3338
3361
  "version": "8.23.0",
3339
3362
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz",
@@ -4027,6 +4050,11 @@
4027
4050
  "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
4028
4051
  "dev": true
4029
4052
  },
4053
+ "node_modules/async": {
4054
+ "version": "3.2.6",
4055
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
4056
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="
4057
+ },
4030
4058
  "node_modules/async-function": {
4031
4059
  "version": "1.0.0",
4032
4060
  "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
@@ -4457,12 +4485,42 @@
4457
4485
  "version": "1.9.1",
4458
4486
  "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
4459
4487
  "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
4460
- "optional": true,
4461
4488
  "dependencies": {
4462
4489
  "color-name": "^1.0.0",
4463
4490
  "simple-swizzle": "^0.2.2"
4464
4491
  }
4465
4492
  },
4493
+ "node_modules/colorspace": {
4494
+ "version": "1.1.4",
4495
+ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
4496
+ "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
4497
+ "dependencies": {
4498
+ "color": "^3.1.3",
4499
+ "text-hex": "1.0.x"
4500
+ }
4501
+ },
4502
+ "node_modules/colorspace/node_modules/color": {
4503
+ "version": "3.2.1",
4504
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
4505
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
4506
+ "dependencies": {
4507
+ "color-convert": "^1.9.3",
4508
+ "color-string": "^1.6.0"
4509
+ }
4510
+ },
4511
+ "node_modules/colorspace/node_modules/color-convert": {
4512
+ "version": "1.9.3",
4513
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
4514
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
4515
+ "dependencies": {
4516
+ "color-name": "1.1.3"
4517
+ }
4518
+ },
4519
+ "node_modules/colorspace/node_modules/color-name": {
4520
+ "version": "1.1.3",
4521
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
4522
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
4523
+ },
4466
4524
  "node_modules/commander": {
4467
4525
  "version": "4.1.1",
4468
4526
  "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -4707,6 +4765,11 @@
4707
4765
  "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
4708
4766
  "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
4709
4767
  },
4768
+ "node_modules/enabled": {
4769
+ "version": "2.0.0",
4770
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
4771
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
4772
+ },
4710
4773
  "node_modules/enhanced-resolve": {
4711
4774
  "version": "5.18.1",
4712
4775
  "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
@@ -5456,6 +5519,11 @@
5456
5519
  "reusify": "^1.0.4"
5457
5520
  }
5458
5521
  },
5522
+ "node_modules/fecha": {
5523
+ "version": "4.2.3",
5524
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
5525
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
5526
+ },
5459
5527
  "node_modules/file-entry-cache": {
5460
5528
  "version": "8.0.0",
5461
5529
  "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -5514,6 +5582,11 @@
5514
5582
  "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
5515
5583
  "dev": true
5516
5584
  },
5585
+ "node_modules/fn.name": {
5586
+ "version": "1.1.0",
5587
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
5588
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
5589
+ },
5517
5590
  "node_modules/for-each": {
5518
5591
  "version": "0.3.4",
5519
5592
  "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
@@ -5930,6 +6003,11 @@
5930
6003
  "node": ">=0.8.19"
5931
6004
  }
5932
6005
  },
6006
+ "node_modules/inherits": {
6007
+ "version": "2.0.4",
6008
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
6009
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
6010
+ },
5933
6011
  "node_modules/internal-slot": {
5934
6012
  "version": "1.1.0",
5935
6013
  "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -5964,8 +6042,7 @@
5964
6042
  "node_modules/is-arrayish": {
5965
6043
  "version": "0.3.2",
5966
6044
  "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
5967
- "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
5968
- "optional": true
6045
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
5969
6046
  },
5970
6047
  "node_modules/is-async-function": {
5971
6048
  "version": "2.1.1",
@@ -6261,6 +6338,17 @@
6261
6338
  "url": "https://github.com/sponsors/ljharb"
6262
6339
  }
6263
6340
  },
6341
+ "node_modules/is-stream": {
6342
+ "version": "2.0.1",
6343
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
6344
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
6345
+ "engines": {
6346
+ "node": ">=8"
6347
+ },
6348
+ "funding": {
6349
+ "url": "https://github.com/sponsors/sindresorhus"
6350
+ }
6351
+ },
6264
6352
  "node_modules/is-string": {
6265
6353
  "version": "1.1.1",
6266
6354
  "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
@@ -6559,6 +6647,11 @@
6559
6647
  "json-buffer": "3.0.1"
6560
6648
  }
6561
6649
  },
6650
+ "node_modules/kuler": {
6651
+ "version": "2.0.0",
6652
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
6653
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
6654
+ },
6562
6655
  "node_modules/language-subtag-registry": {
6563
6656
  "version": "0.3.23",
6564
6657
  "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -6675,6 +6768,22 @@
6675
6768
  "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
6676
6769
  "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
6677
6770
  },
6771
+ "node_modules/logform": {
6772
+ "version": "2.7.0",
6773
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
6774
+ "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
6775
+ "dependencies": {
6776
+ "@colors/colors": "1.6.0",
6777
+ "@types/triple-beam": "^1.3.2",
6778
+ "fecha": "^4.2.0",
6779
+ "ms": "^2.1.1",
6780
+ "safe-stable-stringify": "^2.3.1",
6781
+ "triple-beam": "^1.3.0"
6782
+ },
6783
+ "engines": {
6784
+ "node": ">= 12.0.0"
6785
+ }
6786
+ },
6678
6787
  "node_modules/long": {
6679
6788
  "version": "5.2.4",
6680
6789
  "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
@@ -7069,6 +7178,14 @@
7069
7178
  "url": "https://github.com/sponsors/ljharb"
7070
7179
  }
7071
7180
  },
7181
+ "node_modules/one-time": {
7182
+ "version": "1.0.0",
7183
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
7184
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
7185
+ "dependencies": {
7186
+ "fn.name": "1.x.x"
7187
+ }
7188
+ },
7072
7189
  "node_modules/optionator": {
7073
7190
  "version": "0.9.4",
7074
7191
  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -7396,7 +7513,6 @@
7396
7513
  "version": "6.3.1",
7397
7514
  "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.3.1.tgz",
7398
7515
  "integrity": "sha512-JKCZWvBC3enxk51tY4TWzS4b5iRt4sSU1uHn2I183giZTvonXaQonzVtjLzpOHE7qu9MxY510kAtFGJwryKe3Q==",
7399
- "devOptional": true,
7400
7516
  "hasInstallScript": true,
7401
7517
  "dependencies": {
7402
7518
  "@prisma/engines": "6.3.1"
@@ -7804,6 +7920,19 @@
7804
7920
  "pify": "^2.3.0"
7805
7921
  }
7806
7922
  },
7923
+ "node_modules/readable-stream": {
7924
+ "version": "3.6.2",
7925
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
7926
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
7927
+ "dependencies": {
7928
+ "inherits": "^2.0.3",
7929
+ "string_decoder": "^1.1.1",
7930
+ "util-deprecate": "^1.0.1"
7931
+ },
7932
+ "engines": {
7933
+ "node": ">= 6"
7934
+ }
7935
+ },
7807
7936
  "node_modules/readdirp": {
7808
7937
  "version": "3.6.0",
7809
7938
  "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -8020,6 +8149,14 @@
8020
8149
  "url": "https://github.com/sponsors/ljharb"
8021
8150
  }
8022
8151
  },
8152
+ "node_modules/safe-stable-stringify": {
8153
+ "version": "2.5.0",
8154
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
8155
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
8156
+ "engines": {
8157
+ "node": ">=10"
8158
+ }
8159
+ },
8023
8160
  "node_modules/safer-buffer": {
8024
8161
  "version": "2.1.2",
8025
8162
  "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -8257,7 +8394,6 @@
8257
8394
  "version": "0.2.2",
8258
8395
  "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
8259
8396
  "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
8260
- "optional": true,
8261
8397
  "dependencies": {
8262
8398
  "is-arrayish": "^0.3.1"
8263
8399
  }
@@ -8320,6 +8456,14 @@
8320
8456
  "integrity": "sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==",
8321
8457
  "dev": true
8322
8458
  },
8459
+ "node_modules/stack-trace": {
8460
+ "version": "0.0.10",
8461
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
8462
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
8463
+ "engines": {
8464
+ "node": "*"
8465
+ }
8466
+ },
8323
8467
  "node_modules/streamsearch": {
8324
8468
  "version": "1.1.0",
8325
8469
  "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -8328,6 +8472,14 @@
8328
8472
  "node": ">=10.0.0"
8329
8473
  }
8330
8474
  },
8475
+ "node_modules/string_decoder": {
8476
+ "version": "1.3.0",
8477
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
8478
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
8479
+ "dependencies": {
8480
+ "safe-buffer": "~5.2.0"
8481
+ }
8482
+ },
8331
8483
  "node_modules/string-width": {
8332
8484
  "version": "5.1.2",
8333
8485
  "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@@ -8813,6 +8965,11 @@
8813
8965
  "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
8814
8966
  "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
8815
8967
  },
8968
+ "node_modules/text-hex": {
8969
+ "version": "1.0.0",
8970
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
8971
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
8972
+ },
8816
8973
  "node_modules/thenify": {
8817
8974
  "version": "3.3.1",
8818
8975
  "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -8874,6 +9031,14 @@
8874
9031
  "tslib": "2"
8875
9032
  }
8876
9033
  },
9034
+ "node_modules/triple-beam": {
9035
+ "version": "1.4.1",
9036
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
9037
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
9038
+ "engines": {
9039
+ "node": ">= 14.0.0"
9040
+ }
9041
+ },
8877
9042
  "node_modules/ts-api-utils": {
8878
9043
  "version": "2.0.1",
8879
9044
  "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
@@ -9152,6 +9317,49 @@
9152
9317
  "uuid": "dist/bin/uuid"
9153
9318
  }
9154
9319
  },
9320
+ "node_modules/vintasend": {
9321
+ "version": "0.1.0",
9322
+ "resolved": "https://registry.npmjs.org/vintasend/-/vintasend-0.1.0.tgz",
9323
+ "integrity": "sha512-36Mkkf6yv/Y5zpuBc0TCIitOuUjsbQzVPqu56bbv3KLmoeT59UDE7OWTJkzrlRdA5iYwTB/sUk7VsYDzLF2wuQ=="
9324
+ },
9325
+ "node_modules/vintasend-nodemailer": {
9326
+ "version": "0.1.0",
9327
+ "resolved": "https://registry.npmjs.org/vintasend-nodemailer/-/vintasend-nodemailer-0.1.0.tgz",
9328
+ "integrity": "sha512-VNKJTDnLzGDZncgy4t/3iHUZ1cwQ+7Db4BNMwn7Gd1zsiL03l9iyB4zzeiu1MdLiSEiMtDrpmPaFx9ZkfPWGww==",
9329
+ "dependencies": {
9330
+ "nodemailer": "^6.10.0",
9331
+ "vintasend": "^0.1.0"
9332
+ }
9333
+ },
9334
+ "node_modules/vintasend-prisma": {
9335
+ "version": "0.1.0",
9336
+ "resolved": "https://registry.npmjs.org/vintasend-prisma/-/vintasend-prisma-0.1.0.tgz",
9337
+ "integrity": "sha512-eHakQHyUeHe95NucnX/ZovfWZcHil/1zswf0pg8wnc8dytOk8s3sR2kqP9MrQk6SbYRxe06tf1uZrHm0SxzaaA==",
9338
+ "dependencies": {
9339
+ "@prisma/client": "^6.3.1",
9340
+ "prisma": "^6.3.1",
9341
+ "vintasend": "^0.1.0"
9342
+ }
9343
+ },
9344
+ "node_modules/vintasend-pug": {
9345
+ "version": "0.1.0",
9346
+ "resolved": "https://registry.npmjs.org/vintasend-pug/-/vintasend-pug-0.1.0.tgz",
9347
+ "integrity": "sha512-SNgUUHJK/3ejydcgkF0AGwVINIrgt3NkPPO21P6RkBIRcF5PCJ6KrINJtr0kYhTHDLpRaZk2Ma2NPh9kNLUUgA==",
9348
+ "dependencies": {
9349
+ "pug": "^3.0.3",
9350
+ "vintasend": "^0.1.0"
9351
+ }
9352
+ },
9353
+ "node_modules/vintasend-winston": {
9354
+ "version": "0.1.0",
9355
+ "resolved": "https://registry.npmjs.org/vintasend-winston/-/vintasend-winston-0.1.0.tgz",
9356
+ "integrity": "sha512-pbirMH+n1uH3Aa7N32AC7kAjvb8u2A59gT8lSLvjA2qRa1cATBFci+FawsB5Jyxfhxm0iAPtbPsLrLBANAyeaw==",
9357
+ "dependencies": {
9358
+ "jsonwebtoken": "^9.0.2",
9359
+ "vintasend": "^0.1.0",
9360
+ "winston": "^3.17.0"
9361
+ }
9362
+ },
9155
9363
  "node_modules/void-elements": {
9156
9364
  "version": "3.1.0",
9157
9365
  "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@@ -9343,6 +9551,40 @@
9343
9551
  "url": "https://github.com/sponsors/ljharb"
9344
9552
  }
9345
9553
  },
9554
+ "node_modules/winston": {
9555
+ "version": "3.17.0",
9556
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
9557
+ "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
9558
+ "dependencies": {
9559
+ "@colors/colors": "^1.6.0",
9560
+ "@dabh/diagnostics": "^2.0.2",
9561
+ "async": "^3.2.3",
9562
+ "is-stream": "^2.0.0",
9563
+ "logform": "^2.7.0",
9564
+ "one-time": "^1.0.0",
9565
+ "readable-stream": "^3.4.0",
9566
+ "safe-stable-stringify": "^2.3.1",
9567
+ "stack-trace": "0.0.x",
9568
+ "triple-beam": "^1.3.0",
9569
+ "winston-transport": "^4.9.0"
9570
+ },
9571
+ "engines": {
9572
+ "node": ">= 12.0.0"
9573
+ }
9574
+ },
9575
+ "node_modules/winston-transport": {
9576
+ "version": "4.9.0",
9577
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
9578
+ "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
9579
+ "dependencies": {
9580
+ "logform": "^2.7.0",
9581
+ "readable-stream": "^3.6.2",
9582
+ "triple-beam": "^1.3.0"
9583
+ },
9584
+ "engines": {
9585
+ "node": ">= 12.0.0"
9586
+ }
9587
+ },
9346
9588
  "node_modules/with": {
9347
9589
  "version": "7.0.2",
9348
9590
  "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
@@ -34,6 +34,11 @@
34
34
  "react-hook-form": "^7.54.2",
35
35
  "tailwind-merge": "^3.0.1",
36
36
  "tailwindcss-animate": "^1.0.7",
37
+ "vintasend": "^0.1.0",
38
+ "vintasend-nodemailer": "^0.1.0",
39
+ "vintasend-prisma": "^0.1.0",
40
+ "vintasend-pug": "^0.1.0",
41
+ "vintasend-winston": "^0.1.0",
37
42
  "zod": "^3.24.1"
38
43
  },
39
44
  "devDependencies": {
@@ -1,21 +1,21 @@
1
- import { PrismaClient } from '@prisma/client';
2
- import type { ContextGenerator } from 'vintasend/services/notification-context-registry';
3
-
4
- export class ForgotPasswordContextGenerator implements ContextGenerator {
5
- async generate(params: { token: string }): Promise<{ firstName: string | null }> {
6
- const prisma = new PrismaClient();
7
-
8
- const token = await prisma.token.findUnique({
9
- where: { token: params.token },
10
- select: { user: true },
11
- });
12
-
13
- if (!token || !token.user) {
14
- throw new Error('Token not found');
15
- }
16
-
17
- return {
18
- firstName: token.user.firstName,
19
- };
20
- }
21
- }
1
+ import { PrismaClient } from '@prisma/client';
2
+ import type { ContextGenerator } from 'vintasend/src/services/notification-context-registry';
3
+
4
+ export class ForgotPasswordContextGenerator implements ContextGenerator {
5
+ async generate(params: { token: string }): Promise<{ firstName: string | null }> {
6
+ const prisma = new PrismaClient();
7
+
8
+ const token = await prisma.token.findUnique({
9
+ where: { token: params.token },
10
+ select: { user: true },
11
+ });
12
+
13
+ if (!token || !token.user) {
14
+ throw new Error('Token not found');
15
+ }
16
+
17
+ return {
18
+ firstName: token.user.firstName,
19
+ };
20
+ }
21
+ }
@@ -1,6 +1,6 @@
1
1
  import { PrismaClient } from '@prisma/client';
2
- import { NotificationService } from 'vintasend/services/notification-service';
3
- import { NotificationContextRegistry } from 'vintasend/services/notification-context-registry';
2
+ import { NotificationService } from 'vintasend/src/services/notification-service';
3
+ import { NotificationContextRegistry } from 'vintasend/src/services/notification-context-registry';
4
4
  import { PrismaNotificationBackend } from 'vintasend-prisma/prisma-notification-backend';
5
5
  import { PugEmailTemplateRenderer } from 'vintasend-pug/pug-email-template-renderer';
6
6
  import { NodemailerNotificationAdapter } from 'vintasend-nodemailer/nodemailer-notification-adapter';
@@ -21,7 +21,7 @@ export function getNotificationService() {
21
21
  number,
22
22
  number
23
23
  >(prisma);
24
- return new NotificationService<ContextMap>(
24
+ return new NotificationService<ContextMap, number, number>(
25
25
  [new NodemailerNotificationAdapter<
26
26
  PugEmailTemplateRenderer<ContextMap>,
27
27
  PrismaNotificationBackend<
@@ -1,8 +1,8 @@
1
1
  import type { Client } from '@temporalio/client';
2
2
  import { sendNotificationWorkflow } from "@/workers/notifications/workflows";
3
- import type { BaseNotificationQueueService } from "vintasend/services/notification-queue-service/base-notification-queue-service";
3
+ import type { BaseNotificationQueueService } from "vintasend/src/services/notification-queue-service/base-notification-queue-service";
4
4
 
5
- export class TemporalQueueService<NotificationIdType> implements BaseNotificationQueueService {
5
+ export class TemporalQueueService<NotificationIdType> implements BaseNotificationQueueService<NotificationIdType> {
6
6
  constructor(private client: Client, private taskQueue: string, ) {}
7
7
 
8
8
  async enqueueNotification(notificationId: NotificationIdType): Promise<void> {
@@ -1,19 +1,20 @@
1
- import type { Notification } from 'vintasend/types/notification'
1
+ import type { Notification } from 'vintasend/src/types/notification'
2
2
 
3
3
  import { type ContextMap, getNotificationService } from '@/lib/services/notifications';
4
4
 
5
+ type NotificationIdType = Parameters<ReturnType<typeof getNotificationService>['getNotification']>[0];
5
6
 
6
- export async function sendNotification<NotificationIdType> (notificationId: NotificationIdType): Promise<void> {
7
- const notificationServices = getNotificationService();
7
+ export async function sendNotification(notificationId: NotificationIdType): Promise<void> {
8
+ const notificationService = getNotificationService();
8
9
 
9
10
  if (!notificationId) {
10
11
  throw new Error("Notification ID is required");
11
12
  }
12
13
 
13
- await notificationServices.delayedSend(notificationId);
14
+ await notificationService.delayedSend(notificationId);
14
15
  };
15
16
 
16
- export const getAllPendingNotifications = async (): Promise<Notification<ContextMap>["id"][]> => {
17
+ export const getAllPendingNotifications = async (): Promise<NotificationIdType[]> => {
17
18
  const notificationServices = getNotificationService();
18
19
  const pendingNotifications = await notificationServices.getPendingNotifications();
19
20
  return pendingNotifications.map((notification) => notification.id);
@@ -1,13 +1,16 @@
1
1
  import { proxyActivities } from '@temporalio/workflow';
2
2
  import type { EmailActivities } from './activities';
3
+ import type { getNotificationService } from '@/lib/services/notifications';
3
4
 
4
5
  // Configure activities with a timeout (adjust as needed)
5
6
  const { sendNotification, getAllPendingNotifications } = proxyActivities<EmailActivities>({
6
7
  startToCloseTimeout: '1 minute',
7
8
  });
8
9
 
9
- export async function sendNotificationWorkflow<NotificationIdType>(notificationId: NotificationIdType): Promise<void> {
10
- await sendNotification<NotificationIdType>(notificationId);
10
+ type NotificationIdType = Parameters<ReturnType<typeof getNotificationService>['getNotification']>[0];
11
+
12
+ export async function sendNotificationWorkflow(notificationId: NotificationIdType): Promise<void> {
13
+ await sendNotification(notificationId);
11
14
  }
12
15
 
13
16
  export async function sendAllPendingNotificationsWorkflow(): Promise<void> {
@@ -1,18 +1,29 @@
1
1
  import nodemailer from 'nodemailer';
2
2
 
3
- import type { BaseNotificationAdapter } from 'vintasend/services/notification-adapters/base-notification-adapter';
4
- import type { BaseEmailTemplateRenderer } from 'vintasend/services/notification-template-renderers/base-email-template-renderer';
5
- import type { BaseNotificationBackend } from 'vintasend/services/notification-backends/base-notification-backend';
6
- import type { Notification } from 'vintasend/types/notification';
7
- import type { JsonObject } from 'vintasend/types/json-values';
8
- import type { NotificationType } from 'vintasend/types/notification-type';
9
- import type { ContextGenerator } from 'vintasend/services/notification-context-registry';
3
+ import type { BaseNotificationAdapter } from 'vintasend/src/services/notification-adapters/base-notification-adapter';
4
+ import type { BaseEmailTemplateRenderer } from 'vintasend/src/services/notification-template-renderers/base-email-template-renderer';
5
+ import type { BaseNotificationBackend } from 'vintasend/src/services/notification-backends/base-notification-backend';
6
+ import type { Notification } from 'vintasend/src/types/notification';
7
+ import type { JsonObject } from 'vintasend/src/types/json-values';
8
+ import type { NotificationType } from 'vintasend/src/types/notification-type';
9
+ import type { ContextGenerator } from 'vintasend/src/services/notification-context-registry';
10
+ import type { Identifier } from 'vintasend/src/types/identifier';
10
11
 
11
12
  export class NodemailerNotificationAdapter<
12
13
  TemplateRenderer extends BaseEmailTemplateRenderer<AvailableContexts>,
13
14
  Backend extends BaseNotificationBackend<AvailableContexts>,
14
- AvailableContexts extends Record<string, ContextGenerator>
15
- > implements BaseNotificationAdapter<TemplateRenderer, Backend, AvailableContexts> {
15
+ AvailableContexts extends Record<string, ContextGenerator>,
16
+ NotificationIdType extends Identifier = Identifier,
17
+ UserIdType extends Identifier = Identifier,
18
+ > implements
19
+ BaseNotificationAdapter<
20
+ TemplateRenderer,
21
+ Backend,
22
+ AvailableContexts,
23
+ NotificationIdType,
24
+ UserIdType
25
+ >
26
+ {
16
27
  private transporter: nodemailer.Transporter;
17
28
  public readonly notificationType: NotificationType = 'EMAIL';
18
29
  public readonly key = 'nodemailer';
@@ -21,19 +32,22 @@ export class NodemailerNotificationAdapter<
21
32
  public templateRenderer: TemplateRenderer,
22
33
  public backend: Backend,
23
34
  public readonly enqueueNotifications: boolean,
24
- transportOptions: nodemailer.SendMailOptions
35
+ transportOptions: nodemailer.SendMailOptions,
25
36
  ) {
26
37
  this.transporter = nodemailer.createTransport(transportOptions);
27
38
  }
28
39
 
29
- async send(notification: Notification<AvailableContexts>, context: JsonObject): Promise<void> {
40
+ async send(
41
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
42
+ context: JsonObject,
43
+ ): Promise<void> {
30
44
  const template = await this.templateRenderer.render(notification, context);
31
45
 
32
46
  if (!notification.id) {
33
47
  throw new Error('Notification ID is required');
34
48
  }
35
49
 
36
- const userEmail = await this.backend.getUserEmailFromNotification(notification.id)
50
+ const userEmail = await this.backend.getUserEmailFromNotification(notification.id);
37
51
 
38
52
  if (!userEmail) {
39
53
  throw new Error('User email not found');
@@ -9,7 +9,8 @@
9
9
  "author": "",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
- "nodemailer": "^6.10.0"
12
+ "nodemailer": "^6.10.0",
13
+ "vintasend": "^0.1.0"
13
14
  },
14
15
  "devDependencies": {
15
16
  "@types/nodemailer": "^6.4.17"
@@ -11,6 +11,7 @@
11
11
  "license": "ISC",
12
12
  "dependencies": {
13
13
  "@prisma/client": "^6.3.1",
14
- "prisma": "^6.3.1"
14
+ "prisma": "^6.3.1",
15
+ "vintasend": "^0.1.0"
15
16
  }
16
17
  }
@@ -1,9 +1,10 @@
1
- import type { BaseNotificationBackend } from 'vintasend/services/notification-backends/base-notification-backend';
2
- import type { ContextGenerator } from 'vintasend/services/notification-context-registry';
3
- import type { InputJsonValue, JsonValue } from 'vintasend/types/json-values';
4
- import type { Notification, NotificationInput } from 'vintasend/types/notification';
5
- import type { NotificationStatus } from 'vintasend/types/notification-status';
6
- import type { NotificationType } from 'vintasend/types/notification-type';
1
+ import type { BaseNotificationBackend } from 'vintasend/src/services/notification-backends/base-notification-backend';
2
+ import type { ContextGenerator } from 'vintasend/src/services/notification-context-registry';
3
+ import type { InputJsonValue, JsonValue } from 'vintasend/src/types/json-values';
4
+ import type { Notification, NotificationInput } from 'vintasend/src/types/notification';
5
+ import type { NotificationStatus } from 'vintasend/src/types/notification-status';
6
+ import type { NotificationType } from 'vintasend/src/types/notification-type';
7
+ import type { Identifier } from 'vintasend/src/types/identifier';
7
8
 
8
9
  export const NotificationStatusEnum = {
9
10
  PENDING_SEND: 'PENDING_SEND',
@@ -145,8 +146,8 @@ function convertJsonValueToRecord(jsonValue: JsonValue): Record<string, string |
145
146
  export class PrismaNotificationBackend<
146
147
  Client extends NotificationPrismaClientInterface<NotificationIdType, UserIdType>,
147
148
  AvailableContexts extends Record<string, ContextGenerator>,
148
- NotificationIdType extends string | number,
149
- UserIdType extends string | number,
149
+ NotificationIdType extends Identifier = Identifier,
150
+ UserIdType extends Identifier = Identifier,
150
151
  > implements BaseNotificationBackend<AvailableContexts>
151
152
  {
152
153
  constructor(private prismaClient: Client) {}
@@ -9,7 +9,8 @@
9
9
  "author": "",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
- "pug": "^3.0.3"
12
+ "pug": "^3.0.3",
13
+ "vintasend": "^0.1.0"
13
14
  },
14
15
  "devDependencies": {
15
16
  "@types/pug": "^2.0.10"
@@ -1,20 +1,24 @@
1
- import type { ContextGenerator } from 'vintasend/services/notification-context-registry';
1
+ import type { ContextGenerator } from 'vintasend/src/services/notification-context-registry';
2
2
  import type {
3
3
  BaseEmailTemplateRenderer,
4
4
  EmailTemplate,
5
- } from 'vintasend/services/notification-template-renderers/base-email-template-renderer';
6
- import type { JsonObject } from 'vintasend/types/json-values';
7
- import type { Notification } from 'vintasend/types/notification';
5
+ } from 'vintasend/src/services/notification-template-renderers/base-email-template-renderer';
6
+ import type { JsonObject } from 'vintasend/src/types/json-values';
7
+ import type { Notification } from 'vintasend/src/types/notification';
8
+ import type { Identifier } from 'vintasend/src/types/identifier';
8
9
 
9
10
  import pug from 'pug';
10
11
 
11
- export class PugEmailTemplateRenderer<AvailableContexts extends Record<string, ContextGenerator>>
12
- implements BaseEmailTemplateRenderer<AvailableContexts>
12
+ export class PugEmailTemplateRenderer<
13
+ AvailableContexts extends Record<string, ContextGenerator>,
14
+ NotificationIdType extends Identifier = Identifier,
15
+ UserIdType extends Identifier = Identifier,
16
+ > implements BaseEmailTemplateRenderer<AvailableContexts, NotificationIdType, UserIdType>
13
17
  {
14
18
  constructor(private options: pug.Options = {}) {}
15
19
 
16
20
  render(
17
- notification: Notification<AvailableContexts>,
21
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
18
22
  context: JsonObject,
19
23
  ): Promise<EmailTemplate> {
20
24
  const bodyTemplate = pug.compileFile(notification.bodyTemplate, this.options);
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "vintasend-winton",
2
+ "name": "vintasend-winston",
3
3
  "version": "0.1.0",
4
4
  "description": "",
5
5
  "main": "index.js",
@@ -10,6 +10,7 @@
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "jsonwebtoken": "^9.0.2",
13
+ "vintasend": "^0.1.0",
13
14
  "winston": "^3.17.0"
14
15
  }
15
16
  }
@@ -1,4 +1,4 @@
1
- import type { BaseLogger } from 'vintasend/services/loggers/base-logger';
1
+ import type { BaseLogger } from 'vintasend/src/services/loggers/base-logger';
2
2
 
3
3
  import * as winston from 'winston';
4
4
 
@@ -4,11 +4,14 @@ import type { BaseNotificationBackend } from '../notification-backends/base-noti
4
4
  import type { BaseNotificationTemplateRenderer } from '../notification-template-renderers/base-notification-template-renderer';
5
5
  import type { ContextGenerator } from '../notification-context-registry';
6
6
  import type { JsonValue } from '../../types/json-values';
7
+ import type { Identifier } from '../../types/identifier';
7
8
 
8
9
  export interface BaseNotificationAdapter<
9
10
  TemplateRenderer extends BaseNotificationTemplateRenderer<AvailableContexts>,
10
11
  Backend extends BaseNotificationBackend<AvailableContexts>,
11
- AvailableContexts extends Record<string, ContextGenerator>
12
+ AvailableContexts extends Record<string, ContextGenerator>,
13
+ NotificationIdType extends Identifier = Identifier,
14
+ UserIdType extends Identifier = Identifier,
12
15
  > {
13
16
  notificationType: NotificationType;
14
17
  key: string;
@@ -16,5 +19,8 @@ export interface BaseNotificationAdapter<
16
19
  backend: Backend;
17
20
  enqueueNotifications: boolean;
18
21
 
19
- send(notification: Notification<AvailableContexts>, context: JsonValue): Promise<void>;
22
+ send(
23
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
24
+ context: JsonValue,
25
+ ): Promise<void>;
20
26
  }
@@ -3,38 +3,42 @@ import type { Identifier } from '../../types/identifier';
3
3
  import type { Notification } from '../../types/notification';
4
4
  import type { ContextGenerator } from '../notification-context-registry';
5
5
 
6
- export interface BaseNotificationBackend<AvailableContexts extends Record<string, ContextGenerator>> {
7
- getAllPendingNotifications(): Promise<Notification<AvailableContexts>[]>;
8
- getPendingNotifications(): Promise<Notification<AvailableContexts>[]>;
9
- getAllFutureNotifications(): Promise<Notification<AvailableContexts>[]>;
10
- getFutureNotifications(): Promise<Notification<AvailableContexts>[]>;
6
+ export interface BaseNotificationBackend<
7
+ AvailableContexts extends Record<string, ContextGenerator>,
8
+ NotificationIdType extends Identifier = Identifier,
9
+ UserIdType extends Identifier = Identifier,
10
+ > {
11
+ getAllPendingNotifications(): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
12
+ getPendingNotifications(): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
13
+ getAllFutureNotifications(): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
14
+ getFutureNotifications(): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
11
15
  getAllFutureNotificationsFromUser(
12
16
  userId: Identifier,
13
- ): Promise<Notification<AvailableContexts>[]>;
14
- getFutureNotificationsFromUser(userId: Identifier): Promise<Notification<AvailableContexts>[]>;
17
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
18
+ getFutureNotificationsFromUser(userId: Identifier): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
15
19
  persistNotification(
16
- notification: Omit<Notification<AvailableContexts>, 'id'>,
17
- ): Promise<Notification<AvailableContexts>>;
20
+ notification: Omit<Notification<AvailableContexts, NotificationIdType, UserIdType>, 'id'>,
21
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>>;
18
22
  persistNotificationUpdate(
19
23
  notificationId: Identifier,
20
- notification: Partial<Omit<Notification<AvailableContexts>, 'id'>>,
21
- ): Promise<Notification<AvailableContexts>>;
22
- markPendingAsSent(notificationId: Identifier): Promise<Notification<AvailableContexts>>;
23
- markPendingAsFailed(notificationId: Identifier): Promise<Notification<AvailableContexts>>;
24
- markSentAsRead(notificationId: Identifier): Promise<Notification<AvailableContexts>>;
24
+ notification: Partial<Omit<Notification<AvailableContexts, NotificationIdType, UserIdType>, 'id'>>,
25
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>>;
26
+ markPendingAsSent(notificationId: Identifier): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>>;
27
+ markPendingAsFailed(notificationId: Identifier): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>>;
28
+ markSentAsRead(notificationId: Identifier): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>>;
25
29
  cancelNotification(notificationId: Identifier): Promise<void>;
26
30
  getNotification(
27
31
  notificationId: Identifier,
28
32
  forUpdate: boolean,
29
- ): Promise<Notification<AvailableContexts> | null>;
33
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType> | null>;
30
34
  filterAllInAppUnreadNotifications(
31
35
  userId: Identifier,
32
- ): Promise<Notification<AvailableContexts>[]>;
36
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
33
37
  filterInAppUnreadNotifications(
34
38
  userId: Identifier,
35
39
  page: number,
36
40
  pageSize: number,
37
- ): Promise<Notification<AvailableContexts>[]>;
41
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>[]>;
38
42
  getUserEmailFromNotification(notificationId: Identifier): Promise<string | undefined>;
39
43
  storeContextUsed(
40
44
  notificationId: Identifier,
@@ -1,5 +1,5 @@
1
- import type { Identifier } from "../../types/identifier";
1
+ import type { Identifier } from '../../types/identifier';
2
2
 
3
- export interface BaseNotificationQueueService {
4
- enqueueNotification(notificationId: Identifier): Promise<void>;
3
+ export interface BaseNotificationQueueService<NotificationIdType extends Identifier = Identifier> {
4
+ enqueueNotification(notificationId: NotificationIdType): Promise<void>;
5
5
  }
@@ -9,25 +9,33 @@ import {
9
9
  type ContextGenerator,
10
10
  NotificationContextRegistry,
11
11
  } from './notification-context-registry';
12
- import type { JsonObject, JsonValue } from '../types/json-values';
12
+ import type { JsonObject } from '../types/json-values';
13
13
 
14
- export class NotificationService<AvailableContexts extends Record<string, ContextGenerator>> {
14
+ export class NotificationService<
15
+ AvailableContexts extends Record<string, ContextGenerator>,
16
+ NotificationIdType extends Identifier = Identifier,
17
+ UserIdType extends Identifier = Identifier,
18
+ > {
15
19
  constructor(
16
20
  private adapters: BaseNotificationAdapter<
17
- BaseNotificationTemplateRenderer<AvailableContexts>,
18
- BaseNotificationBackend<AvailableContexts>,
19
- AvailableContexts
21
+ BaseNotificationTemplateRenderer<AvailableContexts, NotificationIdType, UserIdType>,
22
+ BaseNotificationBackend<AvailableContexts, NotificationIdType, UserIdType>,
23
+ AvailableContexts,
24
+ NotificationIdType,
25
+ UserIdType
20
26
  >[],
21
27
  private backend: BaseNotificationBackend<AvailableContexts>,
22
28
  private logger: BaseLogger,
23
- private queueService?: BaseNotificationQueueService,
29
+ private queueService?: BaseNotificationQueueService<NotificationIdType>,
24
30
  ) {}
25
31
 
26
- registerQueueService(queueService: BaseNotificationQueueService): void {
32
+ registerQueueService(queueService: BaseNotificationQueueService<NotificationIdType>): void {
27
33
  this.queueService = queueService;
28
34
  }
29
35
 
30
- async send(notification: Notification<AvailableContexts>): Promise<void> {
36
+ async send(
37
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
38
+ ): Promise<void> {
31
39
  const adaptersOfType = this.adapters.filter(
32
40
  (adapter) => adapter.notificationType === notification.notificationType,
33
41
  );
@@ -85,9 +93,9 @@ export class NotificationService<AvailableContexts extends Record<string, Contex
85
93
  }
86
94
 
87
95
  async createNotification(
88
- notification: Omit<Notification<AvailableContexts>, 'id'>,
89
- ): Promise<Notification<AvailableContexts>> {
90
- const createdNotification = await this.backend.persistNotification(notification);
96
+ notification: Omit<Notification<AvailableContexts, NotificationIdType, UserIdType>, 'id'>,
97
+ ): Promise<Notification<AvailableContexts, NotificationIdType, UserIdType>> {
98
+ const createdNotification = await this.backend.persistNotification(notification) as Notification<AvailableContexts, NotificationIdType, UserIdType>;
91
99
 
92
100
  if (notification.sendAfter && notification.sendAfter > new Date()) {
93
101
  this.send(createdNotification);
@@ -98,28 +106,26 @@ export class NotificationService<AvailableContexts extends Record<string, Contex
98
106
 
99
107
  async updateNotification(
100
108
  notificationId: Identifier,
101
- notification: Partial<Omit<Notification<AvailableContexts>, 'id'>>,
102
- ): Promise<Notification<AvailableContexts>> {
109
+ notification: Partial<
110
+ Omit<Notification<AvailableContexts, NotificationIdType, UserIdType>, 'id'>
111
+ >,
112
+ ) {
103
113
  return this.backend.persistNotificationUpdate(notificationId, notification);
104
114
  }
105
115
 
106
- async getAllFutureNotifications(): Promise<Notification<AvailableContexts>[]> {
116
+ async getAllFutureNotifications() {
107
117
  return this.backend.getAllFutureNotifications();
108
118
  }
109
119
 
110
- async getAllFutureNotificationsFromUser(
111
- userId: Identifier,
112
- ): Promise<Notification<AvailableContexts>[]> {
120
+ async getAllFutureNotificationsFromUser(userId: NotificationIdType) {
113
121
  return this.backend.getAllFutureNotificationsFromUser(userId);
114
122
  }
115
123
 
116
- async getFutureNotificationsFromUser(
117
- userId: Identifier,
118
- ): Promise<Notification<AvailableContexts>[]> {
124
+ async getFutureNotificationsFromUser(userId: NotificationIdType) {
119
125
  return this.backend.getFutureNotificationsFromUser(userId);
120
126
  }
121
127
 
122
- async getFutureNotifications(): Promise<Notification<AvailableContexts>[]> {
128
+ async getFutureNotifications() {
123
129
  return this.backend.getFutureNotifications();
124
130
  }
125
131
 
@@ -132,33 +138,34 @@ export class NotificationService<AvailableContexts extends Record<string, Contex
132
138
 
133
139
  async sendPendingNotifications(): Promise<void> {
134
140
  const pendingNotifications = await this.backend.getAllPendingNotifications();
135
- await Promise.all(pendingNotifications.map((notification) => this.send(notification)));
141
+ await Promise.all(
142
+ pendingNotifications.map((notification) =>
143
+ this.send(notification as Notification<AvailableContexts, NotificationIdType, UserIdType>),
144
+ ),
145
+ );
136
146
  }
137
147
 
138
- async getPendingNotifications(): Promise<Notification<AvailableContexts>[]> {
148
+ async getPendingNotifications() {
139
149
  return this.backend.getPendingNotifications();
140
150
  }
141
151
 
142
- async getNotification(
143
- notificationId: Identifier,
144
- forUpdate: boolean,
145
- ): Promise<Notification<AvailableContexts> | null> {
152
+ async getNotification(notificationId: NotificationIdType, forUpdate: boolean) {
146
153
  return this.backend.getNotification(notificationId, forUpdate);
147
154
  }
148
155
 
149
- async markRead(notificationId: Identifier): Promise<Notification<AvailableContexts>> {
156
+ async markRead(notificationId: NotificationIdType) {
150
157
  return this.backend.markSentAsRead(notificationId);
151
158
  }
152
159
 
153
- async getInAppUnread(userId: Identifier): Promise<Notification<AvailableContexts>[]> {
160
+ async getInAppUnread(userId: NotificationIdType) {
154
161
  return this.backend.filterAllInAppUnreadNotifications(userId);
155
162
  }
156
163
 
157
- async cancelNotification(notificationId: Identifier): Promise<void> {
164
+ async cancelNotification(notificationId: NotificationIdType): Promise<void> {
158
165
  return this.backend.cancelNotification(notificationId);
159
166
  }
160
167
 
161
- async delayedSend(notificationId: Identifier): Promise<void> {
168
+ async delayedSend(notificationId: NotificationIdType): Promise<void> {
162
169
  const notification = await this.getNotification(notificationId, false);
163
170
 
164
171
  if (!notification) {
@@ -189,7 +196,7 @@ export class NotificationService<AvailableContexts extends Record<string, Contex
189
196
 
190
197
  for (const adapter of enqueueNotificationsAdapters) {
191
198
  try {
192
- await adapter.send(notification, context);
199
+ await adapter.send(notification as Notification<AvailableContexts, NotificationIdType, UserIdType>, context);
193
200
  } catch (sendError) {
194
201
  this.logger.error(
195
202
  `Error sending notification ${notification.id} with adapter ${adapter.constructor.name}: ${sendError}`,
@@ -3,6 +3,7 @@ import type { Notification } from '../../types/notification';
3
3
  import type { Buffer } from 'node:buffer';
4
4
  import type { ContextGenerator } from '../notification-context-registry';
5
5
  import type { JsonObject } from '../../types/json-values';
6
+ import type { Identifier } from '../../types/identifier';
6
7
 
7
8
  export type Attachment = File | Buffer | string;
8
9
 
@@ -11,10 +12,18 @@ export type EmailTemplate = {
11
12
  body: string;
12
13
  };
13
14
 
14
- export interface BaseEmailTemplateRenderer<AvailableContexts extends Record<string, ContextGenerator>>
15
- extends BaseNotificationTemplateRenderer<AvailableContexts, EmailTemplate> {
15
+ export interface BaseEmailTemplateRenderer<
16
+ AvailableContexts extends Record<string, ContextGenerator>,
17
+ NotificationIdType extends Identifier = Identifier,
18
+ UserIdType extends Identifier = Identifier,
19
+ > extends BaseNotificationTemplateRenderer<
20
+ AvailableContexts,
21
+ NotificationIdType,
22
+ UserIdType,
23
+ EmailTemplate
24
+ > {
16
25
  render(
17
- notification: Notification<AvailableContexts>,
18
- context: JsonObject
26
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
27
+ context: JsonObject,
19
28
  ): Promise<EmailTemplate>;
20
29
  }
@@ -1,7 +1,16 @@
1
+ import type { Identifier } from '../../types/identifier';
1
2
  import type { JsonObject } from '../../types/json-values';
2
3
  import type { Notification } from '../../types/notification';
3
4
  import type { ContextGenerator } from '../notification-context-registry';
4
5
 
5
- export interface BaseNotificationTemplateRenderer<AvailableContexts extends Record<string, ContextGenerator>, T = unknown> {
6
- render(notification: Notification<AvailableContexts>, context: JsonObject): Promise<T>;
6
+ export interface BaseNotificationTemplateRenderer<
7
+ AvailableContexts extends Record<string, ContextGenerator>,
8
+ NotificationIdType extends Identifier = Identifier,
9
+ UserIdType extends Identifier = Identifier,
10
+ T = unknown,
11
+ > {
12
+ render(
13
+ notification: Notification<AvailableContexts, NotificationIdType, UserIdType>,
14
+ context: JsonObject,
15
+ ): Promise<T>;
7
16
  }