@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.
- package/dist/api/handlers/notifications.js +77 -0
- package/dist/api/handlers/preferences.js +43 -0
- package/dist/api/index.d.ts +16 -0
- package/dist/api/index.js +21 -0
- package/dist/api/types.d.ts +22 -0
- package/dist/api/types.js +0 -0
- package/dist/channels/discord/channel.d.ts +18 -0
- package/dist/channels/discord/channel.js +15 -0
- package/dist/channels/discord/index.d.ts +3 -0
- package/dist/channels/discord/index.js +4 -0
- package/dist/channels/discord/message.d.ts +147 -0
- package/dist/channels/discord/message.js +176 -0
- package/dist/channels/discord/types.d.ts +52 -0
- package/dist/channels/discord/types.js +0 -0
- package/dist/channels/fcm/channel.d.ts +22 -0
- package/dist/channels/fcm/channel.js +44 -0
- package/dist/channels/fcm/index.d.ts +3 -0
- package/dist/channels/fcm/index.js +4 -0
- package/dist/channels/fcm/message.d.ts +64 -0
- package/dist/channels/fcm/message.js +122 -0
- package/dist/channels/fcm/types.d.ts +29 -0
- package/dist/channels/fcm/types.js +0 -0
- package/dist/channels/slack/channel.d.ts +18 -0
- package/dist/channels/slack/channel.js +15 -0
- package/dist/channels/slack/index.d.ts +3 -0
- package/dist/channels/slack/index.js +4 -0
- package/dist/channels/slack/message.d.ts +209 -0
- package/dist/channels/slack/message.js +390 -0
- package/dist/channels/slack/types.d.ts +7 -0
- package/dist/channels/slack/types.js +0 -0
- package/dist/channels/transmit/channel.d.ts +21 -0
- package/dist/channels/transmit/channel.js +27 -0
- package/dist/channels/transmit/index.d.ts +3 -0
- package/dist/channels/transmit/index.js +4 -0
- package/dist/channels/transmit/message.d.ts +11 -0
- package/dist/channels/transmit/message.js +17 -0
- package/dist/channels/transmit/types.d.ts +11 -0
- package/dist/channels/transmit/types.js +0 -0
- package/dist/channels/twilio/channel.d.ts +21 -0
- package/dist/channels/twilio/channel.js +56 -0
- package/dist/channels/twilio/index.d.ts +4 -0
- package/dist/channels/twilio/index.js +4 -0
- package/dist/channels/twilio/message.d.ts +86 -0
- package/dist/channels/twilio/message.js +152 -0
- package/dist/channels/twilio/types.d.ts +51 -0
- package/dist/channels/twilio/types.js +0 -0
- package/dist/channels/webhook/exceptions.d.ts +18 -0
- package/dist/channels/webhook/exceptions.js +24 -0
- package/dist/channels/webhook/index.d.ts +4 -0
- package/dist/channels/webhook/index.js +5 -0
- package/dist/channels/webhook/message.d.ts +24 -0
- package/dist/channels/webhook/message.js +40 -0
- package/dist/channels/webhook/provider.d.ts +19 -0
- package/dist/channels/webhook/provider.js +63 -0
- package/dist/channels/webhook/types.d.ts +15 -0
- package/dist/channels/webhook/types.js +0 -0
- package/dist/channels/webpush/channel.d.ts +26 -0
- package/dist/channels/webpush/channel.js +55 -0
- package/dist/channels/webpush/index.d.ts +3 -0
- package/dist/channels/webpush/index.js +4 -0
- package/dist/channels/webpush/message.d.ts +90 -0
- package/dist/channels/webpush/message.js +174 -0
- package/dist/channels/webpush/types.d.ts +50 -0
- package/dist/channels/webpush/types.js +0 -0
- package/dist/database/adapters/knex.d.ts +6 -0
- package/dist/database/adapters/knex.js +116 -0
- package/dist/database/adapters/kysely.d.ts +6 -0
- package/dist/database/adapters/kysely.js +101 -0
- package/dist/database/channel.d.ts +24 -0
- package/dist/database/channel.js +42 -0
- package/dist/database/database.d.ts +18 -0
- package/dist/database/database.js +89 -0
- package/dist/database/index.d.ts +3 -0
- package/dist/database/index.js +4 -0
- package/dist/database/message.d.ts +26 -0
- package/dist/database/message.js +51 -0
- package/dist/database/types.d.ts +147 -0
- package/dist/database/types.js +0 -0
- package/dist/debug.js +7 -0
- package/dist/errors/duplicate_notification_exception.d.ts +13 -0
- package/dist/errors/duplicate_notification_exception.js +21 -0
- package/dist/errors/http_error.d.ts +16 -0
- package/dist/errors/http_error.js +30 -0
- package/dist/errors/index.d.ts +38 -0
- package/dist/errors/index.js +39 -0
- package/dist/events/events.d.ts +90 -0
- package/dist/events/events.js +83 -0
- package/dist/facteur.d.ts +37 -0
- package/dist/facteur.js +83 -0
- package/dist/fake.d.ts +47 -0
- package/dist/fake.js +85 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +16 -0
- package/dist/notifications/channel_resolver.js +91 -0
- package/dist/notifications/notification_discoverer.d.ts +40 -0
- package/dist/notifications/notification_discoverer.js +113 -0
- package/dist/notifications/notification_sender.js +210 -0
- package/dist/options.d.ts +22 -0
- package/dist/options.js +57 -0
- package/dist/types/channel.d.ts +18 -0
- package/dist/types/channel.js +5 -0
- package/dist/types/events.d.ts +27 -0
- package/dist/types/extend.d.ts +25 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.js +4 -0
- package/dist/types/notifications.d.ts +60 -0
- package/dist/types/notifications.js +38 -0
- package/dist/types/options.d.ts +157 -0
- package/dist/types/preferences.d.ts +40 -0
- package/dist/types/queue.d.ts +11 -0
- 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,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 };
|
package/dist/facteur.js
ADDED
|
@@ -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 };
|