alepha 0.12.1 → 0.13.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 (198) hide show
  1. package/dist/api-notifications/index.d.ts +111 -111
  2. package/dist/api-users/index.d.ts +1240 -1240
  3. package/dist/api-verifications/index.d.ts +94 -94
  4. package/dist/cli/{dist-Sz2EXvQX.cjs → dist-Dl9Vl7Ur.js} +17 -13
  5. package/dist/cli/{dist-BBPjuQ56.js.map → dist-Dl9Vl7Ur.js.map} +1 -1
  6. package/dist/cli/index.d.ts +3 -11
  7. package/dist/cli/index.js +106 -74
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/email/index.js +71 -73
  10. package/dist/email/index.js.map +1 -1
  11. package/dist/orm/index.d.ts +1 -1
  12. package/dist/orm/index.js.map +1 -1
  13. package/dist/queue/index.d.ts +4 -4
  14. package/dist/redis/index.d.ts +10 -10
  15. package/dist/retry/index.d.ts +1 -1
  16. package/dist/retry/index.js +2 -2
  17. package/dist/retry/index.js.map +1 -1
  18. package/dist/scheduler/index.d.ts +6 -6
  19. package/dist/server/index.js +1 -1
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server-auth/index.d.ts +193 -193
  22. package/dist/server-health/index.d.ts +17 -17
  23. package/dist/server-links/index.d.ts +34 -34
  24. package/dist/server-metrics/index.js +170 -174
  25. package/dist/server-metrics/index.js.map +1 -1
  26. package/dist/server-security/index.d.ts +9 -9
  27. package/dist/vite/index.js +4 -5
  28. package/dist/vite/index.js.map +1 -1
  29. package/dist/websocket/index.d.ts +7 -7
  30. package/package.json +52 -103
  31. package/src/cli/apps/AlephaPackageBuilderCli.ts +7 -2
  32. package/src/cli/assets/appRouterTs.ts +9 -0
  33. package/src/cli/assets/indexHtml.ts +2 -1
  34. package/src/cli/assets/mainBrowserTs.ts +10 -0
  35. package/src/cli/commands/CoreCommands.ts +6 -5
  36. package/src/cli/commands/DrizzleCommands.ts +65 -57
  37. package/src/cli/commands/VerifyCommands.ts +1 -1
  38. package/src/cli/services/ProjectUtils.ts +44 -38
  39. package/src/orm/providers/DrizzleKitProvider.ts +1 -1
  40. package/src/retry/descriptors/$retry.ts +5 -3
  41. package/src/server/providers/NodeHttpServerProvider.ts +1 -1
  42. package/src/vite/helpers/boot.ts +3 -3
  43. package/dist/api-files/index.cjs +0 -1293
  44. package/dist/api-files/index.cjs.map +0 -1
  45. package/dist/api-files/index.d.cts +0 -829
  46. package/dist/api-jobs/index.cjs +0 -274
  47. package/dist/api-jobs/index.cjs.map +0 -1
  48. package/dist/api-jobs/index.d.cts +0 -654
  49. package/dist/api-notifications/index.cjs +0 -380
  50. package/dist/api-notifications/index.cjs.map +0 -1
  51. package/dist/api-notifications/index.d.cts +0 -289
  52. package/dist/api-parameters/index.cjs +0 -66
  53. package/dist/api-parameters/index.cjs.map +0 -1
  54. package/dist/api-parameters/index.d.cts +0 -84
  55. package/dist/api-users/index.cjs +0 -6009
  56. package/dist/api-users/index.cjs.map +0 -1
  57. package/dist/api-users/index.d.cts +0 -4740
  58. package/dist/api-verifications/index.cjs +0 -407
  59. package/dist/api-verifications/index.cjs.map +0 -1
  60. package/dist/api-verifications/index.d.cts +0 -207
  61. package/dist/batch/index.cjs +0 -408
  62. package/dist/batch/index.cjs.map +0 -1
  63. package/dist/batch/index.d.cts +0 -330
  64. package/dist/bin/index.cjs +0 -17
  65. package/dist/bin/index.cjs.map +0 -1
  66. package/dist/bin/index.d.cts +0 -1
  67. package/dist/bucket/index.cjs +0 -303
  68. package/dist/bucket/index.cjs.map +0 -1
  69. package/dist/bucket/index.d.cts +0 -355
  70. package/dist/cache/index.cjs +0 -241
  71. package/dist/cache/index.cjs.map +0 -1
  72. package/dist/cache/index.d.cts +0 -202
  73. package/dist/cache-redis/index.cjs +0 -84
  74. package/dist/cache-redis/index.cjs.map +0 -1
  75. package/dist/cache-redis/index.d.cts +0 -40
  76. package/dist/cli/chunk-DSlc6foC.cjs +0 -43
  77. package/dist/cli/dist-BBPjuQ56.js +0 -2778
  78. package/dist/cli/dist-Sz2EXvQX.cjs.map +0 -1
  79. package/dist/cli/index.cjs +0 -1241
  80. package/dist/cli/index.cjs.map +0 -1
  81. package/dist/cli/index.d.cts +0 -422
  82. package/dist/command/index.cjs +0 -693
  83. package/dist/command/index.cjs.map +0 -1
  84. package/dist/command/index.d.cts +0 -340
  85. package/dist/core/index.cjs +0 -2264
  86. package/dist/core/index.cjs.map +0 -1
  87. package/dist/core/index.d.cts +0 -1927
  88. package/dist/datetime/index.cjs +0 -318
  89. package/dist/datetime/index.cjs.map +0 -1
  90. package/dist/datetime/index.d.cts +0 -145
  91. package/dist/email/index.cjs +0 -10874
  92. package/dist/email/index.cjs.map +0 -1
  93. package/dist/email/index.d.cts +0 -186
  94. package/dist/fake/index.cjs +0 -34641
  95. package/dist/fake/index.cjs.map +0 -1
  96. package/dist/fake/index.d.cts +0 -74
  97. package/dist/file/index.cjs +0 -1212
  98. package/dist/file/index.cjs.map +0 -1
  99. package/dist/file/index.d.cts +0 -698
  100. package/dist/lock/index.cjs +0 -226
  101. package/dist/lock/index.cjs.map +0 -1
  102. package/dist/lock/index.d.cts +0 -361
  103. package/dist/lock-redis/index.cjs +0 -113
  104. package/dist/lock-redis/index.cjs.map +0 -1
  105. package/dist/lock-redis/index.d.cts +0 -24
  106. package/dist/logger/index.cjs +0 -521
  107. package/dist/logger/index.cjs.map +0 -1
  108. package/dist/logger/index.d.cts +0 -281
  109. package/dist/orm/index.cjs +0 -2986
  110. package/dist/orm/index.cjs.map +0 -1
  111. package/dist/orm/index.d.cts +0 -2213
  112. package/dist/queue/index.cjs +0 -1044
  113. package/dist/queue/index.cjs.map +0 -1
  114. package/dist/queue/index.d.cts +0 -1265
  115. package/dist/queue-redis/index.cjs +0 -873
  116. package/dist/queue-redis/index.cjs.map +0 -1
  117. package/dist/queue-redis/index.d.cts +0 -82
  118. package/dist/redis/index.cjs +0 -153
  119. package/dist/redis/index.cjs.map +0 -1
  120. package/dist/redis/index.d.cts +0 -82
  121. package/dist/retry/index.cjs +0 -146
  122. package/dist/retry/index.cjs.map +0 -1
  123. package/dist/retry/index.d.cts +0 -172
  124. package/dist/router/index.cjs +0 -111
  125. package/dist/router/index.cjs.map +0 -1
  126. package/dist/router/index.d.cts +0 -46
  127. package/dist/scheduler/index.cjs +0 -576
  128. package/dist/scheduler/index.cjs.map +0 -1
  129. package/dist/scheduler/index.d.cts +0 -145
  130. package/dist/security/index.cjs +0 -2402
  131. package/dist/security/index.cjs.map +0 -1
  132. package/dist/security/index.d.cts +0 -598
  133. package/dist/server/index.cjs +0 -1680
  134. package/dist/server/index.cjs.map +0 -1
  135. package/dist/server/index.d.cts +0 -810
  136. package/dist/server-auth/index.cjs +0 -3146
  137. package/dist/server-auth/index.cjs.map +0 -1
  138. package/dist/server-auth/index.d.cts +0 -1164
  139. package/dist/server-cache/index.cjs +0 -252
  140. package/dist/server-cache/index.cjs.map +0 -1
  141. package/dist/server-cache/index.d.cts +0 -164
  142. package/dist/server-compress/index.cjs +0 -141
  143. package/dist/server-compress/index.cjs.map +0 -1
  144. package/dist/server-compress/index.d.cts +0 -38
  145. package/dist/server-cookies/index.cjs +0 -234
  146. package/dist/server-cookies/index.cjs.map +0 -1
  147. package/dist/server-cookies/index.d.cts +0 -144
  148. package/dist/server-cors/index.cjs +0 -201
  149. package/dist/server-cors/index.cjs.map +0 -1
  150. package/dist/server-cors/index.d.cts +0 -140
  151. package/dist/server-health/index.cjs +0 -62
  152. package/dist/server-health/index.cjs.map +0 -1
  153. package/dist/server-health/index.d.cts +0 -58
  154. package/dist/server-helmet/index.cjs +0 -131
  155. package/dist/server-helmet/index.cjs.map +0 -1
  156. package/dist/server-helmet/index.d.cts +0 -97
  157. package/dist/server-links/index.cjs +0 -992
  158. package/dist/server-links/index.cjs.map +0 -1
  159. package/dist/server-links/index.d.cts +0 -513
  160. package/dist/server-metrics/index.cjs +0 -4535
  161. package/dist/server-metrics/index.cjs.map +0 -1
  162. package/dist/server-metrics/index.d.cts +0 -35
  163. package/dist/server-multipart/index.cjs +0 -237
  164. package/dist/server-multipart/index.cjs.map +0 -1
  165. package/dist/server-multipart/index.d.cts +0 -50
  166. package/dist/server-proxy/index.cjs +0 -186
  167. package/dist/server-proxy/index.cjs.map +0 -1
  168. package/dist/server-proxy/index.d.cts +0 -234
  169. package/dist/server-rate-limit/index.cjs +0 -241
  170. package/dist/server-rate-limit/index.cjs.map +0 -1
  171. package/dist/server-rate-limit/index.d.cts +0 -183
  172. package/dist/server-security/index.cjs +0 -316
  173. package/dist/server-security/index.cjs.map +0 -1
  174. package/dist/server-security/index.d.cts +0 -173
  175. package/dist/server-static/index.cjs +0 -170
  176. package/dist/server-static/index.cjs.map +0 -1
  177. package/dist/server-static/index.d.cts +0 -121
  178. package/dist/server-swagger/index.cjs +0 -1021
  179. package/dist/server-swagger/index.cjs.map +0 -1
  180. package/dist/server-swagger/index.d.cts +0 -382
  181. package/dist/sms/index.cjs +0 -221
  182. package/dist/sms/index.cjs.map +0 -1
  183. package/dist/sms/index.d.cts +0 -130
  184. package/dist/thread/index.cjs +0 -350
  185. package/dist/thread/index.cjs.map +0 -1
  186. package/dist/thread/index.d.cts +0 -260
  187. package/dist/topic/index.cjs +0 -282
  188. package/dist/topic/index.cjs.map +0 -1
  189. package/dist/topic/index.d.cts +0 -523
  190. package/dist/topic-redis/index.cjs +0 -71
  191. package/dist/topic-redis/index.cjs.map +0 -1
  192. package/dist/topic-redis/index.d.cts +0 -42
  193. package/dist/vite/index.cjs +0 -1077
  194. package/dist/vite/index.cjs.map +0 -1
  195. package/dist/vite/index.d.cts +0 -542
  196. package/dist/websocket/index.cjs +0 -1117
  197. package/dist/websocket/index.cjs.map +0 -1
  198. package/dist/websocket/index.d.cts +0 -861
