@facteurjs/core 1.0.0-beta.4 → 2.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/README.md +27 -0
- package/dist/api/handlers/{notifications.js → notifications.mjs} +39 -16
- package/dist/api/handlers/preferences.mjs +73 -0
- package/dist/api/handlers/utils.mjs +23 -0
- package/dist/api/types.d.mts +52 -0
- package/dist/api/types.mjs +1 -0
- package/dist/api.d.mts +22 -0
- package/dist/api.mjs +25 -0
- package/dist/channels/aws-sns/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/channels/aws-sns/{channel.js → channel.mjs} +2 -3
- package/dist/channels/aws-sns/types.mjs +1 -0
- package/dist/channels/aws-sns.d.mts +3 -0
- package/dist/channels/aws-sns.mjs +4 -0
- package/dist/channels/discord/{channel.d.ts → channel.d.mts} +5 -5
- package/dist/channels/discord/{channel.js → channel.mjs} +1 -1
- package/dist/channels/discord/{message.d.ts → message.d.mts} +2 -2
- package/dist/channels/discord/{message.js → message.mjs} +1 -1
- package/dist/channels/discord/{types.d.ts → types.d.mts} +1 -1
- package/dist/channels/discord/types.mjs +1 -0
- package/dist/channels/discord.d.mts +3 -0
- package/dist/channels/discord.mjs +4 -0
- package/dist/channels/expo/{channel.d.ts → channel.d.mts} +5 -3
- package/dist/channels/expo/channel.mjs +69 -0
- package/dist/channels/expo/types.mjs +1 -0
- package/dist/channels/expo.d.mts +3 -0
- package/dist/channels/expo.mjs +4 -0
- package/dist/channels/fcm/{channel.d.ts → channel.d.mts} +5 -5
- package/dist/channels/fcm/channel.mjs +68 -0
- package/dist/channels/fcm/types.mjs +1 -0
- package/dist/channels/fcm.d.mts +3 -0
- package/dist/channels/fcm.mjs +4 -0
- package/dist/channels/slack/{channel.d.ts → channel.d.mts} +5 -5
- package/dist/channels/slack/{channel.js → channel.mjs} +2 -2
- package/dist/channels/slack/{message.d.ts → message.d.mts} +1 -1
- package/dist/channels/slack/{message.js → message.mjs} +1 -1
- package/dist/channels/slack/{types.d.ts → types.d.mts} +1 -1
- package/dist/channels/slack/types.mjs +1 -0
- package/dist/channels/slack.d.mts +3 -0
- package/dist/channels/slack.mjs +4 -0
- package/dist/channels/socketio/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/channels/socketio/{channel.js → channel.mjs} +2 -3
- package/dist/channels/socketio/types.mjs +1 -0
- package/dist/channels/socketio.d.mts +3 -0
- package/dist/channels/socketio.mjs +4 -0
- package/dist/channels/transmit/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/channels/transmit/{channel.js → channel.mjs} +2 -3
- package/dist/channels/transmit/types.mjs +1 -0
- package/dist/channels/transmit.d.mts +3 -0
- package/dist/channels/transmit.mjs +4 -0
- package/dist/channels/twilio/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/channels/twilio/{channel.js → channel.mjs} +3 -6
- package/dist/channels/twilio/types.mjs +1 -0
- package/dist/channels/twilio.d.mts +4 -0
- package/dist/channels/twilio.mjs +4 -0
- package/dist/channels/webhook/{exceptions.d.ts → exceptions.d.mts} +1 -1
- package/dist/channels/webhook/{provider.d.ts → provider.d.mts} +3 -3
- package/dist/channels/webhook/{provider.js → provider.mjs} +6 -8
- package/dist/channels/webhook/types.mjs +1 -0
- package/dist/channels/webhook.d.mts +4 -0
- package/dist/channels/webhook.mjs +5 -0
- package/dist/channels/webpush/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/channels/webpush/{channel.js → channel.mjs} +2 -3
- package/dist/channels/webpush/types.mjs +1 -0
- package/dist/channels/webpush.d.mts +3 -0
- package/dist/channels/webpush.mjs +4 -0
- package/dist/database/adapters/{knex.d.ts → knex.d.mts} +1 -1
- package/dist/database/adapters/{knex.js → knex.mjs} +19 -15
- package/dist/database/adapters/{kysely.d.ts → kysely.d.mts} +1 -1
- package/dist/database/adapters/{kysely.js → kysely.mjs} +2 -4
- package/dist/database/{channel.d.ts → channel.d.mts} +3 -3
- package/dist/database/{channel.js → channel.mjs} +4 -6
- package/dist/database/{database.d.ts → database.d.mts} +3 -3
- package/dist/database/{database.js → database.mjs} +15 -12
- package/dist/database/{message.d.ts → message.d.mts} +2 -2
- package/dist/database/{types.d.ts → types.d.mts} +3 -3
- package/dist/database/types.mjs +1 -0
- package/dist/database.d.mts +3 -0
- package/dist/database.mjs +4 -0
- package/dist/errors/{duplicate_notification_exception.js → duplicate_notification_exception.mjs} +1 -2
- package/dist/errors/{http_error.d.ts → http_error.d.mts} +0 -3
- package/dist/errors/{index.d.ts → index.d.mts} +1 -1
- package/dist/errors/{index.js → index.mjs} +2 -3
- package/dist/events/{events.d.ts → events.d.mts} +2 -2
- package/dist/facteur.d.mts +45 -0
- package/dist/facteur.mjs +167 -0
- package/dist/{fake.d.ts → fake.d.mts} +3 -3
- package/dist/{fake.js → fake.mjs} +2 -3
- package/dist/{index.d.ts → index.d.mts} +3 -3
- package/dist/{index.js → index.mjs} +2 -2
- package/dist/notifications/batching_sender.mjs +148 -0
- package/dist/notifications/{channel_resolver.js → channel_resolver.mjs} +40 -31
- package/dist/notifications/notification_builder.mjs +77 -0
- package/dist/notifications/{notification_discoverer.d.ts → notification_discoverer.d.mts} +1 -1
- package/dist/notifications/{notification_discoverer.js → notification_discoverer.mjs} +9 -14
- package/dist/notifications/notification_sender.mjs +356 -0
- package/dist/notifications/orchestration_sender.mjs +92 -0
- package/dist/{options.d.ts → options.d.mts} +7 -6
- package/dist/{options.js → options.mjs} +5 -4
- package/dist/types/builder.d.mts +122 -0
- package/dist/types/channel.d.mts +56 -0
- package/dist/types/{events.d.ts → events.d.mts} +1 -1
- package/dist/types/{extend.d.ts → extend.d.mts} +2 -2
- package/dist/types/{notifications.d.ts → notifications.d.mts} +3 -3
- package/dist/types/{options.d.ts → options.d.mts} +94 -11
- package/dist/types/{preferences.d.ts → preferences.d.mts} +1 -1
- package/dist/types.d.mts +9 -0
- package/dist/types.mjs +4 -0
- package/dist/utils/chunk.mjs +28 -0
- package/package.json +69 -54
- package/dist/api/handlers/preferences.js +0 -43
- package/dist/api/index.d.ts +0 -16
- package/dist/api/index.js +0 -21
- package/dist/api/types.d.ts +0 -22
- package/dist/api/types.js +0 -0
- package/dist/channels/aws-sns/index.d.ts +0 -3
- package/dist/channels/aws-sns/index.js +0 -4
- package/dist/channels/aws-sns/types.js +0 -0
- package/dist/channels/discord/index.d.ts +0 -3
- package/dist/channels/discord/index.js +0 -4
- package/dist/channels/discord/types.js +0 -0
- package/dist/channels/expo/channel.js +0 -38
- package/dist/channels/expo/index.d.ts +0 -3
- package/dist/channels/expo/index.js +0 -4
- package/dist/channels/expo/types.js +0 -0
- package/dist/channels/fcm/channel.js +0 -44
- package/dist/channels/fcm/index.d.ts +0 -3
- package/dist/channels/fcm/index.js +0 -4
- package/dist/channels/fcm/types.js +0 -0
- package/dist/channels/slack/index.d.ts +0 -3
- package/dist/channels/slack/index.js +0 -4
- package/dist/channels/slack/types.js +0 -0
- package/dist/channels/socketio/index.d.ts +0 -3
- package/dist/channels/socketio/index.js +0 -4
- package/dist/channels/socketio/types.js +0 -0
- package/dist/channels/transmit/index.d.ts +0 -3
- package/dist/channels/transmit/index.js +0 -4
- package/dist/channels/transmit/types.js +0 -0
- package/dist/channels/twilio/index.d.ts +0 -4
- package/dist/channels/twilio/index.js +0 -4
- package/dist/channels/twilio/types.js +0 -0
- package/dist/channels/webhook/index.d.ts +0 -4
- package/dist/channels/webhook/index.js +0 -5
- package/dist/channels/webhook/types.js +0 -0
- package/dist/channels/webpush/index.d.ts +0 -3
- package/dist/channels/webpush/index.js +0 -4
- package/dist/channels/webpush/types.js +0 -0
- package/dist/database/index.d.ts +0 -3
- package/dist/database/index.js +0 -4
- package/dist/database/types.js +0 -0
- package/dist/facteur.d.ts +0 -37
- package/dist/facteur.js +0 -100
- package/dist/notifications/notification_sender.js +0 -211
- package/dist/types/channel.d.ts +0 -18
- package/dist/types/index.d.ts +0 -8
- package/dist/types/index.js +0 -4
- /package/dist/channels/aws-sns/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/aws-sns/{message.js → message.mjs} +0 -0
- /package/dist/channels/aws-sns/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/expo/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/expo/{message.js → message.mjs} +0 -0
- /package/dist/channels/expo/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/fcm/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/fcm/{message.js → message.mjs} +0 -0
- /package/dist/channels/fcm/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/socketio/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/socketio/{message.js → message.mjs} +0 -0
- /package/dist/channels/socketio/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/transmit/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/transmit/{message.js → message.mjs} +0 -0
- /package/dist/channels/transmit/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/twilio/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/twilio/{message.js → message.mjs} +0 -0
- /package/dist/channels/twilio/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/webhook/{exceptions.js → exceptions.mjs} +0 -0
- /package/dist/channels/webhook/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/webhook/{message.js → message.mjs} +0 -0
- /package/dist/channels/webhook/{types.d.ts → types.d.mts} +0 -0
- /package/dist/channels/webpush/{message.d.ts → message.d.mts} +0 -0
- /package/dist/channels/webpush/{message.js → message.mjs} +0 -0
- /package/dist/channels/webpush/{types.d.ts → types.d.mts} +0 -0
- /package/dist/database/{message.js → message.mjs} +0 -0
- /package/dist/{debug.js → debug.mjs} +0 -0
- /package/dist/errors/{duplicate_notification_exception.d.ts → duplicate_notification_exception.d.mts} +0 -0
- /package/dist/errors/{http_error.js → http_error.mjs} +0 -0
- /package/dist/events/{events.js → events.mjs} +0 -0
- /package/dist/{helpers.js → helpers.mjs} +0 -0
- /package/dist/types/{channel.js → channel.mjs} +0 -0
- /package/dist/types/{notifications.js → notifications.mjs} +0 -0
- /package/dist/types/{queue.d.ts → queue.d.mts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ChannelName, NotificationChannels } from "./extend.mjs";
|
|
2
|
+
import { ExtractChannelTargets, MessageCtx, NotificationOptions } from "./options.mjs";
|
|
3
|
+
import { Identifier } from "../database/types.mjs";
|
|
4
4
|
import { Awaitable } from "@julr/utils/types";
|
|
5
5
|
|
|
6
6
|
//#region src/types/notifications.d.ts
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { Channel } from "./channel.mjs";
|
|
2
|
+
import { QueueAdapter } from "./queue.mjs";
|
|
3
|
+
import { DefaultPreferences } from "./preferences.mjs";
|
|
4
|
+
import { ChannelName, NotificationChannels } from "./extend.mjs";
|
|
5
|
+
import { Emitter } from "./events.mjs";
|
|
6
|
+
import { Notifiable, Notification, NotificationClass } from "./notifications.mjs";
|
|
7
|
+
import { DatabaseAdapter, Identifier } from "../database/types.mjs";
|
|
8
8
|
import { Logger } from "@julr/utils/logger";
|
|
9
9
|
import { Awaitable } from "@julr/utils/types";
|
|
10
|
+
import { Duration } from "@julr/tenace/types";
|
|
10
11
|
|
|
11
12
|
//#region src/types/options.d.ts
|
|
12
13
|
|
|
@@ -58,6 +59,11 @@ interface FacteurConfiguration<KnownChannels extends Record<string, Channel> = R
|
|
|
58
59
|
* If not provided, the default constructor will be used.
|
|
59
60
|
*/
|
|
60
61
|
notificationResolver?: NotificationResolver;
|
|
62
|
+
/**
|
|
63
|
+
* Global retry configuration for channel sends.
|
|
64
|
+
* Can be overridden per-channel or per-send.
|
|
65
|
+
*/
|
|
66
|
+
retry?: RetryConfig<KnownChannels>;
|
|
61
67
|
}
|
|
62
68
|
/**
|
|
63
69
|
* Resolver function type for notifications
|
|
@@ -144,11 +150,11 @@ type IsAnonymousNotification<T> = T extends NotificationClass<infer N, any> ? (N
|
|
|
144
150
|
/**
|
|
145
151
|
* Options for the `send` method
|
|
146
152
|
*/
|
|
147
|
-
type SendOptions<TNotificationClass extends NotificationClass<any, any>> = IsAnonymousNotification<TNotificationClass> extends true ? CommonSendOptions<TNotificationClass> & {
|
|
153
|
+
type SendOptions<TNotificationClass extends NotificationClass<any, any>> = IsAnonymousNotification<TNotificationClass> extends true ? CommonSendOptions<TNotificationClass> & RetryOptions & {
|
|
148
154
|
notification: TNotificationClass;
|
|
149
155
|
via: { [K in ChannelName]?: ProviderTarget<any, K> };
|
|
150
156
|
tenantId?: Identifier;
|
|
151
|
-
} : CommonSendOptions<TNotificationClass> & {
|
|
157
|
+
} : CommonSendOptions<TNotificationClass> & BulkSendOptions & {
|
|
152
158
|
notification: TNotificationClass;
|
|
153
159
|
to: Arrayable<NonNullable<ExtractNotifiable<TNotificationClass>>>;
|
|
154
160
|
via?: ChannelSpecificConfig<ExtractNotifiable<TNotificationClass>>;
|
|
@@ -156,6 +162,83 @@ type SendOptions<TNotificationClass extends NotificationClass<any, any>> = IsAno
|
|
|
156
162
|
};
|
|
157
163
|
type ChannelSpecificConfig<N extends Notifiable> = { [K in ChannelName]?: boolean | ProviderTarget<N, K> };
|
|
158
164
|
type ExtractChannelTargets<T> = T extends Channel<any, any, any, infer U> ? U : never;
|
|
159
|
-
type ProviderTarget<_N extends Notifiable, K extends ChannelName> = ExtractChannelTargets<NotificationChannels[K]>;
|
|
165
|
+
type ProviderTarget<_N extends Notifiable, K$1 extends ChannelName> = ExtractChannelTargets<NotificationChannels[K$1]>;
|
|
166
|
+
/**
|
|
167
|
+
* Retry options for channel sends
|
|
168
|
+
*/
|
|
169
|
+
interface RetryOptions {
|
|
170
|
+
/**
|
|
171
|
+
* Number of retry attempts when a channel send fails.
|
|
172
|
+
* Uses exponential backoff with jitter.
|
|
173
|
+
* @default 0 (no retries)
|
|
174
|
+
*/
|
|
175
|
+
retries?: number;
|
|
176
|
+
/**
|
|
177
|
+
* Timeout for each channel send operation.
|
|
178
|
+
* Accepts milliseconds or duration strings like '30s', '1m'.
|
|
179
|
+
*/
|
|
180
|
+
timeout?: Duration;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Global retry configuration with per-channel overrides
|
|
184
|
+
*/
|
|
185
|
+
interface RetryConfig<KnownChannels extends Record<string, Channel> = Record<string, Channel>> extends RetryOptions {
|
|
186
|
+
/**
|
|
187
|
+
* Per-channel retry overrides
|
|
188
|
+
*/
|
|
189
|
+
channels?: { [K in keyof KnownChannels]?: RetryOptions };
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Options for bulk sending operations
|
|
193
|
+
*/
|
|
194
|
+
interface BulkSendOptions extends RetryOptions {
|
|
195
|
+
/**
|
|
196
|
+
* Number of recipients to process per chunk.
|
|
197
|
+
* Useful for memory management with large recipient lists.
|
|
198
|
+
* @default Infinity (no chunking)
|
|
199
|
+
*/
|
|
200
|
+
chunkSize?: number;
|
|
201
|
+
/**
|
|
202
|
+
* Maximum number of concurrent sends.
|
|
203
|
+
* @default 10
|
|
204
|
+
*/
|
|
205
|
+
concurrency?: number;
|
|
206
|
+
/**
|
|
207
|
+
* If true, continues sending even if some recipients fail (Promise.allSettled behavior).
|
|
208
|
+
* If false, stops on first error (Promise.all behavior).
|
|
209
|
+
* @default false
|
|
210
|
+
*/
|
|
211
|
+
continueOnError?: boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Number of retry attempts per recipient.
|
|
214
|
+
* Uses exponential backoff with jitter.
|
|
215
|
+
* @default 0 (no retries)
|
|
216
|
+
*/
|
|
217
|
+
retries?: number;
|
|
218
|
+
/**
|
|
219
|
+
* Timeout per recipient send operation.
|
|
220
|
+
* Accepts milliseconds or duration strings like '30s', '1m'.
|
|
221
|
+
*/
|
|
222
|
+
timeout?: Duration;
|
|
223
|
+
/**
|
|
224
|
+
* Callback invoked after each recipient is processed.
|
|
225
|
+
*/
|
|
226
|
+
onProgress?: (completed: number, total: number) => void;
|
|
227
|
+
/**
|
|
228
|
+
* Disable driver-level batching even if the channel supports it.
|
|
229
|
+
* When true, each message is sent individually.
|
|
230
|
+
* @default false
|
|
231
|
+
*/
|
|
232
|
+
disableDriverBatch?: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Enable batch mode which groups messages by channel and uses batch APIs when available.
|
|
235
|
+
* This mode has different semantics:
|
|
236
|
+
* - Retries and timeouts apply at the batch level, not per-recipient
|
|
237
|
+
* - Progress callback is called per chunk, not per recipient
|
|
238
|
+
* - More efficient for channels that support batch APIs (FCM, Expo)
|
|
239
|
+
* @default false
|
|
240
|
+
*/
|
|
241
|
+
useDriverBatching?: boolean;
|
|
242
|
+
}
|
|
160
243
|
//#endregion
|
|
161
|
-
export { Arrayable, ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, SendOptions };
|
|
244
|
+
export { Arrayable, BulkSendOptions, ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, RetryConfig, RetryOptions, SendOptions };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BatchConfig, BatchSendResult, Channel, ChannelSendParams, kTargetSymbol } from "./types/channel.mjs";
|
|
2
|
+
import { QueueAdapter, QueueItemOptions } from "./types/queue.mjs";
|
|
3
|
+
import { DefaultPreferences, ResolvedDefaultPreferences } from "./types/preferences.mjs";
|
|
4
|
+
import { BuilderOptions, BuilderState, HasRequiredParams, InternalSendOptions, IsAnonymous, NotificationBuilder } from "./types/builder.mjs";
|
|
5
|
+
import { ChannelName, DatabaseContent, InferChannelsFromConfig, NotificationChannels } from "./types/extend.mjs";
|
|
6
|
+
import { Emitter, FacteurEvents } from "./types/events.mjs";
|
|
7
|
+
import { Arrayable, BulkSendOptions, ChannelSpecificConfig, CommonSendOptions, DeliverByOptions, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, MessageCtx, NotificationOptions, NotificationParams, NotificationResolver, ProviderTarget, RetryConfig, RetryOptions, SendOptions } from "./types/options.mjs";
|
|
8
|
+
import { ChannelSendResult, Notifiable, NotifiableTargets, Notification, NotificationClass, NotificationSendResult } from "./types/notifications.mjs";
|
|
9
|
+
export { Arrayable, BatchConfig, BatchSendResult, BuilderOptions, BuilderState, BulkSendOptions, Channel, ChannelName, ChannelSendParams, ChannelSendResult, ChannelSpecificConfig, CommonSendOptions, DatabaseContent, DefaultPreferences, DeliverByOptions, Emitter, ExtractChannelTargets, ExtractNotifiable, ExtractParams, FacteurConfiguration, FacteurEvents, HasRequiredParams, InferChannelsFromConfig, InternalSendOptions, IsAnonymous, MessageCtx, Notifiable, NotifiableTargets, Notification, NotificationBuilder, NotificationChannels, NotificationClass, NotificationOptions, NotificationParams, NotificationResolver, NotificationSendResult, ProviderTarget, QueueAdapter, QueueItemOptions, ResolvedDefaultPreferences, RetryConfig, RetryOptions, SendOptions, kTargetSymbol };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/utils/chunk.ts
|
|
2
|
+
/**
|
|
3
|
+
* Split an array into chunks of a given size
|
|
4
|
+
*/
|
|
5
|
+
function chunk(array, size) {
|
|
6
|
+
if (size <= 0) throw new Error("Chunk size must be greater than 0");
|
|
7
|
+
if (size === Infinity) return [array];
|
|
8
|
+
const chunks = [];
|
|
9
|
+
for (let i = 0; i < array.length; i += size) chunks.push(array.slice(i, i + size));
|
|
10
|
+
return chunks;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Collect items from an async iterable into an array
|
|
14
|
+
*/
|
|
15
|
+
async function collect(iterable) {
|
|
16
|
+
const items = [];
|
|
17
|
+
for await (const item of iterable) items.push(item);
|
|
18
|
+
return items;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if a value is an async iterable
|
|
22
|
+
*/
|
|
23
|
+
function isAsyncIterable(value) {
|
|
24
|
+
return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { chunk, collect, isAsyncIterable };
|
package/package.json
CHANGED
|
@@ -1,52 +1,83 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@facteurjs/core",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "2.0.0-beta.0",
|
|
4
|
+
"description": "Framework-agnostic notification system for Node.js with support for multiple channels (email, SMS, push, webhooks, etc.)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"discord",
|
|
7
|
+
"email",
|
|
8
|
+
"expo",
|
|
9
|
+
"fcm",
|
|
10
|
+
"firebase",
|
|
11
|
+
"nodejs",
|
|
12
|
+
"notification-system",
|
|
13
|
+
"notifications",
|
|
14
|
+
"push-notifications",
|
|
15
|
+
"slack",
|
|
16
|
+
"sms",
|
|
17
|
+
"twilio",
|
|
18
|
+
"webhooks",
|
|
19
|
+
"webpush"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
6
22
|
"author": "Julien Ripouteau <julien@ripouteau.com>",
|
|
7
|
-
"license": "ISC",
|
|
8
|
-
"keywords": [],
|
|
9
23
|
"files": [
|
|
10
24
|
"dist"
|
|
11
25
|
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.mjs",
|
|
28
|
+
"module": "./dist/index.mjs",
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
12
30
|
"exports": {
|
|
13
|
-
".": "./dist/index.
|
|
14
|
-
"./api": "./dist/api
|
|
15
|
-
"./api/types": "./dist/api/types.
|
|
16
|
-
"./channels/aws-sns": "./dist/channels/aws-sns
|
|
17
|
-
"./channels/aws-sns/types": "./dist/channels/aws-sns/types.
|
|
18
|
-
"./channels/discord": "./dist/channels/discord
|
|
19
|
-
"./channels/discord/types": "./dist/channels/discord/types.
|
|
20
|
-
"./channels/expo": "./dist/channels/expo
|
|
21
|
-
"./channels/expo/types": "./dist/channels/expo/types.
|
|
22
|
-
"./channels/fcm": "./dist/channels/fcm
|
|
23
|
-
"./channels/fcm/types": "./dist/channels/fcm/types.
|
|
24
|
-
"./channels/slack": "./dist/channels/slack
|
|
25
|
-
"./channels/slack/types": "./dist/channels/slack/types.
|
|
26
|
-
"./channels/socketio": "./dist/channels/socketio
|
|
27
|
-
"./channels/socketio/types": "./dist/channels/socketio/types.
|
|
28
|
-
"./channels/transmit": "./dist/channels/transmit
|
|
29
|
-
"./channels/transmit/types": "./dist/channels/transmit/types.
|
|
30
|
-
"./channels/twilio": "./dist/channels/twilio
|
|
31
|
-
"./channels/twilio/types": "./dist/channels/twilio/types.
|
|
32
|
-
"./channels/webhook": "./dist/channels/webhook
|
|
33
|
-
"./channels/webhook/types": "./dist/channels/webhook/types.
|
|
34
|
-
"./channels/webpush": "./dist/channels/webpush
|
|
35
|
-
"./channels/webpush/types": "./dist/channels/webpush/types.
|
|
36
|
-
"./database
|
|
37
|
-
"./database/adapters/
|
|
38
|
-
"./database": "./dist/database/
|
|
39
|
-
"./database/types": "./dist/database/types.
|
|
40
|
-
"./types": "./dist/types
|
|
31
|
+
".": "./dist/index.mjs",
|
|
32
|
+
"./api": "./dist/api.mjs",
|
|
33
|
+
"./api/types": "./dist/api/types.mjs",
|
|
34
|
+
"./channels/aws-sns": "./dist/channels/aws-sns.mjs",
|
|
35
|
+
"./channels/aws-sns/types": "./dist/channels/aws-sns/types.mjs",
|
|
36
|
+
"./channels/discord": "./dist/channels/discord.mjs",
|
|
37
|
+
"./channels/discord/types": "./dist/channels/discord/types.mjs",
|
|
38
|
+
"./channels/expo": "./dist/channels/expo.mjs",
|
|
39
|
+
"./channels/expo/types": "./dist/channels/expo/types.mjs",
|
|
40
|
+
"./channels/fcm": "./dist/channels/fcm.mjs",
|
|
41
|
+
"./channels/fcm/types": "./dist/channels/fcm/types.mjs",
|
|
42
|
+
"./channels/slack": "./dist/channels/slack.mjs",
|
|
43
|
+
"./channels/slack/types": "./dist/channels/slack/types.mjs",
|
|
44
|
+
"./channels/socketio": "./dist/channels/socketio.mjs",
|
|
45
|
+
"./channels/socketio/types": "./dist/channels/socketio/types.mjs",
|
|
46
|
+
"./channels/transmit": "./dist/channels/transmit.mjs",
|
|
47
|
+
"./channels/transmit/types": "./dist/channels/transmit/types.mjs",
|
|
48
|
+
"./channels/twilio": "./dist/channels/twilio.mjs",
|
|
49
|
+
"./channels/twilio/types": "./dist/channels/twilio/types.mjs",
|
|
50
|
+
"./channels/webhook": "./dist/channels/webhook.mjs",
|
|
51
|
+
"./channels/webhook/types": "./dist/channels/webhook/types.mjs",
|
|
52
|
+
"./channels/webpush": "./dist/channels/webpush.mjs",
|
|
53
|
+
"./channels/webpush/types": "./dist/channels/webpush/types.mjs",
|
|
54
|
+
"./database": "./dist/database.mjs",
|
|
55
|
+
"./database/adapters/knex": "./dist/database/adapters/knex.mjs",
|
|
56
|
+
"./database/adapters/kysely": "./dist/database/adapters/kysely.mjs",
|
|
57
|
+
"./database/types": "./dist/database/types.mjs",
|
|
58
|
+
"./types": "./dist/types.mjs",
|
|
41
59
|
"./package.json": "./package.json"
|
|
42
60
|
},
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
46
64
|
"dependencies": {
|
|
65
|
+
"@julr/tenace": "1.0.0-next.0",
|
|
47
66
|
"@julr/utils": "1.9.0",
|
|
48
|
-
"@poppinss/exception": "^1.2.
|
|
49
|
-
"ky": "^1.
|
|
67
|
+
"@poppinss/exception": "^1.2.3",
|
|
68
|
+
"ky": "^1.14.2"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@aws-sdk/client-sns": "^3.958.0",
|
|
72
|
+
"@boringnode/transmit": "^0.3.0",
|
|
73
|
+
"@types/web-push": "^3.6.4",
|
|
74
|
+
"expo-server-sdk": "^4.0.0",
|
|
75
|
+
"firebase-admin": "^13.6.0",
|
|
76
|
+
"knex": "^3.1.0",
|
|
77
|
+
"kysely": "^0.28.9",
|
|
78
|
+
"socket.io": "^4.8.3",
|
|
79
|
+
"twilio": "^5.11.1",
|
|
80
|
+
"web-push": "^3.6.7"
|
|
50
81
|
},
|
|
51
82
|
"peerDependencies": {
|
|
52
83
|
"@aws-sdk/client-sns": "^3.856.0",
|
|
@@ -88,22 +119,6 @@
|
|
|
88
119
|
"optional": true
|
|
89
120
|
}
|
|
90
121
|
},
|
|
91
|
-
"devDependencies": {
|
|
92
|
-
"@aws-sdk/client-sns": "^3.856.0",
|
|
93
|
-
"@boringnode/transmit": "^0.3.0",
|
|
94
|
-
"@types/web-push": "^3.6.4",
|
|
95
|
-
"expo-server-sdk": "^3.15.0",
|
|
96
|
-
"firebase-admin": "^13.4.0",
|
|
97
|
-
"knex": "^3.1.0",
|
|
98
|
-
"kysely": "^0.28.3",
|
|
99
|
-
"p-event": "^6.0.1",
|
|
100
|
-
"socket.io": "^4.8.1",
|
|
101
|
-
"twilio": "^5.8.0",
|
|
102
|
-
"web-push": "^3.6.7"
|
|
103
|
-
},
|
|
104
|
-
"publishConfig": {
|
|
105
|
-
"access": "public"
|
|
106
|
-
},
|
|
107
122
|
"scripts": {
|
|
108
123
|
"build": "tsdown",
|
|
109
124
|
"stub": "tsdown",
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { defineRoute } from "../index.js";
|
|
2
|
-
|
|
3
|
-
//#region src/api/handlers/preferences.ts
|
|
4
|
-
const getPreferencesRoute = defineRoute(({ facteur }) => ({
|
|
5
|
-
method: "get",
|
|
6
|
-
route: "/notifications/notifiable/:notifiableId/preferences",
|
|
7
|
-
handler: async (request) => {
|
|
8
|
-
const userId = request.params.notifiableId;
|
|
9
|
-
const preferences = await facteur.db.getPreferences({
|
|
10
|
-
notifiableId: userId,
|
|
11
|
-
tenantId: request.query.tenantId
|
|
12
|
-
});
|
|
13
|
-
return {
|
|
14
|
-
status: 200,
|
|
15
|
-
body: preferences || {}
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
}));
|
|
19
|
-
const updatePreferencesRoute = defineRoute(({ facteur }) => ({
|
|
20
|
-
method: "post",
|
|
21
|
-
route: "/notifications/notifiable/:notifiableId/preferences",
|
|
22
|
-
handler: async (request) => {
|
|
23
|
-
const userId = request.params.notifiableId;
|
|
24
|
-
const preferences = request.body.preferences;
|
|
25
|
-
if (!preferences) return {
|
|
26
|
-
status: 400,
|
|
27
|
-
body: { error: "Preferences are required" }
|
|
28
|
-
};
|
|
29
|
-
await facteur.db.updatePreferences({
|
|
30
|
-
notifiableId: userId,
|
|
31
|
-
tenantId: request.body.tenantId,
|
|
32
|
-
notificationName: request.body.notificationName,
|
|
33
|
-
channelPreferences: preferences
|
|
34
|
-
});
|
|
35
|
-
return {
|
|
36
|
-
status: 204,
|
|
37
|
-
body: {}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
|
-
//#endregion
|
|
43
|
-
export { getPreferencesRoute, updatePreferencesRoute };
|
package/dist/api/index.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Facteur } from "../facteur.js";
|
|
2
|
-
import { RouteDefinition, ServerAdapter } from "./types.js";
|
|
3
|
-
|
|
4
|
-
//#region src/api/index.d.ts
|
|
5
|
-
declare function defineRoute(routeDefinition: (options: {
|
|
6
|
-
facteur: Facteur<any, any>;
|
|
7
|
-
}) => RouteDefinition): (options: {
|
|
8
|
-
facteur: Facteur<any, any>;
|
|
9
|
-
}) => RouteDefinition;
|
|
10
|
-
declare const routes: (facteur: Facteur<any, any>) => RouteDefinition[];
|
|
11
|
-
declare function createFacteurServer(options: {
|
|
12
|
-
adapter: ServerAdapter;
|
|
13
|
-
facteur: Facteur<any, any>;
|
|
14
|
-
}): void;
|
|
15
|
-
//#endregion
|
|
16
|
-
export { createFacteurServer, defineRoute, routes };
|
package/dist/api/index.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { getPreferencesRoute, updatePreferencesRoute } from "./handlers/preferences.js";
|
|
2
|
-
import { getNotificationRoute, markAllNotificationsAsRoute, markNotificationAsRoute } from "./handlers/notifications.js";
|
|
3
|
-
|
|
4
|
-
//#region src/api/index.ts
|
|
5
|
-
function defineRoute(routeDefinition) {
|
|
6
|
-
return routeDefinition;
|
|
7
|
-
}
|
|
8
|
-
const routes = (facteur) => [
|
|
9
|
-
getNotificationRoute({ facteur }),
|
|
10
|
-
markNotificationAsRoute({ facteur }),
|
|
11
|
-
markAllNotificationsAsRoute({ facteur }),
|
|
12
|
-
getPreferencesRoute({ facteur }),
|
|
13
|
-
updatePreferencesRoute({ facteur })
|
|
14
|
-
];
|
|
15
|
-
function createFacteurServer(options) {
|
|
16
|
-
const { adapter, facteur } = options;
|
|
17
|
-
adapter.setRoutes(routes(facteur));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
//#endregion
|
|
21
|
-
export { createFacteurServer, defineRoute, routes };
|
package/dist/api/types.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//#region src/api/types.d.ts
|
|
2
|
-
type HTTPMethod = 'get' | 'post' | 'put' | 'patch';
|
|
3
|
-
interface HTTPRequest {
|
|
4
|
-
body: Record<string, any>;
|
|
5
|
-
params: Record<string, any>;
|
|
6
|
-
query: Record<string, any>;
|
|
7
|
-
headers: Record<string, string | undefined>;
|
|
8
|
-
}
|
|
9
|
-
interface HTTPResponse {
|
|
10
|
-
status: number;
|
|
11
|
-
body: Record<string, any>;
|
|
12
|
-
}
|
|
13
|
-
interface RouteDefinition {
|
|
14
|
-
method: HTTPMethod;
|
|
15
|
-
route: string;
|
|
16
|
-
handler: (request: HTTPRequest) => Promise<HTTPResponse>;
|
|
17
|
-
}
|
|
18
|
-
interface ServerAdapter {
|
|
19
|
-
setRoutes(routes: RouteDefinition[]): void;
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { HTTPMethod, HTTPRequest, HTTPResponse, RouteDefinition, ServerAdapter };
|
package/dist/api/types.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,38 +0,0 @@
|
|
|
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 };
|
|
File without changes
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { errors } from "../../errors/index.js";
|
|
2
|
-
import { kTargetSymbol } from "../../types/channel.js";
|
|
3
|
-
import "../../types/index.js";
|
|
4
|
-
import { cert, initializeApp } from "firebase-admin/app";
|
|
5
|
-
import { getMessaging } from "firebase-admin/messaging";
|
|
6
|
-
|
|
7
|
-
//#region src/channels/fcm/channel.ts
|
|
8
|
-
function fcmChannel(config) {
|
|
9
|
-
return new FcmChannel(config);
|
|
10
|
-
}
|
|
11
|
-
var FcmChannel = class {
|
|
12
|
-
name = "fcm";
|
|
13
|
-
[kTargetSymbol] = null;
|
|
14
|
-
messaging;
|
|
15
|
-
constructor(config) {
|
|
16
|
-
this.config = config;
|
|
17
|
-
const app = initializeApp({
|
|
18
|
-
...config,
|
|
19
|
-
...config.serviceAccountKeyPath ? { credential: cert(config.serviceAccountKeyPath) } : {}
|
|
20
|
-
});
|
|
21
|
-
this.messaging = getMessaging(app);
|
|
22
|
-
}
|
|
23
|
-
#resolveTargets(options) {
|
|
24
|
-
if (options.targets) return options.targets;
|
|
25
|
-
throw new errors.E_UNAVAILABLE_TARGETS(["FCM"]);
|
|
26
|
-
}
|
|
27
|
-
#handleError(error) {
|
|
28
|
-
if (error.code === "messaging/registration-token-not-registered") throw new Error(`FCM token is no longer valid: ${error.message}`);
|
|
29
|
-
if (error.code === "messaging/invalid-argument") throw new Error(`Invalid FCM message format: ${error.message}`);
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
async send(options) {
|
|
33
|
-
const message = options.message.serialize();
|
|
34
|
-
const targets = this.#resolveTargets(options);
|
|
35
|
-
if (this.config.debugToken) message.token = this.config.debugToken;
|
|
36
|
-
if (targets.token) message.token = this.config.debugToken || targets.token;
|
|
37
|
-
else if (targets.topic) message.topic = targets.topic;
|
|
38
|
-
else if (targets.condition) message.condition = targets.condition;
|
|
39
|
-
return await this.messaging.send(message).catch((error) => this.#handleError(error));
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
//#endregion
|
|
44
|
-
export { FcmChannel, fcmChannel };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|