@facteurjs/core 1.0.0-beta.0 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channels/aws-sns/channel.d.ts +21 -0
- package/dist/channels/aws-sns/channel.js +42 -0
- package/dist/channels/aws-sns/index.d.ts +3 -0
- package/dist/channels/aws-sns/index.js +4 -0
- package/dist/channels/aws-sns/message.d.ts +23 -0
- package/dist/channels/aws-sns/message.js +29 -0
- package/dist/channels/aws-sns/types.d.ts +35 -0
- package/dist/channels/aws-sns/types.js +0 -0
- package/dist/channels/expo/channel.d.ts +23 -0
- package/dist/channels/expo/channel.js +38 -0
- package/dist/channels/expo/index.d.ts +3 -0
- package/dist/channels/expo/index.js +4 -0
- package/dist/channels/expo/message.d.ts +70 -0
- package/dist/channels/expo/message.js +130 -0
- package/dist/channels/expo/types.d.ts +9 -0
- package/dist/channels/expo/types.js +0 -0
- package/dist/channels/socketio/channel.d.ts +23 -0
- package/dist/channels/socketio/channel.js +29 -0
- package/dist/channels/socketio/index.d.ts +3 -0
- package/dist/channels/socketio/index.js +4 -0
- package/dist/channels/socketio/message.d.ts +11 -0
- package/dist/channels/socketio/message.js +17 -0
- package/dist/channels/socketio/types.d.ts +21 -0
- package/dist/channels/socketio/types.js +0 -0
- package/dist/facteur.js +18 -1
- package/dist/fake.d.ts +1 -1
- package/dist/fake.js +6 -2
- package/dist/helpers.js +8 -0
- package/dist/notifications/channel_resolver.js +5 -5
- package/dist/notifications/notification_sender.js +8 -7
- package/dist/types/channel.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/notifications.js +1 -1
- package/dist/types/options.d.ts +8 -4
- package/package.json +50 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Channel, ChannelSendParams, kTargetSymbol } from "../../types/channel.js";
|
|
2
|
+
import { AwsSnsMessage } from "./message.js";
|
|
3
|
+
import { AwsSnsConfig, AwsSnsTargets } from "./types.js";
|
|
4
|
+
|
|
5
|
+
//#region src/channels/aws-sns/channel.d.ts
|
|
6
|
+
declare function awsSnsChannel(config: AwsSnsConfig): AwsSnsChannel;
|
|
7
|
+
declare class AwsSnsChannel implements Channel<AwsSnsConfig, AwsSnsMessage, any, AwsSnsTargets> {
|
|
8
|
+
#private;
|
|
9
|
+
private config;
|
|
10
|
+
name: "awsSns";
|
|
11
|
+
[kTargetSymbol]: AwsSnsTargets;
|
|
12
|
+
constructor(config: AwsSnsConfig);
|
|
13
|
+
send(options: ChannelSendParams<AwsSnsMessage, AwsSnsTargets>): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
declare module '@facteurjs/core/types' {
|
|
16
|
+
interface Notification {
|
|
17
|
+
asAwsSnsMessage(): AwsSnsMessage;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { AwsSnsChannel, awsSnsChannel };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { errors } from "../../errors/index.js";
|
|
2
|
+
import { kTargetSymbol } from "../../types/channel.js";
|
|
3
|
+
import "../../types/index.js";
|
|
4
|
+
import { PublishCommand, SNSClient } from "@aws-sdk/client-sns";
|
|
5
|
+
|
|
6
|
+
//#region src/channels/aws-sns/channel.ts
|
|
7
|
+
function awsSnsChannel(config) {
|
|
8
|
+
return new AwsSnsChannel(config);
|
|
9
|
+
}
|
|
10
|
+
var AwsSnsChannel = class {
|
|
11
|
+
name = "awsSns";
|
|
12
|
+
[kTargetSymbol] = null;
|
|
13
|
+
#client;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.#client = new SNSClient({
|
|
17
|
+
region: this.config.region,
|
|
18
|
+
credentials: {
|
|
19
|
+
accessKeyId: this.config.accessKeyId,
|
|
20
|
+
secretAccessKey: this.config.secretAccessKey,
|
|
21
|
+
...this.config.sessionToken && { sessionToken: this.config.sessionToken }
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
#resolveTargets(options) {
|
|
26
|
+
if (options.targets) return options.targets;
|
|
27
|
+
throw new errors.E_UNAVAILABLE_TARGETS(["AWS SNS"]);
|
|
28
|
+
}
|
|
29
|
+
async send(options) {
|
|
30
|
+
const message = options.message;
|
|
31
|
+
const targets = this.#resolveTargets(options);
|
|
32
|
+
const messageData = message.serialize();
|
|
33
|
+
const command = new PublishCommand({
|
|
34
|
+
PhoneNumber: targets.to,
|
|
35
|
+
Message: messageData.Message
|
|
36
|
+
});
|
|
37
|
+
await this.#client.send(command);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { AwsSnsChannel, awsSnsChannel };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/channels/aws-sns/message.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* AWS SNS SMS message
|
|
4
|
+
*/
|
|
5
|
+
declare class AwsSnsMessage {
|
|
6
|
+
#private;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new instance of AwsSnsMessage
|
|
9
|
+
*/
|
|
10
|
+
static create(): AwsSnsMessage;
|
|
11
|
+
/**
|
|
12
|
+
* Set the message content
|
|
13
|
+
*/
|
|
14
|
+
setMessage(message: string): this;
|
|
15
|
+
/**
|
|
16
|
+
* Serialize the message to AWS SNS format
|
|
17
|
+
*/
|
|
18
|
+
serialize(): {
|
|
19
|
+
Message: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { AwsSnsMessage };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/channels/aws-sns/message.ts
|
|
2
|
+
/**
|
|
3
|
+
* AWS SNS SMS message
|
|
4
|
+
*/
|
|
5
|
+
var AwsSnsMessage = class AwsSnsMessage {
|
|
6
|
+
#message = "";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new instance of AwsSnsMessage
|
|
9
|
+
*/
|
|
10
|
+
static create() {
|
|
11
|
+
return new AwsSnsMessage();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Set the message content
|
|
15
|
+
*/
|
|
16
|
+
setMessage(message) {
|
|
17
|
+
this.#message = message;
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Serialize the message to AWS SNS format
|
|
22
|
+
*/
|
|
23
|
+
serialize() {
|
|
24
|
+
return { Message: this.#message };
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { AwsSnsMessage };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/channels/aws-sns/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for AWS SNS SMS channel
|
|
4
|
+
*/
|
|
5
|
+
interface AwsSnsConfig {
|
|
6
|
+
region: string;
|
|
7
|
+
accessKeyId: string;
|
|
8
|
+
secretAccessKey: string;
|
|
9
|
+
sessionToken?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SMS message data for AWS SNS
|
|
13
|
+
*/
|
|
14
|
+
interface AwsSnsSmsData {
|
|
15
|
+
to: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* AWS SNS targets
|
|
20
|
+
*/
|
|
21
|
+
interface AwsSnsTargets {
|
|
22
|
+
to: string;
|
|
23
|
+
}
|
|
24
|
+
interface AwsSnsTargets {
|
|
25
|
+
/**
|
|
26
|
+
* The phone number to send the SMS to (in E.164 format)
|
|
27
|
+
*/
|
|
28
|
+
to: string;
|
|
29
|
+
/**
|
|
30
|
+
* Override the sender ID for this specific message
|
|
31
|
+
*/
|
|
32
|
+
senderId?: string;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { AwsSnsConfig, AwsSnsSmsData, AwsSnsTargets };
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Channel, ChannelSendParams, kTargetSymbol } from "../../types/channel.js";
|
|
2
|
+
import { ExpoMessage } from "./message.js";
|
|
3
|
+
import { ExpoConfig, ExpoTargets } from "./types.js";
|
|
4
|
+
|
|
5
|
+
//#region src/channels/expo/channel.d.ts
|
|
6
|
+
declare function expoChannel(config?: ExpoConfig): ExpoChannel;
|
|
7
|
+
declare class ExpoChannel implements Channel<ExpoConfig, ExpoMessage, any, ExpoTargets> {
|
|
8
|
+
#private;
|
|
9
|
+
name: "expo";
|
|
10
|
+
[kTargetSymbol]: ExpoTargets;
|
|
11
|
+
constructor(config: ExpoConfig);
|
|
12
|
+
send(options: ChannelSendParams<ExpoMessage, ExpoTargets>): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
status: "ok";
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
declare module '@facteurjs/core/types' {
|
|
18
|
+
interface Notification {
|
|
19
|
+
asExpoMessage(): ExpoMessage;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ExpoChannel, expoChannel };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { errors } from "../../errors/index.js";
|
|
2
|
+
import { kTargetSymbol } from "../../types/channel.js";
|
|
3
|
+
import "../../types/index.js";
|
|
4
|
+
import { Expo } from "expo-server-sdk";
|
|
5
|
+
|
|
6
|
+
//#region src/channels/expo/channel.ts
|
|
7
|
+
function expoChannel(config = {}) {
|
|
8
|
+
return new ExpoChannel(config);
|
|
9
|
+
}
|
|
10
|
+
var ExpoChannel = class {
|
|
11
|
+
name = "expo";
|
|
12
|
+
[kTargetSymbol] = null;
|
|
13
|
+
#expo;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.#expo = new Expo(config);
|
|
16
|
+
if (config.accessToken) this.#validateExpoToken(config.accessToken);
|
|
17
|
+
}
|
|
18
|
+
#validateExpoToken(token) {
|
|
19
|
+
if (!Expo.isExpoPushToken(token)) throw new Error(`Invalid Expo push token: ${token}`);
|
|
20
|
+
}
|
|
21
|
+
#resolveTargets(options) {
|
|
22
|
+
if (options.targets) return options.targets;
|
|
23
|
+
throw new errors.E_UNAVAILABLE_TARGETS(["Expo"]);
|
|
24
|
+
}
|
|
25
|
+
async send(options) {
|
|
26
|
+
const targets = this.#resolveTargets(options);
|
|
27
|
+
const message = options.message.serialize({ to: targets.expoToken });
|
|
28
|
+
const [ticket] = await this.#expo.sendPushNotificationsAsync([message]);
|
|
29
|
+
if (ticket?.status === "error") throw new Error(`Expo push notification failed: ${ticket.message}`);
|
|
30
|
+
return {
|
|
31
|
+
id: ticket?.id,
|
|
32
|
+
status: ticket?.status
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { ExpoChannel, expoChannel };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ExpoPushMessage } from "expo-server-sdk";
|
|
2
|
+
|
|
3
|
+
//#region src/channels/expo/message.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Expo push notification message
|
|
7
|
+
*/
|
|
8
|
+
declare class ExpoMessage {
|
|
9
|
+
#private;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new instance of ExpoMessage
|
|
12
|
+
*/
|
|
13
|
+
static create(): ExpoMessage;
|
|
14
|
+
/**
|
|
15
|
+
* Set the notification title
|
|
16
|
+
*/
|
|
17
|
+
setTitle(title: string): this;
|
|
18
|
+
/**
|
|
19
|
+
* Set the notification body
|
|
20
|
+
*/
|
|
21
|
+
setBody(body: string): this;
|
|
22
|
+
/**
|
|
23
|
+
* Set additional data payload
|
|
24
|
+
*/
|
|
25
|
+
setData(data: any): this;
|
|
26
|
+
/**
|
|
27
|
+
* Set the sound to play. Use 'default' for default sound
|
|
28
|
+
*/
|
|
29
|
+
setSound(sound: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Set the badge number for iOS
|
|
32
|
+
*/
|
|
33
|
+
setBadge(badge: number): this;
|
|
34
|
+
/**
|
|
35
|
+
* Set the notification channel ID for Android
|
|
36
|
+
*/
|
|
37
|
+
setChannelId(channelId: string): this;
|
|
38
|
+
/**
|
|
39
|
+
* Set the notification category ID
|
|
40
|
+
*/
|
|
41
|
+
setCategoryId(categoryId: string): this;
|
|
42
|
+
/**
|
|
43
|
+
* Set the subtitle (iOS only)
|
|
44
|
+
*/
|
|
45
|
+
setSubtitle(subtitle: string): this;
|
|
46
|
+
/**
|
|
47
|
+
* Set the delivery priority
|
|
48
|
+
*/
|
|
49
|
+
setPriority(priority: 'default' | 'normal' | 'high'): this;
|
|
50
|
+
/**
|
|
51
|
+
* Set time to live in seconds
|
|
52
|
+
*/
|
|
53
|
+
setTtl(ttl: number): this;
|
|
54
|
+
/**
|
|
55
|
+
* Set expiration timestamp
|
|
56
|
+
*/
|
|
57
|
+
setExpiration(expiration: number): this;
|
|
58
|
+
/**
|
|
59
|
+
* Set whether notification can be intercepted by client app (iOS only)
|
|
60
|
+
*/
|
|
61
|
+
setMutableContent(mutableContent: boolean): this;
|
|
62
|
+
/**
|
|
63
|
+
* Serialize the message to Expo format
|
|
64
|
+
*/
|
|
65
|
+
serialize(options: {
|
|
66
|
+
to: string;
|
|
67
|
+
}): ExpoPushMessage;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { ExpoMessage };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
//#region src/channels/expo/message.ts
|
|
2
|
+
/**
|
|
3
|
+
* Expo push notification message
|
|
4
|
+
*/
|
|
5
|
+
var ExpoMessage = class ExpoMessage {
|
|
6
|
+
#title;
|
|
7
|
+
#body;
|
|
8
|
+
#data;
|
|
9
|
+
#sound;
|
|
10
|
+
#badge;
|
|
11
|
+
#channelId;
|
|
12
|
+
#categoryId;
|
|
13
|
+
#subtitle;
|
|
14
|
+
#priority = "default";
|
|
15
|
+
#ttl;
|
|
16
|
+
#expiration;
|
|
17
|
+
#mutableContent;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new instance of ExpoMessage
|
|
20
|
+
*/
|
|
21
|
+
static create() {
|
|
22
|
+
return new ExpoMessage();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Set the notification title
|
|
26
|
+
*/
|
|
27
|
+
setTitle(title) {
|
|
28
|
+
this.#title = title;
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Set the notification body
|
|
33
|
+
*/
|
|
34
|
+
setBody(body) {
|
|
35
|
+
this.#body = body;
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Set additional data payload
|
|
40
|
+
*/
|
|
41
|
+
setData(data) {
|
|
42
|
+
this.#data = data;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Set the sound to play. Use 'default' for default sound
|
|
47
|
+
*/
|
|
48
|
+
setSound(sound) {
|
|
49
|
+
this.#sound = sound;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Set the badge number for iOS
|
|
54
|
+
*/
|
|
55
|
+
setBadge(badge) {
|
|
56
|
+
this.#badge = badge;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set the notification channel ID for Android
|
|
61
|
+
*/
|
|
62
|
+
setChannelId(channelId) {
|
|
63
|
+
this.#channelId = channelId;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Set the notification category ID
|
|
68
|
+
*/
|
|
69
|
+
setCategoryId(categoryId) {
|
|
70
|
+
this.#categoryId = categoryId;
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Set the subtitle (iOS only)
|
|
75
|
+
*/
|
|
76
|
+
setSubtitle(subtitle) {
|
|
77
|
+
this.#subtitle = subtitle;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Set the delivery priority
|
|
82
|
+
*/
|
|
83
|
+
setPriority(priority) {
|
|
84
|
+
this.#priority = priority;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Set time to live in seconds
|
|
89
|
+
*/
|
|
90
|
+
setTtl(ttl) {
|
|
91
|
+
this.#ttl = ttl;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Set expiration timestamp
|
|
96
|
+
*/
|
|
97
|
+
setExpiration(expiration) {
|
|
98
|
+
this.#expiration = expiration;
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Set whether notification can be intercepted by client app (iOS only)
|
|
103
|
+
*/
|
|
104
|
+
setMutableContent(mutableContent) {
|
|
105
|
+
this.#mutableContent = mutableContent;
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Serialize the message to Expo format
|
|
110
|
+
*/
|
|
111
|
+
serialize(options) {
|
|
112
|
+
const message = { to: options.to };
|
|
113
|
+
if (this.#title) message.title = this.#title;
|
|
114
|
+
if (this.#body) message.body = this.#body;
|
|
115
|
+
if (this.#data !== void 0) message.data = this.#data;
|
|
116
|
+
if (this.#sound) message.sound = this.#sound;
|
|
117
|
+
if (this.#badge !== void 0) message.badge = this.#badge;
|
|
118
|
+
if (this.#channelId) message.channelId = this.#channelId;
|
|
119
|
+
if (this.#categoryId) message.categoryId = this.#categoryId;
|
|
120
|
+
if (this.#subtitle) message.subtitle = this.#subtitle;
|
|
121
|
+
if (this.#priority !== "default") message.priority = this.#priority;
|
|
122
|
+
if (this.#ttl !== void 0) message.ttl = this.#ttl;
|
|
123
|
+
if (this.#expiration !== void 0) message.expiration = this.#expiration;
|
|
124
|
+
if (this.#mutableContent !== void 0) message.mutableContent = this.#mutableContent;
|
|
125
|
+
return message;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
export { ExpoMessage };
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Channel, ChannelSendParams, kTargetSymbol } from "../../types/channel.js";
|
|
2
|
+
import { SocketIoMessage } from "./message.js";
|
|
3
|
+
import { SocketIOConfig, SocketIOTargets } from "./types.js";
|
|
4
|
+
import { Server } from "socket.io";
|
|
5
|
+
|
|
6
|
+
//#region src/channels/socketio/channel.d.ts
|
|
7
|
+
declare function socketIoChannel(config: SocketIOConfig): SocketIOChannel;
|
|
8
|
+
declare class SocketIOChannel implements Channel<SocketIOConfig, SocketIoMessage, any, SocketIOTargets> {
|
|
9
|
+
#private;
|
|
10
|
+
private config;
|
|
11
|
+
name: "socketIo";
|
|
12
|
+
[kTargetSymbol]: SocketIOTargets;
|
|
13
|
+
protected server: () => Server;
|
|
14
|
+
constructor(config: SocketIOConfig);
|
|
15
|
+
send(options: ChannelSendParams<SocketIoMessage, SocketIOTargets>): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
declare module '@facteurjs/core/types' {
|
|
18
|
+
interface Notification {
|
|
19
|
+
asSocketIoMessage(): SocketIoMessage;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { SocketIOChannel, socketIoChannel };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { errors } from "../../errors/index.js";
|
|
2
|
+
import { kTargetSymbol } from "../../types/channel.js";
|
|
3
|
+
import "../../types/index.js";
|
|
4
|
+
|
|
5
|
+
//#region src/channels/socketio/channel.ts
|
|
6
|
+
function socketIoChannel(config) {
|
|
7
|
+
return new SocketIOChannel(config);
|
|
8
|
+
}
|
|
9
|
+
var SocketIOChannel = class {
|
|
10
|
+
name = "socketIo";
|
|
11
|
+
[kTargetSymbol] = null;
|
|
12
|
+
server;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.server = typeof this.config.server === "function" ? this.config.server : () => this.config.server;
|
|
16
|
+
}
|
|
17
|
+
#resolveTargets(options) {
|
|
18
|
+
if (options.targets) return options.targets;
|
|
19
|
+
throw new errors.E_UNAVAILABLE_TARGETS(["SocketIO"]);
|
|
20
|
+
}
|
|
21
|
+
async send(options) {
|
|
22
|
+
const message = options.message.serialize();
|
|
23
|
+
const targets = this.#resolveTargets(options);
|
|
24
|
+
this.server().of(targets.namespace || "/").emit(targets.event, message.data);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { SocketIOChannel, socketIoChannel };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/channels/socketio/message.d.ts
|
|
2
|
+
declare class SocketIoMessage {
|
|
3
|
+
#private;
|
|
4
|
+
static create(): SocketIoMessage;
|
|
5
|
+
setData(data: Record<string, any>): this;
|
|
6
|
+
serialize(): {
|
|
7
|
+
data: Record<string, any>;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SocketIoMessage };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/channels/socketio/message.ts
|
|
2
|
+
var SocketIoMessage = class SocketIoMessage {
|
|
3
|
+
#data = {};
|
|
4
|
+
static create() {
|
|
5
|
+
return new SocketIoMessage();
|
|
6
|
+
}
|
|
7
|
+
setData(data) {
|
|
8
|
+
this.#data = data;
|
|
9
|
+
return this;
|
|
10
|
+
}
|
|
11
|
+
serialize() {
|
|
12
|
+
return { data: this.#data };
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { SocketIoMessage };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Server } from "socket.io";
|
|
2
|
+
|
|
3
|
+
//#region src/channels/socketio/types.d.ts
|
|
4
|
+
interface SocketIOTargets {
|
|
5
|
+
/**
|
|
6
|
+
* Namespace to emit the event to
|
|
7
|
+
*/
|
|
8
|
+
namespace?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Event to emit
|
|
11
|
+
*/
|
|
12
|
+
event: string;
|
|
13
|
+
}
|
|
14
|
+
interface SocketIOConfig {
|
|
15
|
+
/**
|
|
16
|
+
* Socket.IO server instance. Can be a function that will be resolved when needed
|
|
17
|
+
*/
|
|
18
|
+
server: Server | (() => Server);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { SocketIOConfig, SocketIOTargets };
|
|
File without changes
|
package/dist/facteur.js
CHANGED
|
@@ -62,8 +62,25 @@ var Facteur = class {
|
|
|
62
62
|
* Send a notification
|
|
63
63
|
*/
|
|
64
64
|
async send(options) {
|
|
65
|
+
if ("via" in options && !("to" in options)) return this.#sendToSingle(options);
|
|
66
|
+
const optionsWithTo = options;
|
|
67
|
+
const recipients = Array.isArray(optionsWithTo.to) ? optionsWithTo.to : [optionsWithTo.to];
|
|
68
|
+
const results = await Promise.all(recipients.map((recipient) => this.#sendToSingle({
|
|
69
|
+
...optionsWithTo,
|
|
70
|
+
to: recipient
|
|
71
|
+
})));
|
|
72
|
+
return {
|
|
73
|
+
success: results.reduce((sum, result) => sum + result.success, 0),
|
|
74
|
+
failed: results.reduce((sum, result) => sum + result.failed, 0),
|
|
75
|
+
results: results.flatMap((result) => result.results)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Send notification to a single recipient
|
|
80
|
+
*/
|
|
81
|
+
async #sendToSingle(options) {
|
|
65
82
|
const notification = await this.#options.notificationResolver(options.notification, {
|
|
66
|
-
|
|
83
|
+
to: "to" in options ? options.to : void 0,
|
|
67
84
|
params: options.params,
|
|
68
85
|
tenantId: options.tenantId
|
|
69
86
|
});
|
package/dist/fake.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Notification, NotificationSendResult } from "./types/notifications.js";
|
|
|
4
4
|
//#region src/fake.d.ts
|
|
5
5
|
interface SentNotification<N extends Notification = Notification> {
|
|
6
6
|
notification: N;
|
|
7
|
-
|
|
7
|
+
to: N extends Notification<infer TNotifiable, any> ? TNotifiable : never;
|
|
8
8
|
params?: N extends Notification<any, infer P> ? P : never;
|
|
9
9
|
via?: any;
|
|
10
10
|
}
|
package/dist/fake.js
CHANGED
|
@@ -7,10 +7,14 @@ var FacteurFake = class {
|
|
|
7
7
|
* Record a notification as sent during fake mode
|
|
8
8
|
*/
|
|
9
9
|
recordSent(options) {
|
|
10
|
-
const notification = new options.notification(
|
|
10
|
+
const notification = new options.notification({
|
|
11
|
+
to: options.to,
|
|
12
|
+
params: options.params,
|
|
13
|
+
tenantId: options.tenantId
|
|
14
|
+
});
|
|
11
15
|
this.#sentNotifications.push({
|
|
12
16
|
notification,
|
|
13
|
-
|
|
17
|
+
to: options.to,
|
|
14
18
|
params: options.params,
|
|
15
19
|
via: options.via
|
|
16
20
|
});
|
package/dist/helpers.js
ADDED
|
@@ -12,7 +12,7 @@ var ChannelResolver = class {
|
|
|
12
12
|
* Resolve channels and targets provided by via
|
|
13
13
|
*/
|
|
14
14
|
#resolveVia(options) {
|
|
15
|
-
const notifiableTargets = options.
|
|
15
|
+
const notifiableTargets = options.to?.notificationTargets?.();
|
|
16
16
|
return mapEntries(options.via, (channelName, channelConfig) => {
|
|
17
17
|
const shouldSend = typeof channelConfig === "boolean" ? channelConfig : true;
|
|
18
18
|
const target = invoke(() => {
|
|
@@ -26,10 +26,10 @@ var ChannelResolver = class {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
async resolveChannels(options) {
|
|
29
|
-
const { notification,
|
|
29
|
+
const { notification, to, params, via, tenantId } = options;
|
|
30
30
|
const notificationOptions = notification.options;
|
|
31
31
|
const notificationIdentifier = notificationOptions.identifier || notification.name;
|
|
32
|
-
const notifiableTargets = options.
|
|
32
|
+
const notifiableTargets = options.to?.notificationTargets?.();
|
|
33
33
|
/**
|
|
34
34
|
* First, if via is provided it should override everything.
|
|
35
35
|
*/
|
|
@@ -38,7 +38,7 @@ var ChannelResolver = class {
|
|
|
38
38
|
* Get preferences for the notifiable and tenant
|
|
39
39
|
*/
|
|
40
40
|
const preferences = await this.#database?.getPreferences({
|
|
41
|
-
notifiableId:
|
|
41
|
+
notifiableId: to.id,
|
|
42
42
|
tenantId
|
|
43
43
|
});
|
|
44
44
|
/**
|
|
@@ -48,7 +48,7 @@ var ChannelResolver = class {
|
|
|
48
48
|
const shouldSend = invoke(() => {
|
|
49
49
|
if (typeof deliverBy === "boolean") return deliverBy;
|
|
50
50
|
return deliverBy.if({
|
|
51
|
-
|
|
51
|
+
to,
|
|
52
52
|
params,
|
|
53
53
|
preferences
|
|
54
54
|
});
|
|
@@ -2,7 +2,7 @@ import { errors } from "../errors/index.js";
|
|
|
2
2
|
import debug_default from "../debug.js";
|
|
3
3
|
import { facteurEvents } from "../events/events.js";
|
|
4
4
|
import "./channel_resolver.js";
|
|
5
|
-
import {
|
|
5
|
+
import { capitalizeFirstLetter } from "../helpers.js";
|
|
6
6
|
|
|
7
7
|
//#region src/notifications/notification_sender.ts
|
|
8
8
|
/**
|
|
@@ -96,11 +96,12 @@ var NotificationSender = class {
|
|
|
96
96
|
* `as<ChannelName>Message` method
|
|
97
97
|
*/
|
|
98
98
|
const channel = this.#getChannel(channelName);
|
|
99
|
-
const
|
|
99
|
+
const capitalizedChannelName = capitalizeFirstLetter(channelName);
|
|
100
|
+
const channelMethodName = `as${capitalizedChannelName}Message`;
|
|
100
101
|
const messageBuilder = options.notification[channelMethodName];
|
|
101
|
-
if (typeof messageBuilder !== "function") throw new errors.E_MISSING_MESSAGE_METHOD([
|
|
102
|
+
if (typeof messageBuilder !== "function") throw new errors.E_MISSING_MESSAGE_METHOD([capitalizedChannelName]);
|
|
102
103
|
const messageContent = messageBuilder.call(options.notification, {
|
|
103
|
-
|
|
104
|
+
to: sendOptions.to,
|
|
104
105
|
params: sendOptions.params,
|
|
105
106
|
tenantId: sendOptions.tenantId
|
|
106
107
|
});
|
|
@@ -115,7 +116,7 @@ var NotificationSender = class {
|
|
|
115
116
|
tenantId: sendOptions.tenantId,
|
|
116
117
|
message: messageContent,
|
|
117
118
|
targets: channelConfig.target,
|
|
118
|
-
|
|
119
|
+
to: sendOptions.to
|
|
119
120
|
});
|
|
120
121
|
debug_default(`Message sent via ${channelName}`);
|
|
121
122
|
this.#emitMessageSent(options.notification, channelName, messageContent);
|
|
@@ -166,9 +167,9 @@ var NotificationSender = class {
|
|
|
166
167
|
*/
|
|
167
168
|
async send(options, notification) {
|
|
168
169
|
const { via, params, tenantId } = options;
|
|
169
|
-
const
|
|
170
|
+
const to = "to" in options ? options.to : void 0;
|
|
170
171
|
const resolvedChannels = await this.channelResolver.resolveChannels({
|
|
171
|
-
|
|
172
|
+
to,
|
|
172
173
|
params,
|
|
173
174
|
tenantId,
|
|
174
175
|
notification: options.notification,
|
package/dist/types/channel.d.ts
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ import { Emitter, FacteurEvents } from "./events.js";
|
|
|
3
3
|
import { QueueAdapter, QueueItemOptions } from "./queue.js";
|
|
4
4
|
import { DefaultPreferences, ResolvedDefaultPreferences } from "./preferences.js";
|
|
5
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";
|
|
6
|
+
import { Arrayable, ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions } from "./options.js";
|
|
7
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 };
|
|
8
|
+
export { Arrayable, 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 };
|
package/dist/types/options.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { Awaitable } from "@julr/utils/types";
|
|
|
10
10
|
|
|
11
11
|
//#region src/types/options.d.ts
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Type for values that can be a single item or an array of items
|
|
15
|
+
*/
|
|
16
|
+
type Arrayable<T> = T | T[];
|
|
13
17
|
/**
|
|
14
18
|
* Configuration options for the Facteur library
|
|
15
19
|
*/
|
|
@@ -92,7 +96,7 @@ interface NotificationOptions<N extends Notifiable = Notifiable> {
|
|
|
92
96
|
}
|
|
93
97
|
interface DeliverByOptions<N extends Notifiable = Notifiable> {
|
|
94
98
|
if: (options: {
|
|
95
|
-
|
|
99
|
+
to: N;
|
|
96
100
|
params?: any;
|
|
97
101
|
preferences?: Record<string, boolean | undefined>;
|
|
98
102
|
}) => boolean;
|
|
@@ -101,7 +105,7 @@ interface DeliverByOptions<N extends Notifiable = Notifiable> {
|
|
|
101
105
|
* Parameters received by the `as*Message` methods of a notification.
|
|
102
106
|
*/
|
|
103
107
|
interface MessageCtx<N extends Notifiable | undefined = Notifiable, Params extends Record<string, any> = {}> {
|
|
104
|
-
|
|
108
|
+
to: N;
|
|
105
109
|
params: Params;
|
|
106
110
|
tenantId?: Identifier | undefined;
|
|
107
111
|
}
|
|
@@ -146,7 +150,7 @@ type SendOptions<TNotificationClass extends NotificationClass<any, any>> = IsAno
|
|
|
146
150
|
tenantId?: Identifier;
|
|
147
151
|
} : CommonSendOptions<TNotificationClass> & {
|
|
148
152
|
notification: TNotificationClass;
|
|
149
|
-
|
|
153
|
+
to: Arrayable<NonNullable<ExtractNotifiable<TNotificationClass>>>;
|
|
150
154
|
via?: ChannelSpecificConfig<ExtractNotifiable<TNotificationClass>>;
|
|
151
155
|
tenantId?: Identifier;
|
|
152
156
|
};
|
|
@@ -154,4 +158,4 @@ type ChannelSpecificConfig<N extends Notifiable> = { [K in ChannelName]?: boolea
|
|
|
154
158
|
type ExtractChannelTargets<T> = T extends Channel<any, any, any, infer U> ? U : never;
|
|
155
159
|
type ProviderTarget<_N extends Notifiable, K extends ChannelName> = ExtractChannelTargets<NotificationChannels[K]>;
|
|
156
160
|
//#endregion
|
|
157
|
-
export { ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions };
|
|
161
|
+
export { Arrayable, ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@facteurjs/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.1",
|
|
5
5
|
"description": "Core package for facteur",
|
|
6
6
|
"author": "Julien Ripouteau <julien@ripouteau.com>",
|
|
7
7
|
"license": "ISC",
|
|
@@ -13,12 +13,18 @@
|
|
|
13
13
|
".": "./dist/index.js",
|
|
14
14
|
"./api": "./dist/api/index.js",
|
|
15
15
|
"./api/types": "./dist/api/types.js",
|
|
16
|
+
"./channels/aws-sns": "./dist/channels/aws-sns/index.js",
|
|
17
|
+
"./channels/aws-sns/types": "./dist/channels/aws-sns/types.js",
|
|
16
18
|
"./channels/discord": "./dist/channels/discord/index.js",
|
|
17
19
|
"./channels/discord/types": "./dist/channels/discord/types.js",
|
|
20
|
+
"./channels/expo": "./dist/channels/expo/index.js",
|
|
21
|
+
"./channels/expo/types": "./dist/channels/expo/types.js",
|
|
18
22
|
"./channels/fcm": "./dist/channels/fcm/index.js",
|
|
19
23
|
"./channels/fcm/types": "./dist/channels/fcm/types.js",
|
|
20
24
|
"./channels/slack": "./dist/channels/slack/index.js",
|
|
21
25
|
"./channels/slack/types": "./dist/channels/slack/types.js",
|
|
26
|
+
"./channels/socketio": "./dist/channels/socketio/index.js",
|
|
27
|
+
"./channels/socketio/types": "./dist/channels/socketio/types.js",
|
|
22
28
|
"./channels/transmit": "./dist/channels/transmit/index.js",
|
|
23
29
|
"./channels/transmit/types": "./dist/channels/transmit/types.js",
|
|
24
30
|
"./channels/twilio": "./dist/channels/twilio/index.js",
|
|
@@ -42,13 +48,56 @@
|
|
|
42
48
|
"@poppinss/exception": "^1.2.2",
|
|
43
49
|
"ky": "^1.8.2"
|
|
44
50
|
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@aws-sdk/client-sns": "^3.856.0",
|
|
53
|
+
"@boringnode/transmit": "^0.3.0",
|
|
54
|
+
"expo-server-sdk": "^3.15.0",
|
|
55
|
+
"firebase-admin": "^13.4.0",
|
|
56
|
+
"knex": "^3.1.0",
|
|
57
|
+
"kysely": "^0.28.3",
|
|
58
|
+
"socket.io": "^4.8.1",
|
|
59
|
+
"twilio": "^5.8.0",
|
|
60
|
+
"web-push": "^3.6.7"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@aws-sdk/client-sns": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@boringnode/transmit": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"expo-server-sdk": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"firebase-admin": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"knex": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"kysely": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"socket.io": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"twilio": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"web-push": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
45
91
|
"devDependencies": {
|
|
92
|
+
"@aws-sdk/client-sns": "^3.856.0",
|
|
46
93
|
"@boringnode/transmit": "^0.3.0",
|
|
47
94
|
"@types/web-push": "^3.6.4",
|
|
95
|
+
"expo-server-sdk": "^3.15.0",
|
|
48
96
|
"firebase-admin": "^13.4.0",
|
|
49
97
|
"knex": "^3.1.0",
|
|
50
98
|
"kysely": "^0.28.3",
|
|
51
99
|
"p-event": "^6.0.1",
|
|
100
|
+
"socket.io": "^4.8.1",
|
|
52
101
|
"twilio": "^5.8.0",
|
|
53
102
|
"web-push": "^3.6.7"
|
|
54
103
|
},
|