@vynelix/vynemit-core 1.0.0 → 1.0.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.
- package/README.md +11 -11
- package/dist/index.d.mts +208 -0
- package/dist/index.d.ts +208 -0
- package/dist/index.js +227 -1
- package/dist/index.mjs +227 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,6 +29,10 @@ module.exports = __toCommonJS(src_exports);
|
|
|
29
29
|
|
|
30
30
|
// src/notification_center.ts
|
|
31
31
|
var NotificationCenter = class {
|
|
32
|
+
/**
|
|
33
|
+
* Initializes a new NotificationCenter with the provided configuration.
|
|
34
|
+
* @param config - The configuration options including adapters and transports.
|
|
35
|
+
*/
|
|
32
36
|
constructor(config) {
|
|
33
37
|
this.config = config;
|
|
34
38
|
this.storage = config.storage;
|
|
@@ -45,6 +49,13 @@ var NotificationCenter = class {
|
|
|
45
49
|
this.isRunning = false;
|
|
46
50
|
}
|
|
47
51
|
// ========== DISPATCH ==========
|
|
52
|
+
/**
|
|
53
|
+
* Dispatches a single notification based on the provided input.
|
|
54
|
+
* If a queue is configured, the delivery takes place asynchronously.
|
|
55
|
+
*
|
|
56
|
+
* @param input - The notification payload and routing instructions.
|
|
57
|
+
* @returns A promise that resolves to the processed Notification object.
|
|
58
|
+
*/
|
|
48
59
|
async send(input) {
|
|
49
60
|
let notification = this.buildNotification(input);
|
|
50
61
|
notification = await this.applyBeforeSendMiddleware(notification);
|
|
@@ -74,12 +85,25 @@ var NotificationCenter = class {
|
|
|
74
85
|
throw error;
|
|
75
86
|
}
|
|
76
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Dispatches an array of notifications sequentially or concurrently.
|
|
90
|
+
*
|
|
91
|
+
* @param inputs - An array of notification inputs.
|
|
92
|
+
* @returns A promise resolving to an array of generated Notification objects.
|
|
93
|
+
*/
|
|
77
94
|
async sendBatch(inputs) {
|
|
78
95
|
const notifications = await Promise.all(
|
|
79
96
|
inputs.map((input) => this.send(input))
|
|
80
97
|
);
|
|
81
98
|
return notifications;
|
|
82
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Sends an identical notification to a list of users (multicast).
|
|
102
|
+
* Automatically optimizes push/sms transport delivery if transport supports bulk send.
|
|
103
|
+
*
|
|
104
|
+
* @param input - Multicast payload including the target `userIds`.
|
|
105
|
+
* @returns A promise resolving to the dispatched notifications.
|
|
106
|
+
*/
|
|
83
107
|
async sendMulticast(input) {
|
|
84
108
|
const notifications = await Promise.all(input.userIds.map(async (userId) => {
|
|
85
109
|
const notificationInput = { ...input, userId };
|
|
@@ -114,15 +138,56 @@ var NotificationCenter = class {
|
|
|
114
138
|
await Promise.all(receipts.map((r) => this.storage.saveReceipt(r)));
|
|
115
139
|
}
|
|
116
140
|
} else {
|
|
117
|
-
await Promise.all(validNotifications.map((n) =>
|
|
141
|
+
await Promise.all(validNotifications.map(async (n) => {
|
|
142
|
+
const prefs = await this.storage.getPreferences(n.userId);
|
|
143
|
+
if (transport.canSend(n, prefs)) {
|
|
144
|
+
try {
|
|
145
|
+
const receipt = await transport.send(n, prefs);
|
|
146
|
+
if (this.storage.saveReceipt)
|
|
147
|
+
await this.storage.saveReceipt(receipt);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const receipt = {
|
|
150
|
+
notificationId: n.id,
|
|
151
|
+
channel,
|
|
152
|
+
status: "failed",
|
|
153
|
+
attempts: 1,
|
|
154
|
+
lastAttempt: /* @__PURE__ */ new Date(),
|
|
155
|
+
error: error.message
|
|
156
|
+
};
|
|
157
|
+
if (this.storage.saveReceipt)
|
|
158
|
+
await this.storage.saveReceipt(receipt);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}));
|
|
118
162
|
}
|
|
119
163
|
} catch (error) {
|
|
120
164
|
console.error(`Multicast failed for channel ${channel}:`, error);
|
|
121
165
|
await Promise.all(validNotifications.map((n) => this.applyErrorMiddleware(error, n)));
|
|
122
166
|
}
|
|
123
167
|
}
|
|
168
|
+
await Promise.all(validNotifications.map(async (notification) => {
|
|
169
|
+
notification.status = "sent";
|
|
170
|
+
await this.applyAfterSendMiddleware(notification);
|
|
171
|
+
if (notification.channels.includes("inapp") || channels.includes("inapp")) {
|
|
172
|
+
this.notifySubscribers(notification);
|
|
173
|
+
}
|
|
174
|
+
this.notifyEventSubscribers({
|
|
175
|
+
type: "sent",
|
|
176
|
+
notification,
|
|
177
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
178
|
+
});
|
|
179
|
+
await this.storage.save(notification);
|
|
180
|
+
}));
|
|
124
181
|
return validNotifications;
|
|
125
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Schedules a notification to be sent at a specific future date/time.
|
|
185
|
+
* Automatically enqueues it if the queue adapter supports delayed jobs.
|
|
186
|
+
*
|
|
187
|
+
* @param input - The notification input.
|
|
188
|
+
* @param when - The Date at which the notification should be delivered.
|
|
189
|
+
* @returns A promise resolving to the generated Notification ID.
|
|
190
|
+
*/
|
|
126
191
|
async schedule(input, when) {
|
|
127
192
|
let notification = this.buildNotification({ ...input, scheduledFor: when });
|
|
128
193
|
let _notification = await this.applyBeforeSendMiddleware(notification);
|
|
@@ -141,15 +206,40 @@ var NotificationCenter = class {
|
|
|
141
206
|
return _notification.id;
|
|
142
207
|
}
|
|
143
208
|
// ========== QUERYING ==========
|
|
209
|
+
/**
|
|
210
|
+
* Retrieves notifications intended for a specific user ID.
|
|
211
|
+
*
|
|
212
|
+
* @param userId - The target user's ID.
|
|
213
|
+
* @param filters - Optional filters like status, type, limit, offset.
|
|
214
|
+
* @returns A promise resolving to the list of matched notifications.
|
|
215
|
+
*/
|
|
144
216
|
async getForUser(userId, filters) {
|
|
145
217
|
return this.storage.findByUser(userId, filters);
|
|
146
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Retrieves the current number of unread notifications for a specified user.
|
|
221
|
+
*
|
|
222
|
+
* @param userId - The target user's ID.
|
|
223
|
+
* @returns The count of unread notifications.
|
|
224
|
+
*/
|
|
147
225
|
async getUnreadCount(userId) {
|
|
148
226
|
return this.storage.countUnread(userId);
|
|
149
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Retrieves a specific notification by its unique ID.
|
|
230
|
+
*
|
|
231
|
+
* @param id - The Notification ID.
|
|
232
|
+
* @returns The notification object if found, otherwise null.
|
|
233
|
+
*/
|
|
150
234
|
async getById(id) {
|
|
151
235
|
return this.storage.findById(id);
|
|
152
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Aggregates notification statistics for a specified user (e.g., total, unread, counts by channel).
|
|
239
|
+
*
|
|
240
|
+
* @param userId - The user's ID to fetch stats for.
|
|
241
|
+
* @returns An object containing grouped statistics.
|
|
242
|
+
*/
|
|
153
243
|
async getStats(userId) {
|
|
154
244
|
const all = await this.storage.findByUser(userId, {});
|
|
155
245
|
const unread = await this.storage.countUnread(userId);
|
|
@@ -170,6 +260,11 @@ var NotificationCenter = class {
|
|
|
170
260
|
return stats;
|
|
171
261
|
}
|
|
172
262
|
// ========== STATE MANAGEMENT ==========
|
|
263
|
+
/**
|
|
264
|
+
* Marks a specific notification as "read" and triggers real-time updates for listeners.
|
|
265
|
+
*
|
|
266
|
+
* @param notificationId - The unique ID of the notification.
|
|
267
|
+
*/
|
|
173
268
|
async markAsRead(notificationId) {
|
|
174
269
|
await this.storage.markAsRead(notificationId);
|
|
175
270
|
const notification = await this.storage.findById(notificationId);
|
|
@@ -183,10 +278,20 @@ var NotificationCenter = class {
|
|
|
183
278
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
184
279
|
}
|
|
185
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Marks all notifications belonging to a user as "read".
|
|
283
|
+
*
|
|
284
|
+
* @param userId - The user's ID.
|
|
285
|
+
*/
|
|
186
286
|
async markAllAsRead(userId) {
|
|
187
287
|
await this.storage.markAllAsRead(userId);
|
|
188
288
|
this.notifyUnreadSubscribers(userId, 0);
|
|
189
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Reverts a notification status back to "unread".
|
|
292
|
+
*
|
|
293
|
+
* @param notificationId - The unique ID of the notification.
|
|
294
|
+
*/
|
|
190
295
|
async markAsUnread(notificationId) {
|
|
191
296
|
await this.storage.markAsUnread(notificationId);
|
|
192
297
|
const notification = await this.storage.findById(notificationId);
|
|
@@ -200,10 +305,20 @@ var NotificationCenter = class {
|
|
|
200
305
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
201
306
|
}
|
|
202
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Marks all notifications belonging to a user as "unread".
|
|
310
|
+
*
|
|
311
|
+
* @param userId - The target user's ID.
|
|
312
|
+
*/
|
|
203
313
|
async markAllAsUnread(userId) {
|
|
204
314
|
await this.storage.markAllAsUnread(userId);
|
|
205
315
|
this.notifyUnreadSubscribers(userId, 0);
|
|
206
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* Deletes a specific notification from storage.
|
|
319
|
+
*
|
|
320
|
+
* @param notificationId - The Notification ID to delete.
|
|
321
|
+
*/
|
|
207
322
|
async delete(notificationId) {
|
|
208
323
|
const notification = await this.storage.findById(notificationId);
|
|
209
324
|
await this.storage.delete(notificationId);
|
|
@@ -212,6 +327,11 @@ var NotificationCenter = class {
|
|
|
212
327
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
213
328
|
}
|
|
214
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Deletes all notifications for a specific user.
|
|
332
|
+
*
|
|
333
|
+
* @param userId - The user's ID.
|
|
334
|
+
*/
|
|
215
335
|
async deleteAll(userId) {
|
|
216
336
|
const notifications = await this.storage.findByUser(userId, {});
|
|
217
337
|
await Promise.all(
|
|
@@ -220,9 +340,21 @@ var NotificationCenter = class {
|
|
|
220
340
|
this.notifyUnreadSubscribers(userId, 0);
|
|
221
341
|
}
|
|
222
342
|
// ========== PREFERENCES ==========
|
|
343
|
+
/**
|
|
344
|
+
* Retrieves the notification opt-in/opt-out routing preferences for a given user.
|
|
345
|
+
*
|
|
346
|
+
* @param userId - The user's ID.
|
|
347
|
+
* @returns A promise resolving to the user's NotificationPreferences.
|
|
348
|
+
*/
|
|
223
349
|
async getPreferences(userId) {
|
|
224
350
|
return this.storage.getPreferences(userId);
|
|
225
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Updates the notification routing and delivery preferences for an user.
|
|
354
|
+
*
|
|
355
|
+
* @param userId - The user's ID.
|
|
356
|
+
* @param prefs - A partial object containing the updated preferences.
|
|
357
|
+
*/
|
|
226
358
|
async updatePreferences(userId, prefs) {
|
|
227
359
|
const current = await this.storage.getPreferences(userId);
|
|
228
360
|
const updated = {
|
|
@@ -234,16 +366,38 @@ var NotificationCenter = class {
|
|
|
234
366
|
await this.storage.savePreferences(userId, updated);
|
|
235
367
|
}
|
|
236
368
|
// ========== TEMPLATES ==========
|
|
369
|
+
/**
|
|
370
|
+
* Registers a notification template, mapping a named key to dynamic defaults/formatting.
|
|
371
|
+
*
|
|
372
|
+
* @param template - The NotificationTemplate definitions.
|
|
373
|
+
*/
|
|
237
374
|
registerTemplate(template) {
|
|
238
375
|
this.templates.set(template.id, template);
|
|
239
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Looks up a registered template by its ID.
|
|
379
|
+
*
|
|
380
|
+
* @param id - The ID of the template.
|
|
381
|
+
* @returns The template object, or undefined if not found.
|
|
382
|
+
*/
|
|
240
383
|
getTemplate(id) {
|
|
241
384
|
return this.templates.get(id);
|
|
242
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Unregisters a template from the NotificationCenter.
|
|
388
|
+
*
|
|
389
|
+
* @param id - The template ID to remove.
|
|
390
|
+
*/
|
|
243
391
|
unregisterTemplate(id) {
|
|
244
392
|
this.templates.delete(id);
|
|
245
393
|
}
|
|
246
394
|
// ========== DIGEST ==========
|
|
395
|
+
/**
|
|
396
|
+
* Enables batch notification "digests" for a specific user to prevent notification fatigue.
|
|
397
|
+
*
|
|
398
|
+
* @param userId - The user's ID.
|
|
399
|
+
* @param config - The timeframe and configuration for the user's digest.
|
|
400
|
+
*/
|
|
247
401
|
async enableDigest(userId, config) {
|
|
248
402
|
const prefs = await this.getPreferences(userId);
|
|
249
403
|
await this.updatePreferences(userId, {
|
|
@@ -254,6 +408,11 @@ var NotificationCenter = class {
|
|
|
254
408
|
}
|
|
255
409
|
});
|
|
256
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Disables the digest feature for a user, reverting to immediate delivery.
|
|
413
|
+
*
|
|
414
|
+
* @param userId - The target user's ID.
|
|
415
|
+
*/
|
|
257
416
|
async disableDigest(userId) {
|
|
258
417
|
const prefs = await this.getPreferences(userId);
|
|
259
418
|
const newData = { ...prefs.data || {} };
|
|
@@ -263,17 +422,36 @@ var NotificationCenter = class {
|
|
|
263
422
|
data: newData
|
|
264
423
|
});
|
|
265
424
|
}
|
|
425
|
+
/**
|
|
426
|
+
* Fetches the current digest rules configured for a user.
|
|
427
|
+
*
|
|
428
|
+
* @param userId - The user's ID.
|
|
429
|
+
* @returns The digest configuration, or null if disabled.
|
|
430
|
+
*/
|
|
266
431
|
async getDigestConfig(userId) {
|
|
267
432
|
const prefs = await this.getPreferences(userId);
|
|
268
433
|
return prefs.data?.digestConfig || null;
|
|
269
434
|
}
|
|
270
435
|
// ========== DELIVERY STATUS ==========
|
|
436
|
+
/**
|
|
437
|
+
* Retrieves all delivery receipts generated from transports for a specific notification.
|
|
438
|
+
* Useful to see which channels succeeded and which failed.
|
|
439
|
+
*
|
|
440
|
+
* @param notificationId - The notification's ID.
|
|
441
|
+
* @returns An array of delivery receipts.
|
|
442
|
+
*/
|
|
271
443
|
async getDeliveryStatus(notificationId) {
|
|
272
444
|
if (!this.storage.getReceipts) {
|
|
273
445
|
return [];
|
|
274
446
|
}
|
|
275
447
|
return this.storage.getReceipts(notificationId);
|
|
276
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Attempts to resend a notification for any channels that previously marked it as "failed".
|
|
451
|
+
*
|
|
452
|
+
* @param notificationId - The target notification ID.
|
|
453
|
+
* @param channel - Optional channel scope. If provided, retries only on this specific transport.
|
|
454
|
+
*/
|
|
277
455
|
async retryFailed(notificationId, channel) {
|
|
278
456
|
const notification = await this.storage.findById(notificationId);
|
|
279
457
|
if (!notification) {
|
|
@@ -292,6 +470,13 @@ var NotificationCenter = class {
|
|
|
292
470
|
}
|
|
293
471
|
}
|
|
294
472
|
// ========== SUBSCRIPTIONS (Reactive) ==========
|
|
473
|
+
/**
|
|
474
|
+
* Registers a callback to be invoked whenever a notification is sent to a specific user.
|
|
475
|
+
*
|
|
476
|
+
* @param userId - The target user's ID.
|
|
477
|
+
* @param callback - Function to handle the raw notification map.
|
|
478
|
+
* @returns A cleanup function to unsubscribe from this event.
|
|
479
|
+
*/
|
|
295
480
|
subscribe(userId, callback) {
|
|
296
481
|
const sid = String(userId);
|
|
297
482
|
if (!this.subscribers.has(sid)) {
|
|
@@ -308,6 +493,13 @@ var NotificationCenter = class {
|
|
|
308
493
|
}
|
|
309
494
|
};
|
|
310
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Registers a callback for state changes (e.g. read/unread status updates) for a user's notifications.
|
|
498
|
+
*
|
|
499
|
+
* @param userId - The target user's ID.
|
|
500
|
+
* @param callback - Lifecycle event listener.
|
|
501
|
+
* @returns A cleanup function to unsubscribe.
|
|
502
|
+
*/
|
|
311
503
|
subscribeToEvents(userId, callback) {
|
|
312
504
|
const sid = String(userId);
|
|
313
505
|
if (!this.eventSubscribers.has(sid)) {
|
|
@@ -324,6 +516,13 @@ var NotificationCenter = class {
|
|
|
324
516
|
}
|
|
325
517
|
};
|
|
326
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Registers a listener to react to changes in the unread notification count for a user.
|
|
521
|
+
*
|
|
522
|
+
* @param userId - The user's ID.
|
|
523
|
+
* @param callback - Handlers receiving the current unread count.
|
|
524
|
+
* @returns Unsubscribe function.
|
|
525
|
+
*/
|
|
327
526
|
onUnreadCountChange(userId, callback) {
|
|
328
527
|
const sid = String(userId);
|
|
329
528
|
if (!this.unreadSubscribers.has(sid)) {
|
|
@@ -341,13 +540,26 @@ var NotificationCenter = class {
|
|
|
341
540
|
};
|
|
342
541
|
}
|
|
343
542
|
// ========== MIDDLEWARE ==========
|
|
543
|
+
/**
|
|
544
|
+
* Injects a middleware interceptor to apply custom logic before or after notifications are sent.
|
|
545
|
+
*
|
|
546
|
+
* @param middleware - The middleware object conforming to `NotificationMiddleware`.
|
|
547
|
+
*/
|
|
344
548
|
use(middleware) {
|
|
345
549
|
this.middleware.push(middleware);
|
|
346
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Removes a previously configured middleware globally.
|
|
553
|
+
*
|
|
554
|
+
* @param name - The name identifier of the middleware to remove.
|
|
555
|
+
*/
|
|
347
556
|
removeMiddleware(name) {
|
|
348
557
|
this.middleware = this.middleware.filter((m) => m.name !== name);
|
|
349
558
|
}
|
|
350
559
|
// ========== LIFECYCLE ==========
|
|
560
|
+
/**
|
|
561
|
+
* Boots up the NotificationCenter, initializing storage, queues, and worker loops if enabled.
|
|
562
|
+
*/
|
|
351
563
|
async start() {
|
|
352
564
|
if (this.isRunning) {
|
|
353
565
|
return;
|
|
@@ -366,6 +578,9 @@ var NotificationCenter = class {
|
|
|
366
578
|
this.startCleanup();
|
|
367
579
|
}
|
|
368
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Gracefully shuts down the NotificationCenter, terminating background queues and workers.
|
|
583
|
+
*/
|
|
369
584
|
async stop() {
|
|
370
585
|
if (!this.isRunning) {
|
|
371
586
|
return;
|
|
@@ -379,6 +594,11 @@ var NotificationCenter = class {
|
|
|
379
594
|
await this.queue.stop();
|
|
380
595
|
}
|
|
381
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* Pings all registered transports to report on their current health and active status.
|
|
599
|
+
*
|
|
600
|
+
* @returns A map representing the readiness boolean state of each registered transport.
|
|
601
|
+
*/
|
|
382
602
|
async healthCheck() {
|
|
383
603
|
const results = {};
|
|
384
604
|
for (const [name, transport] of this.transports) {
|
|
@@ -395,6 +615,9 @@ var NotificationCenter = class {
|
|
|
395
615
|
return results;
|
|
396
616
|
}
|
|
397
617
|
// ========== PRIVATE METHODS ==========
|
|
618
|
+
/**
|
|
619
|
+
* Applies metadata, templates, and defaults to construct the internal Notification shape.
|
|
620
|
+
*/
|
|
398
621
|
buildNotification(input) {
|
|
399
622
|
const allChannels = Array.from(this.transports.keys());
|
|
400
623
|
if (input.template) {
|
|
@@ -450,6 +673,9 @@ var NotificationCenter = class {
|
|
|
450
673
|
actions: input.actions
|
|
451
674
|
};
|
|
452
675
|
}
|
|
676
|
+
/**
|
|
677
|
+
* Internal mechanism sending payload out across desired transports without queue delay.
|
|
678
|
+
*/
|
|
453
679
|
async sendNow(notification) {
|
|
454
680
|
const prefs = await this.getPreferences(notification.userId);
|
|
455
681
|
const receipts = await Promise.all(
|