@facteurjs/core 1.0.0-beta.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.
Files changed (111) hide show
  1. package/dist/api/handlers/notifications.js +77 -0
  2. package/dist/api/handlers/preferences.js +43 -0
  3. package/dist/api/index.d.ts +16 -0
  4. package/dist/api/index.js +21 -0
  5. package/dist/api/types.d.ts +22 -0
  6. package/dist/api/types.js +0 -0
  7. package/dist/channels/discord/channel.d.ts +18 -0
  8. package/dist/channels/discord/channel.js +15 -0
  9. package/dist/channels/discord/index.d.ts +3 -0
  10. package/dist/channels/discord/index.js +4 -0
  11. package/dist/channels/discord/message.d.ts +147 -0
  12. package/dist/channels/discord/message.js +176 -0
  13. package/dist/channels/discord/types.d.ts +52 -0
  14. package/dist/channels/discord/types.js +0 -0
  15. package/dist/channels/fcm/channel.d.ts +22 -0
  16. package/dist/channels/fcm/channel.js +44 -0
  17. package/dist/channels/fcm/index.d.ts +3 -0
  18. package/dist/channels/fcm/index.js +4 -0
  19. package/dist/channels/fcm/message.d.ts +64 -0
  20. package/dist/channels/fcm/message.js +122 -0
  21. package/dist/channels/fcm/types.d.ts +29 -0
  22. package/dist/channels/fcm/types.js +0 -0
  23. package/dist/channels/slack/channel.d.ts +18 -0
  24. package/dist/channels/slack/channel.js +15 -0
  25. package/dist/channels/slack/index.d.ts +3 -0
  26. package/dist/channels/slack/index.js +4 -0
  27. package/dist/channels/slack/message.d.ts +209 -0
  28. package/dist/channels/slack/message.js +390 -0
  29. package/dist/channels/slack/types.d.ts +7 -0
  30. package/dist/channels/slack/types.js +0 -0
  31. package/dist/channels/transmit/channel.d.ts +21 -0
  32. package/dist/channels/transmit/channel.js +27 -0
  33. package/dist/channels/transmit/index.d.ts +3 -0
  34. package/dist/channels/transmit/index.js +4 -0
  35. package/dist/channels/transmit/message.d.ts +11 -0
  36. package/dist/channels/transmit/message.js +17 -0
  37. package/dist/channels/transmit/types.d.ts +11 -0
  38. package/dist/channels/transmit/types.js +0 -0
  39. package/dist/channels/twilio/channel.d.ts +21 -0
  40. package/dist/channels/twilio/channel.js +56 -0
  41. package/dist/channels/twilio/index.d.ts +4 -0
  42. package/dist/channels/twilio/index.js +4 -0
  43. package/dist/channels/twilio/message.d.ts +86 -0
  44. package/dist/channels/twilio/message.js +152 -0
  45. package/dist/channels/twilio/types.d.ts +51 -0
  46. package/dist/channels/twilio/types.js +0 -0
  47. package/dist/channels/webhook/exceptions.d.ts +18 -0
  48. package/dist/channels/webhook/exceptions.js +24 -0
  49. package/dist/channels/webhook/index.d.ts +4 -0
  50. package/dist/channels/webhook/index.js +5 -0
  51. package/dist/channels/webhook/message.d.ts +24 -0
  52. package/dist/channels/webhook/message.js +40 -0
  53. package/dist/channels/webhook/provider.d.ts +19 -0
  54. package/dist/channels/webhook/provider.js +63 -0
  55. package/dist/channels/webhook/types.d.ts +15 -0
  56. package/dist/channels/webhook/types.js +0 -0
  57. package/dist/channels/webpush/channel.d.ts +26 -0
  58. package/dist/channels/webpush/channel.js +55 -0
  59. package/dist/channels/webpush/index.d.ts +3 -0
  60. package/dist/channels/webpush/index.js +4 -0
  61. package/dist/channels/webpush/message.d.ts +90 -0
  62. package/dist/channels/webpush/message.js +174 -0
  63. package/dist/channels/webpush/types.d.ts +50 -0
  64. package/dist/channels/webpush/types.js +0 -0
  65. package/dist/database/adapters/knex.d.ts +6 -0
  66. package/dist/database/adapters/knex.js +116 -0
  67. package/dist/database/adapters/kysely.d.ts +6 -0
  68. package/dist/database/adapters/kysely.js +101 -0
  69. package/dist/database/channel.d.ts +24 -0
  70. package/dist/database/channel.js +42 -0
  71. package/dist/database/database.d.ts +18 -0
  72. package/dist/database/database.js +89 -0
  73. package/dist/database/index.d.ts +3 -0
  74. package/dist/database/index.js +4 -0
  75. package/dist/database/message.d.ts +26 -0
  76. package/dist/database/message.js +51 -0
  77. package/dist/database/types.d.ts +147 -0
  78. package/dist/database/types.js +0 -0
  79. package/dist/debug.js +7 -0
  80. package/dist/errors/duplicate_notification_exception.d.ts +13 -0
  81. package/dist/errors/duplicate_notification_exception.js +21 -0
  82. package/dist/errors/http_error.d.ts +16 -0
  83. package/dist/errors/http_error.js +30 -0
  84. package/dist/errors/index.d.ts +38 -0
  85. package/dist/errors/index.js +39 -0
  86. package/dist/events/events.d.ts +90 -0
  87. package/dist/events/events.js +83 -0
  88. package/dist/facteur.d.ts +37 -0
  89. package/dist/facteur.js +83 -0
  90. package/dist/fake.d.ts +47 -0
  91. package/dist/fake.js +85 -0
  92. package/dist/index.d.ts +15 -0
  93. package/dist/index.js +16 -0
  94. package/dist/notifications/channel_resolver.js +91 -0
  95. package/dist/notifications/notification_discoverer.d.ts +40 -0
  96. package/dist/notifications/notification_discoverer.js +113 -0
  97. package/dist/notifications/notification_sender.js +210 -0
  98. package/dist/options.d.ts +22 -0
  99. package/dist/options.js +57 -0
  100. package/dist/types/channel.d.ts +18 -0
  101. package/dist/types/channel.js +5 -0
  102. package/dist/types/events.d.ts +27 -0
  103. package/dist/types/extend.d.ts +25 -0
  104. package/dist/types/index.d.ts +8 -0
  105. package/dist/types/index.js +4 -0
  106. package/dist/types/notifications.d.ts +60 -0
  107. package/dist/types/notifications.js +38 -0
  108. package/dist/types/options.d.ts +157 -0
  109. package/dist/types/preferences.d.ts +40 -0
  110. package/dist/types/queue.d.ts +11 -0
  111. package/package.json +65 -0
