@lyxa.ai/core 1.4.334 → 1.4.336
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/libraries/mongo/models/payment-intent.model.d.ts +2 -1
- package/dist/libraries/mongo/models/payment-intent.model.js +5 -0
- package/dist/libraries/mongo/models/payment-intent.model.js.map +1 -1
- package/dist/libraries/notification/firebase-message.builder.d.ts +1 -5
- package/dist/libraries/notification/firebase-message.builder.js +1 -34
- package/dist/libraries/notification/firebase-message.builder.js.map +1 -1
- package/dist/libraries/notification/index.d.ts +0 -2
- package/dist/libraries/notification/index.js.map +1 -1
- package/dist/libraries/notification/lyxa-fcm-sender.js +0 -2
- package/dist/libraries/notification/lyxa-fcm-sender.js.map +1 -1
- package/dist/libraries/notification/lyxa-fcm.service.d.ts +0 -1
- package/dist/libraries/notification/lyxa-fcm.service.js +0 -21
- package/dist/libraries/notification/lyxa-fcm.service.js.map +1 -1
- package/dist/types/README.md +1 -1
- package/dist/types/package.json +1 -1
- package/dist/utilities/pagination.d.ts +2 -2
- package/dist/utilities/pagination.js +3 -3
- package/dist/utilities/pagination.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Ref } from '@typegoose/typegoose';
|
|
2
2
|
import { TimeStamps } from '@typegoose/typegoose/lib/defaultClasses';
|
|
3
3
|
import { CoreUser } from './core-user.model';
|
|
4
|
-
import { PaymentIntentStatus } from '../../../utilities/enum';
|
|
4
|
+
import { PaymentIntentStatus, PaymentProvider } from '../../../utilities/enum';
|
|
5
5
|
import { User } from './user.model';
|
|
6
6
|
export declare class PaymentIntent extends TimeStamps {
|
|
7
7
|
coreUser: Ref<CoreUser>;
|
|
@@ -14,4 +14,5 @@ export declare class PaymentIntent extends TimeStamps {
|
|
|
14
14
|
authorization?: string;
|
|
15
15
|
paymentContext?: any;
|
|
16
16
|
status?: PaymentIntentStatus;
|
|
17
|
+
provider?: PaymentProvider;
|
|
17
18
|
}
|
|
@@ -26,6 +26,7 @@ let PaymentIntent = class PaymentIntent extends defaultClasses_1.TimeStamps {
|
|
|
26
26
|
authorization;
|
|
27
27
|
paymentContext;
|
|
28
28
|
status;
|
|
29
|
+
provider;
|
|
29
30
|
};
|
|
30
31
|
exports.PaymentIntent = PaymentIntent;
|
|
31
32
|
__decorate([
|
|
@@ -68,6 +69,10 @@ __decorate([
|
|
|
68
69
|
(0, typegoose_1.prop)({ type: String, enum: enum_1.PaymentIntentStatus, default: enum_1.PaymentIntentStatus.PENDING }),
|
|
69
70
|
__metadata("design:type", String)
|
|
70
71
|
], PaymentIntent.prototype, "status", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, typegoose_1.prop)({ type: String, enum: enum_1.PaymentProvider }),
|
|
74
|
+
__metadata("design:type", String)
|
|
75
|
+
], PaymentIntent.prototype, "provider", void 0);
|
|
71
76
|
exports.PaymentIntent = PaymentIntent = __decorate([
|
|
72
77
|
(0, typegoose_1.modelOptions)({
|
|
73
78
|
schemaOptions: { collection: 'paymentIntents' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment-intent.model.js","sourceRoot":"/","sources":["libraries/mongo/models/payment-intent.model.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAmF;AACnF,4EAAqE;AACrE,uDAA6C;AAC7C,
|
|
1
|
+
{"version":3,"file":"payment-intent.model.js","sourceRoot":"/","sources":["libraries/mongo/models/payment-intent.model.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAmF;AACnF,4EAAqE;AACrE,uDAA6C;AAC7C,kDAA+E;AAC/E,6CAAoC;AAQ7B,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,2BAAU;IAErC,QAAQ,CAAiB;IAGzB,IAAI,CAAa;IAGjB,OAAO,CAAU;IAGjB,KAAK,CAAU;IAGf,UAAU,CAAU;IAGpB,MAAM,CAAU;IAGhB,eAAe,CAAU;IAGzB,aAAa,CAAU;IAGvB,cAAc,CAAO;IAGrB,MAAM,CAAuB;IAG7B,QAAQ,CAAmB;CAClC,CAAA;AAjCY,sCAAa;AAElB;IADN,IAAA,gBAAI,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,0BAAQ,EAAE,CAAC;;+CACd;AAGzB;IADN,IAAA,gBAAI,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,iBAAI,EAAE,CAAC;;2CAClB;AAGjB;IADN,IAAA,gBAAI,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;8CACf;AAGjB;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4CACD;AAGf;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;iDACI;AAGpB;IADN,IAAA,gBAAI,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;6CAChB;AAGhB;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;sDACS;AAGzB;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;oDACO;AAGvB;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,oBAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;;qDAChB;AAGrB;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0BAAmB,EAAE,OAAO,EAAE,0BAAmB,CAAC,OAAO,EAAE,CAAC;;6CACpD;AAG7B;IADN,IAAA,gBAAI,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAe,EAAE,CAAC;;+CACZ;wBAhCtB,aAAa;IANzB,IAAA,wBAAY,EAAC;QACb,aAAa,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE;QAC/C,OAAO,EAAE;YACR,UAAU,EAAE,oBAAQ,CAAC,KAAK;SAC1B;KACD,CAAC;GACW,aAAa,CAiCzB","sourcesContent":["import { modelOptions, mongoose, prop, Ref, Severity } from '@typegoose/typegoose';\nimport { TimeStamps } from '@typegoose/typegoose/lib/defaultClasses';\nimport { CoreUser } from './core-user.model';\nimport { PaymentIntentStatus, PaymentProvider } from '../../../utilities/enum';\nimport { User } from './user.model';\n\n@modelOptions({\n\tschemaOptions: { collection: 'paymentIntents' },\n\toptions: {\n\t\tallowMixed: Severity.ALLOW,\n\t},\n})\nexport class PaymentIntent extends TimeStamps {\n\t@prop({ required: true, ref: () => CoreUser })\n\tpublic coreUser!: Ref<CoreUser>;\n\n\t@prop({ required: true, ref: () => User })\n\tpublic user!: Ref<User>;\n\n\t@prop({ required: true, type: String })\n\tpublic orderId!: string;\n\n\t@prop({ type: String })\n\tpublic token?: string; // only for areeba\n\n\t@prop({ type: String })\n\tpublic externalId?: string; // only for whish\n\n\t@prop({ required: true, type: Number })\n\tpublic amount!: number;\n\n\t@prop({ type: Number })\n\tpublic secondaryAmount?: number;\n\n\t@prop({ type: String })\n\tpublic authorization?: string;\n\n\t@prop({ type: mongoose.Schema.Types.Mixed })\n\tpublic paymentContext?: any;\n\n\t@prop({ type: String, enum: PaymentIntentStatus, default: PaymentIntentStatus.PENDING })\n\tpublic status?: PaymentIntentStatus;\n\n\t@prop({ type: String, enum: PaymentProvider })\n\tpublic provider?: PaymentProvider;\n}\n"]}
|
|
@@ -3,8 +3,7 @@ import { FCMNotificationPayload } from './lyxa-fcm.service';
|
|
|
3
3
|
export declare enum MultiMessageType {
|
|
4
4
|
OLD = "old",
|
|
5
5
|
CONSOLE = "console",
|
|
6
|
-
DEFAULT = "default"
|
|
7
|
-
LIVE_ACTIVITY = "live_activity"
|
|
6
|
+
DEFAULT = "default"
|
|
8
7
|
}
|
|
9
8
|
export interface IFirebaseMessageBuilder {
|
|
10
9
|
buildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage;
|
|
@@ -21,6 +20,3 @@ export declare class OldMessageBuilder implements IFirebaseMessageBuilder {
|
|
|
21
20
|
export declare class ConsoleMessageBuilder implements IFirebaseMessageBuilder {
|
|
22
21
|
buildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage;
|
|
23
22
|
}
|
|
24
|
-
export declare class LiveActivityMessageBuilder implements IFirebaseMessageBuilder {
|
|
25
|
-
buildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage;
|
|
26
|
-
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
const dayjs_1 = __importDefault(require("dayjs"));
|
|
3
|
+
exports.ConsoleMessageBuilder = exports.OldMessageBuilder = exports.DefaultMessageBuilder = exports.FirebaseMessageBuilderFactory = exports.MultiMessageType = void 0;
|
|
8
4
|
var MultiMessageType;
|
|
9
5
|
(function (MultiMessageType) {
|
|
10
6
|
MultiMessageType["OLD"] = "old";
|
|
11
7
|
MultiMessageType["CONSOLE"] = "console";
|
|
12
8
|
MultiMessageType["DEFAULT"] = "default";
|
|
13
|
-
MultiMessageType["LIVE_ACTIVITY"] = "live_activity";
|
|
14
9
|
})(MultiMessageType || (exports.MultiMessageType = MultiMessageType = {}));
|
|
15
10
|
class FirebaseMessageBuilderFactory {
|
|
16
11
|
buildMessage(type, payload, tokens) {
|
|
@@ -19,8 +14,6 @@ class FirebaseMessageBuilderFactory {
|
|
|
19
14
|
return new ConsoleMessageBuilder().buildMessage(payload, tokens);
|
|
20
15
|
case MultiMessageType.OLD:
|
|
21
16
|
return new OldMessageBuilder().buildMessage(payload, tokens);
|
|
22
|
-
case MultiMessageType.LIVE_ACTIVITY:
|
|
23
|
-
return new LiveActivityMessageBuilder().buildMessage(payload, tokens);
|
|
24
17
|
default:
|
|
25
18
|
return new DefaultMessageBuilder().buildMessage(payload, tokens);
|
|
26
19
|
}
|
|
@@ -111,30 +104,4 @@ class ConsoleMessageBuilder {
|
|
|
111
104
|
}
|
|
112
105
|
}
|
|
113
106
|
exports.ConsoleMessageBuilder = ConsoleMessageBuilder;
|
|
114
|
-
class LiveActivityMessageBuilder {
|
|
115
|
-
buildMessage(payload, tokens) {
|
|
116
|
-
return {
|
|
117
|
-
notification: {
|
|
118
|
-
title: payload.title,
|
|
119
|
-
body: payload.body,
|
|
120
|
-
},
|
|
121
|
-
tokens: tokens,
|
|
122
|
-
apns: {
|
|
123
|
-
payload: {
|
|
124
|
-
aps: {
|
|
125
|
-
timestamp: (0, dayjs_1.default)().unix(),
|
|
126
|
-
event: payload.data.event,
|
|
127
|
-
'content-state': { status: payload.data.status, etaMinutes: payload.data.deliveredInMinutes },
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
headers: {
|
|
131
|
-
'apns-push-type': 'liveactivity',
|
|
132
|
-
'apns-priority': '10',
|
|
133
|
-
'apns-topic': 'com.lyxa.app.push-type.liveactivity',
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
exports.LiveActivityMessageBuilder = LiveActivityMessageBuilder;
|
|
140
107
|
//# sourceMappingURL=firebase-message.builder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-message.builder.js","sourceRoot":"/","sources":["libraries/notification/firebase-message.builder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"firebase-message.builder.js","sourceRoot":"/","sources":["libraries/notification/firebase-message.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { messaging } from 'firebase-admin';\nimport { FCMNotificationPayload } from './lyxa-fcm.service';\n\nexport enum MultiMessageType {\n\tOLD = 'old',\n\tCONSOLE = 'console',\n\tDEFAULT = 'default',\n}\n\nexport interface IFirebaseMessageBuilder {\n\tbuildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage;\n}\n\nexport class FirebaseMessageBuilderFactory {\n\tpublic buildMessage(\n\t\ttype: MultiMessageType,\n\t\tpayload: FCMNotificationPayload,\n\t\ttokens: string[]\n\t): messaging.MulticastMessage {\n\t\tswitch (type) {\n\t\t\tcase MultiMessageType.CONSOLE:\n\t\t\t\treturn new ConsoleMessageBuilder().buildMessage(payload, tokens);\n\t\t\tcase MultiMessageType.OLD:\n\t\t\t\treturn new OldMessageBuilder().buildMessage(payload, tokens);\n\t\t\t// case MultiMessageType.DEFAULT:\n\t\t\t// \treturn new DefaultMessageBuilder().buildMessage(payload, tokens);\n\t\t\tdefault:\n\t\t\t\treturn new DefaultMessageBuilder().buildMessage(payload, tokens);\n\t\t}\n\t}\n}\n\nexport class DefaultMessageBuilder implements IFirebaseMessageBuilder {\n\tbuildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage {\n\t\tconst isInvisible = payload.invisible === true;\n\t\tconst channelId = payload.sound ? 'order_alert' : 'default';\n\n\t\treturn {\n\t\t\tdata: { ...payload.data, channelId: isInvisible ? 'silent' : channelId },\n\t\t\tnotification: {\n\t\t\t\ttitle: payload.title,\n\t\t\t\tbody: payload.body,\n\t\t\t},\n\t\t\ttokens: tokens,\n\t\t\tandroid: {\n\t\t\t\tpriority: 'high',\n\t\t\t\tnotification: {\n\t\t\t\t\tchannelId: 'silent',\n\t\t\t\t},\n\t\t\t},\n\t\t\tapns: {\n\t\t\t\tpayload: {\n\t\t\t\t\taps: {\n\t\t\t\t\t\tsound: payload.sound || 'default',\n\t\t\t\t\t\tcontentAvailable: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\theaders: {\n\t\t\t\t\t'apns-push-type': 'background',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n}\n\nexport class OldMessageBuilder implements IFirebaseMessageBuilder {\n\tbuildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage {\n\t\tconst isInvisible = payload.invisible === true;\n\n\t\tconst message: messaging.MulticastMessage = {\n\t\t\tdata: payload.data || {},\n\t\t\tnotification: {\n\t\t\t\ttitle: payload.title,\n\t\t\t\tbody: payload.body,\n\t\t\t},\n\t\t\ttokens: tokens,\n\t\t\tandroid: { priority: 'high' },\n\t\t\tapns: {\n\t\t\t\tpayload: {\n\t\t\t\t\taps: {\n\t\t\t\t\t\tsound: payload.sound || 'default',\n\t\t\t\t\t\tcontentAvailable: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\n\t\tif (!isInvisible) {\n\t\t\tmessage.notification = {\n\t\t\t\ttitle: payload.title,\n\t\t\t\tbody: payload.body,\n\t\t\t};\n\n\t\t\tmessage.android = {\n\t\t\t\tpriority: 'high',\n\t\t\t\tnotification: {\n\t\t\t\t\tchannelId: payload.sound ? 'android_Push_Notification_Channel_1' : 'default',\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn message;\n\t}\n}\n\nexport class ConsoleMessageBuilder implements IFirebaseMessageBuilder {\n\tbuildMessage(payload: FCMNotificationPayload, tokens: string[]): messaging.MulticastMessage {\n\t\tconst isInvisible = payload.invisible === true;\n\t\tconst channelId = payload.sound ? 'order_alert' : 'default';\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\t...payload.data,\n\t\t\t\tchannelId: isInvisible ? 'silent' : channelId,\n\t\t\t\tnotificationTitle: payload.title ?? '',\n\t\t\t\tnotificationBody: payload.body ?? '',\n\t\t\t},\n\t\t\ttokens: tokens,\n\t\t};\n\t}\n}\n"]}
|
|
@@ -10,8 +10,6 @@ export interface NotificationEventData {
|
|
|
10
10
|
clickableUrl?: string | null;
|
|
11
11
|
notificationType?: PushNotificationEventType;
|
|
12
12
|
saveNotification?: boolean;
|
|
13
|
-
isLiveActivity?: boolean;
|
|
14
|
-
tokens?: string[];
|
|
15
13
|
[key: string]: any;
|
|
16
14
|
}
|
|
17
15
|
export type NotificationGlobalEventData = Omit<NotificationEventData, 'recipientId'>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"/","sources":["libraries/notification/index.ts"],"names":[],"mappings":";;;AAAA,+CAAqG;AACrG,kDAA+C;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["libraries/notification/index.ts"],"names":[],"mappings":";;;AAAA,+CAAqG;AACrG,kDAA+C;AAyB/C,MAAa,iBAAkB,SAAQ,qBAAgC;IACtE,YACC,OAEC;QAED,MAAM,YAAY,GAA0B;YAC3C,GAAG,OAAO;YACV,IAAI,EAAE;gBACL,WAAW,EAAE,KAAK;gBAClB,WAAW,EAAE,8BAAuB,CAAC,IAAI;gBACzC,GAAG,OAAO,CAAC,IAAI;aACf;SACD,CAAC;QAEF,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACrC,CAAC;CACD;AAjBD,8CAiBC;AAED,MAAa,uBAAwB,SAAQ,qBAAsC;IAClF,YACC,OAEC;QAED,MAAM,YAAY,GAAgC;YACjD,GAAG,OAAO;YACV,IAAI,EAAE;gBACL,WAAW,EAAE,KAAK;gBAClB,WAAW,EAAE,8BAAuB,CAAC,IAAI;gBACzC,GAAG,OAAO,CAAC,IAAI;aACf;SACD,CAAC;QAEF,KAAK,CAAC,qBAAqB,EAAE,YAAY,CAAC,CAAC;IAC5C,CAAC;CACD;AAjBD,0DAiBC","sourcesContent":["import { ClickType, NotificationAccountType, PushNotificationEventType } from '../../utilities/enum';\nimport { BaseEvent } from '../event/BaseEvent';\nimport mongoose from 'mongoose';\nimport { FCMNotificationPayload } from './lyxa-fcm.service';\n\nexport interface NotificationEventData {\n\taccountType: NotificationAccountType;\n\trecipientId: mongoose.Types.ObjectId;\n\tisClickable: boolean;\n\tclickType?: ClickType | null;\n\tclickableUrl?: string | null;\n\tnotificationType?: PushNotificationEventType;\n\tsaveNotification?: boolean;\n\t[key: string]: any;\n}\n\nexport type NotificationGlobalEventData = Omit<NotificationEventData, 'recipientId'>;\n\nexport interface NotificationEventType extends Omit<FCMNotificationPayload, 'data'> {\n\tdata: NotificationEventData;\n}\n\nexport interface NotificationGlobalEventType extends Omit<FCMNotificationPayload, 'data'> {\n\tdata: NotificationGlobalEventData;\n}\n\nexport class NotificationEvent extends BaseEvent<NotificationEventType> {\n\tconstructor(\n\t\tpayload: Partial<Omit<NotificationEventType, 'data'>> & {\n\t\t\tdata: Partial<NotificationEventData> & { recipientId: mongoose.Types.ObjectId };\n\t\t}\n\t) {\n\t\tconst finalPayload: NotificationEventType = {\n\t\t\t...payload,\n\t\t\tdata: {\n\t\t\t\tisClickable: false,\n\t\t\t\taccountType: NotificationAccountType.USER,\n\t\t\t\t...payload.data,\n\t\t\t},\n\t\t};\n\n\t\tsuper('notification', finalPayload);\n\t}\n}\n\nexport class NotificationGlobalEvent extends BaseEvent<NotificationGlobalEventType> {\n\tconstructor(\n\t\tpayload: Partial<Omit<NotificationGlobalEventType, 'data'>> & {\n\t\t\tdata?: Partial<NotificationGlobalEventData>;\n\t\t}\n\t) {\n\t\tconst finalPayload: NotificationGlobalEventType = {\n\t\t\t...payload,\n\t\t\tdata: {\n\t\t\t\tisClickable: false,\n\t\t\t\taccountType: NotificationAccountType.USER,\n\t\t\t\t...payload.data,\n\t\t\t},\n\t\t};\n\n\t\tsuper('notification-global', finalPayload);\n\t}\n}"]}
|
|
@@ -32,7 +32,6 @@ let LyxaFcmSender = class LyxaFcmSender {
|
|
|
32
32
|
if (!tokens.length)
|
|
33
33
|
return { failedTokens: [], tokensToDelete: [] };
|
|
34
34
|
const messages = this.buildMultiCastMessages(type, tokens, payload);
|
|
35
|
-
console.log({ project, type, payload, messages });
|
|
36
35
|
return await this.sendToAllTokens(project, type, payload, messages);
|
|
37
36
|
}
|
|
38
37
|
buildMultiCastMessages(type, tokens, payload) {
|
|
@@ -53,7 +52,6 @@ let LyxaFcmSender = class LyxaFcmSender {
|
|
|
53
52
|
await Promise.all(messages.map(async (message) => {
|
|
54
53
|
let logData;
|
|
55
54
|
try {
|
|
56
|
-
console.log("fcm service send message: ", { project, message });
|
|
57
55
|
const result = await this.fcmService.sendMessage(project, message);
|
|
58
56
|
const payloadKnownValid = result.successCount > 0;
|
|
59
57
|
result.responses.forEach((r, i) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lyxa-fcm-sender.js","sourceRoot":"/","sources":["libraries/notification/lyxa-fcm-sender.ts"],"names":[],"mappings":"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","sourcesContent":["import { Service } from 'typedi';\nimport { FirebaseFcmService } from './firebase-fcm.service';\nimport { FirebaseMessageBuilderFactory, MultiMessageType } from './firebase-message.builder';\nimport { messaging } from 'firebase-admin';\nimport { FCMNotificationPayload, FcmProject } from './lyxa-fcm.service';\nimport { getLibraries } from '../..';\n\nexport interface FcmSendResult {\n\t/** Every token that failed to receive the message, for any reason. */\n\tfailedTokens: string[];\n\t/** Subset of failedTokens that are confirmed invalid and must be deleted. */\n\ttokensToDelete: string[];\n}\n\n@Service()\nexport class LyxaFcmSender {\n\tpublic static readonly MAX_BATCH = 500;\n\n\t/**\n\t * FCM error codes that unambiguously mean the registration token itself is\n\t * malformed or no longer registered, so it will never be valid again and is\n\t * safe to delete from our records.\n\t *\n\t * Everything else (server/internal errors, rate limits, auth/credential\n\t * issues, transport failures) is transient and must NOT cause deletion.\n\t *\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens#ensuring-registration-token-freshness\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens\n\t */\n\tprivate static readonly REMOVABLE_TOKEN_ERROR_CODES: ReadonlySet<string> = new Set([\n\t\t// UNREGISTERED (404): token was unregistered (app uninstalled / token refreshed).\n\t\t'messaging/registration-token-not-registered',\n\t\t// Token is not a valid FCM registration token (wrong format).\n\t\t'messaging/invalid-registration-token',\n\t]);\n\n\tconstructor(\n\t\tprivate readonly fcmService: FirebaseFcmService,\n\t\tprivate readonly builder: FirebaseMessageBuilderFactory\n\t) {}\n\n\t/**\n\t * Sends notifications and reports the outcome. `failedTokens` contains every\n\t * failure; `tokensToDelete` is the subset that is confirmed invalid and must\n\t * be removed from our records. Transient failures stay out of\n\t * `tokensToDelete` so they never trigger token deletion.\n\t */\n\tpublic async sendMessages(\n\t\tproject: FcmProject,\n\t\ttype: MultiMessageType,\n\t\ttokens: string[],\n\t\tpayload: FCMNotificationPayload\n\t): Promise<FcmSendResult> {\n\t\tif (!tokens.length) return { failedTokens: [], tokensToDelete: [] };\n\t\tconst messages = this.buildMultiCastMessages(type, tokens, payload);\t\t\n\t\tconsole.log({ project, type, payload, messages })\n\t\treturn await this.sendToAllTokens(project, type, payload, messages);\n\t}\n\n\tprivate buildMultiCastMessages(\n\t\ttype: MultiMessageType,\n\t\ttokens: string[],\n\t\tpayload: FCMNotificationPayload\n\t): messaging.MulticastMessage[] {\n\t\tconst tokenChunks = this.chunkArray(tokens, LyxaFcmSender.MAX_BATCH);\n\t\treturn tokenChunks.map(chunk => this.builder.buildMessage(type, payload, chunk));\n\t}\n\n\tprivate chunkArray<T>(arr: T[], size: number): T[][] {\n\t\tconst chunks: T[][] = [];\n\t\tfor (let i = 0; i < arr.length; i += size) {\n\t\t\tchunks.push(arr.slice(i, i + size));\n\t\t}\n\t\treturn chunks;\n\t}\n\n\tprivate async sendToAllTokens(\n\t\tproject: FcmProject,\n\t\ttype: MultiMessageType,\n\t\tpayload: FCMNotificationPayload,\n\t\tmessages: messaging.MulticastMessage[]\n\t): Promise<FcmSendResult> {\n\t\tconst logger = getLibraries().getLoggerKit();\n\t\tconst failedTokens: string[] = [];\n\t\tconst tokensToDelete: string[] = [];\n\n\t\tawait Promise.all(\n\t\t\tmessages.map(async message => {\n\t\t\t\tlet logData: Record<string, unknown>;\n\n\t\t\t\ttry {\n\t\t\t\t\tconsole.log(\"fcm service send message: \",{ project, message })\n\t\t\t\t\tconst result = await this.fcmService.sendMessage(project, message);\n\n\t\t\t\t\t// A sibling token succeeding with the identical payload proves the\n\t\t\t\t\t// payload is valid, which is required before treating an\n\t\t\t\t\t// INVALID_ARGUMENT error as a bad token (see shouldRemoveToken).\n\t\t\t\t\tconst payloadKnownValid = result.successCount > 0;\n\n\t\t\t\t\tresult.responses.forEach((r, i) => {\n\t\t\t\t\t\tif (r.success) return;\n\t\t\t\t\t\tfailedTokens.push(message.tokens[i]);\n\t\t\t\t\t\tif (this.shouldRemoveToken(r.error?.code, payloadKnownValid)) {\n\t\t\t\t\t\t\ttokensToDelete.push(message.tokens[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tlogData = {\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tconsoleNotification: type === MultiMessageType.CONSOLE,\n\t\t\t\t\t\tgroupTokens: message.tokens,\n\t\t\t\t\t\tgroupPayload: payload,\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tsuccessCount: result.successCount,\n\t\t\t\t\t\t\tfailureCount: result.failureCount,\n\t\t\t\t\t\t\tresponses: result.responses.map((r, i) => ({\n\t\t\t\t\t\t\t\ttoken: message.tokens[i],\n\t\t\t\t\t\t\t\tsuccess: r.success,\n\t\t\t\t\t\t\t\t...(r.error && {\n\t\t\t\t\t\t\t\t\terrorCode: r.error.code,\n\t\t\t\t\t\t\t\t\terrorMessage: r.error.message,\n\t\t\t\t\t\t\t\t\twillDelete: this.shouldRemoveToken(r.error.code, payloadKnownValid),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tlogger.info('Called Firebase function sendEachForMulticast', {\n\t\t\t\t\t\ttag: 'notification.attempted.new',\n\t\t\t\t\t\tdata: logData,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// The whole batch send threw (transport/auth/infra failure), not a\n\t\t\t\t\t// per-token rejection. They count as failed, but are not proven\n\t\t\t\t\t// invalid, so they must not be deleted.\n\t\t\t\t\tfailedTokens.push(...message.tokens);\n\n\t\t\t\t\tlogData = {\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tconsoleNotification: type === MultiMessageType.CONSOLE,\n\t\t\t\t\t\tgroupTokens: message.tokens,\n\t\t\t\t\t\tgroupPayload: payload,\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t};\n\t\t\t\t\tlogger.error('Called Firebase function sendEachForMulticast', err, {\n\t\t\t\t\t\ttag: 'notification.attempted.new',\n\t\t\t\t\t\tdata: logData,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\n\t\treturn { failedTokens, tokensToDelete };\n\t}\n\n\t/**\n\t * Decides whether a per-token FCM failure means the token should be removed.\n\t *\n\t * Only the codes in {@link LyxaFcmSender.REMOVABLE_TOKEN_ERROR_CODES} are\n\t * unconditionally removable. `messaging/invalid-argument` (INVALID_ARGUMENT)\n\t * is special: Firebase notes it \"can also be returned in cases of issues in\n\t * the message payload, so it signals an invalid token only if the payload is\n\t * completely valid.\" We therefore only remove on it when we know the payload\n\t * was valid (a sibling token in the same batch succeeded).\n\t *\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens\n\t */\n\tprivate shouldRemoveToken(errorCode: string | undefined, payloadKnownValid: boolean): boolean {\n\t\tif (!errorCode) return false;\n\t\tif (LyxaFcmSender.REMOVABLE_TOKEN_ERROR_CODES.has(errorCode)) return true;\n\t\tif (errorCode === 'messaging/invalid-argument') return payloadKnownValid;\n\t\treturn false;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lyxa-fcm-sender.js","sourceRoot":"/","sources":["libraries/notification/lyxa-fcm-sender.ts"],"names":[],"mappings":"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","sourcesContent":["import { Service } from 'typedi';\nimport { FirebaseFcmService } from './firebase-fcm.service';\nimport { FirebaseMessageBuilderFactory, MultiMessageType } from './firebase-message.builder';\nimport { messaging } from 'firebase-admin';\nimport { FCMNotificationPayload, FcmProject } from './lyxa-fcm.service';\nimport { getLibraries } from '../..';\n\nexport interface FcmSendResult {\n\t/** Every token that failed to receive the message, for any reason. */\n\tfailedTokens: string[];\n\t/** Subset of failedTokens that are confirmed invalid and must be deleted. */\n\ttokensToDelete: string[];\n}\n\n@Service()\nexport class LyxaFcmSender {\n\tpublic static readonly MAX_BATCH = 500;\n\n\t/**\n\t * FCM error codes that unambiguously mean the registration token itself is\n\t * malformed or no longer registered, so it will never be valid again and is\n\t * safe to delete from our records.\n\t *\n\t * Everything else (server/internal errors, rate limits, auth/credential\n\t * issues, transport failures) is transient and must NOT cause deletion.\n\t *\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens#ensuring-registration-token-freshness\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens\n\t */\n\tprivate static readonly REMOVABLE_TOKEN_ERROR_CODES: ReadonlySet<string> = new Set([\n\t\t// UNREGISTERED (404): token was unregistered (app uninstalled / token refreshed).\n\t\t'messaging/registration-token-not-registered',\n\t\t// Token is not a valid FCM registration token (wrong format).\n\t\t'messaging/invalid-registration-token',\n\t]);\n\n\tconstructor(\n\t\tprivate readonly fcmService: FirebaseFcmService,\n\t\tprivate readonly builder: FirebaseMessageBuilderFactory\n\t) {}\n\n\t/**\n\t * Sends notifications and reports the outcome. `failedTokens` contains every\n\t * failure; `tokensToDelete` is the subset that is confirmed invalid and must\n\t * be removed from our records. Transient failures stay out of\n\t * `tokensToDelete` so they never trigger token deletion.\n\t */\n\tpublic async sendMessages(\n\t\tproject: FcmProject,\n\t\ttype: MultiMessageType,\n\t\ttokens: string[],\n\t\tpayload: FCMNotificationPayload\n\t): Promise<FcmSendResult> {\n\t\tif (!tokens.length) return { failedTokens: [], tokensToDelete: [] };\n\t\tconst messages = this.buildMultiCastMessages(type, tokens, payload);\n\t\treturn await this.sendToAllTokens(project, type, payload, messages);\n\t}\n\n\tprivate buildMultiCastMessages(\n\t\ttype: MultiMessageType,\n\t\ttokens: string[],\n\t\tpayload: FCMNotificationPayload\n\t): messaging.MulticastMessage[] {\n\t\tconst tokenChunks = this.chunkArray(tokens, LyxaFcmSender.MAX_BATCH);\n\t\treturn tokenChunks.map(chunk => this.builder.buildMessage(type, payload, chunk));\n\t}\n\n\tprivate chunkArray<T>(arr: T[], size: number): T[][] {\n\t\tconst chunks: T[][] = [];\n\t\tfor (let i = 0; i < arr.length; i += size) {\n\t\t\tchunks.push(arr.slice(i, i + size));\n\t\t}\n\t\treturn chunks;\n\t}\n\n\tprivate async sendToAllTokens(\n\t\tproject: FcmProject,\n\t\ttype: MultiMessageType,\n\t\tpayload: FCMNotificationPayload,\n\t\tmessages: messaging.MulticastMessage[]\n\t): Promise<FcmSendResult> {\n\t\tconst logger = getLibraries().getLoggerKit();\n\t\tconst failedTokens: string[] = [];\n\t\tconst tokensToDelete: string[] = [];\n\n\t\tawait Promise.all(\n\t\t\tmessages.map(async message => {\n\t\t\t\tlet logData: Record<string, unknown>;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await this.fcmService.sendMessage(project, message);\n\n\t\t\t\t\t// A sibling token succeeding with the identical payload proves the\n\t\t\t\t\t// payload is valid, which is required before treating an\n\t\t\t\t\t// INVALID_ARGUMENT error as a bad token (see shouldRemoveToken).\n\t\t\t\t\tconst payloadKnownValid = result.successCount > 0;\n\n\t\t\t\t\tresult.responses.forEach((r, i) => {\n\t\t\t\t\t\tif (r.success) return;\n\t\t\t\t\t\tfailedTokens.push(message.tokens[i]);\n\t\t\t\t\t\tif (this.shouldRemoveToken(r.error?.code, payloadKnownValid)) {\n\t\t\t\t\t\t\ttokensToDelete.push(message.tokens[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tlogData = {\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tconsoleNotification: type === MultiMessageType.CONSOLE,\n\t\t\t\t\t\tgroupTokens: message.tokens,\n\t\t\t\t\t\tgroupPayload: payload,\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tsuccessCount: result.successCount,\n\t\t\t\t\t\t\tfailureCount: result.failureCount,\n\t\t\t\t\t\t\tresponses: result.responses.map((r, i) => ({\n\t\t\t\t\t\t\t\ttoken: message.tokens[i],\n\t\t\t\t\t\t\t\tsuccess: r.success,\n\t\t\t\t\t\t\t\t...(r.error && {\n\t\t\t\t\t\t\t\t\terrorCode: r.error.code,\n\t\t\t\t\t\t\t\t\terrorMessage: r.error.message,\n\t\t\t\t\t\t\t\t\twillDelete: this.shouldRemoveToken(r.error.code, payloadKnownValid),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tlogger.info('Called Firebase function sendEachForMulticast', {\n\t\t\t\t\t\ttag: 'notification.attempted.new',\n\t\t\t\t\t\tdata: logData,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// The whole batch send threw (transport/auth/infra failure), not a\n\t\t\t\t\t// per-token rejection. They count as failed, but are not proven\n\t\t\t\t\t// invalid, so they must not be deleted.\n\t\t\t\t\tfailedTokens.push(...message.tokens);\n\n\t\t\t\t\tlogData = {\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tconsoleNotification: type === MultiMessageType.CONSOLE,\n\t\t\t\t\t\tgroupTokens: message.tokens,\n\t\t\t\t\t\tgroupPayload: payload,\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t};\n\t\t\t\t\tlogger.error('Called Firebase function sendEachForMulticast', err, {\n\t\t\t\t\t\ttag: 'notification.attempted.new',\n\t\t\t\t\t\tdata: logData,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\n\t\treturn { failedTokens, tokensToDelete };\n\t}\n\n\t/**\n\t * Decides whether a per-token FCM failure means the token should be removed.\n\t *\n\t * Only the codes in {@link LyxaFcmSender.REMOVABLE_TOKEN_ERROR_CODES} are\n\t * unconditionally removable. `messaging/invalid-argument` (INVALID_ARGUMENT)\n\t * is special: Firebase notes it \"can also be returned in cases of issues in\n\t * the message payload, so it signals an invalid token only if the payload is\n\t * completely valid.\" We therefore only remove on it when we know the payload\n\t * was valid (a sibling token in the same batch succeeded).\n\t *\n\t * @see https://firebase.google.com/docs/cloud-messaging/manage-tokens\n\t */\n\tprivate shouldRemoveToken(errorCode: string | undefined, payloadKnownValid: boolean): boolean {\n\t\tif (!errorCode) return false;\n\t\tif (LyxaFcmSender.REMOVABLE_TOKEN_ERROR_CODES.has(errorCode)) return true;\n\t\tif (errorCode === 'messaging/invalid-argument') return payloadKnownValid;\n\t\treturn false;\n\t}\n}\n"]}
|
|
@@ -33,7 +33,6 @@ export declare class LyxaFcmService {
|
|
|
33
33
|
private separateTokens;
|
|
34
34
|
static getProjectForAccountType(accountType: NotificationAccountType): FcmProject;
|
|
35
35
|
sendToTokens(project: FcmProject, payload: FCMNotificationPayload, targets: NotificationTokenTarget[]): Promise<FcmSendResult>;
|
|
36
|
-
sendToTokensToSpecificMultiMessageType(project: FcmProject, payload: FCMNotificationPayload, targets: NotificationTokenTarget[]): Promise<FcmSendResult>;
|
|
37
36
|
private isNotifiableEntityType;
|
|
38
37
|
private isConsoleEntityType;
|
|
39
38
|
private compareVersions;
|
|
@@ -136,27 +136,6 @@ let LyxaFcmService = class LyxaFcmService {
|
|
|
136
136
|
tokensToDelete: results.flatMap(r => r.tokensToDelete),
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
|
-
async sendToTokensToSpecificMultiMessageType(project, payload, targets) {
|
|
140
|
-
if (!targets.length)
|
|
141
|
-
return { failedTokens: [], tokensToDelete: [] };
|
|
142
|
-
console.log('targets', targets);
|
|
143
|
-
const cleanedTargets = this.deduplicateTargets(targets);
|
|
144
|
-
const tokens = [];
|
|
145
|
-
for (let target of cleanedTargets) {
|
|
146
|
-
tokens.push(target.token);
|
|
147
|
-
}
|
|
148
|
-
console.log('sendToTokensToSpecificMultiMessageType ', { project });
|
|
149
|
-
console.log('sendToTokensToSpecificMultiMessageType ', { tokens });
|
|
150
|
-
console.log('sendToTokensToSpecificMultiMessageType ', { payload });
|
|
151
|
-
const results = await Promise.all([
|
|
152
|
-
this.lyxaFcmSender.sendMessages(project, firebase_message_builder_1.MultiMessageType.LIVE_ACTIVITY, tokens, payload),
|
|
153
|
-
]);
|
|
154
|
-
console.log({ results });
|
|
155
|
-
return {
|
|
156
|
-
failedTokens: results.flatMap(r => r.failedTokens),
|
|
157
|
-
tokensToDelete: results.flatMap(r => r.tokensToDelete),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
139
|
isNotifiableEntityType(type) {
|
|
161
140
|
return (type === enum_1.NotificationAccountType.USER ||
|
|
162
141
|
type === enum_1.NotificationAccountType.RIDER ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lyxa-fcm.service.js","sourceRoot":"/","sources":["libraries/notification/lyxa-fcm.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Service } from 'typedi';\nimport { MultiMessageType } from './firebase-message.builder';\nimport { AppPlatform, NotificationAccountType } from '../../utilities/enum';\nimport { FcmSendResult, LyxaFcmSender } from './lyxa-fcm-sender';\nimport { getLibraries } from '../..';\n\nexport enum FcmProject {\n\tUSER = 'fcm.service.user',\n\tRIDER = 'fcm.service.rider',\n\tSHOP = 'fcm.service.shop',\n\tCPANEL = 'fcm.service.cpanel',\n}\n\nexport interface FCMNotificationPayload {\n\ttitle?: string;\n\tbody?: string;\n\tdata?: Record<string, string>;\n\tsound?: string;\n\tinvisible?: boolean;\n}\n\nexport interface NotificationTokenTarget {\n\ttoken: string;\n\tentityType: NotificationAccountType;\n\tdeviceId?: string;\n\tentityId?: string;\n\tplatform?: AppPlatform;\n\tappVersion?: string;\n}\n\ntype NotifiableEntityType =\n\t| NotificationAccountType.USER\n\t| NotificationAccountType.SHOP\n\t| NotificationAccountType.RIDER\n\t| NotificationAccountType.PROFESSIONAL;\n\nconst NotificationVersionRules: Record<NotifiableEntityType, Partial<Record<AppPlatform, string>>> = {\n\t[NotificationAccountType.RIDER]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.4',\n\t},\n\n\t[NotificationAccountType.USER]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n\n\t[NotificationAccountType.SHOP]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n\n\t[NotificationAccountType.PROFESSIONAL]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n};\n\nexport type LyxaTokens = {\n\toldTokens: string[];\n\tnewTokens: string[];\n\tconsoleTokens: string[];\n};\n\n@Service()\nexport class LyxaFcmService {\n\tconstructor(private readonly lyxaFcmSender: LyxaFcmSender) {}\n\n\tprivate deduplicateTargets(targets: NotificationTokenTarget[]): NotificationTokenTarget[] {\n\t\tconst sorted = targets.slice().sort((a, b) => {\n\t\t\tif (a.token !== b.token) return a.token < b.token ? -1 : 1;\n\t\t\tif (!a.appVersion && !b.appVersion) return 0;\n\t\t\tif (!a.appVersion) return 1;\n\t\t\tif (!b.appVersion) return -1;\n\t\t\treturn this.compareVersions(b.appVersion, a.appVersion);\n\t\t});\n\t\treturn sorted.filter((t, i) => i === 0 || t.token !== sorted[i - 1].token);\n\t}\n\n\tprivate separateTokens(targets: NotificationTokenTarget[]): LyxaTokens {\n\t\tconst oldTokens: string[] = [];\n\t\tconst newTokens: string[] = [];\n\t\tconst consoleTokens: string[] = [];\n\n\t\tfor (const t of targets) {\n\t\t\tif (this.isConsoleEntityType(t.entityType)) {\n\t\t\t\tconsoleTokens.push(t.token);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst useNew = this.shouldUseNewStructure(t.entityType, t.platform, t.appVersion);\n\n\t\t\tif (useNew) newTokens.push(t.token);\n\t\t\telse oldTokens.push(t.token);\n\t\t}\n\n\t\tif (true) {\n\t\t\tgetLibraries()\n\t\t\t\t.getLoggerKit()\n\t\t\t\t.debug('FCM token separation', {\n\t\t\t\t\ttag: 'notification.token.separated',\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttotalTargets: targets.length,\n\t\t\t\t\t\tbuckets: {\n\t\t\t\t\t\t\told: oldTokens.length,\n\t\t\t\t\t\t\tnew: newTokens.length,\n\t\t\t\t\t\t\tconsole: consoleTokens.length,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttargets: targets.map(t => ({\n\t\t\t\t\t\t\tentityId: t.entityId,\n\t\t\t\t\t\t\tentityType: t.entityType,\n\t\t\t\t\t\t\tplatform: t.platform,\n\t\t\t\t\t\t\tappVersion: t.appVersion,\n\t\t\t\t\t\t\tbucket: this.isConsoleEntityType(t.entityType)\n\t\t\t\t\t\t\t\t? 'console'\n\t\t\t\t\t\t\t\t: this.shouldUseNewStructure(t.entityType, t.platform, t.appVersion)\n\t\t\t\t\t\t\t\t\t? 'new'\n\t\t\t\t\t\t\t\t\t: 'old',\n\t\t\t\t\t\t})),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\toldTokens,\n\t\t\tnewTokens,\n\t\t\tconsoleTokens,\n\t\t};\n\t}\n\n\tpublic static getProjectForAccountType(accountType: NotificationAccountType): FcmProject {\n\t\tswitch (accountType) {\n\t\t\tcase NotificationAccountType.USER:\n\t\t\t\treturn FcmProject.USER;\n\t\t\tcase NotificationAccountType.SHOP:\n\t\t\tcase NotificationAccountType.PROFESSIONAL:\n\t\t\t\treturn FcmProject.SHOP;\n\t\t\tcase NotificationAccountType.RIDER:\n\t\t\t\treturn FcmProject.RIDER;\n\t\t\tdefault:\n\t\t\t\treturn FcmProject.USER;\n\t\t}\n\t}\n\n\tpublic async sendToTokens(\n\t\tproject: FcmProject,\n\t\tpayload: FCMNotificationPayload,\n\t\ttargets: NotificationTokenTarget[]\n\t): Promise<FcmSendResult> {\n\t\tif (!targets.length) return { failedTokens: [], tokensToDelete: [] };\n\t\tconsole.log('targets', targets);\n\t\tconst cleanedTargets = this.deduplicateTargets(targets);\n\t\tconsole.log('cleanedTargets', cleanedTargets);\n\t\tconst tokens = this.separateTokens(cleanedTargets);\n\n\t\tconst results = await Promise.all([\n\t\t\tthis.lyxaFcmSender.sendMessages(project, MultiMessageType.OLD, tokens.oldTokens, payload),\n\t\t\tthis.lyxaFcmSender.sendMessages(project, MultiMessageType.DEFAULT, tokens.newTokens, payload),\n\t\t\tthis.lyxaFcmSender.sendMessages(\n\t\t\t\tFcmProject.CPANEL,\n\t\t\t\tMultiMessageType.CONSOLE,\n\t\t\t\ttokens.consoleTokens,\n\t\t\t\tpayload\n\t\t\t),\n\t\t]);\n\n\t\treturn {\n\t\t\tfailedTokens: results.flatMap(r => r.failedTokens),\n\t\t\ttokensToDelete: results.flatMap(r => r.tokensToDelete),\n\t\t};\n\t}\n\n\tpublic async sendToTokensToSpecificMultiMessageType(\n\t\tproject: FcmProject,\n\t\tpayload: FCMNotificationPayload,\n\t\ttargets: NotificationTokenTarget[]\n\t): Promise<FcmSendResult> {\n\t\tif (!targets.length) return { failedTokens: [], tokensToDelete: [] };\n\t\tconsole.log('targets', targets);\n\t\tconst cleanedTargets = this.deduplicateTargets(targets);\n\n\t\tconst tokens: string[] = [];\n\t\tfor (let target of cleanedTargets) {\n\t\t\ttokens.push(target.token);\n\t\t}\n\t\tconsole.log('sendToTokensToSpecificMultiMessageType ', { project })\n\t\tconsole.log('sendToTokensToSpecificMultiMessageType ',{ tokens });\n\t\tconsole.log('sendToTokensToSpecificMultiMessageType ', { payload });\n\t\tconst results = await Promise.all([\n\t\t\tthis.lyxaFcmSender.sendMessages(project, MultiMessageType.LIVE_ACTIVITY, tokens, payload),\n\t\t]);\n\t\tconsole.log({ results });\n\t\treturn {\n\t\t\tfailedTokens: results.flatMap(r => r.failedTokens),\n\t\t\ttokensToDelete: results.flatMap(r => r.tokensToDelete),\n\t\t};\n\t}\n\n\tprivate isNotifiableEntityType(type: NotificationAccountType): type is NotifiableEntityType {\n\t\treturn (\n\t\t\ttype === NotificationAccountType.USER ||\n\t\t\ttype === NotificationAccountType.RIDER ||\n\t\t\ttype === NotificationAccountType.SHOP ||\n\t\t\ttype === NotificationAccountType.PROFESSIONAL\n\t\t);\n\t}\n\n\tprivate isConsoleEntityType(type: NotificationAccountType): type is NotifiableEntityType {\n\t\treturn (\n\t\t\ttype === NotificationAccountType.SHOP_CONSOLE ||\n\t\t\ttype === NotificationAccountType.PARENT ||\n\t\t\ttype === NotificationAccountType.VENDOR ||\n\t\t\ttype === NotificationAccountType.VENDOR_PARENT\n\t\t);\n\t}\n\n\tprivate compareVersions(v1: string, v2: string): number {\n\t\tconst a = v1.split('.').map(Number);\n\t\tconst b = v2.split('.').map(Number);\n\n\t\tfor (let i = 0; i < Math.max(a.length, b.length); i++) {\n\t\t\tconst diff = (a[i] || 0) - (b[i] || 0);\n\t\t\tif (diff !== 0) return diff;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tprivate shouldUseNewStructure(\n\t\tentityType: NotificationAccountType,\n\t\tplatform?: AppPlatform,\n\t\tversion?: string\n\t): boolean {\n\t\tif (!this.isNotifiableEntityType(entityType)) return false;\n\n\t\tif (!platform || !version) return false;\n\n\t\tconst minVersion = NotificationVersionRules?.[entityType]?.[platform];\n\n\t\tif (!minVersion) return false;\n\n\t\treturn this.compareVersions(version, minVersion) >= 0;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lyxa-fcm.service.js","sourceRoot":"/","sources":["libraries/notification/lyxa-fcm.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Service } from 'typedi';\nimport { MultiMessageType } from './firebase-message.builder';\nimport { AppPlatform, NotificationAccountType } from '../../utilities/enum';\nimport { FcmSendResult, LyxaFcmSender } from './lyxa-fcm-sender';\nimport { getLibraries } from '../..';\n\nexport enum FcmProject {\n\tUSER = 'fcm.service.user',\n\tRIDER = 'fcm.service.rider',\n\tSHOP = 'fcm.service.shop',\n\tCPANEL = 'fcm.service.cpanel',\n}\n\nexport interface FCMNotificationPayload {\n\ttitle?: string;\n\tbody?: string;\n\tdata?: Record<string, string>;\n\tsound?: string;\n\tinvisible?: boolean;\n}\n\nexport interface NotificationTokenTarget {\n\ttoken: string;\n\tentityType: NotificationAccountType;\n\tdeviceId?: string;\n\tentityId?: string;\n\tplatform?: AppPlatform;\n\tappVersion?: string;\n}\n\ntype NotifiableEntityType =\n\t| NotificationAccountType.USER\n\t| NotificationAccountType.SHOP\n\t| NotificationAccountType.RIDER\n\t| NotificationAccountType.PROFESSIONAL;\n\nconst NotificationVersionRules: Record<NotifiableEntityType, Partial<Record<AppPlatform, string>>> = {\n\t[NotificationAccountType.RIDER]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.4',\n\t},\n\n\t[NotificationAccountType.USER]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n\n\t[NotificationAccountType.SHOP]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n\n\t[NotificationAccountType.PROFESSIONAL]: {\n\t\t[AppPlatform.IOS]: '2.0.3',\n\t\t[AppPlatform.ANDROID]: '2.0.3',\n\t},\n};\n\nexport type LyxaTokens = {\n\toldTokens: string[];\n\tnewTokens: string[];\n\tconsoleTokens: string[];\n};\n\n@Service()\nexport class LyxaFcmService {\n\tconstructor(private readonly lyxaFcmSender: LyxaFcmSender) {}\n\n\tprivate deduplicateTargets(targets: NotificationTokenTarget[]): NotificationTokenTarget[] {\n\t\tconst sorted = targets.slice().sort((a, b) => {\n\t\t\tif (a.token !== b.token) return a.token < b.token ? -1 : 1;\n\t\t\tif (!a.appVersion && !b.appVersion) return 0;\n\t\t\tif (!a.appVersion) return 1;\n\t\t\tif (!b.appVersion) return -1;\n\t\t\treturn this.compareVersions(b.appVersion, a.appVersion);\n\t\t});\n\t\treturn sorted.filter((t, i) => i === 0 || t.token !== sorted[i - 1].token);\n\t}\n\n\tprivate separateTokens(targets: NotificationTokenTarget[]): LyxaTokens {\n\t\tconst oldTokens: string[] = [];\n\t\tconst newTokens: string[] = [];\n\t\tconst consoleTokens: string[] = [];\n\n\t\tfor (const t of targets) {\n\t\t\tif (this.isConsoleEntityType(t.entityType)) {\n\t\t\t\tconsoleTokens.push(t.token);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst useNew = this.shouldUseNewStructure(t.entityType, t.platform, t.appVersion);\n\n\t\t\tif (useNew) newTokens.push(t.token);\n\t\t\telse oldTokens.push(t.token);\n\t\t}\n\n\t\tif (true) {\n\t\t\tgetLibraries()\n\t\t\t\t.getLoggerKit()\n\t\t\t\t.debug('FCM token separation', {\n\t\t\t\t\ttag: 'notification.token.separated',\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttotalTargets: targets.length,\n\t\t\t\t\t\tbuckets: {\n\t\t\t\t\t\t\told: oldTokens.length,\n\t\t\t\t\t\t\tnew: newTokens.length,\n\t\t\t\t\t\t\tconsole: consoleTokens.length,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttargets: targets.map(t => ({\n\t\t\t\t\t\t\tentityId: t.entityId,\n\t\t\t\t\t\t\tentityType: t.entityType,\n\t\t\t\t\t\t\tplatform: t.platform,\n\t\t\t\t\t\t\tappVersion: t.appVersion,\n\t\t\t\t\t\t\tbucket: this.isConsoleEntityType(t.entityType)\n\t\t\t\t\t\t\t\t? 'console'\n\t\t\t\t\t\t\t\t: this.shouldUseNewStructure(t.entityType, t.platform, t.appVersion)\n\t\t\t\t\t\t\t\t\t? 'new'\n\t\t\t\t\t\t\t\t\t: 'old',\n\t\t\t\t\t\t})),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\toldTokens,\n\t\t\tnewTokens,\n\t\t\tconsoleTokens,\n\t\t};\n\t}\n\n\tpublic static getProjectForAccountType(accountType: NotificationAccountType): FcmProject {\n\t\tswitch (accountType) {\n\t\t\tcase NotificationAccountType.USER:\n\t\t\t\treturn FcmProject.USER;\n\t\t\tcase NotificationAccountType.SHOP:\n\t\t\tcase NotificationAccountType.PROFESSIONAL:\n\t\t\t\treturn FcmProject.SHOP;\n\t\t\tcase NotificationAccountType.RIDER:\n\t\t\t\treturn FcmProject.RIDER;\n\t\t\tdefault:\n\t\t\t\treturn FcmProject.USER;\n\t\t}\n\t}\n\n\tpublic async sendToTokens(\n\t\tproject: FcmProject,\n\t\tpayload: FCMNotificationPayload,\n\t\ttargets: NotificationTokenTarget[]\n\t): Promise<FcmSendResult> {\n\t\tif (!targets.length) return { failedTokens: [], tokensToDelete: [] };\n\t\tconsole.log('targets', targets);\n\t\tconst cleanedTargets = this.deduplicateTargets(targets);\n\t\tconsole.log('cleanedTargets', cleanedTargets);\n\t\tconst tokens = this.separateTokens(cleanedTargets);\n\n\t\tconst results = await Promise.all([\n\t\t\tthis.lyxaFcmSender.sendMessages(project, MultiMessageType.OLD, tokens.oldTokens, payload),\n\t\t\tthis.lyxaFcmSender.sendMessages(project, MultiMessageType.DEFAULT, tokens.newTokens, payload),\n\t\t\tthis.lyxaFcmSender.sendMessages(\n\t\t\t\tFcmProject.CPANEL,\n\t\t\t\tMultiMessageType.CONSOLE,\n\t\t\t\ttokens.consoleTokens,\n\t\t\t\tpayload\n\t\t\t),\n\t\t]);\n\n\t\treturn {\n\t\t\tfailedTokens: results.flatMap(r => r.failedTokens),\n\t\t\ttokensToDelete: results.flatMap(r => r.tokensToDelete),\n\t\t};\n\t}\n\n\tprivate isNotifiableEntityType(type: NotificationAccountType): type is NotifiableEntityType {\n\t\treturn (\n\t\t\ttype === NotificationAccountType.USER ||\n\t\t\ttype === NotificationAccountType.RIDER ||\n\t\t\ttype === NotificationAccountType.SHOP ||\n\t\t\ttype === NotificationAccountType.PROFESSIONAL\n\t\t);\n\t}\n\n\tprivate isConsoleEntityType(type: NotificationAccountType): type is NotifiableEntityType {\n\t\treturn (\n\t\t\ttype === NotificationAccountType.SHOP_CONSOLE ||\n\t\t\ttype === NotificationAccountType.PARENT ||\n\t\t\ttype === NotificationAccountType.VENDOR ||\n\t\t\ttype === NotificationAccountType.VENDOR_PARENT\n\t\t);\n\t}\n\n\tprivate compareVersions(v1: string, v2: string): number {\n\t\tconst a = v1.split('.').map(Number);\n\t\tconst b = v2.split('.').map(Number);\n\n\t\tfor (let i = 0; i < Math.max(a.length, b.length); i++) {\n\t\t\tconst diff = (a[i] || 0) - (b[i] || 0);\n\t\t\tif (diff !== 0) return diff;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tprivate shouldUseNewStructure(\n\t\tentityType: NotificationAccountType,\n\t\tplatform?: AppPlatform,\n\t\tversion?: string\n\t): boolean {\n\t\tif (!this.isNotifiableEntityType(entityType)) return false;\n\n\t\tif (!platform || !version) return false;\n\n\t\tconst minVersion = NotificationVersionRules?.[entityType]?.[platform];\n\n\t\tif (!minVersion) return false;\n\n\t\treturn this.compareVersions(version, minVersion) >= 0;\n\t}\n}\n"]}
|
package/dist/types/README.md
CHANGED
package/dist/types/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { FilterQuery, PopulateOptions, Model } from 'mongoose';
|
|
2
|
+
import { ClientSession, FilterQuery, PopulateOptions, Model } from 'mongoose';
|
|
3
3
|
import { AnyParamConstructor } from '@typegoose/typegoose/lib/types';
|
|
4
4
|
import { DocumentType, ReturnModelType } from '@typegoose/typegoose';
|
|
5
5
|
import { CustomPaginatedResponse, CustomPaginatorOptions } from './validation';
|
|
@@ -72,7 +72,7 @@ export declare function createPaginatorObject<T extends AnyParamConstructor<any>
|
|
|
72
72
|
[k: string]: string | number | boolean | null | undefined;
|
|
73
73
|
};
|
|
74
74
|
}>;
|
|
75
|
-
export declare function paginateAggregation(model: any, pipeline: any[], page?: number, size?: number, sort?: any, populateOptions?: any): Promise<{
|
|
75
|
+
export declare function paginateAggregation(model: any, pipeline: any[], page?: number, size?: number, sort?: any, populateOptions?: any, session?: ClientSession | null): Promise<{
|
|
76
76
|
metadata: {
|
|
77
77
|
page: number;
|
|
78
78
|
size: number;
|
|
@@ -62,12 +62,12 @@ function createPaginatorObject(model, itemSchema, transformFn) {
|
|
|
62
62
|
return PaginatedSchema.parse(paginatedResult);
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
async function paginateAggregation(model, pipeline, page = 1, size = 10, sort, populateOptions) {
|
|
65
|
+
async function paginateAggregation(model, pipeline, page = 1, size = 10, sort, populateOptions, session) {
|
|
66
66
|
const skip = (page - 1) * size;
|
|
67
67
|
const limit = size;
|
|
68
68
|
const pipelineWithCount = [...pipeline];
|
|
69
69
|
pipelineWithCount.push({ $count: 'totalCount' });
|
|
70
|
-
const totalCountResult = await model.aggregate(pipelineWithCount).exec();
|
|
70
|
+
const totalCountResult = await model.aggregate(pipelineWithCount).session(session ?? null).exec();
|
|
71
71
|
const totalElements = totalCountResult?.[0]?.totalCount || 0;
|
|
72
72
|
const totalPages = Math.ceil(totalElements / size);
|
|
73
73
|
const paginatedPipeline = [...pipeline];
|
|
@@ -76,7 +76,7 @@ async function paginateAggregation(model, pipeline, page = 1, size = 10, sort, p
|
|
|
76
76
|
}
|
|
77
77
|
paginatedPipeline.push({ $skip: skip });
|
|
78
78
|
paginatedPipeline.push({ $limit: limit });
|
|
79
|
-
const data = await model.aggregate(paginatedPipeline).exec();
|
|
79
|
+
const data = await model.aggregate(paginatedPipeline).session(session ?? null).exec();
|
|
80
80
|
const populatedData = populateOptions ? await model.populate(data, populateOptions) : data;
|
|
81
81
|
return {
|
|
82
82
|
metadata: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"/","sources":["utilities/pagination.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { FilterQuery, PopulateOptions, Model } from 'mongoose';\nimport { AnyParamConstructor } from '@typegoose/typegoose/lib/types';\nimport { DocumentType, ReturnModelType } from '@typegoose/typegoose';\nimport { CustomPaginatedResponse, CustomPaginatorOptions } from './validation';\n\n/**\n * A helper to create a paginated Zod schema for an item type.\n */\nexport function createPaginatedSchema<ItemType extends z.ZodTypeAny>(itemSchema: ItemType) {\n\treturn z.object({\n\t\tmetadata: z\n\t\t\t.object({\n\t\t\t\tpage: z.number(),\n\t\t\t\tsize: z.number(),\n\t\t\t\ttotalElements: z.number(),\n\t\t\t\ttotalPages: z.number(),\n\t\t\t})\n\t\t\t.catchall(z.string().or(z.number()).or(z.boolean()).or(z.null()).or(z.undefined())),\n\t\titems: z.array(itemSchema),\n\t});\n}\n\nexport interface RawPaginatedResult<T extends AnyParamConstructor<any>> {\n\tmetadata: {\n\t\tpage: number;\n\t\tsize: number;\n\t\ttotalElements: number;\n\t\ttotalPages: number;\n\t\t// Use a more specific index signature\n\t\t[key: string]: string | number | boolean | null | undefined;\n\t};\n\tdocuments: DocumentType<T>[];\n}\n\n/**\n * The common pagination options.\n */\nexport interface PaginatorOptions<TClass extends AnyParamConstructor<any>> {\n\tquery?: FilterQuery<DocumentType<TClass>>;\n\tpage?: number;\n\tsize?: number;\n\tsort?: Record<string, 1 | -1>;\n\tselect?: Record<string, 0 | 1>;\n\tpopulate?: PopulateOptions | (PopulateOptions | string)[];\n}\n\n/**\n * This internal function wraps the common query logic:\n * - filter, page, size, sort, populate\n * - fetch documents, count documents\n * - compute totalPages\n * Returns a standard object with `metadata` & `documents`.\n */\nasync function _basePaginate<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\toptions: PaginatorOptions<T>\n): Promise<RawPaginatedResult<T>> {\n\tconst { query = {}, page = 1, size = 10, sort = {}, select, populate } = options;\n\n\tconst skip = (page - 1) * size;\n\n\tlet result = model.find(query).sort(sort).skip(skip).limit(size);\n\n\tif (select) {\n\t\tresult = result.select(select) as any;\n\t}\n\tif (populate) {\n\t\tresult = result.populate(populate);\n\t}\n\n\tconst [documents, totalElements] = await Promise.all([result.exec(), model.countDocuments(query)]);\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: documents as unknown as DocumentType<T>[],\n\t};\n}\n\n/**\n * Creates a paginator returning raw documents.\n *\n * @param model The Typegoose model\n * @returns A function that, when passed `PaginatorOptions`, returns raw docs + metadata.\n */\nexport function createRawDocumentPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>\n) {\n\treturn async function paginate(options: PaginatorOptions<T>): Promise<RawPaginatedResult<T>> {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\treturn {\n\t\t\tmetadata,\n\t\t\tdocuments,\n\t\t};\n\t};\n}\n\n/**\n * Creates a paginator that returns Zod-validated items.\n *\n * @param model The Typegoose model\n * @param itemSchema A Zod schema describing the shape of each item\n * @param transformFn Optional transform function to convert raw doc -> item\n */\nexport function createPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\titemSchema: z.ZodTypeAny,\n\ttransformFn?: (doc: DocumentType<T>) => z.infer<typeof itemSchema>\n) {\n\tconst PaginatedSchema = createPaginatedSchema(itemSchema);\n\n\treturn async function paginate(options: PaginatorOptions<T>) {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\tconst items = transformFn ? documents.map(transformFn) : documents;\n\n\t\tconst paginatedResult = {\n\t\t\tmetadata,\n\t\t\titems,\n\t\t};\n\n\t\treturn PaginatedSchema.parse(paginatedResult);\n\t};\n}\nexport async function paginateAggregation(\n\tmodel: any,\n\tpipeline: any[],\n\tpage: number = 1,\n\tsize: number = 10,\n\tsort?: any,\n\tpopulateOptions?: any\n) {\n\t// Calculate skip and limit based on the page and size\n\tconst skip = (page - 1) * size;\n\tconst limit = size;\n\n\t// Copy the pipeline to avoid mutation\n\tconst pipelineWithCount = [...pipeline];\n\n\t// Step 1: Calculate total count\n\tpipelineWithCount.push({ $count: 'totalCount' });\n\n\t// Step 2: Execute to get total count\n\tconst totalCountResult = await model.aggregate(pipelineWithCount).exec();\n\tconst totalElements = totalCountResult?.[0]?.totalCount || 0;\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\t// Step 3: Apply pagination to the original pipeline\n\tconst paginatedPipeline = [...pipeline];\n\n\tif (sort && Object.keys(sort).length > 0) {\n\t\tpaginatedPipeline.push({ $sort: sort });\n\t}\n\n\tpaginatedPipeline.push({ $skip: skip });\n\tpaginatedPipeline.push({ $limit: limit });\n\n\t// Step 4: Execute the paginated pipeline\n\tconst data = await model.aggregate(paginatedPipeline).exec();\n\n\t// Step 5: Optional populate\n\tconst populatedData = populateOptions ? await model.populate(data, populateOptions) : data;\n\n\t// Return the paginated data with metadata\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: populatedData,\n\t};\n}\n\n/**\n * Generic pagination function for Mongoose models or arrays\n */\nexport async function customPaginate<T extends Document>(\n\toptions: CustomPaginatorOptions<T>,\n\tmodel?: Model<T>\n): Promise<CustomPaginatedResponse<any>> {\n\tconst page = options.page && options.page > 0 ? options.page : 1;\n\tconst size = options.size && options.size > 0 ? options.size : 10;\n\n\tlet documents: T[] = [];\n\tlet totalElements = 0;\n\n\tif (model) {\n\t\t// Mongoose query\n\t\tlet query: any = model.find(options.query || {});\n\n\t\tif (options.select) query = query.select(options.select);\n\t\tif (options.populate) query = query.populate(options.populate as any);\n\t\tif (options.sort) query = query.sort(options.sort);\n\n\t\ttotalElements = await model.countDocuments(options.query || {});\n\t\tdocuments = await query.skip((page - 1) * size).limit(size);\n\t} else if (Array.isArray(options.query)) {\n\t\t// In-memory array\n\t\ttotalElements = options.query.length;\n\t\tdocuments = options.query.slice((page - 1) * size, page * size);\n\t} else {\n\t\tthrow new Error('Either a Mongoose model or array must be provided');\n\t}\n\n\t// Apply optional transform\n\tif (options.transform) {\n\t\tdocuments = documents.map(options.transform);\n\t}\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tdocuments,\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"/","sources":["utilities/pagination.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { ClientSession, FilterQuery, PopulateOptions, Model } from 'mongoose';\nimport { AnyParamConstructor } from '@typegoose/typegoose/lib/types';\nimport { DocumentType, ReturnModelType } from '@typegoose/typegoose';\nimport { CustomPaginatedResponse, CustomPaginatorOptions } from './validation';\n\n/**\n * A helper to create a paginated Zod schema for an item type.\n */\nexport function createPaginatedSchema<ItemType extends z.ZodTypeAny>(itemSchema: ItemType) {\n\treturn z.object({\n\t\tmetadata: z\n\t\t\t.object({\n\t\t\t\tpage: z.number(),\n\t\t\t\tsize: z.number(),\n\t\t\t\ttotalElements: z.number(),\n\t\t\t\ttotalPages: z.number(),\n\t\t\t})\n\t\t\t.catchall(z.string().or(z.number()).or(z.boolean()).or(z.null()).or(z.undefined())),\n\t\titems: z.array(itemSchema),\n\t});\n}\n\nexport interface RawPaginatedResult<T extends AnyParamConstructor<any>> {\n\tmetadata: {\n\t\tpage: number;\n\t\tsize: number;\n\t\ttotalElements: number;\n\t\ttotalPages: number;\n\t\t// Use a more specific index signature\n\t\t[key: string]: string | number | boolean | null | undefined;\n\t};\n\tdocuments: DocumentType<T>[];\n}\n\n/**\n * The common pagination options.\n */\nexport interface PaginatorOptions<TClass extends AnyParamConstructor<any>> {\n\tquery?: FilterQuery<DocumentType<TClass>>;\n\tpage?: number;\n\tsize?: number;\n\tsort?: Record<string, 1 | -1>;\n\tselect?: Record<string, 0 | 1>;\n\tpopulate?: PopulateOptions | (PopulateOptions | string)[];\n}\n\n/**\n * This internal function wraps the common query logic:\n * - filter, page, size, sort, populate\n * - fetch documents, count documents\n * - compute totalPages\n * Returns a standard object with `metadata` & `documents`.\n */\nasync function _basePaginate<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\toptions: PaginatorOptions<T>\n): Promise<RawPaginatedResult<T>> {\n\tconst { query = {}, page = 1, size = 10, sort = {}, select, populate } = options;\n\n\tconst skip = (page - 1) * size;\n\n\tlet result = model.find(query).sort(sort).skip(skip).limit(size);\n\n\tif (select) {\n\t\tresult = result.select(select) as any;\n\t}\n\tif (populate) {\n\t\tresult = result.populate(populate);\n\t}\n\n\tconst [documents, totalElements] = await Promise.all([result.exec(), model.countDocuments(query)]);\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: documents as unknown as DocumentType<T>[],\n\t};\n}\n\n/**\n * Creates a paginator returning raw documents.\n *\n * @param model The Typegoose model\n * @returns A function that, when passed `PaginatorOptions`, returns raw docs + metadata.\n */\nexport function createRawDocumentPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>\n) {\n\treturn async function paginate(options: PaginatorOptions<T>): Promise<RawPaginatedResult<T>> {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\treturn {\n\t\t\tmetadata,\n\t\t\tdocuments,\n\t\t};\n\t};\n}\n\n/**\n * Creates a paginator that returns Zod-validated items.\n *\n * @param model The Typegoose model\n * @param itemSchema A Zod schema describing the shape of each item\n * @param transformFn Optional transform function to convert raw doc -> item\n */\nexport function createPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\titemSchema: z.ZodTypeAny,\n\ttransformFn?: (doc: DocumentType<T>) => z.infer<typeof itemSchema>\n) {\n\tconst PaginatedSchema = createPaginatedSchema(itemSchema);\n\n\treturn async function paginate(options: PaginatorOptions<T>) {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\tconst items = transformFn ? documents.map(transformFn) : documents;\n\n\t\tconst paginatedResult = {\n\t\t\tmetadata,\n\t\t\titems,\n\t\t};\n\n\t\treturn PaginatedSchema.parse(paginatedResult);\n\t};\n}\nexport async function paginateAggregation(\n\tmodel: any,\n\tpipeline: any[],\n\tpage: number = 1,\n\tsize: number = 10,\n\tsort?: any,\n\tpopulateOptions?: any,\n\tsession?: ClientSession | null\n) {\n\t// Calculate skip and limit based on the page and size\n\tconst skip = (page - 1) * size;\n\tconst limit = size;\n\n\t// Copy the pipeline to avoid mutation\n\tconst pipelineWithCount = [...pipeline];\n\n\t// Step 1: Calculate total count\n\tpipelineWithCount.push({ $count: 'totalCount' });\n\n\t// Step 2: Execute to get total count\n\tconst totalCountResult = await model.aggregate(pipelineWithCount).session(session ?? null).exec();\n\tconst totalElements = totalCountResult?.[0]?.totalCount || 0;\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\t// Step 3: Apply pagination to the original pipeline\n\tconst paginatedPipeline = [...pipeline];\n\n\tif (sort && Object.keys(sort).length > 0) {\n\t\tpaginatedPipeline.push({ $sort: sort });\n\t}\n\n\tpaginatedPipeline.push({ $skip: skip });\n\tpaginatedPipeline.push({ $limit: limit });\n\n\t// Step 4: Execute the paginated pipeline\n\tconst data = await model.aggregate(paginatedPipeline).session(session ?? null).exec();\n\n\t// Step 5: Optional populate\n\tconst populatedData = populateOptions ? await model.populate(data, populateOptions) : data;\n\n\t// Return the paginated data with metadata\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: populatedData,\n\t};\n}\n\n/**\n * Generic pagination function for Mongoose models or arrays\n */\nexport async function customPaginate<T extends Document>(\n\toptions: CustomPaginatorOptions<T>,\n\tmodel?: Model<T>\n): Promise<CustomPaginatedResponse<any>> {\n\tconst page = options.page && options.page > 0 ? options.page : 1;\n\tconst size = options.size && options.size > 0 ? options.size : 10;\n\n\tlet documents: T[] = [];\n\tlet totalElements = 0;\n\n\tif (model) {\n\t\t// Mongoose query\n\t\tlet query: any = model.find(options.query || {});\n\n\t\tif (options.select) query = query.select(options.select);\n\t\tif (options.populate) query = query.populate(options.populate as any);\n\t\tif (options.sort) query = query.sort(options.sort);\n\n\t\ttotalElements = await model.countDocuments(options.query || {});\n\t\tdocuments = await query.skip((page - 1) * size).limit(size);\n\t} else if (Array.isArray(options.query)) {\n\t\t// In-memory array\n\t\ttotalElements = options.query.length;\n\t\tdocuments = options.query.slice((page - 1) * size, page * size);\n\t} else {\n\t\tthrow new Error('Either a Mongoose model or array must be provided');\n\t}\n\n\t// Apply optional transform\n\tif (options.transform) {\n\t\tdocuments = documents.map(options.transform);\n\t}\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tdocuments,\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t};\n}\n"]}
|