@astralibx/email-rule-engine 5.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +45 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -92,6 +92,8 @@ interface EmailRule {
|
|
|
92
92
|
cooldownDays?: number;
|
|
93
93
|
autoApprove: boolean;
|
|
94
94
|
maxPerRun?: number;
|
|
95
|
+
validFrom?: Date;
|
|
96
|
+
validTill?: Date;
|
|
95
97
|
bypassThrottle: boolean;
|
|
96
98
|
emailType: EmailType;
|
|
97
99
|
totalSent: number;
|
|
@@ -112,6 +114,8 @@ interface CreateEmailRuleInput {
|
|
|
112
114
|
cooldownDays?: number;
|
|
113
115
|
autoApprove?: boolean;
|
|
114
116
|
maxPerRun?: number;
|
|
117
|
+
validFrom?: Date;
|
|
118
|
+
validTill?: Date;
|
|
115
119
|
bypassThrottle?: boolean;
|
|
116
120
|
emailType?: EmailType;
|
|
117
121
|
}
|
|
@@ -127,6 +131,8 @@ interface UpdateEmailRuleInput {
|
|
|
127
131
|
cooldownDays?: number;
|
|
128
132
|
autoApprove?: boolean;
|
|
129
133
|
maxPerRun?: number;
|
|
134
|
+
validFrom?: Date;
|
|
135
|
+
validTill?: Date;
|
|
130
136
|
bypassThrottle?: boolean;
|
|
131
137
|
emailType?: EmailType;
|
|
132
138
|
}
|
|
@@ -289,6 +295,7 @@ interface EmailTemplate {
|
|
|
289
295
|
textBody?: string;
|
|
290
296
|
subjects: string[];
|
|
291
297
|
bodies: string[];
|
|
298
|
+
fields?: Record<string, string>;
|
|
292
299
|
variables: string[];
|
|
293
300
|
version: number;
|
|
294
301
|
isActive: boolean;
|
|
@@ -305,6 +312,7 @@ interface CreateEmailTemplateInput {
|
|
|
305
312
|
textBody?: string;
|
|
306
313
|
subjects: string[];
|
|
307
314
|
bodies: string[];
|
|
315
|
+
fields?: Record<string, string>;
|
|
308
316
|
variables?: string[];
|
|
309
317
|
}
|
|
310
318
|
interface UpdateEmailTemplateInput {
|
|
@@ -316,6 +324,7 @@ interface UpdateEmailTemplateInput {
|
|
|
316
324
|
textBody?: string;
|
|
317
325
|
subjects?: string[];
|
|
318
326
|
bodies?: string[];
|
|
327
|
+
fields?: Record<string, string>;
|
|
319
328
|
variables?: string[];
|
|
320
329
|
isActive?: boolean;
|
|
321
330
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -92,6 +92,8 @@ interface EmailRule {
|
|
|
92
92
|
cooldownDays?: number;
|
|
93
93
|
autoApprove: boolean;
|
|
94
94
|
maxPerRun?: number;
|
|
95
|
+
validFrom?: Date;
|
|
96
|
+
validTill?: Date;
|
|
95
97
|
bypassThrottle: boolean;
|
|
96
98
|
emailType: EmailType;
|
|
97
99
|
totalSent: number;
|
|
@@ -112,6 +114,8 @@ interface CreateEmailRuleInput {
|
|
|
112
114
|
cooldownDays?: number;
|
|
113
115
|
autoApprove?: boolean;
|
|
114
116
|
maxPerRun?: number;
|
|
117
|
+
validFrom?: Date;
|
|
118
|
+
validTill?: Date;
|
|
115
119
|
bypassThrottle?: boolean;
|
|
116
120
|
emailType?: EmailType;
|
|
117
121
|
}
|
|
@@ -127,6 +131,8 @@ interface UpdateEmailRuleInput {
|
|
|
127
131
|
cooldownDays?: number;
|
|
128
132
|
autoApprove?: boolean;
|
|
129
133
|
maxPerRun?: number;
|
|
134
|
+
validFrom?: Date;
|
|
135
|
+
validTill?: Date;
|
|
130
136
|
bypassThrottle?: boolean;
|
|
131
137
|
emailType?: EmailType;
|
|
132
138
|
}
|
|
@@ -289,6 +295,7 @@ interface EmailTemplate {
|
|
|
289
295
|
textBody?: string;
|
|
290
296
|
subjects: string[];
|
|
291
297
|
bodies: string[];
|
|
298
|
+
fields?: Record<string, string>;
|
|
292
299
|
variables: string[];
|
|
293
300
|
version: number;
|
|
294
301
|
isActive: boolean;
|
|
@@ -305,6 +312,7 @@ interface CreateEmailTemplateInput {
|
|
|
305
312
|
textBody?: string;
|
|
306
313
|
subjects: string[];
|
|
307
314
|
bodies: string[];
|
|
315
|
+
fields?: Record<string, string>;
|
|
308
316
|
variables?: string[];
|
|
309
317
|
}
|
|
310
318
|
interface UpdateEmailTemplateInput {
|
|
@@ -316,6 +324,7 @@ interface UpdateEmailTemplateInput {
|
|
|
316
324
|
textBody?: string;
|
|
317
325
|
subjects?: string[];
|
|
318
326
|
bodies?: string[];
|
|
327
|
+
fields?: Record<string, string>;
|
|
319
328
|
variables?: string[];
|
|
320
329
|
isActive?: boolean;
|
|
321
330
|
}
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,7 @@ function createEmailTemplateSchema(platformValues, audienceValues, categoryValue
|
|
|
79
79
|
textBody: String,
|
|
80
80
|
subjects: { type: [{ type: String }], required: true, validate: [(v) => v.length >= 1, "At least one subject is required"] },
|
|
81
81
|
bodies: { type: [{ type: String }], required: true, validate: [(v) => v.length >= 1, "At least one body is required"] },
|
|
82
|
+
fields: { type: mongoose.Schema.Types.Mixed, default: {} },
|
|
82
83
|
variables: [{ type: String }],
|
|
83
84
|
version: { type: Number, default: 1 },
|
|
84
85
|
isActive: { type: Boolean, default: true, index: true }
|
|
@@ -113,6 +114,7 @@ function createEmailTemplateSchema(platformValues, audienceValues, categoryValue
|
|
|
113
114
|
textBody: input.textBody,
|
|
114
115
|
subjects: input.subjects,
|
|
115
116
|
bodies: input.bodies,
|
|
117
|
+
fields: input.fields || {},
|
|
116
118
|
variables: input.variables || [],
|
|
117
119
|
version: 1,
|
|
118
120
|
isActive: true
|
|
@@ -161,6 +163,8 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
161
163
|
cooldownDays: Number,
|
|
162
164
|
autoApprove: { type: Boolean, default: true },
|
|
163
165
|
maxPerRun: Number,
|
|
166
|
+
validFrom: { type: Date },
|
|
167
|
+
validTill: { type: Date },
|
|
164
168
|
bypassThrottle: { type: Boolean, default: false },
|
|
165
169
|
emailType: { type: String, enum: Object.values(EMAIL_TYPE), default: EMAIL_TYPE.Automated },
|
|
166
170
|
totalSent: { type: Number, default: 0 },
|
|
@@ -191,6 +195,8 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
191
195
|
cooldownDays: input.cooldownDays,
|
|
192
196
|
autoApprove: input.autoApprove ?? true,
|
|
193
197
|
maxPerRun: input.maxPerRun,
|
|
198
|
+
validFrom: input.validFrom,
|
|
199
|
+
validTill: input.validTill,
|
|
194
200
|
bypassThrottle: input.bypassThrottle ?? false,
|
|
195
201
|
emailType: input.emailType ?? EMAIL_TYPE.Automated,
|
|
196
202
|
totalSent: 0,
|
|
@@ -563,7 +569,8 @@ var UPDATEABLE_FIELDS = /* @__PURE__ */ new Set([
|
|
|
563
569
|
"subjects",
|
|
564
570
|
"bodies",
|
|
565
571
|
"variables",
|
|
566
|
-
"isActive"
|
|
572
|
+
"isActive",
|
|
573
|
+
"fields"
|
|
567
574
|
]);
|
|
568
575
|
function slugify(name) {
|
|
569
576
|
return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -727,7 +734,9 @@ var UPDATEABLE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
|
727
734
|
"autoApprove",
|
|
728
735
|
"maxPerRun",
|
|
729
736
|
"bypassThrottle",
|
|
730
|
-
"emailType"
|
|
737
|
+
"emailType",
|
|
738
|
+
"validFrom",
|
|
739
|
+
"validTill"
|
|
731
740
|
]);
|
|
732
741
|
function validateRuleTemplateCompat(targetRole, targetPlatform, template) {
|
|
733
742
|
const templateAudience = template.audience;
|
|
@@ -966,7 +975,13 @@ var RuleRunnerService = class {
|
|
|
966
975
|
let runStatus = "completed";
|
|
967
976
|
try {
|
|
968
977
|
const throttleConfig = await this.EmailThrottleConfig.getConfig();
|
|
969
|
-
const
|
|
978
|
+
const allActiveRules = await this.EmailRule.findActive();
|
|
979
|
+
const now = /* @__PURE__ */ new Date();
|
|
980
|
+
const activeRules = allActiveRules.filter((rule) => {
|
|
981
|
+
if (rule.validFrom && now < new Date(rule.validFrom)) return false;
|
|
982
|
+
if (rule.validTill && now > new Date(rule.validTill)) return false;
|
|
983
|
+
return true;
|
|
984
|
+
});
|
|
970
985
|
this.config.hooks?.onRunStart?.({ rulesCount: activeRules.length, triggeredBy });
|
|
971
986
|
await this.updateRunProgress(runId, {
|
|
972
987
|
progress: { rulesTotal: activeRules.length, rulesCompleted: 0, sent: 0, failed: 0, skipped: 0, invalid: 0 }
|
|
@@ -1170,7 +1185,8 @@ var RuleRunnerService = class {
|
|
|
1170
1185
|
continue;
|
|
1171
1186
|
}
|
|
1172
1187
|
const user = { _id: identifier.id, email };
|
|
1173
|
-
const
|
|
1188
|
+
const resolvedData = this.config.adapters.resolveData(user);
|
|
1189
|
+
const templateData = { ...template.fields || {}, ...resolvedData };
|
|
1174
1190
|
const si = Math.floor(Math.random() * compiledVariants.subjectFns.length);
|
|
1175
1191
|
const bi = Math.floor(Math.random() * compiledVariants.bodyFns.length);
|
|
1176
1192
|
const renderedSubject = compiledVariants.subjectFns[si](templateData);
|
|
@@ -1253,6 +1269,29 @@ var RuleRunnerService = class {
|
|
|
1253
1269
|
$set: { lastRunAt: /* @__PURE__ */ new Date(), lastRunStats: stats },
|
|
1254
1270
|
$inc: { totalSent: stats.sent, totalSkipped: stats.skipped }
|
|
1255
1271
|
});
|
|
1272
|
+
if (rule.sendOnce) {
|
|
1273
|
+
const allIdentifiers = rule.target.identifiers;
|
|
1274
|
+
const sends = await this.EmailRuleSend.find({
|
|
1275
|
+
ruleId: rule._id
|
|
1276
|
+
}).lean();
|
|
1277
|
+
const sentOrProcessedIds = new Set(
|
|
1278
|
+
sends.filter((s) => s.status !== "throttled").map((s) => String(s.userId || s.emailIdentifierId))
|
|
1279
|
+
);
|
|
1280
|
+
let pendingCount = 0;
|
|
1281
|
+
for (const email of allIdentifiers) {
|
|
1282
|
+
const identifier = identifierMap.get(email.toLowerCase().trim());
|
|
1283
|
+
if (!identifier) continue;
|
|
1284
|
+
if (!sentOrProcessedIds.has(String(identifier.id))) {
|
|
1285
|
+
pendingCount++;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
const throttledCount = sends.filter((s) => s.status === "throttled").length;
|
|
1289
|
+
pendingCount += throttledCount;
|
|
1290
|
+
if (pendingCount === 0) {
|
|
1291
|
+
await this.EmailRule.findByIdAndUpdate(rule._id, { $set: { isActive: false } });
|
|
1292
|
+
this.logger.info(`Rule '${rule.name}' auto-disabled \u2014 all identifiers processed`);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1256
1295
|
this.config.hooks?.onRuleComplete?.({ ruleId, ruleName: rule.name, stats });
|
|
1257
1296
|
return stats;
|
|
1258
1297
|
}
|
|
@@ -1349,7 +1388,8 @@ var RuleRunnerService = class {
|
|
|
1349
1388
|
this.config.hooks?.onSend?.({ ruleId, ruleName: rule.name, email, status: "skipped" });
|
|
1350
1389
|
continue;
|
|
1351
1390
|
}
|
|
1352
|
-
const
|
|
1391
|
+
const resolvedData = this.config.adapters.resolveData(user);
|
|
1392
|
+
const templateData = { ...template.fields || {}, ...resolvedData };
|
|
1353
1393
|
const si = Math.floor(Math.random() * compiledVariants.subjectFns.length);
|
|
1354
1394
|
const bi = Math.floor(Math.random() * compiledVariants.bodyFns.length);
|
|
1355
1395
|
const renderedSubject = compiledVariants.subjectFns[si](templateData);
|