@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
package/dist/options.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { errors } from "./errors/index.js";
|
|
2
|
+
import EventEmitter from "node:events";
|
|
3
|
+
import { noopLogger } from "@julr/utils/logger";
|
|
4
|
+
import { invoke } from "@julr/utils/functions";
|
|
5
|
+
|
|
6
|
+
//#region src/options.ts
|
|
7
|
+
var FacteurOptions = class {
|
|
8
|
+
logger = noopLogger();
|
|
9
|
+
emitter = new EventEmitter();
|
|
10
|
+
channels;
|
|
11
|
+
queueAdapter;
|
|
12
|
+
databaseAdapter = null;
|
|
13
|
+
notificationResolver;
|
|
14
|
+
defaultPreferences;
|
|
15
|
+
#resolveDefaultPreferences(preferences) {
|
|
16
|
+
preferences = preferences || {};
|
|
17
|
+
const allChannels = Object.keys(this.channels);
|
|
18
|
+
/**
|
|
19
|
+
* Pick global preferences or set all channels to true
|
|
20
|
+
*/
|
|
21
|
+
const globalChannelPreferences = preferences.global?.channels || Object.fromEntries(allChannels.map((channel) => [channel, true]));
|
|
22
|
+
/**
|
|
23
|
+
* Build categories preferences
|
|
24
|
+
*/
|
|
25
|
+
const categories = Object.entries(preferences.categories || {}).map(([category, config]) => {
|
|
26
|
+
const value = invoke(() => {
|
|
27
|
+
if (typeof config === "boolean") return Object.fromEntries(allChannels.map((channel) => [channel, config]));
|
|
28
|
+
return Object.assign({}, globalChannelPreferences, config.channels || {});
|
|
29
|
+
});
|
|
30
|
+
return [category, { channels: value }];
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
enabled: preferences.enabled ?? true,
|
|
34
|
+
global: { channels: globalChannelPreferences },
|
|
35
|
+
categories: Object.fromEntries(categories)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.logger = config.logger ?? this.logger;
|
|
40
|
+
this.emitter = config.emitter ?? this.emitter;
|
|
41
|
+
this.channels = config.channels;
|
|
42
|
+
this.databaseAdapter = config.databaseAdapter ?? null;
|
|
43
|
+
this.defaultPreferences = this.#resolveDefaultPreferences(config.preferences);
|
|
44
|
+
this.notificationResolver = config.notificationResolver || ((notification, ctx) => new notification(ctx));
|
|
45
|
+
const throwIfQueueNotSet = () => {
|
|
46
|
+
throw new errors.E_QUEUE_NOT_SET();
|
|
47
|
+
};
|
|
48
|
+
this.queueAdapter = config.queueAdapter || {
|
|
49
|
+
queue: throwIfQueueNotSet,
|
|
50
|
+
startQueueProcessor: throwIfQueueNotSet,
|
|
51
|
+
disconnect: throwIfQueueNotSet
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { FacteurOptions };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Identifier } from "../database/types.js";
|
|
2
|
+
import { Awaitable } from "@julr/utils/types";
|
|
3
|
+
|
|
4
|
+
//#region src/types/channel.d.ts
|
|
5
|
+
type ChannelSendParams<Message, Targets> = {
|
|
6
|
+
notifiable?: any;
|
|
7
|
+
message: Message;
|
|
8
|
+
targets?: Targets;
|
|
9
|
+
tenantId?: Identifier | undefined;
|
|
10
|
+
};
|
|
11
|
+
declare const kTargetSymbol: unique symbol;
|
|
12
|
+
interface Channel<_Options = any, Message = any, Response = any, Targets = any> {
|
|
13
|
+
[kTargetSymbol]: Targets;
|
|
14
|
+
name: string;
|
|
15
|
+
send: (options: ChannelSendParams<Message, Targets>) => Awaitable<Response>;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { Channel, ChannelSendParams, kTargetSymbol };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { facteurEvents } from "../events/events.js";
|
|
2
|
+
|
|
3
|
+
//#region src/types/events.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shape of the emitter accepted by facteur
|
|
7
|
+
* Should be compatible with node's EventEmitter and Emittery
|
|
8
|
+
*/
|
|
9
|
+
interface Emitter {
|
|
10
|
+
on: (event: string, callback: (...values: any[]) => void) => void;
|
|
11
|
+
once: (event: string, callback: (...values: any[]) => void) => void;
|
|
12
|
+
off: (event: string, callback: (...values: any[]) => void) => void;
|
|
13
|
+
emit: (event: string, ...values: any[]) => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Name/payload of the events emitted by facteur
|
|
17
|
+
*/
|
|
18
|
+
type FacteurEvents = {
|
|
19
|
+
'facteur:message:sending': ReturnType<typeof facteurEvents.messageSending>['data'];
|
|
20
|
+
'facteur:message:sent': ReturnType<typeof facteurEvents.messageSent>['data'];
|
|
21
|
+
'facteur:message:failed': ReturnType<typeof facteurEvents.messageFailed>['data'];
|
|
22
|
+
'facteur:notification:sending': ReturnType<typeof facteurEvents.notificationSending>['data'];
|
|
23
|
+
'facteur:notification:sent': ReturnType<typeof facteurEvents.notificationSent>['data'];
|
|
24
|
+
'facteur:notification:failed': ReturnType<typeof facteurEvents.notificationFailed>['data'];
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { Emitter, FacteurEvents };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FacteurConfiguration } from "./options.js";
|
|
2
|
+
import { Facteur } from "../facteur.js";
|
|
3
|
+
|
|
4
|
+
//#region src/types/extend.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* List of available channels
|
|
8
|
+
*/
|
|
9
|
+
type ChannelName = keyof NotificationChannels;
|
|
10
|
+
/**
|
|
11
|
+
* The list of channels configured in the Facteur instance. This must
|
|
12
|
+
* be extended user-land with module augmentation
|
|
13
|
+
*/
|
|
14
|
+
interface NotificationChannels {}
|
|
15
|
+
/**
|
|
16
|
+
* The type of the notification.content in database notifications.
|
|
17
|
+
* This must be extended user-land with module augmentation
|
|
18
|
+
*/
|
|
19
|
+
interface DatabaseContent {}
|
|
20
|
+
/**
|
|
21
|
+
* Infer the channels from the Facteur instance
|
|
22
|
+
*/
|
|
23
|
+
type InferChannelsFromConfig<T> = T extends Facteur<infer U> ? U : T extends FacteurConfiguration<infer X> ? X : never;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { ChannelName, DatabaseContent, InferChannelsFromConfig, NotificationChannels };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Channel, ChannelSendParams, kTargetSymbol } from "./channel.js";
|
|
2
|
+
import { Emitter, FacteurEvents } from "./events.js";
|
|
3
|
+
import { QueueAdapter, QueueItemOptions } from "./queue.js";
|
|
4
|
+
import { DefaultPreferences, ResolvedDefaultPreferences } from "./preferences.js";
|
|
5
|
+
import { ChannelName, DatabaseContent, InferChannelsFromConfig, NotificationChannels } from "./extend.js";
|
|
6
|
+
import { ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions } from "./options.js";
|
|
7
|
+
import { ChannelSendResult, Notifiable, NotifiableTargets, Notification, NotificationClass, NotificationSendResult } from "./notifications.js";
|
|
8
|
+
export { Channel, ChannelName, ChannelSendParams, ChannelSendResult, ChannelSpecificConfig, CommonSendOptions, DatabaseContent, DefaultPreferences, DeliverByOptions, Emitter, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, FacteurEvents, InferChannelsFromConfig, MessageCtx, Notifiable, NotifiableTargets, Notification, NotificationChannels, NotificationClass, NotificationOptions, NotificationParams, NotificationResolver, NotificationSendResult, ProviderTarget, QueueAdapter, QueueItemOptions, ResolvedDefaultPreferences, SendOptions, kTargetSymbol };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Identifier } from "../database/types.js";
|
|
2
|
+
import { ChannelName, NotificationChannels } from "./extend.js";
|
|
3
|
+
import { ExtractChannelTargets, MessageCtx, NotificationOptions } from "./options.js";
|
|
4
|
+
import { Awaitable } from "@julr/utils/types";
|
|
5
|
+
|
|
6
|
+
//#region src/types/notifications.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Constructor type for notification classes
|
|
10
|
+
*/
|
|
11
|
+
type NotificationClass<TNotifiable extends Notifiable | undefined, TParams extends Record<string, any> = Record<string, any>> = new (...args: any[]) => Notification<TNotifiable, TParams>;
|
|
12
|
+
/**
|
|
13
|
+
* Base abstract class for all notifications
|
|
14
|
+
*/
|
|
15
|
+
declare abstract class Notification<N extends Notifiable | undefined = Notifiable | undefined, Params extends Record<string, any> = any> {
|
|
16
|
+
protected notifiable: N;
|
|
17
|
+
protected params: Params;
|
|
18
|
+
protected tenantId: Identifier | undefined;
|
|
19
|
+
constructor(ctx: MessageCtx<N, Params>);
|
|
20
|
+
static options: NotificationOptions<any>;
|
|
21
|
+
/**
|
|
22
|
+
* Determine if the notification should be sent or not
|
|
23
|
+
*/
|
|
24
|
+
shouldSend(): Awaitable<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Method invoked before sending the notification.
|
|
27
|
+
* Can be used to perform any pre-send logic.
|
|
28
|
+
*/
|
|
29
|
+
beforeSend(): Awaitable<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Method invoked after the notification has been sent.
|
|
32
|
+
* Can be used to perform any post-send logic.
|
|
33
|
+
*/
|
|
34
|
+
afterSend(): Awaitable<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of sending notification through a specific channel
|
|
38
|
+
*/
|
|
39
|
+
interface ChannelSendResult {
|
|
40
|
+
channel: ChannelName;
|
|
41
|
+
status: 'success' | 'failed';
|
|
42
|
+
error?: any;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Overall result of sending a notification across all channels
|
|
46
|
+
*/
|
|
47
|
+
interface NotificationSendResult {
|
|
48
|
+
success: number;
|
|
49
|
+
failed: number;
|
|
50
|
+
results: ChannelSendResult[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Interface for entities that can receive notifications
|
|
54
|
+
*/
|
|
55
|
+
interface Notifiable {
|
|
56
|
+
notificationTargets?(): NotifiableTargets;
|
|
57
|
+
}
|
|
58
|
+
type NotifiableTargets = { [K in keyof NotificationChannels]?: ExtractChannelTargets<NotificationChannels[K]> };
|
|
59
|
+
//#endregion
|
|
60
|
+
export { ChannelSendResult, Notifiable, NotifiableTargets, Notification, NotificationClass, NotificationSendResult };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/types/notifications.ts
|
|
2
|
+
/**
|
|
3
|
+
* Base abstract class for all notifications
|
|
4
|
+
*/
|
|
5
|
+
var Notification = class {
|
|
6
|
+
notifiable;
|
|
7
|
+
params;
|
|
8
|
+
tenantId;
|
|
9
|
+
constructor(ctx) {
|
|
10
|
+
this.notifiable = ctx.notifiable;
|
|
11
|
+
this.params = ctx.params;
|
|
12
|
+
this.tenantId = ctx.tenantId;
|
|
13
|
+
}
|
|
14
|
+
static options = {
|
|
15
|
+
name: "",
|
|
16
|
+
tags: [],
|
|
17
|
+
deliverBy: {}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Determine if the notification should be sent or not
|
|
21
|
+
*/
|
|
22
|
+
shouldSend() {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Method invoked before sending the notification.
|
|
27
|
+
* Can be used to perform any pre-send logic.
|
|
28
|
+
*/
|
|
29
|
+
beforeSend() {}
|
|
30
|
+
/**
|
|
31
|
+
* Method invoked after the notification has been sent.
|
|
32
|
+
* Can be used to perform any post-send logic.
|
|
33
|
+
*/
|
|
34
|
+
afterSend() {}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { Notification };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { DatabaseAdapter, Identifier } from "../database/types.js";
|
|
2
|
+
import { Channel } from "./channel.js";
|
|
3
|
+
import { Emitter } from "./events.js";
|
|
4
|
+
import { QueueAdapter } from "./queue.js";
|
|
5
|
+
import { DefaultPreferences } from "./preferences.js";
|
|
6
|
+
import { ChannelName, NotificationChannels } from "./extend.js";
|
|
7
|
+
import { Notifiable, Notification, NotificationClass } from "./notifications.js";
|
|
8
|
+
import { Logger } from "@julr/utils/logger";
|
|
9
|
+
import { Awaitable } from "@julr/utils/types";
|
|
10
|
+
|
|
11
|
+
//#region src/types/options.d.ts
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for the Facteur library
|
|
15
|
+
*/
|
|
16
|
+
interface FacteurConfiguration<KnownChannels extends Record<string, Channel> = Record<string, Channel>, DBAdapter extends DatabaseAdapter | null = null> {
|
|
17
|
+
logger?: Logger;
|
|
18
|
+
emitter?: Emitter;
|
|
19
|
+
/**
|
|
20
|
+
* Channels to use for sending notifications.
|
|
21
|
+
*/
|
|
22
|
+
channels: KnownChannels;
|
|
23
|
+
/**
|
|
24
|
+
* A queue adapter to use for sending notifications.
|
|
25
|
+
* Needs to be provided if you want to use some queueing capabilities.
|
|
26
|
+
*/
|
|
27
|
+
queueAdapter?: QueueAdapter;
|
|
28
|
+
/**
|
|
29
|
+
* Database adapter to use for storing things, like topics and preferences.
|
|
30
|
+
* If not provided, you will not be able these features.
|
|
31
|
+
*/
|
|
32
|
+
databaseAdapter?: DBAdapter;
|
|
33
|
+
/**
|
|
34
|
+
* Discoverer configuration
|
|
35
|
+
*/
|
|
36
|
+
discoverer: {
|
|
37
|
+
/**
|
|
38
|
+
* Directory to search for notification classes. Will scan recursively.
|
|
39
|
+
*/
|
|
40
|
+
searchDirectory: URL;
|
|
41
|
+
/**
|
|
42
|
+
* Suffix for notification files.
|
|
43
|
+
* @default '_notification.ts'
|
|
44
|
+
*/
|
|
45
|
+
fileSuffix?: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The default preferences for the users.
|
|
49
|
+
*/
|
|
50
|
+
preferences?: DefaultPreferences<KnownChannels>;
|
|
51
|
+
/**
|
|
52
|
+
* A callback that will be called to instantiate a notification class.
|
|
53
|
+
* Can be handy for using dependency injection or other custom instantiation logic.
|
|
54
|
+
* If not provided, the default constructor will be used.
|
|
55
|
+
*/
|
|
56
|
+
notificationResolver?: NotificationResolver;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolver function type for notifications
|
|
60
|
+
*/
|
|
61
|
+
type NotificationResolver = (notification: new (ctx: MessageCtx<any, any>, ...args: any[]) => Notification, ctx: MessageCtx<any, any>) => Awaitable<Notification>;
|
|
62
|
+
interface NotificationOptions<N extends Notifiable = Notifiable> {
|
|
63
|
+
/**
|
|
64
|
+
* A human readable name for the notification.
|
|
65
|
+
* Used for UI purpose
|
|
66
|
+
*/
|
|
67
|
+
name: string;
|
|
68
|
+
/**
|
|
69
|
+
* A unique identifier for the notification.
|
|
70
|
+
* Used to identify the notification in the database and preferences.
|
|
71
|
+
*
|
|
72
|
+
* By default it is the class name
|
|
73
|
+
*/
|
|
74
|
+
identifier?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Bypass preferences and send the notification regardless of user settings.
|
|
77
|
+
* Useful for critical notifications that should always be sent.
|
|
78
|
+
*/
|
|
79
|
+
critical?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Human readable tags. Also used for UI purpose
|
|
82
|
+
*/
|
|
83
|
+
tags?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Channel category
|
|
86
|
+
*/
|
|
87
|
+
category?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Channels to deliver the notification by.
|
|
90
|
+
*/
|
|
91
|
+
deliverBy: Partial<Record<ChannelName, boolean | DeliverByOptions<N>>>;
|
|
92
|
+
}
|
|
93
|
+
interface DeliverByOptions<N extends Notifiable = Notifiable> {
|
|
94
|
+
if: (options: {
|
|
95
|
+
notifiable: N;
|
|
96
|
+
params?: any;
|
|
97
|
+
preferences?: Record<string, boolean | undefined>;
|
|
98
|
+
}) => boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parameters received by the `as*Message` methods of a notification.
|
|
102
|
+
*/
|
|
103
|
+
interface MessageCtx<N extends Notifiable | undefined = Notifiable, Params extends Record<string, any> = {}> {
|
|
104
|
+
notifiable: N;
|
|
105
|
+
params: Params;
|
|
106
|
+
tenantId?: Identifier | undefined;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Extract the parameters type from a notification class
|
|
110
|
+
*/
|
|
111
|
+
type ExtractParams<T> = T extends NotificationClass<any, infer P> ? P : never;
|
|
112
|
+
/**
|
|
113
|
+
* Extract the notifiable type from a notification class
|
|
114
|
+
*/
|
|
115
|
+
type ExtractNotifiable<T> = T extends NotificationClass<infer N, any> ? N : never;
|
|
116
|
+
/**
|
|
117
|
+
* Determine if a notification requires parameters or if they are optional
|
|
118
|
+
*/
|
|
119
|
+
type NotificationParams<TNotificationClass extends NotificationClass<any, any>> = ExtractParams<TNotificationClass> extends unknown ? unknown extends ExtractParams<TNotificationClass> ? {
|
|
120
|
+
params?: ExtractParams<TNotificationClass>;
|
|
121
|
+
} : {
|
|
122
|
+
params: ExtractParams<TNotificationClass>;
|
|
123
|
+
} : {
|
|
124
|
+
params: ExtractParams<TNotificationClass>;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Common options available for all send operations
|
|
128
|
+
*/
|
|
129
|
+
type CommonSendOptions<TNotificationClass extends NotificationClass<any, any>> = NotificationParams<TNotificationClass> & {
|
|
130
|
+
/**
|
|
131
|
+
* Throw an error if at least one channel fails to send
|
|
132
|
+
* If false, the result will contain the details of each channel send attempt
|
|
133
|
+
*/
|
|
134
|
+
throwOnError?: boolean;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Helper type to determine if a notification is anonymous (notifiable is undefined)
|
|
138
|
+
*/
|
|
139
|
+
type IsAnonymousNotification<T> = T extends NotificationClass<infer N, any> ? (N extends undefined ? true : false) : false;
|
|
140
|
+
/**
|
|
141
|
+
* Options for the `send` method
|
|
142
|
+
*/
|
|
143
|
+
type SendOptions<TNotificationClass extends NotificationClass<any, any>> = IsAnonymousNotification<TNotificationClass> extends true ? CommonSendOptions<TNotificationClass> & {
|
|
144
|
+
notification: TNotificationClass;
|
|
145
|
+
via: { [K in ChannelName]?: ProviderTarget<any, K> };
|
|
146
|
+
tenantId?: Identifier;
|
|
147
|
+
} : CommonSendOptions<TNotificationClass> & {
|
|
148
|
+
notification: TNotificationClass;
|
|
149
|
+
notifiable: NonNullable<ExtractNotifiable<TNotificationClass>>;
|
|
150
|
+
via?: ChannelSpecificConfig<ExtractNotifiable<TNotificationClass>>;
|
|
151
|
+
tenantId?: Identifier;
|
|
152
|
+
};
|
|
153
|
+
type ChannelSpecificConfig<N extends Notifiable> = { [K in ChannelName]?: boolean | ProviderTarget<N, K> };
|
|
154
|
+
type ExtractChannelTargets<T> = T extends Channel<any, any, any, infer U> ? U : never;
|
|
155
|
+
type ProviderTarget<_N extends Notifiable, K extends ChannelName> = ExtractChannelTargets<NotificationChannels[K]>;
|
|
156
|
+
//#endregion
|
|
157
|
+
export { ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Channel } from "./channel.js";
|
|
2
|
+
|
|
3
|
+
//#region src/types/preferences.d.ts
|
|
4
|
+
type ChannelPreferences<KnownChannels extends Record<string, Channel>> = Record<keyof KnownChannels, boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* Shape for the `preferences` option in facteur configuration
|
|
7
|
+
*/
|
|
8
|
+
interface DefaultPreferences<KnownChannels extends Record<string, Channel>> {
|
|
9
|
+
/**
|
|
10
|
+
* If false, user preferences will not be taken into account before sending notifications.
|
|
11
|
+
*/
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Global preferences for all notifications.
|
|
15
|
+
*/
|
|
16
|
+
global?: {
|
|
17
|
+
channels?: ChannelPreferences<KnownChannels>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Per-category preferences.
|
|
21
|
+
* Use `Notification.options.category` to define category on a notification.
|
|
22
|
+
*/
|
|
23
|
+
categories?: Record<string, {
|
|
24
|
+
channels?: Partial<ChannelPreferences<KnownChannels>>;
|
|
25
|
+
} | boolean>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Shape for the resolved/processed `preferences` option in facteur configuration
|
|
29
|
+
*/
|
|
30
|
+
interface ResolvedDefaultPreferences<KnownChannels extends Record<string, Channel>> {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
global: {
|
|
33
|
+
channels: ChannelPreferences<KnownChannels>;
|
|
34
|
+
};
|
|
35
|
+
categories: Record<string, {
|
|
36
|
+
channels: ChannelPreferences<KnownChannels>;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { DefaultPreferences, ResolvedDefaultPreferences };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/types/queue.d.ts
|
|
2
|
+
interface QueueItemOptions {
|
|
3
|
+
delay?: number;
|
|
4
|
+
}
|
|
5
|
+
interface QueueAdapter {
|
|
6
|
+
queue(message: any, options?: QueueItemOptions): Promise<void>;
|
|
7
|
+
startQueueProcessor(): void;
|
|
8
|
+
disconnect(): void;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { QueueAdapter, QueueItemOptions };
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@facteurjs/core",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0-beta.0",
|
|
5
|
+
"description": "Core package for facteur",
|
|
6
|
+
"author": "Julien Ripouteau <julien@ripouteau.com>",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"keywords": [],
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./api": "./dist/api/index.js",
|
|
15
|
+
"./api/types": "./dist/api/types.js",
|
|
16
|
+
"./channels/discord": "./dist/channels/discord/index.js",
|
|
17
|
+
"./channels/discord/types": "./dist/channels/discord/types.js",
|
|
18
|
+
"./channels/fcm": "./dist/channels/fcm/index.js",
|
|
19
|
+
"./channels/fcm/types": "./dist/channels/fcm/types.js",
|
|
20
|
+
"./channels/slack": "./dist/channels/slack/index.js",
|
|
21
|
+
"./channels/slack/types": "./dist/channels/slack/types.js",
|
|
22
|
+
"./channels/transmit": "./dist/channels/transmit/index.js",
|
|
23
|
+
"./channels/transmit/types": "./dist/channels/transmit/types.js",
|
|
24
|
+
"./channels/twilio": "./dist/channels/twilio/index.js",
|
|
25
|
+
"./channels/twilio/types": "./dist/channels/twilio/types.js",
|
|
26
|
+
"./channels/webhook": "./dist/channels/webhook/index.js",
|
|
27
|
+
"./channels/webhook/types": "./dist/channels/webhook/types.js",
|
|
28
|
+
"./channels/webpush": "./dist/channels/webpush/index.js",
|
|
29
|
+
"./channels/webpush/types": "./dist/channels/webpush/types.js",
|
|
30
|
+
"./database/adapters/knex": "./dist/database/adapters/knex.js",
|
|
31
|
+
"./database/adapters/kysely": "./dist/database/adapters/kysely.js",
|
|
32
|
+
"./database": "./dist/database/index.js",
|
|
33
|
+
"./database/types": "./dist/database/types.js",
|
|
34
|
+
"./types": "./dist/types/index.js",
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"main": "./dist/index.js",
|
|
38
|
+
"module": "./dist/index.js",
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@julr/utils": "1.9.0",
|
|
42
|
+
"@poppinss/exception": "^1.2.2",
|
|
43
|
+
"ky": "^1.8.2"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@boringnode/transmit": "^0.3.0",
|
|
47
|
+
"@types/web-push": "^3.6.4",
|
|
48
|
+
"firebase-admin": "^13.4.0",
|
|
49
|
+
"knex": "^3.1.0",
|
|
50
|
+
"kysely": "^0.28.3",
|
|
51
|
+
"p-event": "^6.0.1",
|
|
52
|
+
"twilio": "^5.8.0",
|
|
53
|
+
"web-push": "^3.6.7"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsdown",
|
|
60
|
+
"stub": "tsdown",
|
|
61
|
+
"test": "tsx tests/index.ts",
|
|
62
|
+
"typecheck": "tsc --noEmit",
|
|
63
|
+
"quick:test": "tsx tests/index.ts"
|
|
64
|
+
}
|
|
65
|
+
}
|