@astralibx/email-rule-engine 12.3.0 → 12.5.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.cjs +34 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.mjs +34 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -178,6 +178,15 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
178
178
|
validFrom: { type: Date },
|
|
179
179
|
validTill: { type: Date },
|
|
180
180
|
bypassThrottle: { type: Boolean, default: false },
|
|
181
|
+
throttleOverride: {
|
|
182
|
+
type: {
|
|
183
|
+
maxPerUserPerDay: { type: Number },
|
|
184
|
+
maxPerUserPerWeek: { type: Number },
|
|
185
|
+
minGapDays: { type: Number }
|
|
186
|
+
},
|
|
187
|
+
_id: false,
|
|
188
|
+
default: void 0
|
|
189
|
+
},
|
|
181
190
|
emailType: { type: String, enum: Object.values(EMAIL_TYPE), default: EMAIL_TYPE.Automated },
|
|
182
191
|
totalSent: { type: Number, default: 0 },
|
|
183
192
|
totalSkipped: { type: Number, default: 0 },
|
|
@@ -210,6 +219,7 @@ function createEmailRuleSchema(platformValues, audienceValues, collectionPrefix)
|
|
|
210
219
|
validFrom: input.validFrom,
|
|
211
220
|
validTill: input.validTill,
|
|
212
221
|
bypassThrottle: input.bypassThrottle ?? false,
|
|
222
|
+
throttleOverride: input.throttleOverride,
|
|
213
223
|
emailType: input.emailType ?? EMAIL_TYPE.Automated,
|
|
214
224
|
totalSent: 0,
|
|
215
225
|
totalSkipped: 0
|
|
@@ -750,6 +760,7 @@ var UPDATEABLE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
|
750
760
|
"autoApprove",
|
|
751
761
|
"maxPerRun",
|
|
752
762
|
"bypassThrottle",
|
|
763
|
+
"throttleOverride",
|
|
753
764
|
"emailType",
|
|
754
765
|
"validFrom",
|
|
755
766
|
"validTill"
|
|
@@ -883,13 +894,19 @@ var RuleService = class {
|
|
|
883
894
|
if (!rule) {
|
|
884
895
|
throw new RuleNotFoundError(id);
|
|
885
896
|
}
|
|
897
|
+
const defaultMaxPerRun = this.config.options?.defaultMaxPerRun;
|
|
898
|
+
const effectiveLimit = rule.maxPerRun || defaultMaxPerRun || 500;
|
|
886
899
|
const target = rule.target;
|
|
887
900
|
if (target.mode === "list") {
|
|
888
901
|
const identifiers = target.identifiers || [];
|
|
889
|
-
|
|
902
|
+
const matchedCount2 = identifiers.length;
|
|
903
|
+
const willProcess2 = Math.min(matchedCount2, effectiveLimit);
|
|
904
|
+
return { matchedCount: matchedCount2, effectiveLimit, willProcess: willProcess2, ruleId: id };
|
|
890
905
|
}
|
|
891
906
|
const users = await this.config.adapters.queryUsers(rule.target, 5e4);
|
|
892
|
-
|
|
907
|
+
const matchedCount = users.length;
|
|
908
|
+
const willProcess = Math.min(matchedCount, effectiveLimit);
|
|
909
|
+
return { matchedCount, effectiveLimit, willProcess, ruleId: id };
|
|
893
910
|
}
|
|
894
911
|
async getRunHistory(limit = 20) {
|
|
895
912
|
return this.EmailRuleRunLog.getRecent(limit);
|
|
@@ -1146,6 +1163,9 @@ var RuleRunnerService = class {
|
|
|
1146
1163
|
const rawIdentifiers = rule.target.identifiers || [];
|
|
1147
1164
|
const uniqueEmails = [...new Set(rawIdentifiers.map((e) => e.toLowerCase().trim()).filter(Boolean))];
|
|
1148
1165
|
const limit = rule.maxPerRun || this.config.options?.defaultMaxPerRun || 500;
|
|
1166
|
+
if (uniqueEmails.length > limit) {
|
|
1167
|
+
this.logger.warn(`Rule "${rule.name}" matched ${uniqueEmails.length} users but maxPerRun is ${limit} \u2014 only ${limit} will be processed`, { ruleId: rule._id.toString(), matchedCount: uniqueEmails.length, maxPerRun: limit });
|
|
1168
|
+
}
|
|
1149
1169
|
const emailsToProcess = uniqueEmails.slice(0, limit);
|
|
1150
1170
|
stats.matched = emailsToProcess.length;
|
|
1151
1171
|
const ruleId = rule._id.toString();
|
|
@@ -1344,14 +1364,18 @@ var RuleRunnerService = class {
|
|
|
1344
1364
|
return stats;
|
|
1345
1365
|
}
|
|
1346
1366
|
async executeQueryMode(rule, template, throttleMap, throttleConfig, stats, runId) {
|
|
1367
|
+
const limit = rule.maxPerRun || this.config.options?.defaultMaxPerRun || 500;
|
|
1347
1368
|
let users;
|
|
1348
1369
|
try {
|
|
1349
|
-
users = await this.config.adapters.queryUsers(rule.target,
|
|
1370
|
+
users = await this.config.adapters.queryUsers(rule.target, limit);
|
|
1350
1371
|
} catch (err) {
|
|
1351
1372
|
this.logger.error(`Rule "${rule.name}": query failed`, { error: err });
|
|
1352
1373
|
stats.errorCount = 1;
|
|
1353
1374
|
return stats;
|
|
1354
1375
|
}
|
|
1376
|
+
if (users.length > limit) {
|
|
1377
|
+
this.logger.warn(`Rule "${rule.name}" matched ${users.length} users but maxPerRun is ${limit} \u2014 only ${limit} will be processed`, { ruleId: rule._id.toString(), matchedCount: users.length, maxPerRun: limit });
|
|
1378
|
+
}
|
|
1355
1379
|
stats.matched = users.length;
|
|
1356
1380
|
this.config.hooks?.onRuleStart?.({ ruleId: rule._id.toString(), ruleName: rule.name, matchedCount: users.length, templateId: rule.templateId.toString(), runId: runId || "" });
|
|
1357
1381
|
if (users.length === 0) return stats;
|
|
@@ -1541,20 +1565,24 @@ var RuleRunnerService = class {
|
|
|
1541
1565
|
}
|
|
1542
1566
|
checkThrottle(rule, userId, email, throttleMap, config, stats, templateId, runId) {
|
|
1543
1567
|
if (rule.emailType === EMAIL_TYPE.Transactional || rule.bypassThrottle) return true;
|
|
1568
|
+
const overrides = rule.throttleOverride || {};
|
|
1569
|
+
const dailyLimit = overrides.maxPerUserPerDay ?? config.maxPerUserPerDay;
|
|
1570
|
+
const weeklyLimit = overrides.maxPerUserPerWeek ?? config.maxPerUserPerWeek;
|
|
1571
|
+
const minGap = overrides.minGapDays ?? config.minGapDays;
|
|
1544
1572
|
const userThrottle = throttleMap.get(userId) || { today: 0, thisWeek: 0, lastSentDate: null };
|
|
1545
|
-
if (userThrottle.today >=
|
|
1573
|
+
if (userThrottle.today >= dailyLimit) {
|
|
1546
1574
|
stats.skippedByThrottle++;
|
|
1547
1575
|
this.config.hooks?.onSend?.({ ruleId: rule._id.toString(), ruleName: rule.name, email, status: "throttled", accountId: "", templateId: templateId || "", runId: runId || "", subjectIndex: -1, bodyIndex: -1, failureReason: "daily throttle limit" });
|
|
1548
1576
|
return false;
|
|
1549
1577
|
}
|
|
1550
|
-
if (userThrottle.thisWeek >=
|
|
1578
|
+
if (userThrottle.thisWeek >= weeklyLimit) {
|
|
1551
1579
|
stats.skippedByThrottle++;
|
|
1552
1580
|
this.config.hooks?.onSend?.({ ruleId: rule._id.toString(), ruleName: rule.name, email, status: "throttled", accountId: "", templateId: templateId || "", runId: runId || "", subjectIndex: -1, bodyIndex: -1, failureReason: "weekly throttle limit" });
|
|
1553
1581
|
return false;
|
|
1554
1582
|
}
|
|
1555
1583
|
if (userThrottle.lastSentDate) {
|
|
1556
1584
|
const daysSinceLastSend = (Date.now() - userThrottle.lastSentDate.getTime()) / MS_PER_DAY;
|
|
1557
|
-
if (daysSinceLastSend <
|
|
1585
|
+
if (daysSinceLastSend < minGap) {
|
|
1558
1586
|
stats.skippedByThrottle++;
|
|
1559
1587
|
this.config.hooks?.onSend?.({ ruleId: rule._id.toString(), ruleName: rule.name, email, status: "throttled", accountId: "", templateId: templateId || "", runId: runId || "", subjectIndex: -1, bodyIndex: -1, failureReason: "min gap days" });
|
|
1560
1588
|
return false;
|