@@ -0,0 +1,51 @@
1
+ //#region src/database/message.ts
2
+ var DatabaseMessage = class DatabaseMessage {
3
+ static create() {
4
+ return new DatabaseMessage();
5
+ }
6
+ #type = "default";
7
+ #tags = [];
8
+ #content = {};
9
+ #notifiableId;
10
+ #tenantId;
11
+ #status = "unread";
12
+ setType(type) {
13
+ this.#type = type;
14
+ return this;
15
+ }
16
+ setTags(tags) {
17
+ this.#tags = tags;
18
+ return this;
19
+ }
20
+ setNotifiableId(notifiableId) {
21
+ this.#notifiableId = notifiableId;
22
+ return this;
23
+ }
24
+ setTenantId(tenantId) {
25
+ this.#tenantId = tenantId;
26
+ return this;
27
+ }
28
+ setStatus(status) {
29
+ this.#status = status;
30
+ return this;
31
+ }
32
+ setContent(content) {
33
+ this.#content = content;
34
+ return this;
35
+ }
36
+ serialize() {
37
+ return {
38
+ type: this.#type,
39
+ content: this.#content,
40
+ notifiableId: this.#notifiableId,
41
+ tenantId: this.#tenantId,
42
+ status: this.#status,
43
+ tags: this.#tags,
44
+ createdAt: /* @__PURE__ */ new Date(),
45
+ updatedAt: /* @__PURE__ */ new Date()
46
+ };
47
+ }
48
+ };
49
+
50
+ //#endregion
51
+ export { DatabaseMessage };
@@ -0,0 +1,147 @@
1
+ import { ChannelName } from "../types/extend.js";
2
+ import { Knex } from "knex";
3
+ import { Kysely } from "kysely";
4
+
5
+ //#region src/database/types.d.ts
6
+ type NotificationStatus = 'read' | 'seen' | 'unread' | 'unseen';
7
+ type Identifier = string | number;
8
+ interface AdapterGetNotificationsParams {
9
+ notifiableId: Identifier;
10
+ tenantId: Identifier | undefined;
11
+ page?: number | undefined;
12
+ status?: NotificationStatus | undefined;
13
+ limit?: number;
14
+ }
15
+ interface GetNotificationsParams {
16
+ notifiableId: Identifier;
17
+ tenantId?: Identifier;
18
+ page?: number;
19
+ limit?: number;
20
+ status?: NotificationStatus;
21
+ }
22
+ interface Notification {
23
+ id: Identifier;
24
+ notifiableId: Identifier;
25
+ tenantId?: Identifier | undefined;
26
+ type: string;
27
+ content: Record<string, any>;
28
+ status: NotificationStatus;
29
+ tags?: string[];
30
+ readAt?: Date;
31
+ seenAt?: Date;
32
+ createdAt?: Date;
33
+ updatedAt?: Date;
34
+ }
35
+ interface SaveToDatabaseParams extends Omit<Notification, 'id'> {}
36
+ interface UpdateNotificationParams {
37
+ id: Identifier;
38
+ status: NotificationStatus;
39
+ }
40
+ interface UpdateAllNotificationsParams {
41
+ notifiableId: Identifier;
42
+ tenantId?: Identifier | undefined;
43
+ status: NotificationStatus;
44
+ }
45
+ interface PruneNotificationsParams {
46
+ notifiableId?: Identifier;
47
+ tenantId?: Identifier;
48
+ olderThan?: Date;
49
+ }
50
+ /**
51
+ * Options accepted by the database provider
52
+ */
53
+ interface DatabaseConfig {
54
+ adapter: DatabaseAdapter;
55
+ }
56
+ interface DatabaseAdapterCommonOptions {
57
+ tableNames?: {
58
+ /**
59
+ * The table name to use for storing notifications
60
+ * @default 'notifications'
61
+ */
62
+ notifications?: string | undefined;
63
+ /**
64
+ * The table name to use for storing notification preferences
65
+ * @default 'notification_preferences'
66
+ */
67
+ preferences?: string | undefined;
68
+ };
69
+ }
70
+ /**
71
+ * Options accepted by the Kysely adapter
72
+ */
73
+ interface KyselyConfig extends DatabaseAdapterCommonOptions {
74
+ connection: Kysely<any>;
75
+ }
76
+ /**
77
+ * Options accepted by the Knex adapter
78
+ */
79
+ interface KnexConfig extends DatabaseAdapterCommonOptions {
80
+ connection: Knex;
81
+ }
82
+ interface GetPreferencesParams {
83
+ notifiableId: Identifier;
84
+ tenantId?: Identifier;
85
+ }
86
+ interface RawPreferenceRow {
87
+ id: Identifier;
88
+ user_id: Identifier;
89
+ tenant_id?: Identifier | null;
90
+ notification_name?: string | null;
91
+ channels: Record<string, boolean>;
92
+ created_at: Date;
93
+ updated_at?: Date | null;
94
+ }
95
+ interface NotificationsPreferences {
96
+ /**
97
+ * Global preferences
98
+ */
99
+ global: {
100
+ channels: Record<ChannelName, boolean>;
101
+ };
102
+ /**
103
+ * Per-notification preferences
104
+ */
105
+ notifications: Array<{
106
+ notification: {
107
+ name?: string;
108
+ identifier: string;
109
+ };
110
+ channels: Record<ChannelName, boolean>;
111
+ }>;
112
+ }
113
+ interface Preferences {
114
+ /**
115
+ * Global preferences
116
+ */
117
+ global: NotificationsPreferences;
118
+ /**
119
+ * Per-tenant per-notification preferences
120
+ */
121
+ tenants?: Record<Identifier, NotificationsPreferences>;
122
+ }
123
+ interface SavePreferencesParams {
124
+ notifiableId: Identifier;
125
+ tenantId?: Identifier;
126
+ preferences: Preferences;
127
+ }
128
+ interface UpdatePreferencesParams {
129
+ notifiableId: Identifier;
130
+ tenantId?: Identifier;
131
+ notificationName: string;
132
+ channelPreferences: Record<ChannelName, boolean>;
133
+ }
134
+ /**
135
+ * The interface for implementing a new database adapter
136
+ */
137
+ interface DatabaseAdapter {
138
+ save: (options: SaveToDatabaseParams) => Promise<void>;
139
+ getNotifications: (options: AdapterGetNotificationsParams) => Promise<Notification[]>;
140
+ updateNotification: (options: UpdateNotificationParams) => Promise<void>;
141
+ updateAllNotifications: (options: UpdateAllNotificationsParams) => Promise<void>;
142
+ pruneNotifications: (options: PruneNotificationsParams) => Promise<void>;
143
+ getPreferences: (options: GetPreferencesParams) => Promise<RawPreferenceRow[]>;
144
+ updatePreferences: (options: UpdatePreferencesParams) => Promise<void>;
145
+ }
146
+ //#endregion
147
+ export { AdapterGetNotificationsParams, DatabaseAdapter, DatabaseAdapterCommonOptions, DatabaseConfig, GetNotificationsParams, GetPreferencesParams, Identifier, KnexConfig, KyselyConfig, Notification, NotificationStatus, NotificationsPreferences, Preferences, PruneNotificationsParams, RawPreferenceRow, SavePreferencesParams, SaveToDatabaseParams, UpdateAllNotificationsParams, UpdateNotificationParams, UpdatePreferencesParams };
File without changes
package/dist/debug.js ADDED
@@ -0,0 +1,7 @@
1
+ import { debuglog } from "node:util";
2
+
3
+ //#region src/debug.ts
4
+ var debug_default = debuglog("facteur:core");
5
+
6
+ //#endregion
7
+ export { debug_default as default };
@@ -0,0 +1,13 @@
1
+ //#region src/errors/duplicate_notification_exception.d.ts
2
+ interface DuplicateNotification {
3
+ notificationName: string;
4
+ notifications: Array<{
5
+ notification: any;
6
+ file: URL | string;
7
+ }> | undefined;
8
+ }
9
+ declare class E_DUPLICATE_NOTIFICATION extends Error {
10
+ constructor(appRoot: URL, duplicates: DuplicateNotification[]);
11
+ }
12
+ //#endregion
13
+ export { E_DUPLICATE_NOTIFICATION };
@@ -0,0 +1,21 @@
1
+ import { fileURLToPath } from "node:url";
2
+
3
+ //#region src/errors/duplicate_notification_exception.ts
4
+ var E_DUPLICATE_NOTIFICATION = class extends Error {
5
+ constructor(appRoot, duplicates) {
6
+ let errorMessage = "Duplicate notification names detected:";
7
+ for (const { notificationName, notifications = [] } of duplicates) {
8
+ errorMessage += `\n\nNotification name "${notificationName}" is used in multiple files:\n`;
9
+ errorMessage += notifications.map(({ file }) => {
10
+ const relativePath = fileURLToPath(file).replace(appRoot.pathname, "");
11
+ return `- ${relativePath}`;
12
+ }).join("\n");
13
+ }
14
+ errorMessage += "\n\nEach notification must have a unique name. You can use a static \"notificationName\" property to customize the notification name.";
15
+ super(errorMessage);
16
+ this.name = "DuplicateNotificationException";
17
+ }
18
+ };
19
+
20
+ //#endregion
21
+ export { E_DUPLICATE_NOTIFICATION };
@@ -0,0 +1,16 @@
1
+ //#region src/errors/http_error.d.ts
2
+
3
+ /**
4
+ * Represents an HTTP error with decoded response body
5
+ */
6
+ interface HTTPErrorInfo {
7
+ url: string;
8
+ status: number;
9
+ statusText: string;
10
+ responseBody: string;
11
+ }
12
+ /**
13
+ * Extracts information from an HTTPError with async response body decoding
14
+ */
15
+ //#endregion
16
+ export { HTTPErrorInfo };
@@ -0,0 +1,30 @@
1
+ //#region src/errors/http_error.ts
2
+ /**
3
+ * Extracts information from an HTTPError with async response body decoding
4
+ */
5
+ var HTTPErrorExtractor = class {
6
+ /**
7
+ * Extracts HTTP error information with properly decoded response body
8
+ */
9
+ static async extract(httpError) {
10
+ const url = httpError.request.url;
11
+ const status = httpError.response.status;
12
+ const statusText = httpError.response.statusText;
13
+ let responseBody;
14
+ try {
15
+ const jsonBody = await httpError.response.clone().json();
16
+ responseBody = JSON.stringify(jsonBody, null, 2);
17
+ } catch {
18
+ responseBody = await httpError.response.text();
19
+ }
20
+ return {
21
+ url,
22
+ status,
23
+ statusText,
24
+ responseBody
25
+ };
26
+ }
27
+ };
28
+
29
+ //#endregion
30
+ export { HTTPErrorExtractor };
@@ -0,0 +1,38 @@
1
+ import { E_DUPLICATE_NOTIFICATION } from "./duplicate_notification_exception.js";
2
+ import * as _poppinss_exception0 from "@poppinss/exception";
3
+
4
+ //#region src/errors/index.d.ts
5
+
6
+ /**
7
+ * Thrown when the notification targets for a channel cannot be determined
8
+ * before sending the notification.
9
+ */
10
+ declare const E_UNAVAILABLE_TARGETS: new (args: [channelName: string], options?: ErrorOptions) => _poppinss_exception0.Exception;
11
+ /**
12
+ * Thrown when the queue adapter is not set before using jobs specific features.
13
+ */
14
+ declare const E_QUEUE_NOT_SET: new (args?: any, options?: ErrorOptions) => _poppinss_exception0.Exception;
15
+ /**
16
+ * Thrown when a `as<ChannelName>Message` method is not defined
17
+ */
18
+ declare const E_MISSING_MESSAGE_METHOD: new (args: [channelName: string], options?: ErrorOptions) => _poppinss_exception0.Exception;
19
+ /**
20
+ * Thrown when a send() operation fails. Could be due to one or more channels
21
+ * failing to send the notification.
22
+ */
23
+ declare class E_SEND_NOTIFICATION_FAILED extends AggregateError {
24
+ code: string;
25
+ status: number;
26
+ constructor(errors: Array<{
27
+ error: any;
28
+ }>);
29
+ }
30
+ declare const errors: {
31
+ E_QUEUE_NOT_SET: new (args?: any, options?: ErrorOptions) => _poppinss_exception0.Exception;
32
+ E_UNAVAILABLE_TARGETS: new (args: [channelName: string], options?: ErrorOptions) => _poppinss_exception0.Exception;
33
+ E_DUPLICATE_NOTIFICATION: typeof E_DUPLICATE_NOTIFICATION;
34
+ E_MISSING_MESSAGE_METHOD: new (args: [channelName: string], options?: ErrorOptions) => _poppinss_exception0.Exception;
35
+ E_SEND_NOTIFICATION_FAILED: typeof E_SEND_NOTIFICATION_FAILED;
36
+ };
37
+ //#endregion
38
+ export { E_MISSING_MESSAGE_METHOD, E_QUEUE_NOT_SET, E_SEND_NOTIFICATION_FAILED, E_UNAVAILABLE_TARGETS, errors };
@@ -0,0 +1,39 @@
1
+ import { E_DUPLICATE_NOTIFICATION } from "./duplicate_notification_exception.js";
2
+ import { createError } from "@poppinss/exception";
3
+
4
+ //#region src/errors/index.ts
5
+ /**
6
+ * Thrown when the notification targets for a channel cannot be determined
7
+ * before sending the notification.
8
+ */
9
+ const E_UNAVAILABLE_TARGETS = createError(`Not able to determine targets for channel "%s". Provide targets or implement 'notificationTargets()' method.`, "E_UNAVAILABLE_TARGETS", 500);
10
+ /**
11
+ * Thrown when the queue adapter is not set before using jobs specific features.
12
+ */
13
+ const E_QUEUE_NOT_SET = createError(`Queue adapter is not set. Set it via "setQueueAdapter" method before using jobs specific features.`, "E_QUEUE_NOT_SET", 500);
14
+ /**
15
+ * Thrown when a `as<ChannelName>Message` method is not defined
16
+ */
17
+ const E_MISSING_MESSAGE_METHOD = createError(`Notification is missing "as%sMessage" method. Define it to build the message content for the channel.`, "E_MISSING_MESSAGE_METHOD", 500);
18
+ /**
19
+ * Thrown when a send() operation fails. Could be due to one or more channels
20
+ * failing to send the notification.
21
+ */
22
+ var E_SEND_NOTIFICATION_FAILED = class extends AggregateError {
23
+ code = "E_SEND_NOTIFICATION_FAILED";
24
+ status = 500;
25
+ constructor(errors$1) {
26
+ const message = "Failed to send notification due to errors in one or more channels.";
27
+ super(errors$1, message);
28
+ }
29
+ };
30
+ const errors = {
31
+ E_QUEUE_NOT_SET,
32
+ E_UNAVAILABLE_TARGETS,
33
+ E_DUPLICATE_NOTIFICATION,
34
+ E_MISSING_MESSAGE_METHOD,
35
+ E_SEND_NOTIFICATION_FAILED
36
+ };
37
+
38
+ //#endregion
39
+ export { E_MISSING_MESSAGE_METHOD, E_QUEUE_NOT_SET, E_SEND_NOTIFICATION_FAILED, E_UNAVAILABLE_TARGETS, errors };
@@ -0,0 +1,90 @@
1
+ import { ChannelName } from "../types/extend.js";
2
+ import { Notification } from "../types/notifications.js";
3
+
4
+ //#region src/events/events.d.ts
5
+ interface MessageEventOptions {
6
+ notification: Notification<any, any>;
7
+ channelName: ChannelName;
8
+ message: any;
9
+ }
10
+ interface NotificationEventOptions {
11
+ notification: Notification<any, any>;
12
+ }
13
+ declare class FacteurEvents {
14
+ #private;
15
+ /**
16
+ * Sent when a message is about to be sent.
17
+ */
18
+ messageSending(options: MessageEventOptions): {
19
+ name: "facteur:message:sending";
20
+ data: {
21
+ notification: Notification<any, any>;
22
+ channelName: never;
23
+ message: any;
24
+ };
25
+ };
26
+ /**
27
+ * Sent when a message has been successfully sent.
28
+ */
29
+ messageSent(options: MessageEventOptions): {
30
+ name: "facteur:message:sent";
31
+ data: {
32
+ notification: Notification<any, any>;
33
+ channelName: never;
34
+ message: any;
35
+ };
36
+ };
37
+ /**
38
+ * Sent when a message failed to send.
39
+ */
40
+ messageFailed(options: MessageEventOptions & {
41
+ error: Error;
42
+ }): {
43
+ name: "facteur:message:failed";
44
+ data: {
45
+ error: Error;
46
+ notification: Notification<any, any>;
47
+ channelName: never;
48
+ message: any;
49
+ };
50
+ };
51
+ /**
52
+ * Sent when a notification is about to be sent.
53
+ */
54
+ notificationSending(options: NotificationEventOptions & {
55
+ resolvedChannels: Record<string, any>;
56
+ }): {
57
+ name: "facteur:notification:sending";
58
+ data: {
59
+ resolvedChannels: Record<string, any>;
60
+ notification: Notification<any, any>;
61
+ };
62
+ };
63
+ /**
64
+ * Sent when a notification has been successfully sent.
65
+ */
66
+ notificationSent(options: NotificationEventOptions & {
67
+ results: any[];
68
+ }): {
69
+ name: "facteur:notification:sent";
70
+ data: {
71
+ results: any[];
72
+ notification: Notification<any, any>;
73
+ };
74
+ };
75
+ /**
76
+ * Sent when a notification failed to send.
77
+ */
78
+ notificationFailed(options: NotificationEventOptions & {
79
+ errors: Error[];
80
+ }): {
81
+ name: "facteur:notification:failed";
82
+ data: {
83
+ errors: Error[];
84
+ notification: Notification<any, any>;
85
+ };
86
+ };
87
+ }
88
+ declare const facteurEvents: FacteurEvents;
89
+ //#endregion
90
+ export { facteurEvents };
@@ -0,0 +1,83 @@
1
+ //#region src/events/events.ts
2
+ var FacteurEvents = class {
3
+ #buildMessageEventData(options) {
4
+ return {
5
+ notification: options.notification,
6
+ channelName: options.channelName,
7
+ message: options.message
8
+ };
9
+ }
10
+ #buildNotificationEventData(options) {
11
+ return { notification: options.notification };
12
+ }
13
+ /**
14
+ * Sent when a message is about to be sent.
15
+ */
16
+ messageSending(options) {
17
+ return {
18
+ name: "facteur:message:sending",
19
+ data: this.#buildMessageEventData(options)
20
+ };
21
+ }
22
+ /**
23
+ * Sent when a message has been successfully sent.
24
+ */
25
+ messageSent(options) {
26
+ return {
27
+ name: "facteur:message:sent",
28
+ data: this.#buildMessageEventData(options)
29
+ };
30
+ }
31
+ /**
32
+ * Sent when a message failed to send.
33
+ */
34
+ messageFailed(options) {
35
+ return {
36
+ name: "facteur:message:failed",
37
+ data: {
38
+ ...this.#buildMessageEventData(options),
39
+ error: options.error
40
+ }
41
+ };
42
+ }
43
+ /**
44
+ * Sent when a notification is about to be sent.
45
+ */
46
+ notificationSending(options) {
47
+ return {
48
+ name: "facteur:notification:sending",
49
+ data: {
50
+ ...this.#buildNotificationEventData(options),
51
+ resolvedChannels: options.resolvedChannels
52
+ }
53
+ };
54
+ }
55
+ /**
56
+ * Sent when a notification has been successfully sent.
57
+ */
58
+ notificationSent(options) {
59
+ return {
60
+ name: "facteur:notification:sent",
61
+ data: {
62
+ ...this.#buildNotificationEventData(options),
63
+ results: options.results
64
+ }
65
+ };
66
+ }
67
+ /**
68
+ * Sent when a notification failed to send.
69
+ */
70
+ notificationFailed(options) {
71
+ return {
72
+ name: "facteur:notification:failed",
73
+ data: {
74
+ ...this.#buildNotificationEventData(options),
75
+ errors: options.errors
76
+ }
77
+ };
78
+ }
79
+ };
80
+ const facteurEvents = new FacteurEvents();
81
+
82
+ //#endregion
83
+ export { facteurEvents };
@@ -0,0 +1,37 @@
1
+ import { DatabaseAdapter } from "./database/types.js";
2
+ import { Channel } from "./types/channel.js";
3
+ import { FacteurConfiguration, SendOptions } from "./types/options.js";
4
+ import { Notification, NotificationClass, NotificationSendResult } from "./types/notifications.js";
5
+ import { FacteurFake } from "./fake.js";
6
+ import { FacteurDatabase } from "./database/database.js";
7
+
8
+ //#region src/facteur.d.ts
9
+ declare function createFacteur<T extends Record<string, Channel>>(config: FacteurConfiguration<T>): Facteur<T, null>;
10
+ /**
11
+ * Main manager class for Facteur library.
12
+ */
13
+ declare class Facteur<KnownChannels extends Record<string, Channel>, DBAdapter extends DatabaseAdapter | null = null> {
14
+ #private;
15
+ constructor(config: FacteurConfiguration<KnownChannels, DBAdapter>);
16
+ get db(): DBAdapter extends DatabaseAdapter ? FacteurDatabase : never;
17
+ get discoverer(): {
18
+ discoverNotifications: () => Promise<(new (...args: any[]) => Notification)[]>;
19
+ getNotifications: () => Promise<(new (...args: any[]) => Notification)[]>;
20
+ getNotificationTags: () => Promise<string[]>;
21
+ clearCache: () => void;
22
+ };
23
+ /**
24
+ * Fake the notification sending process for testing purposes
25
+ */
26
+ fake(): FacteurFake;
27
+ /**
28
+ * Restore the original notification sending process after faking it
29
+ */
30
+ restore(): void;
31
+ /**
32
+ * Send a notification
33
+ */
34
+ send<TNotificationClass extends NotificationClass<any, any>>(options: SendOptions<TNotificationClass>): Promise<NotificationSendResult>;
35
+ }
36
+ //#endregion
37
+ export { Facteur, createFacteur };
@@ -0,0 +1,83 @@
1
+ import { FacteurFake } from "./fake.js";
2
+ import { FacteurOptions } from "./options.js";
3
+ import { FacteurDatabase } from "./database/database.js";
4
+ import { ChannelResolver } from "./notifications/channel_resolver.js";
5
+ import { NotificationSender } from "./notifications/notification_sender.js";
6
+ import "./types/index.js";
7
+ import { NotificationDiscoverer } from "./notifications/notification_discoverer.js";
8
+
9
+ //#region src/facteur.ts
10
+ function createFacteur(config) {
11
+ return new Facteur(config);
12
+ }
13
+ /**
14
+ * Main manager class for Facteur library.
15
+ */
16
+ var Facteur = class {
17
+ #sender;
18
+ #fake = null;
19
+ #db = null;
20
+ #discoverer;
21
+ #channelResolver;
22
+ #options;
23
+ constructor(config) {
24
+ this.#options = new FacteurOptions(config);
25
+ this.#discoverer = new NotificationDiscoverer({
26
+ searchDirectory: config.discoverer.searchDirectory,
27
+ fileSuffix: config.discoverer.fileSuffix
28
+ });
29
+ if (this.#options.databaseAdapter) {
30
+ const options = this.#options;
31
+ this.#db = new FacteurDatabase(options, this.#discoverer);
32
+ this.#channelResolver = new ChannelResolver(this.#db);
33
+ } else this.#channelResolver = new ChannelResolver();
34
+ this.#sender = new NotificationSender(this.#options.channels, this.#channelResolver, this.#options.emitter);
35
+ }
36
+ get db() {
37
+ if (!this.#options.databaseAdapter) throw new Error("No database adapter configured");
38
+ return this.#db;
39
+ }
40
+ get discoverer() {
41
+ return {
42
+ discoverNotifications: () => this.#discoverer.discoverNotifications(),
43
+ getNotifications: () => this.#discoverer.getNotifications(),
44
+ getNotificationTags: () => this.#discoverer.getAllNotificationTags(),
45
+ clearCache: () => this.#discoverer.clearCache()
46
+ };
47
+ }
48
+ /**
49
+ * Fake the notification sending process for testing purposes
50
+ */
51
+ fake() {
52
+ this.#fake = new FacteurFake();
53
+ return this.#fake;
54
+ }
55
+ /**
56
+ * Restore the original notification sending process after faking it
57
+ */
58
+ restore() {
59
+ this.#fake = null;
60
+ }
61
+ /**
62
+ * Send a notification
63
+ */
64
+ async send(options) {
65
+ const notification = await this.#options.notificationResolver(options.notification, {
66
+ notifiable: "notifiable" in options ? options.notifiable : void 0,
67
+ params: options.params,
68
+ tenantId: options.tenantId
69
+ });
70
+ await notification.beforeSend();
71
+ const shouldSend = await notification.shouldSend();
72
+ if (shouldSend === false) return {
73
+ success: 0,
74
+ failed: 0,
75
+ results: []
76
+ };
77
+ if (this.#fake) return this.#fake.recordSent(options);
78
+ return this.#sender.send(options, notification);
79
+ }
80
+ };
81
+
82
+ //#endregion
83
+ export { Facteur, createFacteur };