@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.mjs
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// src/notification_center.ts
|
|
2
2
|
var NotificationCenter = class {
|
|
3
|
+
/**
|
|
4
|
+
* Initializes a new NotificationCenter with the provided configuration.
|
|
5
|
+
* @param config - The configuration options including adapters and transports.
|
|
6
|
+
*/
|
|
3
7
|
constructor(config) {
|
|
4
8
|
this.config = config;
|
|
5
9
|
this.storage = config.storage;
|
|
@@ -16,6 +20,13 @@ var NotificationCenter = class {
|
|
|
16
20
|
this.isRunning = false;
|
|
17
21
|
}
|
|
18
22
|
// ========== DISPATCH ==========
|
|
23
|
+
/**
|
|
24
|
+
* Dispatches a single notification based on the provided input.
|
|
25
|
+
* If a queue is configured, the delivery takes place asynchronously.
|
|
26
|
+
*
|
|
27
|
+
* @param input - The notification payload and routing instructions.
|
|
28
|
+
* @returns A promise that resolves to the processed Notification object.
|
|
29
|
+
*/
|
|
19
30
|
async send(input) {
|
|
20
31
|
let notification = this.buildNotification(input);
|
|
21
32
|
notification = await this.applyBeforeSendMiddleware(notification);
|
|
@@ -45,12 +56,25 @@ var NotificationCenter = class {
|
|
|
45
56
|
throw error;
|
|
46
57
|
}
|
|
47
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Dispatches an array of notifications sequentially or concurrently.
|
|
61
|
+
*
|
|
62
|
+
* @param inputs - An array of notification inputs.
|
|
63
|
+
* @returns A promise resolving to an array of generated Notification objects.
|
|
64
|
+
*/
|
|
48
65
|
async sendBatch(inputs) {
|
|
49
66
|
const notifications = await Promise.all(
|
|
50
67
|
inputs.map((input) => this.send(input))
|
|
51
68
|
);
|
|
52
69
|
return notifications;
|
|
53
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Sends an identical notification to a list of users (multicast).
|
|
73
|
+
* Automatically optimizes push/sms transport delivery if transport supports bulk send.
|
|
74
|
+
*
|
|
75
|
+
* @param input - Multicast payload including the target `userIds`.
|
|
76
|
+
* @returns A promise resolving to the dispatched notifications.
|
|
77
|
+
*/
|
|
54
78
|
async sendMulticast(input) {
|
|
55
79
|
const notifications = await Promise.all(input.userIds.map(async (userId) => {
|
|
56
80
|
const notificationInput = { ...input, userId };
|
|
@@ -85,15 +109,56 @@ var NotificationCenter = class {
|
|
|
85
109
|
await Promise.all(receipts.map((r) => this.storage.saveReceipt(r)));
|
|
86
110
|
}
|
|
87
111
|
} else {
|
|
88
|
-
await Promise.all(validNotifications.map((n) =>
|
|
112
|
+
await Promise.all(validNotifications.map(async (n) => {
|
|
113
|
+
const prefs = await this.storage.getPreferences(n.userId);
|
|
114
|
+
if (transport.canSend(n, prefs)) {
|
|
115
|
+
try {
|
|
116
|
+
const receipt = await transport.send(n, prefs);
|
|
117
|
+
if (this.storage.saveReceipt)
|
|
118
|
+
await this.storage.saveReceipt(receipt);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
const receipt = {
|
|
121
|
+
notificationId: n.id,
|
|
122
|
+
channel,
|
|
123
|
+
status: "failed",
|
|
124
|
+
attempts: 1,
|
|
125
|
+
lastAttempt: /* @__PURE__ */ new Date(),
|
|
126
|
+
error: error.message
|
|
127
|
+
};
|
|
128
|
+
if (this.storage.saveReceipt)
|
|
129
|
+
await this.storage.saveReceipt(receipt);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
89
133
|
}
|
|
90
134
|
} catch (error) {
|
|
91
135
|
console.error(`Multicast failed for channel ${channel}:`, error);
|
|
92
136
|
await Promise.all(validNotifications.map((n) => this.applyErrorMiddleware(error, n)));
|
|
93
137
|
}
|
|
94
138
|
}
|
|
139
|
+
await Promise.all(validNotifications.map(async (notification) => {
|
|
140
|
+
notification.status = "sent";
|
|
141
|
+
await this.applyAfterSendMiddleware(notification);
|
|
142
|
+
if (notification.channels.includes("inapp") || channels.includes("inapp")) {
|
|
143
|
+
this.notifySubscribers(notification);
|
|
144
|
+
}
|
|
145
|
+
this.notifyEventSubscribers({
|
|
146
|
+
type: "sent",
|
|
147
|
+
notification,
|
|
148
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
149
|
+
});
|
|
150
|
+
await this.storage.save(notification);
|
|
151
|
+
}));
|
|
95
152
|
return validNotifications;
|
|
96
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Schedules a notification to be sent at a specific future date/time.
|
|
156
|
+
* Automatically enqueues it if the queue adapter supports delayed jobs.
|
|
157
|
+
*
|
|
158
|
+
* @param input - The notification input.
|
|
159
|
+
* @param when - The Date at which the notification should be delivered.
|
|
160
|
+
* @returns A promise resolving to the generated Notification ID.
|
|
161
|
+
*/
|
|
97
162
|
async schedule(input, when) {
|
|
98
163
|
let notification = this.buildNotification({ ...input, scheduledFor: when });
|
|
99
164
|
let _notification = await this.applyBeforeSendMiddleware(notification);
|
|
@@ -112,15 +177,40 @@ var NotificationCenter = class {
|
|
|
112
177
|
return _notification.id;
|
|
113
178
|
}
|
|
114
179
|
// ========== QUERYING ==========
|
|
180
|
+
/**
|
|
181
|
+
* Retrieves notifications intended for a specific user ID.
|
|
182
|
+
*
|
|
183
|
+
* @param userId - The target user's ID.
|
|
184
|
+
* @param filters - Optional filters like status, type, limit, offset.
|
|
185
|
+
* @returns A promise resolving to the list of matched notifications.
|
|
186
|
+
*/
|
|
115
187
|
async getForUser(userId, filters) {
|
|
116
188
|
return this.storage.findByUser(userId, filters);
|
|
117
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Retrieves the current number of unread notifications for a specified user.
|
|
192
|
+
*
|
|
193
|
+
* @param userId - The target user's ID.
|
|
194
|
+
* @returns The count of unread notifications.
|
|
195
|
+
*/
|
|
118
196
|
async getUnreadCount(userId) {
|
|
119
197
|
return this.storage.countUnread(userId);
|
|
120
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Retrieves a specific notification by its unique ID.
|
|
201
|
+
*
|
|
202
|
+
* @param id - The Notification ID.
|
|
203
|
+
* @returns The notification object if found, otherwise null.
|
|
204
|
+
*/
|
|
121
205
|
async getById(id) {
|
|
122
206
|
return this.storage.findById(id);
|
|
123
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Aggregates notification statistics for a specified user (e.g., total, unread, counts by channel).
|
|
210
|
+
*
|
|
211
|
+
* @param userId - The user's ID to fetch stats for.
|
|
212
|
+
* @returns An object containing grouped statistics.
|
|
213
|
+
*/
|
|
124
214
|
async getStats(userId) {
|
|
125
215
|
const all = await this.storage.findByUser(userId, {});
|
|
126
216
|
const unread = await this.storage.countUnread(userId);
|
|
@@ -141,6 +231,11 @@ var NotificationCenter = class {
|
|
|
141
231
|
return stats;
|
|
142
232
|
}
|
|
143
233
|
// ========== STATE MANAGEMENT ==========
|
|
234
|
+
/**
|
|
235
|
+
* Marks a specific notification as "read" and triggers real-time updates for listeners.
|
|
236
|
+
*
|
|
237
|
+
* @param notificationId - The unique ID of the notification.
|
|
238
|
+
*/
|
|
144
239
|
async markAsRead(notificationId) {
|
|
145
240
|
await this.storage.markAsRead(notificationId);
|
|
146
241
|
const notification = await this.storage.findById(notificationId);
|
|
@@ -154,10 +249,20 @@ var NotificationCenter = class {
|
|
|
154
249
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
155
250
|
}
|
|
156
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Marks all notifications belonging to a user as "read".
|
|
254
|
+
*
|
|
255
|
+
* @param userId - The user's ID.
|
|
256
|
+
*/
|
|
157
257
|
async markAllAsRead(userId) {
|
|
158
258
|
await this.storage.markAllAsRead(userId);
|
|
159
259
|
this.notifyUnreadSubscribers(userId, 0);
|
|
160
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Reverts a notification status back to "unread".
|
|
263
|
+
*
|
|
264
|
+
* @param notificationId - The unique ID of the notification.
|
|
265
|
+
*/
|
|
161
266
|
async markAsUnread(notificationId) {
|
|
162
267
|
await this.storage.markAsUnread(notificationId);
|
|
163
268
|
const notification = await this.storage.findById(notificationId);
|
|
@@ -171,10 +276,20 @@ var NotificationCenter = class {
|
|
|
171
276
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
172
277
|
}
|
|
173
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Marks all notifications belonging to a user as "unread".
|
|
281
|
+
*
|
|
282
|
+
* @param userId - The target user's ID.
|
|
283
|
+
*/
|
|
174
284
|
async markAllAsUnread(userId) {
|
|
175
285
|
await this.storage.markAllAsUnread(userId);
|
|
176
286
|
this.notifyUnreadSubscribers(userId, 0);
|
|
177
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Deletes a specific notification from storage.
|
|
290
|
+
*
|
|
291
|
+
* @param notificationId - The Notification ID to delete.
|
|
292
|
+
*/
|
|
178
293
|
async delete(notificationId) {
|
|
179
294
|
const notification = await this.storage.findById(notificationId);
|
|
180
295
|
await this.storage.delete(notificationId);
|
|
@@ -183,6 +298,11 @@ var NotificationCenter = class {
|
|
|
183
298
|
this.notifyUnreadSubscribers(notification.userId, count);
|
|
184
299
|
}
|
|
185
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Deletes all notifications for a specific user.
|
|
303
|
+
*
|
|
304
|
+
* @param userId - The user's ID.
|
|
305
|
+
*/
|
|
186
306
|
async deleteAll(userId) {
|
|
187
307
|
const notifications = await this.storage.findByUser(userId, {});
|
|
188
308
|
await Promise.all(
|
|
@@ -191,9 +311,21 @@ var NotificationCenter = class {
|
|
|
191
311
|
this.notifyUnreadSubscribers(userId, 0);
|
|
192
312
|
}
|
|
193
313
|
// ========== PREFERENCES ==========
|
|
314
|
+
/**
|
|
315
|
+
* Retrieves the notification opt-in/opt-out routing preferences for a given user.
|
|
316
|
+
*
|
|
317
|
+
* @param userId - The user's ID.
|
|
318
|
+
* @returns A promise resolving to the user's NotificationPreferences.
|
|
319
|
+
*/
|
|
194
320
|
async getPreferences(userId) {
|
|
195
321
|
return this.storage.getPreferences(userId);
|
|
196
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Updates the notification routing and delivery preferences for an user.
|
|
325
|
+
*
|
|
326
|
+
* @param userId - The user's ID.
|
|
327
|
+
* @param prefs - A partial object containing the updated preferences.
|
|
328
|
+
*/
|
|
197
329
|
async updatePreferences(userId, prefs) {
|
|
198
330
|
const current = await this.storage.getPreferences(userId);
|
|
199
331
|
const updated = {
|
|
@@ -205,16 +337,38 @@ var NotificationCenter = class {
|
|
|
205
337
|
await this.storage.savePreferences(userId, updated);
|
|
206
338
|
}
|
|
207
339
|
// ========== TEMPLATES ==========
|
|
340
|
+
/**
|
|
341
|
+
* Registers a notification template, mapping a named key to dynamic defaults/formatting.
|
|
342
|
+
*
|
|
343
|
+
* @param template - The NotificationTemplate definitions.
|
|
344
|
+
*/
|
|
208
345
|
registerTemplate(template) {
|
|
209
346
|
this.templates.set(template.id, template);
|
|
210
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Looks up a registered template by its ID.
|
|
350
|
+
*
|
|
351
|
+
* @param id - The ID of the template.
|
|
352
|
+
* @returns The template object, or undefined if not found.
|
|
353
|
+
*/
|
|
211
354
|
getTemplate(id) {
|
|
212
355
|
return this.templates.get(id);
|
|
213
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* Unregisters a template from the NotificationCenter.
|
|
359
|
+
*
|
|
360
|
+
* @param id - The template ID to remove.
|
|
361
|
+
*/
|
|
214
362
|
unregisterTemplate(id) {
|
|
215
363
|
this.templates.delete(id);
|
|
216
364
|
}
|
|
217
365
|
// ========== DIGEST ==========
|
|
366
|
+
/**
|
|
367
|
+
* Enables batch notification "digests" for a specific user to prevent notification fatigue.
|
|
368
|
+
*
|
|
369
|
+
* @param userId - The user's ID.
|
|
370
|
+
* @param config - The timeframe and configuration for the user's digest.
|
|
371
|
+
*/
|
|
218
372
|
async enableDigest(userId, config) {
|
|
219
373
|
const prefs = await this.getPreferences(userId);
|
|
220
374
|
await this.updatePreferences(userId, {
|
|
@@ -225,6 +379,11 @@ var NotificationCenter = class {
|
|
|
225
379
|
}
|
|
226
380
|
});
|
|
227
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Disables the digest feature for a user, reverting to immediate delivery.
|
|
384
|
+
*
|
|
385
|
+
* @param userId - The target user's ID.
|
|
386
|
+
*/
|
|
228
387
|
async disableDigest(userId) {
|
|
229
388
|
const prefs = await this.getPreferences(userId);
|
|
230
389
|
const newData = { ...prefs.data || {} };
|
|
@@ -234,17 +393,36 @@ var NotificationCenter = class {
|
|
|
234
393
|
data: newData
|
|
235
394
|
});
|
|
236
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Fetches the current digest rules configured for a user.
|
|
398
|
+
*
|
|
399
|
+
* @param userId - The user's ID.
|
|
400
|
+
* @returns The digest configuration, or null if disabled.
|
|
401
|
+
*/
|
|
237
402
|
async getDigestConfig(userId) {
|
|
238
403
|
const prefs = await this.getPreferences(userId);
|
|
239
404
|
return prefs.data?.digestConfig || null;
|
|
240
405
|
}
|
|
241
406
|
// ========== DELIVERY STATUS ==========
|
|
407
|
+
/**
|
|
408
|
+
* Retrieves all delivery receipts generated from transports for a specific notification.
|
|
409
|
+
* Useful to see which channels succeeded and which failed.
|
|
410
|
+
*
|
|
411
|
+
* @param notificationId - The notification's ID.
|
|
412
|
+
* @returns An array of delivery receipts.
|
|
413
|
+
*/
|
|
242
414
|
async getDeliveryStatus(notificationId) {
|
|
243
415
|
if (!this.storage.getReceipts) {
|
|
244
416
|
return [];
|
|
245
417
|
}
|
|
246
418
|
return this.storage.getReceipts(notificationId);
|
|
247
419
|
}
|
|
420
|
+
/**
|
|
421
|
+
* Attempts to resend a notification for any channels that previously marked it as "failed".
|
|
422
|
+
*
|
|
423
|
+
* @param notificationId - The target notification ID.
|
|
424
|
+
* @param channel - Optional channel scope. If provided, retries only on this specific transport.
|
|
425
|
+
*/
|
|
248
426
|
async retryFailed(notificationId, channel) {
|
|
249
427
|
const notification = await this.storage.findById(notificationId);
|
|
250
428
|
if (!notification) {
|
|
@@ -263,6 +441,13 @@ var NotificationCenter = class {
|
|
|
263
441
|
}
|
|
264
442
|
}
|
|
265
443
|
// ========== SUBSCRIPTIONS (Reactive) ==========
|
|
444
|
+
/**
|
|
445
|
+
* Registers a callback to be invoked whenever a notification is sent to a specific user.
|
|
446
|
+
*
|
|
447
|
+
* @param userId - The target user's ID.
|
|
448
|
+
* @param callback - Function to handle the raw notification map.
|
|
449
|
+
* @returns A cleanup function to unsubscribe from this event.
|
|
450
|
+
*/
|
|
266
451
|
subscribe(userId, callback) {
|
|
267
452
|
const sid = String(userId);
|
|
268
453
|
if (!this.subscribers.has(sid)) {
|
|
@@ -279,6 +464,13 @@ var NotificationCenter = class {
|
|
|
279
464
|
}
|
|
280
465
|
};
|
|
281
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Registers a callback for state changes (e.g. read/unread status updates) for a user's notifications.
|
|
469
|
+
*
|
|
470
|
+
* @param userId - The target user's ID.
|
|
471
|
+
* @param callback - Lifecycle event listener.
|
|
472
|
+
* @returns A cleanup function to unsubscribe.
|
|
473
|
+
*/
|
|
282
474
|
subscribeToEvents(userId, callback) {
|
|
283
475
|
const sid = String(userId);
|
|
284
476
|
if (!this.eventSubscribers.has(sid)) {
|
|
@@ -295,6 +487,13 @@ var NotificationCenter = class {
|
|
|
295
487
|
}
|
|
296
488
|
};
|
|
297
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* Registers a listener to react to changes in the unread notification count for a user.
|
|
492
|
+
*
|
|
493
|
+
* @param userId - The user's ID.
|
|
494
|
+
* @param callback - Handlers receiving the current unread count.
|
|
495
|
+
* @returns Unsubscribe function.
|
|
496
|
+
*/
|
|
298
497
|
onUnreadCountChange(userId, callback) {
|
|
299
498
|
const sid = String(userId);
|
|
300
499
|
if (!this.unreadSubscribers.has(sid)) {
|
|
@@ -312,13 +511,26 @@ var NotificationCenter = class {
|
|
|
312
511
|
};
|
|
313
512
|
}
|
|
314
513
|
// ========== MIDDLEWARE ==========
|
|
514
|
+
/**
|
|
515
|
+
* Injects a middleware interceptor to apply custom logic before or after notifications are sent.
|
|
516
|
+
*
|
|
517
|
+
* @param middleware - The middleware object conforming to `NotificationMiddleware`.
|
|
518
|
+
*/
|
|
315
519
|
use(middleware) {
|
|
316
520
|
this.middleware.push(middleware);
|
|
317
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Removes a previously configured middleware globally.
|
|
524
|
+
*
|
|
525
|
+
* @param name - The name identifier of the middleware to remove.
|
|
526
|
+
*/
|
|
318
527
|
removeMiddleware(name) {
|
|
319
528
|
this.middleware = this.middleware.filter((m) => m.name !== name);
|
|
320
529
|
}
|
|
321
530
|
// ========== LIFECYCLE ==========
|
|
531
|
+
/**
|
|
532
|
+
* Boots up the NotificationCenter, initializing storage, queues, and worker loops if enabled.
|
|
533
|
+
*/
|
|
322
534
|
async start() {
|
|
323
535
|
if (this.isRunning) {
|
|
324
536
|
return;
|
|
@@ -337,6 +549,9 @@ var NotificationCenter = class {
|
|
|
337
549
|
this.startCleanup();
|
|
338
550
|
}
|
|
339
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* Gracefully shuts down the NotificationCenter, terminating background queues and workers.
|
|
554
|
+
*/
|
|
340
555
|
async stop() {
|
|
341
556
|
if (!this.isRunning) {
|
|
342
557
|
return;
|
|
@@ -350,6 +565,11 @@ var NotificationCenter = class {
|
|
|
350
565
|
await this.queue.stop();
|
|
351
566
|
}
|
|
352
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Pings all registered transports to report on their current health and active status.
|
|
570
|
+
*
|
|
571
|
+
* @returns A map representing the readiness boolean state of each registered transport.
|
|
572
|
+
*/
|
|
353
573
|
async healthCheck() {
|
|
354
574
|
const results = {};
|
|
355
575
|
for (const [name, transport] of this.transports) {
|
|
@@ -366,6 +586,9 @@ var NotificationCenter = class {
|
|
|
366
586
|
return results;
|
|
367
587
|
}
|
|
368
588
|
// ========== PRIVATE METHODS ==========
|
|
589
|
+
/**
|
|
590
|
+
* Applies metadata, templates, and defaults to construct the internal Notification shape.
|
|
591
|
+
*/
|
|
369
592
|
buildNotification(input) {
|
|
370
593
|
const allChannels = Array.from(this.transports.keys());
|
|
371
594
|
if (input.template) {
|
|
@@ -421,6 +644,9 @@ var NotificationCenter = class {
|
|
|
421
644
|
actions: input.actions
|
|
422
645
|
};
|
|
423
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Internal mechanism sending payload out across desired transports without queue delay.
|
|
649
|
+
*/
|
|
424
650
|
async sendNow(notification) {
|
|
425
651
|
const prefs = await this.getPreferences(notification.userId);
|
|
426
652
|
const receipts = await Promise.all(
|
package/package.json
CHANGED