@@ -1,380 +0,0 @@
1
- let alepha = require("alepha");
2
- let alepha_batch = require("alepha/batch");
3
- let alepha_datetime = require("alepha/datetime");
4
- let alepha_logger = require("alepha/logger");
5
- let alepha_orm = require("alepha/orm");
6
- let alepha_queue = require("alepha/queue");
7
- let alepha_email = require("alepha/email");
8
-
9
- //#region src/api-notifications/controllers/NotificationController.ts
10
- var NotificationController = class {};
11
-
12
- //#endregion
13
- //#region src/api-notifications/entities/notifications.ts
14
- const notifications = (0, alepha_orm.$entity)({
15
- name: "notifications",
16
- schema: alepha.t.object({
17
- id: alepha_orm.pg.primaryKey(alepha.t.uuid()),
18
- version: alepha_orm.pg.version(),
19
- createdAt: alepha_orm.pg.createdAt(),
20
- updatedAt: alepha_orm.pg.updatedAt(),
21
- type: alepha.t.enum(["email", "sms"]),
22
- template: alepha.t.text(),
23
- category: alepha.t.optional(alepha.t.text({ description: "For grouping related notifications (e.g., 'authentication', 'marketing'). Contact can filter notifications by category." })),
24
- critical: alepha.t.optional(alepha.t.boolean({ description: "Prioritize delivery of this notification. Set to true for important system alerts." })),
25
- sensitive: alepha.t.optional(alepha.t.boolean({ description: "Message won't be logged or stored in plain text. Set to true when notification contains passwords or codes." })),
26
- contact: alepha.t.text(),
27
- variables: alepha.t.optional(alepha.t.record(alepha.t.text(), alepha.t.any())),
28
- scheduledAt: alepha.t.optional(alepha.t.datetime({ description: "When set, the notification will be sent at or after this date/time." })),
29
- sentAt: alepha.t.optional(alepha.t.datetime()),
30
- error: alepha.t.optional(alepha.t.object({
31
- at: alepha.t.datetime(),
32
- name: alepha.t.text(),
33
- message: alepha.t.text({ size: "rich" })
34
- }))
35
- })
36
- });
37
-
38
- //#endregion
39
- //#region src/api-notifications/providers/SmsProvider.ts
40
- var SmsProvider = class {};
41
-
42
- //#endregion
43
- //#region src/api-notifications/services/NotificationSenderService.ts
44
- var NotificationSenderService = class {
45
- alepha = (0, alepha.$inject)(alepha.Alepha);
46
- log = (0, alepha_logger.$logger)();
47
- notificationRepository = (0, alepha_orm.$repository)(notifications);
48
- dateTimeProvider = (0, alepha.$inject)(alepha_datetime.DateTimeProvider);
49
- emailProvider = (0, alepha.$inject)(alepha_email.EmailProvider);
50
- smsProvider = (0, alepha.$inject)(SmsProvider);
51
- async send(notificationId) {
52
- this.log.trace("Sending notification", { notificationId: typeof notificationId === "string" ? notificationId : notificationId.id });
53
- const notification = typeof notificationId === "string" ? await this.notificationRepository.findById(notificationId) : notificationId;
54
- if (notification.sentAt) {
55
- this.log.debug("Notification already sent", {
56
- notificationId: notification.id,
57
- sentAt: notification.sentAt
58
- });
59
- return;
60
- }
61
- this.log.debug("Processing notification", {
62
- id: notification.id,
63
- type: notification.type,
64
- template: notification.template,
65
- contact: notification.contact
66
- });
67
- try {
68
- if (notification.type === "email") {
69
- await this.emailProvider.send(this.renderEmail(notification));
70
- notification.sentAt = this.dateTimeProvider.nowISOString();
71
- this.log.info("Email notification sent", {
72
- id: notification.id,
73
- template: notification.template,
74
- contact: notification.contact
75
- });
76
- }
77
- if (notification.type === "sms") {
78
- await this.smsProvider.send(this.renderSms(notification));
79
- notification.sentAt = this.dateTimeProvider.nowISOString();
80
- this.log.info("SMS notification sent", {
81
- id: notification.id,
82
- template: notification.template,
83
- contact: notification.contact
84
- });
85
- }
86
- } catch (e) {
87
- this.log.error("Failed to send notification", {
88
- id: notification.id,
89
- type: notification.type,
90
- template: notification.template,
91
- contact: notification.contact,
92
- error: e
93
- });
94
- if (e instanceof Error) notification.error = {
95
- at: this.dateTimeProvider.nowISOString(),
96
- name: e.name,
97
- message: e.message
98
- };
99
- } finally {
100
- await this.notificationRepository.save(notification);
101
- }
102
- }
103
- renderSms(notification) {
104
- this.log.trace("Rendering SMS notification", {
105
- id: notification.id,
106
- template: notification.template
107
- });
108
- const { variables, contact, template } = this.load(notification);
109
- const sms = template.options.sms;
110
- if (!sms) {
111
- this.log.error("Notification template has no SMS defined", {
112
- id: notification.id,
113
- template: notification.template
114
- });
115
- throw new alepha.AlephaError(`Notification template ${notification.template} has no sms defined`);
116
- }
117
- this.log.debug("Rendering SMS", {
118
- template: notification.template,
119
- contact
120
- });
121
- return {
122
- to: contact,
123
- message: typeof sms.message === "function" ? sms.message(variables) : sms.message
124
- };
125
- }
126
- renderEmail(notification) {
127
- this.log.trace("Rendering email notification", {
128
- id: notification.id,
129
- template: notification.template
130
- });
131
- const { variables, contact, template } = this.load(notification);
132
- const email = template.options.email;
133
- if (!email) {
134
- this.log.error("Notification template has no email defined", {
135
- id: notification.id,
136
- template: notification.template
137
- });
138
- throw new alepha.AlephaError(`Notification template ${notification.template} has no email defined`);
139
- }
140
- this.log.debug("Rendering email", {
141
- template: notification.template,
142
- contact,
143
- subject: email.subject
144
- });
145
- return {
146
- to: contact,
147
- subject: email.subject,
148
- body: typeof email.body === "function" ? email.body(variables) : email.body
149
- };
150
- }
151
- load(notification) {
152
- const variables = notification.variables || {};
153
- const contact = notification.contact;
154
- const template = this.alepha.descriptors($notification).find((it) => it.name === notification.template);
155
- if (!template) {
156
- this.log.error("Notification template not found", {
157
- id: notification.id,
158
- template: notification.template
159
- });
160
- throw new alepha.AlephaError(`No notification template found for ${notification.template}`);
161
- }
162
- return {
163
- template,
164
- variables,
165
- contact
166
- };
167
- }
168
- };
169
-
170
- //#endregion
171
- //#region src/api-notifications/queues/NotificationQueues.ts
172
- var NotificationQueues = class {
173
- notificationSenderService = (0, alepha.$inject)(NotificationSenderService);
174
- processNotification = (0, alepha_queue.$queue)({
175
- description: "Queue for processing notifications",
176
- schema: alepha.t.object({ notificationId: alepha.t.string({ format: "uuid" }) }),
177
- handler: async (message) => {
178
- await this.notificationSenderService.send(message.payload.notificationId);
179
- }
180
- });
181
- };
182
-
183
- //#endregion
184
- //#region src/api-notifications/schemas/notificationCreateSchema.ts
185
- const notificationCreateSchema = alepha.t.pick(notifications.schema, [
186
- "type",
187
- "contact",
188
- "template",
189
- "variables"
190
- ]);
191
-
192
- //#endregion
193
- //#region src/api-notifications/services/NotificationService.ts
194
- const notificationServiceEnvSchema = alepha.t.object({ NOTIFICATION_QUEUE: alepha.t.optional(alepha.t.boolean({ description: "If true, notifications will be queued instead of sent immediately" })) });
195
- var NotificationService = class {
196
- alepha = (0, alepha.$inject)(alepha.Alepha);
197
- log = (0, alepha_logger.$logger)();
198
- env = (0, alepha.$env)(notificationServiceEnvSchema);
199
- notificationRepository = (0, alepha_orm.$repository)(notifications);
200
- dateTimeProvider = (0, alepha.$inject)(alepha_datetime.DateTimeProvider);
201
- notificationSenderService = (0, alepha.$inject)(NotificationSenderService);
202
- notificationBatch = (0, alepha_batch.$batch)({
203
- maxSize: 100,
204
- maxDuration: [15, "seconds"],
205
- schema: notificationCreateSchema,
206
- handler: async (notifications$1) => {
207
- this.log.debug("Processing notification batch", {
208
- size: notifications$1.length,
209
- templates: [...new Set(notifications$1.map((n) => n.template))]
210
- });
211
- const entities = await this.notificationRepository.createMany(notifications$1);
212
- await this.alepha.inject(NotificationQueues).processNotification.push(...entities.map((it) => ({ notificationId: it.id })));
213
- this.log.info("Notification batch queued", {
214
- count: entities.length,
215
- ids: entities.map((it) => it.id)
216
- });
217
- }
218
- });
219
- async findNotificationById(id) {
220
- this.log.trace("Finding notification by ID", { id });
221
- return this.notificationRepository.findOne({ where: { id } });
222
- }
223
- /**
224
- * Create a new notification.
225
- */
226
- async createNotification(entry) {
227
- this.log.trace("Creating notification", {
228
- template: entry.template,
229
- type: entry.type,
230
- contact: entry.contact
231
- });
232
- if (this.env.NOTIFICATION_QUEUE !== true || this.alepha.isServerless() || this.alepha.isTest()) {
233
- this.log.debug("Sending notification immediately", {
234
- template: entry.template,
235
- type: entry.type,
236
- contact: entry.contact
237
- });
238
- const notification = await this.notificationRepository.create(entry);
239
- await this.notificationSenderService.send(notification);
240
- return;
241
- }
242
- this.log.debug("Queuing notification to batch", {
243
- template: entry.template,
244
- type: entry.type,
245
- contact: entry.contact
246
- });
247
- this.notificationBatch.push(entry).catch((e) => {
248
- this.log.error("Failed to push notification to batch", {
249
- template: entry.template,
250
- type: entry.type,
251
- contact: entry.contact,
252
- error: e
253
- });
254
- });
255
- }
256
- };
257
-
258
- //#endregion
259
- //#region src/api-notifications/descriptors/$notification.ts
260
- /**
261
- * Creates a notification descriptor for managing email/SMS notification templates.
262
- *
263
- * Provides type-safe, reusable notification templates with multi-language support,
264
- * variable substitution, and categorization for different notification channels.
265
- *
266
- * @example
267
- * ```ts
268
- * class NotificationTemplates {
269
- * welcomeEmail = $notification({
270
- * name: "welcome-email",
271
- * category: "onboarding",
272
- * schema: t.object({ username: t.text(), activationLink: t.text() }),
273
- * email: {
274
- * subject: "Welcome to our platform!",
275
- * body: (vars) => `Hello ${vars.username}, click: ${vars.activationLink}`
276
- * }
277
- * });
278
- *
279
- * async sendWelcome(user: User) {
280
- * await this.welcomeEmail.push({
281
- * variables: { username: user.name, activationLink: generateLink() },
282
- * contact: user.email
283
- * });
284
- * }
285
- * }
286
- * ```
287
- */
288
- const $notification = (options) => (0, alepha.createDescriptor)(NotificationDescriptor, options);
289
- var NotificationDescriptor = class extends alepha.Descriptor {
290
- notificationService = (0, alepha.$inject)(NotificationService);
291
- get name() {
292
- return this.options.name ?? `${this.config.propertyKey}`;
293
- }
294
- async push(options) {
295
- if (this.options.email) await this.notificationService.createNotification({
296
- ...options,
297
- type: "email",
298
- template: this.name
299
- });
300
- }
301
- configure(options) {
302
- Object.assign(this.options, options);
303
- }
304
- };
305
- $notification[alepha.KIND] = NotificationDescriptor;
306
-
307
- //#endregion
308
- //#region src/api-notifications/jobs/NotificationJobs.ts
309
- var NotificationJobs = class {};
310
-
311
- //#endregion
312
- //#region src/api-notifications/providers/MemorySmsProvider.ts
313
- var MemorySmsProvider = class extends SmsProvider {
314
- records = [];
315
- async send(options) {
316
- const { to, message } = options;
317
- this.records.push({
318
- to,
319
- message,
320
- sentAt: /* @__PURE__ */ new Date()
321
- });
322
- }
323
- };
324
-
325
- //#endregion
326
- //#region src/api-notifications/schemas/notificationContactPreferencesSchema.ts
327
- const notificationContactPreferencesSchema = alepha.t.object({
328
- language: alepha.t.optional(alepha.t.text()),
329
- exclude: alepha.t.array(alepha.t.text())
330
- });
331
-
332
- //#endregion
333
- //#region src/api-notifications/index.ts
334
- /**
335
- * Provides notification management API endpoints for Alepha applications.
336
- *
337
- * This module includes notification sending, retrieval, status tracking,
338
- * and user notification preferences management.
339
- *
340
- * @module alepha.api.notifications
341
- */
342
- const AlephaApiNotifications = (0, alepha.$module)({
343
- name: "alepha.api.notifications",
344
- descriptors: [$notification],
345
- services: [
346
- NotificationController,
347
- NotificationService,
348
- NotificationSenderService,
349
- NotificationQueues,
350
- NotificationJobs,
351
- SmsProvider,
352
- MemorySmsProvider
353
- ],
354
- register: (alepha$1) => {
355
- alepha$1.with({
356
- optional: true,
357
- provide: SmsProvider,
358
- use: MemorySmsProvider
359
- });
360
- if (alepha$1.parseEnv(notificationServiceEnvSchema).NOTIFICATION_QUEUE) alepha$1.with(NotificationQueues);
361
- alepha$1.with(NotificationController).with(NotificationService).with(NotificationSenderService).with(NotificationJobs);
362
- }
363
- });
364
-
365
- //#endregion
366
- exports.$notification = $notification;
367
- exports.AlephaApiNotifications = AlephaApiNotifications;
368
- exports.MemorySmsProvider = MemorySmsProvider;
369
- exports.NotificationController = NotificationController;
370
- exports.NotificationDescriptor = NotificationDescriptor;
371
- exports.NotificationJobs = NotificationJobs;
372
- exports.NotificationQueues = NotificationQueues;
373
- exports.NotificationSenderService = NotificationSenderService;
374
- exports.NotificationService = NotificationService;
375
- exports.SmsProvider = SmsProvider;
376
- exports.notificationContactPreferencesSchema = notificationContactPreferencesSchema;
377
- exports.notificationCreateSchema = notificationCreateSchema;
378
- exports.notificationServiceEnvSchema = notificationServiceEnvSchema;
379
- exports.notifications = notifications;
380
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["t","pg","Alepha","DateTimeProvider","EmailProvider","AlephaError","t","t","t","Alepha","DateTimeProvider","notifications","Descriptor","KIND","t","alepha"],"sources":["../../src/api-notifications/controllers/NotificationController.ts","../../src/api-notifications/entities/notifications.ts","../../src/api-notifications/providers/SmsProvider.ts","../../src/api-notifications/services/NotificationSenderService.ts","../../src/api-notifications/queues/NotificationQueues.ts","../../src/api-notifications/schemas/notificationCreateSchema.ts","../../src/api-notifications/services/NotificationService.ts","../../src/api-notifications/descriptors/$notification.ts","../../src/api-notifications/jobs/NotificationJobs.ts","../../src/api-notifications/providers/MemorySmsProvider.ts","../../src/api-notifications/schemas/notificationContactPreferencesSchema.ts","../../src/api-notifications/index.ts"],"sourcesContent":["export class NotificationController {}\n","import { type Static, t } from \"alepha\";\nimport { $entity, pg } from \"alepha/orm\";\n\nexport const notifications = $entity({\n name: \"notifications\",\n schema: t.object({\n id: pg.primaryKey(t.uuid()),\n\n version: pg.version(),\n\n createdAt: pg.createdAt(),\n\n updatedAt: pg.updatedAt(),\n\n // -----------------------------------------------------------------------------------------------------------------\n\n type: t.enum([\"email\", \"sms\"]),\n\n template: t.text(), // e.g. 'resetPassword'\n\n category: t.optional(\n t.text({\n description:\n \"For grouping related notifications (e.g., 'authentication', 'marketing'). Contact can filter notifications by category.\",\n }),\n ),\n\n critical: t.optional(\n t.boolean({\n description:\n \"Prioritize delivery of this notification. Set to true for important system alerts.\",\n }),\n ),\n\n sensitive: t.optional(\n t.boolean({\n description:\n \"Message won't be logged or stored in plain text. Set to true when notification contains passwords or codes.\",\n }),\n ),\n\n // -----------------------------------------------------------------------------------------------------------------\n\n contact: t.text(), // e.g. email address or phone number or user ID or whatever\n\n variables: t.optional(t.record(t.text(), t.any())),\n\n scheduledAt: t.optional(\n t.datetime({\n description:\n \"When set, the notification will be sent at or after this date/time.\",\n }),\n ),\n\n // -----------------------------------------------------------------------------------------------------------------\n\n sentAt: t.optional(t.datetime()),\n\n error: t.optional(\n t.object({\n at: t.datetime(),\n name: t.text(),\n message: t.text({ size: \"rich\" }),\n }),\n ),\n\n // TODO: retryCount, lastRetryAt, etc.\n }),\n});\n\nexport type NotificationEntity = Static<typeof notifications.schema>;\n","export abstract class SmsProvider {\n public abstract send(options: SmsSendOptions): Promise<void>;\n}\n\nexport interface SmsSendOptions {\n to: string;\n message: string;\n}\n","import { $inject, Alepha, AlephaError } from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { EmailProvider } from \"alepha/email\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport { $notification } from \"../descriptors/$notification.ts\";\nimport {\n type NotificationEntity,\n notifications,\n} from \"../entities/notifications.ts\";\nimport { SmsProvider } from \"../providers/SmsProvider.ts\";\n\nexport class NotificationSenderService {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly notificationRepository = $repository(notifications);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n protected readonly emailProvider = $inject(EmailProvider);\n protected readonly smsProvider = $inject(SmsProvider);\n\n public async send(notificationId: string | NotificationEntity) {\n this.log.trace(\"Sending notification\", {\n notificationId:\n typeof notificationId === \"string\" ? notificationId : notificationId.id,\n });\n\n const notification =\n typeof notificationId === \"string\"\n ? await this.notificationRepository.findById(notificationId)\n : notificationId;\n\n if (notification.sentAt) {\n this.log.debug(\"Notification already sent\", {\n notificationId: notification.id,\n sentAt: notification.sentAt,\n });\n return;\n }\n\n this.log.debug(\"Processing notification\", {\n id: notification.id,\n type: notification.type,\n template: notification.template,\n contact: notification.contact,\n });\n\n try {\n if (notification.type === \"email\") {\n await this.emailProvider.send(this.renderEmail(notification));\n notification.sentAt = this.dateTimeProvider.nowISOString();\n this.log.info(\"Email notification sent\", {\n id: notification.id,\n template: notification.template,\n contact: notification.contact,\n });\n }\n if (notification.type === \"sms\") {\n await this.smsProvider.send(this.renderSms(notification));\n notification.sentAt = this.dateTimeProvider.nowISOString();\n this.log.info(\"SMS notification sent\", {\n id: notification.id,\n template: notification.template,\n contact: notification.contact,\n });\n }\n } catch (e) {\n this.log.error(\"Failed to send notification\", {\n id: notification.id,\n type: notification.type,\n template: notification.template,\n contact: notification.contact,\n error: e,\n });\n if (e instanceof Error) {\n notification.error = {\n at: this.dateTimeProvider.nowISOString(),\n name: e.name,\n message: e.message,\n };\n }\n } finally {\n await this.notificationRepository.save(notification);\n }\n }\n\n public renderSms(notification: NotificationEntity) {\n this.log.trace(\"Rendering SMS notification\", {\n id: notification.id,\n template: notification.template,\n });\n\n const { variables, contact, template } = this.load(notification);\n\n const sms = template.options.sms;\n if (!sms) {\n this.log.error(\"Notification template has no SMS defined\", {\n id: notification.id,\n template: notification.template,\n });\n throw new AlephaError(\n `Notification template ${notification.template} has no sms defined`,\n );\n }\n\n this.log.debug(\"Rendering SMS\", {\n template: notification.template,\n contact,\n });\n\n const message =\n typeof sms.message === \"function\"\n ? sms.message(variables as any)\n : sms.message;\n\n return {\n to: contact,\n message,\n };\n }\n\n public renderEmail(notification: NotificationEntity) {\n this.log.trace(\"Rendering email notification\", {\n id: notification.id,\n template: notification.template,\n });\n\n const { variables, contact, template } = this.load(notification);\n\n const email = template.options.email;\n if (!email) {\n this.log.error(\"Notification template has no email defined\", {\n id: notification.id,\n template: notification.template,\n });\n throw new AlephaError(\n `Notification template ${notification.template} has no email defined`,\n );\n }\n\n this.log.debug(\"Rendering email\", {\n template: notification.template,\n contact,\n subject: email.subject,\n });\n\n const subject = email.subject;\n\n const body =\n typeof email.body === \"function\"\n ? email.body(variables as any)\n : email.body;\n\n return {\n to: contact,\n subject,\n body,\n };\n }\n\n protected load(notification: NotificationEntity) {\n const variables = notification.variables || {};\n const contact = notification.contact;\n const template = this.alepha\n .descriptors($notification)\n .find((it) => it.name === notification.template);\n\n if (!template) {\n this.log.error(\"Notification template not found\", {\n id: notification.id,\n template: notification.template,\n });\n throw new AlephaError(\n `No notification template found for ${notification.template}`,\n );\n }\n\n return {\n template,\n variables,\n contact,\n };\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $queue } from \"alepha/queue\";\nimport { NotificationSenderService } from \"../services/NotificationSenderService.ts\";\n\nexport class NotificationQueues {\n protected readonly notificationSenderService = $inject(\n NotificationSenderService,\n );\n\n public readonly processNotification = $queue({\n description: \"Queue for processing notifications\",\n schema: t.object({\n notificationId: t.string({ format: \"uuid\" }),\n }),\n handler: async (message) => {\n await this.notificationSenderService.send(message.payload.notificationId);\n },\n });\n}\n","import { type Static, t } from \"alepha\";\nimport { notifications } from \"../entities/notifications.ts\";\n\nexport const notificationCreateSchema = t.pick(notifications.schema, [\n \"type\",\n \"contact\",\n \"template\",\n \"variables\",\n]);\n\nexport type NotificationCreate = Static<typeof notificationCreateSchema>;\n","import { $env, $inject, Alepha, type Static, t } from \"alepha\";\nimport { $batch } from \"alepha/batch\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport { notifications } from \"../entities/notifications.ts\";\nimport { NotificationQueues } from \"../queues/NotificationQueues.ts\";\nimport {\n type NotificationCreate,\n notificationCreateSchema,\n} from \"../schemas/notificationCreateSchema.ts\";\nimport { NotificationSenderService } from \"./NotificationSenderService.ts\";\n\nexport const notificationServiceEnvSchema = t.object({\n NOTIFICATION_QUEUE: t.optional(\n t.boolean({\n description:\n \"If true, notifications will be queued instead of sent immediately\",\n }),\n ),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof notificationServiceEnvSchema>> {}\n}\n\nexport class NotificationService {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly env = $env(notificationServiceEnvSchema);\n protected readonly notificationRepository = $repository(notifications);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n protected readonly notificationSenderService = $inject(\n NotificationSenderService,\n );\n\n public readonly notificationBatch = $batch({\n maxSize: 100,\n maxDuration: [15, \"seconds\"],\n schema: notificationCreateSchema,\n handler: async (notifications: NotificationCreate[]) => {\n this.log.debug(\"Processing notification batch\", {\n size: notifications.length,\n templates: [...new Set(notifications.map((n) => n.template))],\n });\n\n const entities =\n await this.notificationRepository.createMany(notifications);\n\n await this.alepha\n .inject(NotificationQueues)\n .processNotification.push(\n ...entities.map((it) => ({ notificationId: it.id })),\n );\n\n this.log.info(\"Notification batch queued\", {\n count: entities.length,\n ids: entities.map((it) => it.id),\n });\n },\n });\n\n public async findNotificationById(id: string) {\n this.log.trace(\"Finding notification by ID\", { id });\n return this.notificationRepository.findOne({ where: { id } });\n }\n\n /**\n * Create a new notification.\n */\n public async createNotification(entry: NotificationCreate): Promise<void> {\n this.log.trace(\"Creating notification\", {\n template: entry.template,\n type: entry.type,\n contact: entry.contact,\n });\n\n if (\n this.env.NOTIFICATION_QUEUE !== true ||\n this.alepha.isServerless() ||\n this.alepha.isTest()\n ) {\n this.log.debug(\"Sending notification immediately\", {\n template: entry.template,\n type: entry.type,\n contact: entry.contact,\n });\n const notification = await this.notificationRepository.create(entry);\n await this.notificationSenderService.send(notification);\n return;\n }\n\n this.log.debug(\"Queuing notification to batch\", {\n template: entry.template,\n type: entry.type,\n contact: entry.contact,\n });\n\n this.notificationBatch.push(entry).catch((e) => {\n this.log.error(\"Failed to push notification to batch\", {\n template: entry.template,\n type: entry.type,\n contact: entry.contact,\n error: e,\n });\n });\n }\n}\n","import {\n $inject,\n createDescriptor,\n Descriptor,\n KIND,\n type Static,\n type StaticEncode,\n type TObject,\n} from \"alepha\";\nimport { NotificationService } from \"../services/NotificationService.ts\";\n\n/**\n * Creates a notification descriptor for managing email/SMS notification templates.\n *\n * Provides type-safe, reusable notification templates with multi-language support,\n * variable substitution, and categorization for different notification channels.\n *\n * @example\n * ```ts\n * class NotificationTemplates {\n * welcomeEmail = $notification({\n * name: \"welcome-email\",\n * category: \"onboarding\",\n * schema: t.object({ username: t.text(), activationLink: t.text() }),\n * email: {\n * subject: \"Welcome to our platform!\",\n * body: (vars) => `Hello ${vars.username}, click: ${vars.activationLink}`\n * }\n * });\n *\n * async sendWelcome(user: User) {\n * await this.welcomeEmail.push({\n * variables: { username: user.name, activationLink: generateLink() },\n * contact: user.email\n * });\n * }\n * }\n * ```\n */\nexport const $notification = <T extends TObject>(\n options: NotificationDescriptorOptions<T>,\n) => createDescriptor(NotificationDescriptor<T>, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface NotificationDescriptorOptions<T extends TObject>\n extends NotificationMessage<T> {\n name?: string;\n description?: string;\n category?: string;\n critical?: boolean;\n sensitive?: boolean;\n translations?: {\n // e.g., \"en\", \"fr\", even \"en-US\"\n [lang: string]: NotificationMessage<T>;\n };\n schema: T;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class NotificationDescriptor<T extends TObject> extends Descriptor<\n NotificationDescriptorOptions<T>\n> {\n protected readonly notificationService = $inject(NotificationService);\n\n public get name() {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n public async push(options: NotificationPushOptions<T>) {\n if (this.options.email) {\n await this.notificationService.createNotification({\n ...options,\n type: \"email\",\n template: this.name,\n });\n }\n }\n\n public configure(options: Partial<NotificationDescriptorOptions<T>>) {\n Object.assign(this.options, options);\n }\n}\n\n$notification[KIND] = NotificationDescriptor;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface NotificationPushOptions<T extends TObject> {\n variables: StaticEncode<T>;\n contact: string;\n}\n\nexport interface NotificationMessage<T extends TObject> {\n email?: {\n subject: string;\n body: string | ((variables: Static<T>) => string);\n };\n sms?: {\n message: string | ((variables: Static<T>) => string);\n };\n}\n","export class NotificationJobs {\n // - retry (lost, failed) notifications\n // - purge old notifications\n}\n","import { SmsProvider, type SmsSendOptions } from \"./SmsProvider.ts\";\n\nexport interface SmsRecord {\n to: string;\n message: string;\n sentAt: Date;\n}\n\nexport class MemorySmsProvider extends SmsProvider {\n protected records: SmsRecord[] = [];\n\n public async send(options: SmsSendOptions): Promise<void> {\n const { to, message } = options;\n this.records.push({\n to,\n message,\n sentAt: new Date(),\n });\n }\n}\n","import { type Static, t } from \"alepha\";\n\nexport const notificationContactPreferencesSchema = t.object({\n language: t.optional(t.text()),\n exclude: t.array(t.text()),\n});\n\nexport type NotificationContactPreferences = Static<\n typeof notificationContactPreferencesSchema\n>;\n","import { $module } from \"alepha\";\nimport { NotificationController } from \"./controllers/NotificationController.ts\";\nimport { $notification } from \"./descriptors/$notification.ts\";\nimport { NotificationJobs } from \"./jobs/NotificationJobs.ts\";\nimport { MemorySmsProvider } from \"./providers/MemorySmsProvider.ts\";\nimport { SmsProvider } from \"./providers/SmsProvider.ts\";\nimport { NotificationQueues } from \"./queues/NotificationQueues.ts\";\nimport { NotificationSenderService } from \"./services/NotificationSenderService.ts\";\nimport {\n NotificationService,\n notificationServiceEnvSchema,\n} from \"./services/NotificationService.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./controllers/NotificationController.ts\";\nexport * from \"./descriptors/$notification.ts\";\nexport * from \"./entities/notifications.ts\";\nexport * from \"./jobs/NotificationJobs.ts\";\nexport * from \"./providers/MemorySmsProvider.ts\";\nexport * from \"./providers/SmsProvider.ts\";\nexport * from \"./queues/NotificationQueues.ts\";\nexport * from \"./schemas/notificationContactPreferencesSchema.ts\";\nexport * from \"./schemas/notificationCreateSchema.ts\";\nexport * from \"./services/NotificationSenderService.ts\";\nexport * from \"./services/NotificationService.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides notification management API endpoints for Alepha applications.\n *\n * This module includes notification sending, retrieval, status tracking,\n * and user notification preferences management.\n *\n * @module alepha.api.notifications\n */\nexport const AlephaApiNotifications = $module({\n name: \"alepha.api.notifications\",\n descriptors: [$notification],\n services: [\n NotificationController,\n NotificationService,\n NotificationSenderService,\n NotificationQueues,\n NotificationJobs,\n SmsProvider,\n MemorySmsProvider,\n ],\n register: (alepha) => {\n alepha.with({\n optional: true,\n provide: SmsProvider,\n use: MemorySmsProvider,\n });\n\n const env = alepha.parseEnv(notificationServiceEnvSchema);\n if (env.NOTIFICATION_QUEUE) {\n alepha.with(NotificationQueues);\n }\n\n alepha\n .with(NotificationController)\n .with(NotificationService)\n .with(NotificationSenderService)\n .with(NotificationJobs);\n },\n});\n"],"mappings":"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"}