@tyravel/notifications 0.1.0
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/dist/channels/database-channel.d.ts +13 -0
- package/dist/channels/database-channel.d.ts.map +1 -0
- package/dist/channels/database-channel.js +26 -0
- package/dist/channels/database-channel.js.map +1 -0
- package/dist/channels/mail-channel.d.ts +9 -0
- package/dist/channels/mail-channel.d.ts.map +1 -0
- package/dist/channels/mail-channel.js +19 -0
- package/dist/channels/mail-channel.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/notification-manager.d.ts +23 -0
- package/dist/notification-manager.d.ts.map +1 -0
- package/dist/notification-manager.js +62 -0
- package/dist/notification-manager.js.map +1 -0
- package/dist/notification-registry.d.ts +9 -0
- package/dist/notification-registry.d.ts.map +1 -0
- package/dist/notification-registry.js +18 -0
- package/dist/notification-registry.js.map +1 -0
- package/dist/notification.d.ts +15 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +10 -0
- package/dist/notification.js.map +1 -0
- package/dist/notifications.test.d.ts +2 -0
- package/dist/notifications.test.d.ts.map +1 -0
- package/dist/notifications.test.js +44 -0
- package/dist/notifications.test.js.map +1 -0
- package/dist/queue-bridge.d.ts +9 -0
- package/dist/queue-bridge.d.ts.map +1 -0
- package/dist/queue-bridge.js +2 -0
- package/dist/queue-bridge.js.map +1 -0
- package/dist/queued-notification-context.d.ts +13 -0
- package/dist/queued-notification-context.d.ts.map +1 -0
- package/dist/queued-notification-context.js +11 -0
- package/dist/queued-notification-context.js.map +1 -0
- package/dist/queued-notifications.test.d.ts +2 -0
- package/dist/queued-notifications.test.d.ts.map +1 -0
- package/dist/queued-notifications.test.js +65 -0
- package/dist/queued-notifications.test.js.map +1 -0
- package/dist/send-queued-notification.d.ts +13 -0
- package/dist/send-queued-notification.d.ts.map +1 -0
- package/dist/send-queued-notification.js +11 -0
- package/dist/send-queued-notification.js.map +1 -0
- package/dist/send.d.ts +6 -0
- package/dist/send.d.ts.map +1 -0
- package/dist/send.js +11 -0
- package/dist/send.js.map +1 -0
- package/dist/serialized-notifiable.d.ts +14 -0
- package/dist/serialized-notifiable.d.ts.map +1 -0
- package/dist/serialized-notifiable.js +21 -0
- package/dist/serialized-notifiable.js.map +1 -0
- package/dist/should-queue.d.ts +6 -0
- package/dist/should-queue.d.ts.map +1 -0
- package/dist/should-queue.js +4 -0
- package/dist/should-queue.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DatabaseConnection } from '@tyravel/database';
|
|
2
|
+
import type { Notification } from '../notification.js';
|
|
3
|
+
import type { Notifiable } from '../types.js';
|
|
4
|
+
export interface DatabaseChannelOptions {
|
|
5
|
+
connection: DatabaseConnection;
|
|
6
|
+
table?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class DatabaseChannel {
|
|
9
|
+
private readonly options;
|
|
10
|
+
constructor(options: DatabaseChannelOptions);
|
|
11
|
+
send(notifiable: Notifiable, notification: Notification): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=database-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-channel.d.ts","sourceRoot":"","sources":["../../src/channels/database-channel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,sBAAsB;IAEtD,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAiB9E"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { QueryBuilder } from '@tyravel/database';
|
|
3
|
+
export class DatabaseChannel {
|
|
4
|
+
options;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
}
|
|
8
|
+
async send(notifiable, notification) {
|
|
9
|
+
if (!notification.toDatabase) {
|
|
10
|
+
throw new Error(`Notification ${notification.id()} does not implement toDatabase().`);
|
|
11
|
+
}
|
|
12
|
+
const data = await notification.toDatabase(notifiable);
|
|
13
|
+
const table = this.options.table ?? 'notifications';
|
|
14
|
+
const now = new Date().toISOString();
|
|
15
|
+
await new QueryBuilder(this.options.connection, table).insert({
|
|
16
|
+
id: randomUUID(),
|
|
17
|
+
type: notification.id(),
|
|
18
|
+
notifiable_type: notifiable.constructor.name,
|
|
19
|
+
notifiable_id: String(notifiable.getKey()),
|
|
20
|
+
data: JSON.stringify(data),
|
|
21
|
+
read_at: null,
|
|
22
|
+
created_at: now,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=database-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-channel.js","sourceRoot":"","sources":["../../src/channels/database-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAoBjD,MAAM,OAAO,eAAe;IACG;IAA7B,YAA6B,OAA+B;QAA/B,YAAO,GAAP,OAAO,CAAwB;IAAG,CAAC;IAEhE,KAAK,CAAC,IAAI,CAAC,UAAsB,EAAE,YAA0B;QAC3D,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,gBAAgB,YAAY,CAAC,EAAE,EAAE,mCAAmC,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,eAAe,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,YAAY,CAAkB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC;YAC7E,EAAE,EAAE,UAAU,EAAE;YAChB,IAAI,EAAE,YAAY,CAAC,EAAE,EAAE;YACvB,eAAe,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI;YAC5C,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YAC1C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MailManager } from '@tyravel/mail';
|
|
2
|
+
import type { Notification } from '../notification.js';
|
|
3
|
+
import type { Notifiable } from '../types.js';
|
|
4
|
+
export declare class MailChannel {
|
|
5
|
+
private readonly mail;
|
|
6
|
+
constructor(mail: MailManager);
|
|
7
|
+
send(notifiable: Notifiable, notification: Notification): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=mail-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mail-channel.d.ts","sourceRoot":"","sources":["../../src/channels/mail-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAExC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAa9E"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class MailChannel {
|
|
2
|
+
mail;
|
|
3
|
+
constructor(mail) {
|
|
4
|
+
this.mail = mail;
|
|
5
|
+
}
|
|
6
|
+
async send(notifiable, notification) {
|
|
7
|
+
if (!notification.toMail) {
|
|
8
|
+
throw new Error(`Notification ${notification.id()} does not implement toMail().`);
|
|
9
|
+
}
|
|
10
|
+
const message = await notification.toMail(notifiable);
|
|
11
|
+
const address = notifiable.routeNotificationForMail?.();
|
|
12
|
+
const recipient = typeof address === 'string' ? address : address?.address;
|
|
13
|
+
if (!recipient) {
|
|
14
|
+
throw new Error('Notifiable is missing routeNotificationForMail().');
|
|
15
|
+
}
|
|
16
|
+
await this.mail.mailer().to(recipient).send(message);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=mail-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mail-channel.js","sourceRoot":"","sources":["../../src/channels/mail-channel.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,WAAW;IACO;IAA7B,YAA6B,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;IAAG,CAAC;IAElD,KAAK,CAAC,IAAI,CAAC,UAAsB,EAAE,YAA0B;QAC3D,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,gBAAgB,YAAY,CAAC,EAAE,EAAE,+BAA+B,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,UAAU,CAAC,wBAAwB,EAAE,EAAE,CAAC;QACxD,MAAM,SAAS,GACb,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC;QAC3D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { Notifiable, NotificationChannel, NotificationsConfig } from './types.js';
|
|
2
|
+
export { Notification } from './notification.js';
|
|
3
|
+
export { NotificationManager } from './notification-manager.js';
|
|
4
|
+
export { NotificationRegistry } from './notification-registry.js';
|
|
5
|
+
export { notify, setNotificationSender } from './send.js';
|
|
6
|
+
export type { ShouldQueue } from './should-queue.js';
|
|
7
|
+
export { shouldQueue } from './should-queue.js';
|
|
8
|
+
export { SendQueuedNotification } from './send-queued-notification.js';
|
|
9
|
+
export type { SendQueuedNotificationData } from './send-queued-notification.js';
|
|
10
|
+
export { setQueuedNotificationContext } from './queued-notification-context.js';
|
|
11
|
+
export { SerializedNotifiable, serializeNotifiable } from './serialized-notifiable.js';
|
|
12
|
+
export type { NotificationQueueBridge } from './queue-bridge.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,YAAY,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACvF,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Notification } from './notification.js';
|
|
2
|
+
export { NotificationManager } from './notification-manager.js';
|
|
3
|
+
export { NotificationRegistry } from './notification-registry.js';
|
|
4
|
+
export { notify, setNotificationSender } from './send.js';
|
|
5
|
+
export { shouldQueue } from './should-queue.js';
|
|
6
|
+
export { SendQueuedNotification } from './send-queued-notification.js';
|
|
7
|
+
export { setQueuedNotificationContext } from './queued-notification-context.js';
|
|
8
|
+
export { SerializedNotifiable, serializeNotifiable } from './serialized-notifiable.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MailManager } from '@tyravel/mail';
|
|
2
|
+
import type { Notification } from './notification.js';
|
|
3
|
+
import type { Notifiable } from './types.js';
|
|
4
|
+
import type { DatabaseChannelOptions } from './channels/database-channel.js';
|
|
5
|
+
import type { NotificationQueueBridge } from './queue-bridge.js';
|
|
6
|
+
import type { NotificationRegistry } from './notification-registry.js';
|
|
7
|
+
export declare class NotificationManager {
|
|
8
|
+
private readonly queue?;
|
|
9
|
+
private readonly registry?;
|
|
10
|
+
private readonly mailChannel;
|
|
11
|
+
private readonly databaseChannel?;
|
|
12
|
+
private queueDefaults;
|
|
13
|
+
constructor(mail: MailManager, database?: DatabaseChannelOptions, queue?: NotificationQueueBridge | undefined, registry?: NotificationRegistry | undefined);
|
|
14
|
+
setQueueDefaults(options: {
|
|
15
|
+
connection?: string;
|
|
16
|
+
queue?: string;
|
|
17
|
+
}): void;
|
|
18
|
+
send(notifiable: Notifiable, notification: Notification): Promise<void>;
|
|
19
|
+
sendNow(notifiable: Notifiable, notification: Notification): Promise<void>;
|
|
20
|
+
private resolveQueueOptions;
|
|
21
|
+
private sendOnChannel;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=notification-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-manager.d.ts","sourceRoot":"","sources":["../src/notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAKvE,qBAAa,mBAAmB;IAQ5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAR5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAkB;IACnD,OAAO,CAAC,aAAa,CAA+C;gBAGlE,IAAI,EAAE,WAAW,EACjB,QAAQ,CAAC,EAAE,sBAAsB,EAChB,KAAK,CAAC,EAAE,uBAAuB,YAAA,EAC/B,QAAQ,CAAC,EAAE,oBAAoB,YAAA;IAMlD,gBAAgB,CAAC,OAAO,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIlE,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvE,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhF,OAAO,CAAC,mBAAmB;YAiBb,aAAa;CAmB5B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { MailChannel } from './channels/mail-channel.js';
|
|
2
|
+
import { DatabaseChannel } from './channels/database-channel.js';
|
|
3
|
+
import { shouldQueue } from './should-queue.js';
|
|
4
|
+
import { SendQueuedNotification } from './send-queued-notification.js';
|
|
5
|
+
import { serializeNotifiable } from './serialized-notifiable.js';
|
|
6
|
+
export class NotificationManager {
|
|
7
|
+
queue;
|
|
8
|
+
registry;
|
|
9
|
+
mailChannel;
|
|
10
|
+
databaseChannel;
|
|
11
|
+
queueDefaults = {};
|
|
12
|
+
constructor(mail, database, queue, registry) {
|
|
13
|
+
this.queue = queue;
|
|
14
|
+
this.registry = registry;
|
|
15
|
+
this.mailChannel = new MailChannel(mail);
|
|
16
|
+
this.databaseChannel = database ? new DatabaseChannel(database) : undefined;
|
|
17
|
+
}
|
|
18
|
+
setQueueDefaults(options) {
|
|
19
|
+
this.queueDefaults = options;
|
|
20
|
+
}
|
|
21
|
+
async send(notifiable, notification) {
|
|
22
|
+
this.registry?.registerInstance(notification);
|
|
23
|
+
if (shouldQueue(notification) && this.queue) {
|
|
24
|
+
const job = new SendQueuedNotification({
|
|
25
|
+
notification: notification.id(),
|
|
26
|
+
notifiable: serializeNotifiable(notifiable),
|
|
27
|
+
});
|
|
28
|
+
const options = this.resolveQueueOptions(notification);
|
|
29
|
+
await this.queue.dispatch(job, options);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await this.sendNow(notifiable, notification);
|
|
33
|
+
}
|
|
34
|
+
async sendNow(notifiable, notification) {
|
|
35
|
+
const channels = notification.via(notifiable);
|
|
36
|
+
await Promise.all(channels.map((channel) => this.sendOnChannel(notifiable, notification, channel)));
|
|
37
|
+
}
|
|
38
|
+
resolveQueueOptions(notification) {
|
|
39
|
+
const queued = notification;
|
|
40
|
+
return {
|
|
41
|
+
connection: queued.connection ?? this.queueDefaults.connection,
|
|
42
|
+
queue: queued.queue ?? this.queueDefaults.queue,
|
|
43
|
+
delaySeconds: queued.delaySeconds,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async sendOnChannel(notifiable, notification, channel) {
|
|
47
|
+
switch (channel) {
|
|
48
|
+
case 'mail':
|
|
49
|
+
await this.mailChannel.send(notifiable, notification);
|
|
50
|
+
return;
|
|
51
|
+
case 'database':
|
|
52
|
+
if (!this.databaseChannel) {
|
|
53
|
+
throw new Error('Database notification channel is not configured.');
|
|
54
|
+
}
|
|
55
|
+
await this.databaseChannel.send(notifiable, notification);
|
|
56
|
+
return;
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`Unknown notification channel [${channel}].`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=notification-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-manager.js","sourceRoot":"","sources":["../src/notification-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Notification } from './notification.js';
|
|
2
|
+
export type NotificationConstructor = new () => Notification;
|
|
3
|
+
export declare class NotificationRegistry {
|
|
4
|
+
private readonly notifications;
|
|
5
|
+
register(constructor: NotificationConstructor): this;
|
|
6
|
+
registerInstance(notification: Notification): this;
|
|
7
|
+
create(name: string): Notification;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=notification-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-registry.d.ts","sourceRoot":"","sources":["../src/notification-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,uBAAuB,GAAG,UAAU,YAAY,CAAC;AAE7D,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8C;IAE5E,QAAQ,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI;IAKpD,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAIlD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;CAOnC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class NotificationRegistry {
|
|
2
|
+
notifications = new Map();
|
|
3
|
+
register(constructor) {
|
|
4
|
+
this.notifications.set(constructor.name, constructor);
|
|
5
|
+
return this;
|
|
6
|
+
}
|
|
7
|
+
registerInstance(notification) {
|
|
8
|
+
return this.register(notification.constructor);
|
|
9
|
+
}
|
|
10
|
+
create(name) {
|
|
11
|
+
const constructor = this.notifications.get(name);
|
|
12
|
+
if (!constructor) {
|
|
13
|
+
throw new Error(`Notification class not registered: ${name}`);
|
|
14
|
+
}
|
|
15
|
+
return new constructor();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=notification-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-registry.js","sourceRoot":"","sources":["../src/notification-registry.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,oBAAoB;IACd,aAAa,GAAG,IAAI,GAAG,EAAmC,CAAC;IAE5E,QAAQ,CAAC,WAAoC;QAC3C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gBAAgB,CAAC,YAA0B;QACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAsC,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,WAAW,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MailMessage } from '@tyravel/mail';
|
|
2
|
+
import type { NotificationChannel, Notifiable } from './types.js';
|
|
3
|
+
export declare abstract class Notification {
|
|
4
|
+
abstract via(notifiable: Notifiable): NotificationChannel[];
|
|
5
|
+
/** When true (via ShouldQueue + override), notification is pushed to the queue. */
|
|
6
|
+
shouldQueue?(): boolean;
|
|
7
|
+
/** Optional queue routing (Laravel-style). */
|
|
8
|
+
connection?: string;
|
|
9
|
+
queue?: string;
|
|
10
|
+
delaySeconds?: number;
|
|
11
|
+
toMail?(notifiable: Notifiable): MailMessage | Promise<MailMessage>;
|
|
12
|
+
toDatabase?(notifiable: Notifiable): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
13
|
+
id(): string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=notification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAElE,8BAAsB,YAAY;IAChC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,mBAAmB,EAAE;IAE3D,mFAAmF;IACnF,WAAW,CAAC,IAAI,OAAO;IAEvB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,MAAM,CAAC,CAAC,UAAU,EAAE,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAEnE,UAAU,CAAC,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/F,EAAE,IAAI,MAAM;CAGb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAGA,MAAM,OAAgB,YAAY;IAMhC,8CAA8C;IAC9C,UAAU,CAAU;IACpB,KAAK,CAAU;IACf,YAAY,CAAU;IAMtB,EAAE;QACA,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.test.d.ts","sourceRoot":"","sources":["../src/notifications.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { MailManager } from '@tyravel/mail';
|
|
3
|
+
import { Notification } from './notification.js';
|
|
4
|
+
import { NotificationManager } from './notification-manager.js';
|
|
5
|
+
class PingNotification extends Notification {
|
|
6
|
+
via() {
|
|
7
|
+
return ['mail'];
|
|
8
|
+
}
|
|
9
|
+
toMail() {
|
|
10
|
+
return {
|
|
11
|
+
subject: 'Ping',
|
|
12
|
+
to: [],
|
|
13
|
+
text: 'pong',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
class User {
|
|
18
|
+
id;
|
|
19
|
+
email;
|
|
20
|
+
constructor(id, email) {
|
|
21
|
+
this.id = id;
|
|
22
|
+
this.email = email;
|
|
23
|
+
}
|
|
24
|
+
getKey() {
|
|
25
|
+
return this.id;
|
|
26
|
+
}
|
|
27
|
+
routeNotificationForMail() {
|
|
28
|
+
return this.email;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
describe('NotificationManager', () => {
|
|
32
|
+
it('sends mail channel notifications', async () => {
|
|
33
|
+
const mail = new MailManager({
|
|
34
|
+
default: 'array',
|
|
35
|
+
from: { address: 'noreply@example.com' },
|
|
36
|
+
connections: { array: { driver: 'array' } },
|
|
37
|
+
});
|
|
38
|
+
const manager = new NotificationManager(mail);
|
|
39
|
+
await manager.send(new User(1, 'a@b.com'), new PingNotification());
|
|
40
|
+
const transport = mail.transport('array');
|
|
41
|
+
expect(transport.messages[0]?.subject).toBe('Ping');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=notifications.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.test.js","sourceRoot":"","sources":["../src/notifications.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGhE,MAAM,gBAAiB,SAAQ,YAAY;IAChC,GAAG;QACV,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAEQ,MAAM;QACb,OAAO;YACL,OAAO,EAAE,MAAM;YACf,EAAE,EAAE,EAAE;YACN,IAAI,EAAE,MAAM;SACb,CAAC;IACJ,CAAC;CACF;AAED,MAAM,IAAI;IAEC;IACA;IAFT,YACS,EAAU,EACV,KAAa;QADb,OAAE,GAAF,EAAE,CAAQ;QACV,UAAK,GAAL,KAAK,CAAQ;IACnB,CAAC;IAEJ,MAAM;QACJ,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,wBAAwB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC;YAC3B,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE;YACxC,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;SAC5C,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,gBAAgB,EAAE,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAuB,CAAC;QAChE,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-bridge.d.ts","sourceRoot":"","sources":["../src/queue-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7G"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-bridge.js","sourceRoot":"","sources":["../src/queue-bridge.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Container } from '@tyravel/container';
|
|
2
|
+
import type { NotificationManager } from './notification-manager.js';
|
|
3
|
+
import type { NotificationRegistry } from './notification-registry.js';
|
|
4
|
+
import { SerializedNotifiable } from './serialized-notifiable.js';
|
|
5
|
+
export interface QueuedNotificationContext {
|
|
6
|
+
manager: NotificationManager;
|
|
7
|
+
registry: NotificationRegistry;
|
|
8
|
+
SerializedNotifiable: typeof SerializedNotifiable;
|
|
9
|
+
container?: Container;
|
|
10
|
+
}
|
|
11
|
+
export declare function setQueuedNotificationContext(value: QueuedNotificationContext): void;
|
|
12
|
+
export declare function getQueuedNotificationContext(): QueuedNotificationContext;
|
|
13
|
+
//# sourceMappingURL=queued-notification-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-notification-context.d.ts","sourceRoot":"","sources":["../src/queued-notification-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAID,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAEnF;AAED,wBAAgB,4BAA4B,IAAI,yBAAyB,CAKxE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let context;
|
|
2
|
+
export function setQueuedNotificationContext(value) {
|
|
3
|
+
context = value;
|
|
4
|
+
}
|
|
5
|
+
export function getQueuedNotificationContext() {
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new Error('Queued notification context is not configured.');
|
|
8
|
+
}
|
|
9
|
+
return context;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=queued-notification-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-notification-context.js","sourceRoot":"","sources":["../src/queued-notification-context.ts"],"names":[],"mappings":"AAYA,IAAI,OAA8C,CAAC;AAEnD,MAAM,UAAU,4BAA4B,CAAC,KAAgC;IAC3E,OAAO,GAAG,KAAK,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-notifications.test.d.ts","sourceRoot":"","sources":["../src/queued-notifications.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { MailManager } from '@tyravel/mail';
|
|
3
|
+
import { JobRegistry, QueueManager, QueueWorker } from '@tyravel/queue';
|
|
4
|
+
import { Notification } from './notification.js';
|
|
5
|
+
import { NotificationManager } from './notification-manager.js';
|
|
6
|
+
import { NotificationRegistry } from './notification-registry.js';
|
|
7
|
+
import { SendQueuedNotification } from './send-queued-notification.js';
|
|
8
|
+
import { SerializedNotifiable, serializeNotifiable } from './serialized-notifiable.js';
|
|
9
|
+
import { setQueuedNotificationContext } from './queued-notification-context.js';
|
|
10
|
+
class QueuedPing extends Notification {
|
|
11
|
+
shouldQueue() {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
via() {
|
|
15
|
+
return ['mail'];
|
|
16
|
+
}
|
|
17
|
+
toMail() {
|
|
18
|
+
return { subject: 'Queued', to: [], text: 'async' };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class User {
|
|
22
|
+
id;
|
|
23
|
+
email;
|
|
24
|
+
constructor(id, email) {
|
|
25
|
+
this.id = id;
|
|
26
|
+
this.email = email;
|
|
27
|
+
}
|
|
28
|
+
getKey() {
|
|
29
|
+
return this.id;
|
|
30
|
+
}
|
|
31
|
+
routeNotificationForMail() {
|
|
32
|
+
return this.email;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
describe('queued notifications', () => {
|
|
36
|
+
it('dispatches SendQueuedNotification on sync queue', async () => {
|
|
37
|
+
const mail = new MailManager({
|
|
38
|
+
default: 'array',
|
|
39
|
+
from: { address: 'noreply@example.com' },
|
|
40
|
+
connections: { array: { driver: 'array' } },
|
|
41
|
+
});
|
|
42
|
+
const registry = new NotificationRegistry();
|
|
43
|
+
const jobs = new JobRegistry();
|
|
44
|
+
jobs.register(SendQueuedNotification);
|
|
45
|
+
const worker = new QueueWorker(jobs);
|
|
46
|
+
const queueManager = new QueueManager({ default: 'sync', connections: { sync: { driver: 'sync' } } }, worker);
|
|
47
|
+
const manager = new NotificationManager(mail, undefined, {
|
|
48
|
+
dispatch: async (job) => {
|
|
49
|
+
await queueManager.connection('sync').push(job);
|
|
50
|
+
},
|
|
51
|
+
}, registry);
|
|
52
|
+
setQueuedNotificationContext({
|
|
53
|
+
manager,
|
|
54
|
+
registry,
|
|
55
|
+
SerializedNotifiable,
|
|
56
|
+
});
|
|
57
|
+
const user = new User(9, 'queued@example.com');
|
|
58
|
+
registry.register(QueuedPing);
|
|
59
|
+
await manager.send(user, new QueuedPing());
|
|
60
|
+
const transport = mail.transport('array');
|
|
61
|
+
expect(transport.messages[0]?.subject).toBe('Queued');
|
|
62
|
+
expect(serializeNotifiable(user).mail).toBe('queued@example.com');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=queued-notifications.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-notifications.test.js","sourceRoot":"","sources":["../src/queued-notifications.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAsB,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAGhF,MAAM,UAAW,SAAQ,YAAY;IAC1B,WAAW;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAEQ,GAAG;QACV,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAEQ,MAAM;QACb,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACtD,CAAC;CACF;AAED,MAAM,IAAI;IAEC;IACA;IAFT,YACS,EAAU,EACV,KAAa;QADb,OAAE,GAAF,EAAE,CAAQ;QACV,UAAK,GAAL,KAAK,CAAQ;IACnB,CAAC;IACJ,MAAM;QACJ,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IACD,wBAAwB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC;YAC3B,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE;YACxC,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;SAC5C,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,YAAY,GAAG,IAAI,YAAY,CACnC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAC9D,MAAM,CACP,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,mBAAmB,CACrC,IAAI,EACJ,SAAS,EACT;YACE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACtB,MAAM,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC;SACF,EACD,QAAQ,CACT,CAAC;QAEF,4BAA4B,CAAC;YAC3B,OAAO;YACP,QAAQ;YACR,oBAAoB;SACrB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;QAC/C,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC9B,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;QAE3C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAuB,CAAC;QAChE,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Job } from '@tyravel/queue';
|
|
2
|
+
export interface SendQueuedNotificationData extends Record<string, unknown> {
|
|
3
|
+
notification: string;
|
|
4
|
+
notifiable: {
|
|
5
|
+
type: string;
|
|
6
|
+
id: string | number;
|
|
7
|
+
mail?: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare class SendQueuedNotification extends Job<SendQueuedNotificationData> {
|
|
11
|
+
handle(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=send-queued-notification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-queued-notification.d.ts","sourceRoot":"","sources":["../src/send-queued-notification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAGrC,MAAM,WAAW,0BAA2B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,qBAAa,sBAAuB,SAAQ,GAAG,CAAC,0BAA0B,CAAC;IAC1D,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Job } from '@tyravel/queue';
|
|
2
|
+
import { getQueuedNotificationContext } from './queued-notification-context.js';
|
|
3
|
+
export class SendQueuedNotification extends Job {
|
|
4
|
+
async handle() {
|
|
5
|
+
const context = getQueuedNotificationContext();
|
|
6
|
+
const notification = context.registry.create(this.data.notification);
|
|
7
|
+
const notifiable = new context.SerializedNotifiable(this.data.notifiable);
|
|
8
|
+
await context.manager.sendNow(notifiable, notification);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=send-queued-notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-queued-notification.js","sourceRoot":"","sources":["../src/send-queued-notification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAWhF,MAAM,OAAO,sBAAuB,SAAQ,GAA+B;IAChE,KAAK,CAAC,MAAM;QACnB,MAAM,OAAO,GAAG,4BAA4B,EAAE,CAAC;QAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrE,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1E,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC1D,CAAC;CACF"}
|
package/dist/send.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Notification } from './notification.js';
|
|
2
|
+
import type { NotificationManager } from './notification-manager.js';
|
|
3
|
+
import type { Notifiable } from './types.js';
|
|
4
|
+
export declare function setNotificationSender(manager: NotificationManager): void;
|
|
5
|
+
export declare function notify(notifiable: Notifiable, notification: Notification): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=send.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAExE;AAED,wBAAsB,MAAM,CAC1B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,IAAI,CAAC,CAKf"}
|
package/dist/send.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let notifier;
|
|
2
|
+
export function setNotificationSender(manager) {
|
|
3
|
+
notifier = manager;
|
|
4
|
+
}
|
|
5
|
+
export async function notify(notifiable, notification) {
|
|
6
|
+
if (!notifier) {
|
|
7
|
+
throw new Error('Notification manager is not configured.');
|
|
8
|
+
}
|
|
9
|
+
await notifier.send(notifiable, notification);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=send.js.map
|
package/dist/send.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"AAIA,IAAI,QAAyC,CAAC;AAE9C,MAAM,UAAU,qBAAqB,CAAC,OAA4B;IAChE,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,UAAsB,EACtB,YAA0B;IAE1B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Notifiable } from './types.js';
|
|
2
|
+
export interface SerializedNotifiableData {
|
|
3
|
+
type: string;
|
|
4
|
+
id: string | number;
|
|
5
|
+
mail?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class SerializedNotifiable implements Notifiable {
|
|
8
|
+
private readonly data;
|
|
9
|
+
constructor(data: SerializedNotifiableData);
|
|
10
|
+
getKey(): string | number;
|
|
11
|
+
routeNotificationForMail(): string;
|
|
12
|
+
}
|
|
13
|
+
export declare function serializeNotifiable(notifiable: Notifiable): SerializedNotifiableData;
|
|
14
|
+
//# sourceMappingURL=serialized-notifiable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialized-notifiable.d.ts","sourceRoot":"","sources":["../src/serialized-notifiable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,oBAAqB,YAAW,UAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,wBAAwB;IAE3D,MAAM,IAAI,MAAM,GAAG,MAAM;IAIzB,wBAAwB,IAAI,MAAM;CAGnC;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,wBAAwB,CAOpF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class SerializedNotifiable {
|
|
2
|
+
data;
|
|
3
|
+
constructor(data) {
|
|
4
|
+
this.data = data;
|
|
5
|
+
}
|
|
6
|
+
getKey() {
|
|
7
|
+
return this.data.id;
|
|
8
|
+
}
|
|
9
|
+
routeNotificationForMail() {
|
|
10
|
+
return this.data.mail ?? '';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function serializeNotifiable(notifiable) {
|
|
14
|
+
const mail = notifiable.routeNotificationForMail?.();
|
|
15
|
+
return {
|
|
16
|
+
type: notifiable.constructor.name,
|
|
17
|
+
id: notifiable.getKey(),
|
|
18
|
+
mail: typeof mail === 'string' ? mail : mail?.address,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=serialized-notifiable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialized-notifiable.js","sourceRoot":"","sources":["../src/serialized-notifiable.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,oBAAoB;IACF;IAA7B,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,wBAAwB;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,UAAsB;IACxD,MAAM,IAAI,GAAG,UAAU,CAAC,wBAAwB,EAAE,EAAE,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI;QACjC,EAAE,EAAE,UAAU,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO;KACtD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Notification } from './notification.js';
|
|
2
|
+
/** Marker interface — notifications that implement this are queued. */
|
|
3
|
+
export interface ShouldQueue {
|
|
4
|
+
}
|
|
5
|
+
export declare function shouldQueue(notification: Notification): boolean;
|
|
6
|
+
//# sourceMappingURL=should-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"should-queue.d.ts","sourceRoot":"","sources":["../src/should-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,uEAAuE;AACvE,MAAM,WAAW,WAAW;CAAG;AAE/B,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAE/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"should-queue.js","sourceRoot":"","sources":["../src/should-queue.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,WAAW,CAAC,YAA0B;IACpD,OAAO,YAAY,CAAC,WAAW,EAAE,EAAE,KAAK,IAAI,CAAC;AAC/C,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type NotificationChannel = 'mail' | 'database';
|
|
2
|
+
export interface Notifiable {
|
|
3
|
+
getKey(): string | number;
|
|
4
|
+
routeNotificationForMail?(): string | {
|
|
5
|
+
address: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export interface NotificationsConfig {
|
|
10
|
+
table?: string;
|
|
11
|
+
connection?: string;
|
|
12
|
+
queue?: string;
|
|
13
|
+
queueConnection?: string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,UAAU,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,MAAM,IAAI,MAAM,GAAG,MAAM,CAAC;IAC1B,wBAAwB,CAAC,IAAI,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tyravel/notifications",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@tyravel/database": "0.1.0",
|
|
19
|
+
"@tyravel/mail": "0.1.0",
|
|
20
|
+
"@tyravel/queue": "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.15.30"
|
|
30
|
+
},
|
|
31
|
+
"description": "Multi-channel notifications for Tyravel",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/thesimonharms/tyravel.git",
|
|
36
|
+
"directory": "packages/notifications"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|