@astralibx/email-rule-engine 4.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/README.md +1 -1
- 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.mjs
CHANGED
|
@@ -71,6 +71,7 @@ function createEmailTemplateSchema(platformValues, audienceValues, categoryValue
|
|
|
71
71
|
textBody: String,
|
|
72
72
|
subjects: { type: [{ type: String }], required: true, validate: [(v) => v.length >= 1, "At least one subject is required"] },
|
|
73
73
|
bodies: { type: [{ type: String }], required: true, validate: [(v) => v.length >= 1, "At least one body is required"] },
|
|
74
|
+
fields: { type: Schema.Types.Mixed, default: {} },
|
|
74
75
|
variables: [{ type: String }],
|
|
75
76
|
version: { type: Number, default: 1 },
|
|
76
77
|
isActive: { type: Boolean, default: true, index: true }
|
|
@@ -105,6 +106,7 @@ function createEmailTemplateSchema(platformValues, audienceValues, categoryValue
|
|
|
105
106
|
textBody: input.textBody,
|
|
106
107
|
subjects: input.subjects,
|
|
107
108
|
bodies: input.bodies,
|
|
109
|
+
fields: input.fields || {},
|
|
108
110
|
variables: input.variables || [],
|
|
109
111
|
version: 1,
|
|
110
112
|
isActive: true
|
|
@@ -153,6 +155,8 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
153
155
|
cooldownDays: Number,
|
|
154
156
|
autoApprove: { type: Boolean, default: true },
|
|
155
157
|
maxPerRun: Number,
|
|
158
|
+
validFrom: { type: Date },
|
|
159
|
+
validTill: { type: Date },
|
|
156
160
|
bypassThrottle: { type: Boolean, default: false },
|
|
157
161
|
emailType: { type: String, enum: Object.values(EMAIL_TYPE), default: EMAIL_TYPE.Automated },
|
|
158
162
|
totalSent: { type: Number, default: 0 },
|
|
@@ -183,6 +187,8 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
183
187
|
cooldownDays: input.cooldownDays,
|
|
184
188
|
autoApprove: input.autoApprove ?? true,
|
|
185
189
|
maxPerRun: input.maxPerRun,
|
|
190
|
+
validFrom: input.validFrom,
|
|
191
|
+
validTill: input.validTill,
|
|
186
192
|
bypassThrottle: input.bypassThrottle ?? false,
|
|
187
193
|
emailType: input.emailType ?? EMAIL_TYPE.Automated,
|
|
188
194
|
totalSent: 0,
|
|
@@ -555,7 +561,8 @@ var UPDATEABLE_FIELDS = /* @__PURE__ */ new Set([
|
|
|
555
561
|
"subjects",
|
|
556
562
|
"bodies",
|
|
557
563
|
"variables",
|
|
558
|
-
"isActive"
|
|
564
|
+
"isActive",
|
|
565
|
+
"fields"
|
|
559
566
|
]);
|
|
560
567
|
function slugify(name) {
|
|
561
568
|
return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -719,7 +726,9 @@ var UPDATEABLE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
|
719
726
|
"autoApprove",
|
|
720
727
|
"maxPerRun",
|
|
721
728
|
"bypassThrottle",
|
|
722
|
-
"emailType"
|
|
729
|
+
"emailType",
|
|
730
|
+
"validFrom",
|
|
731
|
+
"validTill"
|
|
723
732
|
]);
|
|
724
733
|
function validateRuleTemplateCompat(targetRole, targetPlatform, template) {
|
|
725
734
|
const templateAudience = template.audience;
|
|
@@ -958,7 +967,13 @@ var RuleRunnerService = class {
|
|
|
958
967
|
let runStatus = "completed";
|
|
959
968
|
try {
|
|
960
969
|
const throttleConfig = await this.EmailThrottleConfig.getConfig();
|
|
961
|
-
const
|
|
970
|
+
const allActiveRules = await this.EmailRule.findActive();
|
|
971
|
+
const now = /* @__PURE__ */ new Date();
|
|
972
|
+
const activeRules = allActiveRules.filter((rule) => {
|
|
973
|
+
if (rule.validFrom && now < new Date(rule.validFrom)) return false;
|
|
974
|
+
if (rule.validTill && now > new Date(rule.validTill)) return false;
|
|
975
|
+
return true;
|
|
976
|
+
});
|
|
962
977
|
this.config.hooks?.onRunStart?.({ rulesCount: activeRules.length, triggeredBy });
|
|
963
978
|
await this.updateRunProgress(runId, {
|
|
964
979
|
progress: { rulesTotal: activeRules.length, rulesCompleted: 0, sent: 0, failed: 0, skipped: 0, invalid: 0 }
|
|
@@ -1162,7 +1177,8 @@ var RuleRunnerService = class {
|
|
|
1162
1177
|
continue;
|
|
1163
1178
|
}
|
|
1164
1179
|
const user = { _id: identifier.id, email };
|
|
1165
|
-
const
|
|
1180
|
+
const resolvedData = this.config.adapters.resolveData(user);
|
|
1181
|
+
const templateData = { ...template.fields || {}, ...resolvedData };
|
|
1166
1182
|
const si = Math.floor(Math.random() * compiledVariants.subjectFns.length);
|
|
1167
1183
|
const bi = Math.floor(Math.random() * compiledVariants.bodyFns.length);
|
|
1168
1184
|
const renderedSubject = compiledVariants.subjectFns[si](templateData);
|
|
@@ -1245,6 +1261,29 @@ var RuleRunnerService = class {
|
|
|
1245
1261
|
$set: { lastRunAt: /* @__PURE__ */ new Date(), lastRunStats: stats },
|
|
1246
1262
|
$inc: { totalSent: stats.sent, totalSkipped: stats.skipped }
|
|
1247
1263
|
});
|
|
1264
|
+
if (rule.sendOnce) {
|
|
1265
|
+
const allIdentifiers = rule.target.identifiers;
|
|
1266
|
+
const sends = await this.EmailRuleSend.find({
|
|
1267
|
+
ruleId: rule._id
|
|
1268
|
+
}).lean();
|
|
1269
|
+
const sentOrProcessedIds = new Set(
|
|
1270
|
+
sends.filter((s) => s.status !== "throttled").map((s) => String(s.userId || s.emailIdentifierId))
|
|
1271
|
+
);
|
|
1272
|
+
let pendingCount = 0;
|
|
1273
|
+
for (const email of allIdentifiers) {
|
|
1274
|
+
const identifier = identifierMap.get(email.toLowerCase().trim());
|
|
1275
|
+
if (!identifier) continue;
|
|
1276
|
+
if (!sentOrProcessedIds.has(String(identifier.id))) {
|
|
1277
|
+
pendingCount++;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const throttledCount = sends.filter((s) => s.status === "throttled").length;
|
|
1281
|
+
pendingCount += throttledCount;
|
|
1282
|
+
if (pendingCount === 0) {
|
|
1283
|
+
await this.EmailRule.findByIdAndUpdate(rule._id, { $set: { isActive: false } });
|
|
1284
|
+
this.logger.info(`Rule '${rule.name}' auto-disabled \u2014 all identifiers processed`);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1248
1287
|
this.config.hooks?.onRuleComplete?.({ ruleId, ruleName: rule.name, stats });
|
|
1249
1288
|
return stats;
|
|
1250
1289
|
}
|
|
@@ -1341,7 +1380,8 @@ var RuleRunnerService = class {
|
|
|
1341
1380
|
this.config.hooks?.onSend?.({ ruleId, ruleName: rule.name, email, status: "skipped" });
|
|
1342
1381
|
continue;
|
|
1343
1382
|
}
|
|
1344
|
-
const
|
|
1383
|
+
const resolvedData = this.config.adapters.resolveData(user);
|
|
1384
|
+
const templateData = { ...template.fields || {}, ...resolvedData };
|
|
1345
1385
|
const si = Math.floor(Math.random() * compiledVariants.subjectFns.length);
|
|
1346
1386
|
const bi = Math.floor(Math.random() * compiledVariants.bodyFns.length);
|
|
1347
1387
|
const renderedSubject = compiledVariants.subjectFns[si](templateData);
|