@astralibx/email-rule-engine 1.0.1 → 1.1.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 +381 -85
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/schemas/rule.schema.d.ts +1 -1
- package/dist/schemas/rule.schema.d.ts.map +1 -1
- package/dist/schemas/rule.schema.js +2 -2
- package/dist/schemas/rule.schema.js.map +1 -1
- package/dist/schemas/template.schema.d.ts +1 -1
- package/dist/schemas/template.schema.d.ts.map +1 -1
- package/dist/schemas/template.schema.js +2 -2
- package/dist/schemas/template.schema.js.map +1 -1
- package/dist/types/config.types.d.ts +1 -0
- package/dist/types/config.types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,104 +11,265 @@ Rule-based email automation engine with MJML + Handlebars templates, per-user th
|
|
|
11
11
|
- **Run History**: Detailed logging of every rule execution with per-rule stats
|
|
12
12
|
- **Draft Workflow**: Supports draft → approve → send pipeline via adapter
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
| Dependency | Version | Why |
|
|
17
|
+
|------------|---------|-----|
|
|
18
|
+
| Node.js | >= 18 | Runtime |
|
|
19
|
+
| MongoDB | >= 5.0 | Data storage |
|
|
20
|
+
| Redis | >= 6.0 | Distributed locking |
|
|
21
|
+
|
|
22
|
+
### Peer Dependencies
|
|
23
|
+
|
|
24
|
+
These must be installed in your project:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install express mongoose ioredis handlebars mjml html-to-text
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Package | Version | Purpose |
|
|
31
|
+
|---------|---------|---------|
|
|
32
|
+
| `express` | ^4.18 or ^5.0 | HTTP routes |
|
|
33
|
+
| `mongoose` | ^7.0 or ^8.0 | MongoDB ODM |
|
|
34
|
+
| `ioredis` | ^5.0 | Redis client |
|
|
35
|
+
| `handlebars` | ^4.7 | Template variables |
|
|
36
|
+
| `mjml` | ^4.0 | Responsive email HTML |
|
|
37
|
+
| `html-to-text` | ^9.0 | Plain text fallback |
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
15
40
|
|
|
16
41
|
```bash
|
|
17
42
|
npm install @astralibx/email-rule-engine
|
|
18
43
|
```
|
|
19
44
|
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
The engine handles the **generic plumbing** — templates, rules, throttling, locking, REST API routes, and run history. Your project provides the **specific logic** through 5 adapter functions.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌─────────────────────────────────────────────────────────┐
|
|
51
|
+
│ YOUR APPLICATION │
|
|
52
|
+
│ │
|
|
53
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
54
|
+
│ │ queryUsers │ │ resolveData │ │ sendEmail │ │
|
|
55
|
+
│ │ (find who │ │ (map user to │ │ (deliver or │ │
|
|
56
|
+
│ │ to email) │ │ template │ │ save draft) │ │
|
|
57
|
+
│ │ │ │ variables) │ │ │ │
|
|
58
|
+
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
59
|
+
│ │ │ │ │
|
|
60
|
+
│ ┌──────┴───────┐ ┌──────┴───────┐ │
|
|
61
|
+
│ │ selectAgent │ │findIdentifier│ │
|
|
62
|
+
│ │ (pick sender) │ │ (map email │ │
|
|
63
|
+
│ │ │ │ to contact) │ │
|
|
64
|
+
│ └──────┬───────┘ └──────┬───────┘ │
|
|
65
|
+
└─────────┼─────────────────┼────────────────────────────┘
|
|
66
|
+
│ │
|
|
67
|
+
┌─────────▼─────────────────▼────────────────────────────┐
|
|
68
|
+
│ @astralibx/email-rule-engine │
|
|
69
|
+
│ │
|
|
70
|
+
│ Templates ─► Rules ─► Runner ─► Throttle ─► Lock │
|
|
71
|
+
│ MJML/HBS CRUD Execute Per-user Redis │
|
|
72
|
+
│ Render Match Adapters Limits Prevent │
|
|
73
|
+
│ Duplicates │
|
|
74
|
+
│ │
|
|
75
|
+
│ REST API: /templates, /rules, /runner, /settings │
|
|
76
|
+
│ MongoDB: 5 collections auto-created │
|
|
77
|
+
└──────────────────────────────────────────────────────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
### Step 1: Create Adapters
|
|
83
|
+
|
|
84
|
+
These are the 5 functions that connect the engine to YOUR data and infrastructure.
|
|
85
|
+
|
|
20
86
|
```typescript
|
|
87
|
+
// adapters.ts
|
|
88
|
+
import { SendEmailParams } from '@astralibx/email-rule-engine';
|
|
89
|
+
|
|
90
|
+
// 1. Find users matching rule conditions — YOUR query logic
|
|
91
|
+
async function queryUsers(target: any, limit: number) {
|
|
92
|
+
// `target` contains: { role, platform, conditions[] }
|
|
93
|
+
// Build your own query based on these conditions
|
|
94
|
+
return db.collection('users')
|
|
95
|
+
.find({ role: target.role, platform: target.platform })
|
|
96
|
+
.limit(limit)
|
|
97
|
+
.toArray();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 2. Transform a user record into template variables
|
|
101
|
+
// These variables become available in your Handlebars templates
|
|
102
|
+
function resolveData(user: Record<string, unknown>) {
|
|
103
|
+
return {
|
|
104
|
+
user: {
|
|
105
|
+
name: user.name,
|
|
106
|
+
email: user.email,
|
|
107
|
+
},
|
|
108
|
+
platform: {
|
|
109
|
+
name: 'My App',
|
|
110
|
+
domain: 'myapp.com',
|
|
111
|
+
supportEmail: 'help@myapp.com',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 3. Deliver the email — save as draft, send directly, or queue
|
|
117
|
+
async function sendEmail(params: SendEmailParams) {
|
|
118
|
+
// params contains:
|
|
119
|
+
// identifierId - your internal email contact ID
|
|
120
|
+
// contactId - your internal contact ID
|
|
121
|
+
// accountId - selected sender account ID
|
|
122
|
+
// subject - rendered subject line
|
|
123
|
+
// htmlBody - rendered HTML (from MJML)
|
|
124
|
+
// textBody - rendered plain text
|
|
125
|
+
// ruleId - which rule triggered this
|
|
126
|
+
// autoApprove - whether to send immediately or queue for review
|
|
127
|
+
await myEmailService.send({
|
|
128
|
+
to: params.identifierId,
|
|
129
|
+
subject: params.subject,
|
|
130
|
+
html: params.htmlBody,
|
|
131
|
+
text: params.textBody,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 4. Select a sending account — return null to skip this recipient
|
|
136
|
+
async function selectAgent(identifierId: string) {
|
|
137
|
+
const account = await myAccounts.findBestAvailable();
|
|
138
|
+
return account ? { accountId: account.id } : null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 5. Map an email address to your contact/identifier system
|
|
142
|
+
async function findIdentifier(email: string) {
|
|
143
|
+
const contact = await myContacts.findByEmail(email);
|
|
144
|
+
return contact
|
|
145
|
+
? { id: contact._id.toString(), contactId: contact.contactId.toString() }
|
|
146
|
+
: null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const adapters = {
|
|
150
|
+
queryUsers,
|
|
151
|
+
resolveData,
|
|
152
|
+
sendEmail,
|
|
153
|
+
selectAgent,
|
|
154
|
+
findIdentifier,
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Step 2: Initialize the Engine
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// email-engine-setup.ts
|
|
21
162
|
import { createEmailRuleEngine } from '@astralibx/email-rule-engine';
|
|
22
163
|
import mongoose from 'mongoose';
|
|
23
164
|
import Redis from 'ioredis';
|
|
165
|
+
import { adapters } from './adapters';
|
|
24
166
|
|
|
25
167
|
const dbConnection = mongoose.createConnection('mongodb://localhost/myapp');
|
|
26
168
|
const redis = new Redis();
|
|
27
169
|
|
|
28
170
|
const engine = createEmailRuleEngine({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
adapters: {
|
|
36
|
-
// Find users matching rule conditions — YOUR query logic
|
|
37
|
-
queryUsers: async (target, limit) => {
|
|
38
|
-
return db.collection('users')
|
|
39
|
-
.find({ role: target.role })
|
|
40
|
-
.limit(limit)
|
|
41
|
-
.toArray();
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
// Transform user record into template variables
|
|
45
|
-
resolveData: (user) => ({
|
|
46
|
-
recipient: { name: user.name, email: user.email },
|
|
47
|
-
platform: { name: 'My App', domain: 'myapp.com' }
|
|
48
|
-
}),
|
|
49
|
-
|
|
50
|
-
// Deliver the email (save as draft, send directly, queue — your choice)
|
|
51
|
-
sendEmail: async (params) => {
|
|
52
|
-
await myEmailService.send({
|
|
53
|
-
to: params.identifierId,
|
|
54
|
-
subject: params.subject,
|
|
55
|
-
html: params.htmlBody,
|
|
56
|
-
text: params.textBody
|
|
57
|
-
});
|
|
58
|
-
},
|
|
171
|
+
// MongoDB connection — engine creates 5 collections on this connection
|
|
172
|
+
db: {
|
|
173
|
+
connection: dbConnection,
|
|
174
|
+
collectionPrefix: '', // optional: prefix collection names (e.g., 'myapp_')
|
|
175
|
+
},
|
|
59
176
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
177
|
+
// Redis — used for distributed locking only
|
|
178
|
+
redis: {
|
|
179
|
+
connection: redis,
|
|
180
|
+
keyPrefix: 'myapp:', // optional: prefix Redis keys
|
|
181
|
+
},
|
|
65
182
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
},
|
|
183
|
+
// Custom enum values for your domain
|
|
184
|
+
// These control what values are allowed in template/rule schemas
|
|
185
|
+
platforms: ['web', 'mobile', 'both'], // your platform identifiers
|
|
186
|
+
audiences: ['customer', 'provider', 'all'], // your user role identifiers
|
|
71
187
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
await mySmtp.send({ to, subject, html, text });
|
|
75
|
-
}
|
|
76
|
-
},
|
|
188
|
+
// Your 5 adapter functions
|
|
189
|
+
adapters,
|
|
77
190
|
|
|
191
|
+
// Optional: logger (must have info/warn/error methods)
|
|
78
192
|
logger: console,
|
|
79
193
|
|
|
194
|
+
// Optional: tuning
|
|
80
195
|
options: {
|
|
81
|
-
lockTTLMs: 30 * 60 * 1000, // 30 min
|
|
82
|
-
defaultMaxPerRun: 500
|
|
83
|
-
}
|
|
196
|
+
lockTTLMs: 30 * 60 * 1000, // lock timeout (default: 30 min)
|
|
197
|
+
defaultMaxPerRun: 500, // max users per rule execution (default: 500)
|
|
198
|
+
},
|
|
84
199
|
});
|
|
85
200
|
|
|
86
|
-
|
|
201
|
+
export { engine };
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Step 3: Mount Routes
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// app.ts
|
|
208
|
+
import express from 'express';
|
|
209
|
+
import { engine } from './email-engine-setup';
|
|
210
|
+
|
|
211
|
+
const app = express();
|
|
212
|
+
app.use(express.json());
|
|
213
|
+
|
|
214
|
+
// Mount all email rule engine routes under a prefix
|
|
87
215
|
app.use('/api/email-rules', engine.routes);
|
|
88
216
|
|
|
89
|
-
|
|
90
|
-
|
|
217
|
+
app.listen(3000);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Step 4: Schedule Rule Execution
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import cron from 'node-cron';
|
|
224
|
+
import { engine } from './email-engine-setup';
|
|
225
|
+
|
|
226
|
+
// Run all active rules every day at 9 AM
|
|
227
|
+
cron.schedule('0 9 * * *', () => {
|
|
228
|
+
engine.runner.runAllRules();
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## What You Get Back
|
|
233
|
+
|
|
234
|
+
`createEmailRuleEngine()` returns:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
{
|
|
238
|
+
routes: Router; // Express router — mount with app.use()
|
|
239
|
+
runner: RuleRunnerService; // Call runner.runAllRules() from cron
|
|
240
|
+
templateService: TemplateService; // Direct access if needed
|
|
241
|
+
ruleService: RuleService; // Direct access if needed
|
|
242
|
+
models: {
|
|
243
|
+
EmailTemplate, // Mongoose models if you need direct DB access
|
|
244
|
+
EmailRule,
|
|
245
|
+
EmailRuleSend,
|
|
246
|
+
EmailRuleRunLog,
|
|
247
|
+
EmailThrottleConfig,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
91
250
|
```
|
|
92
251
|
|
|
93
252
|
## API Routes
|
|
94
253
|
|
|
95
|
-
Once mounted,
|
|
254
|
+
Once mounted, these endpoints are available:
|
|
96
255
|
|
|
97
256
|
### Templates
|
|
257
|
+
|
|
98
258
|
| Method | Path | Description |
|
|
99
259
|
|--------|------|-------------|
|
|
100
|
-
| GET | `/templates` | List all templates (filterable by category
|
|
260
|
+
| GET | `/templates` | List all templates (filterable by `category`, `audience`, `platform`) |
|
|
101
261
|
| POST | `/templates` | Create new template |
|
|
102
262
|
| GET | `/templates/:id` | Get template by ID |
|
|
103
263
|
| PUT | `/templates/:id` | Update template |
|
|
104
264
|
| DELETE | `/templates/:id` | Delete template |
|
|
105
265
|
| PATCH | `/templates/:id/toggle` | Toggle active/inactive |
|
|
106
266
|
| POST | `/templates/:id/preview` | Render preview with sample data |
|
|
107
|
-
| POST | `/templates/:id/test-email` | Send test email |
|
|
267
|
+
| POST | `/templates/:id/test-email` | Send test email (requires `sendTestEmail` adapter) |
|
|
108
268
|
| POST | `/templates/validate` | Validate MJML + Handlebars syntax |
|
|
109
|
-
| POST | `/templates/preview` | Preview raw template
|
|
269
|
+
| POST | `/templates/preview` | Preview raw template without saving |
|
|
110
270
|
|
|
111
271
|
### Rules
|
|
272
|
+
|
|
112
273
|
| Method | Path | Description |
|
|
113
274
|
|--------|------|-------------|
|
|
114
275
|
| GET | `/rules` | List all rules (with populated template info) |
|
|
@@ -121,12 +282,14 @@ Once mounted, the engine exposes these endpoints:
|
|
|
121
282
|
| GET | `/rules/run-history` | Get execution history |
|
|
122
283
|
|
|
123
284
|
### Runner
|
|
285
|
+
|
|
124
286
|
| Method | Path | Description |
|
|
125
287
|
|--------|------|-------------|
|
|
126
288
|
| POST | `/runner` | Trigger manual rule run (fire-and-forget) |
|
|
127
289
|
| GET | `/runner/status` | Get latest run result |
|
|
128
290
|
|
|
129
291
|
### Settings
|
|
292
|
+
|
|
130
293
|
| Method | Path | Description |
|
|
131
294
|
|--------|------|-------------|
|
|
132
295
|
| GET | `/settings/throttle` | Get throttle configuration |
|
|
@@ -136,32 +299,79 @@ Once mounted, the engine exposes these endpoints:
|
|
|
136
299
|
|
|
137
300
|
### `EmailRuleEngineConfig`
|
|
138
301
|
|
|
139
|
-
| Field | Type | Required | Description |
|
|
140
|
-
|
|
141
|
-
| `db.connection` | `mongoose.Connection` | Yes | Mongoose connection for
|
|
142
|
-
| `db.collectionPrefix` | `string` | No | Prefix for collection names (e.g., `'myapp_'`) |
|
|
143
|
-
| `redis.connection` | `Redis` | Yes | ioredis instance for distributed locking |
|
|
144
|
-
| `redis.keyPrefix` | `string` | No | Prefix for Redis keys (e.g., `'myapp:'`) |
|
|
145
|
-
| `platforms` | `string[]` | No | Valid platform values for schema validation |
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `options.
|
|
302
|
+
| Field | Type | Required | Default | Description |
|
|
303
|
+
|-------|------|----------|---------|-------------|
|
|
304
|
+
| `db.connection` | `mongoose.Connection` | Yes | — | Mongoose connection for engine collections |
|
|
305
|
+
| `db.collectionPrefix` | `string` | No | `''` | Prefix for collection names (e.g., `'myapp_'`) |
|
|
306
|
+
| `redis.connection` | `Redis` | Yes | — | ioredis instance for distributed locking |
|
|
307
|
+
| `redis.keyPrefix` | `string` | No | `''` | Prefix for Redis keys (e.g., `'myapp:'`) |
|
|
308
|
+
| `platforms` | `string[]` | No | `['web', 'mobile', 'both']` | Valid platform values for schema enum validation |
|
|
309
|
+
| `audiences` | `string[]` | No | `['customer', 'provider', 'all']` | Valid audience/role values for schema enum validation |
|
|
310
|
+
| `adapters` | `object` | Yes | — | Your 5 project-specific callbacks (see below) |
|
|
311
|
+
| `logger` | `LogAdapter` | No | silent | Object with `info`, `warn`, `error` methods |
|
|
312
|
+
| `options.lockTTLMs` | `number` | No | `1800000` | Lock timeout in ms (30 min) |
|
|
313
|
+
| `options.defaultMaxPerRun` | `number` | No | `500` | Max users processed per rule execution |
|
|
150
314
|
|
|
151
315
|
### Adapters
|
|
152
316
|
|
|
153
|
-
| Adapter | Signature | Description |
|
|
154
|
-
|
|
155
|
-
| `queryUsers` | `(target, limit) => Promise<Record[]>` | Find users matching rule conditions |
|
|
156
|
-
| `resolveData` | `(user) => Record` |
|
|
157
|
-
| `sendEmail` | `(params) => Promise<void>` |
|
|
158
|
-
| `selectAgent` | `(identifierId) => Promise<{accountId} \| null>` | Pick sending account |
|
|
159
|
-
| `findIdentifier` | `(email) => Promise<{id, contactId} \| null>` | Map email to
|
|
160
|
-
| `sendTestEmail` | `(to, subject, html, text) => Promise<void>` |
|
|
317
|
+
| Adapter | Signature | Required | Description |
|
|
318
|
+
|---------|-----------|----------|-------------|
|
|
319
|
+
| `queryUsers` | `(target, limit) => Promise<Record[]>` | Yes | Find users matching rule target conditions. `target` has `role`, `platform`, `conditions[]` |
|
|
320
|
+
| `resolveData` | `(user) => Record` | Yes | Transform a user record into Handlebars template variables |
|
|
321
|
+
| `sendEmail` | `(params: SendEmailParams) => Promise<void>` | Yes | Deliver the email (send, queue, or save as draft) |
|
|
322
|
+
| `selectAgent` | `(identifierId) => Promise<{accountId} \| null>` | Yes | Pick a sending account. Return `null` to skip this recipient |
|
|
323
|
+
| `findIdentifier` | `(email) => Promise<{id, contactId} \| null>` | Yes | Map email address to your contact system. Return `null` to skip |
|
|
324
|
+
| `sendTestEmail` | `(to, subject, html, text) => Promise<void>` | No | Send test email for template preview |
|
|
325
|
+
|
|
326
|
+
### `SendEmailParams`
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
{
|
|
330
|
+
identifierId: string; // Your internal email contact ID
|
|
331
|
+
contactId: string; // Your internal contact ID
|
|
332
|
+
accountId: string; // Selected sender account ID
|
|
333
|
+
subject: string; // Rendered subject line
|
|
334
|
+
htmlBody: string; // Rendered HTML from MJML template
|
|
335
|
+
textBody: string; // Rendered plain text
|
|
336
|
+
ruleId: string; // Rule that triggered this send
|
|
337
|
+
autoApprove: boolean; // true = send now, false = save as draft for review
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Template System
|
|
342
|
+
|
|
343
|
+
Templates use [MJML](https://mjml.io/) for responsive email HTML and [Handlebars](https://handlebarsjs.com/) for dynamic variables.
|
|
344
|
+
|
|
345
|
+
### Writing a Template
|
|
346
|
+
|
|
347
|
+
**Subject** (Handlebars only):
|
|
348
|
+
```
|
|
349
|
+
Welcome to {{platform.name}}, {{user.name}}!
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Body** (MJML + Handlebars):
|
|
353
|
+
```html
|
|
354
|
+
<mjml>
|
|
355
|
+
<mj-body>
|
|
356
|
+
<mj-section>
|
|
357
|
+
<mj-column>
|
|
358
|
+
<mj-text>
|
|
359
|
+
Hi {{user.name}},
|
|
360
|
+
Welcome to {{platform.name}}!
|
|
361
|
+
{{#if subscription}}
|
|
362
|
+
Your {{subscription.planName}} plan includes {{subscription.sessions}} sessions.
|
|
363
|
+
{{/if}}
|
|
364
|
+
</mj-text>
|
|
365
|
+
<mj-button href="{{platform.bookingLink}}">Book Now</mj-button>
|
|
366
|
+
</mj-column>
|
|
367
|
+
</mj-section>
|
|
368
|
+
</mj-body>
|
|
369
|
+
</mjml>
|
|
370
|
+
```
|
|
161
371
|
|
|
162
|
-
|
|
372
|
+
The variables available in templates depend on what your `resolveData` adapter returns.
|
|
163
373
|
|
|
164
|
-
Built-in
|
|
374
|
+
### Built-in Handlebars Helpers
|
|
165
375
|
|
|
166
376
|
| Helper | Usage | Output |
|
|
167
377
|
|--------|-------|--------|
|
|
@@ -175,17 +385,103 @@ Built-in template helpers available in all templates:
|
|
|
175
385
|
| `eq/neq/gt/lt/gte/lte` | `{{#if (eq a b)}}` | Comparison |
|
|
176
386
|
| `not` | `{{#if (not val)}}` | Negation |
|
|
177
387
|
|
|
388
|
+
## Rule Execution Flow
|
|
389
|
+
|
|
390
|
+
When `engine.runner.runAllRules()` is called:
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
1. Acquire Redis lock (prevents concurrent runs)
|
|
394
|
+
2. Load throttle config (daily/weekly limits, min gap)
|
|
395
|
+
3. Load all active rules (sorted by priority)
|
|
396
|
+
4. For each rule:
|
|
397
|
+
a. Load linked template
|
|
398
|
+
b. Call YOUR queryUsers(target, limit) adapter
|
|
399
|
+
c. For each matched user:
|
|
400
|
+
- Check send history (sendOnce, resendAfterDays)
|
|
401
|
+
- Call YOUR findIdentifier(email) adapter
|
|
402
|
+
- Check throttle limits (daily, weekly, min gap)
|
|
403
|
+
- Call YOUR selectAgent(identifierId) adapter
|
|
404
|
+
- Call YOUR resolveData(user) adapter
|
|
405
|
+
- Render template (MJML → HTML, Handlebars → variables)
|
|
406
|
+
- Call YOUR sendEmail(params) adapter
|
|
407
|
+
- Log send for deduplication
|
|
408
|
+
d. Update rule stats (totalSent, lastRunAt)
|
|
409
|
+
5. Save run log with per-rule statistics
|
|
410
|
+
6. Release Redis lock
|
|
411
|
+
```
|
|
412
|
+
|
|
178
413
|
## Collections Created
|
|
179
414
|
|
|
180
|
-
The engine creates these MongoDB collections (prefixed if
|
|
415
|
+
The engine creates these MongoDB collections (prefixed if `db.collectionPrefix` is set):
|
|
181
416
|
|
|
182
|
-
| Collection | Purpose |
|
|
183
|
-
|
|
184
|
-
| `email_templates` | MJML + Handlebars templates |
|
|
185
|
-
| `email_rules` | Automation rules with conditions |
|
|
186
|
-
| `email_rule_sends` | Per-user send tracking
|
|
187
|
-
| `email_rule_run_logs` | Execution history | 90 days |
|
|
188
|
-
| `email_throttle_config` | Throttle settings (singleton) |
|
|
417
|
+
| Collection | Purpose | Auto-cleanup |
|
|
418
|
+
|------------|---------|--------------|
|
|
419
|
+
| `email_templates` | MJML + Handlebars templates | — |
|
|
420
|
+
| `email_rules` | Automation rules with conditions and targeting | — |
|
|
421
|
+
| `email_rule_sends` | Per-user send tracking for deduplication | — |
|
|
422
|
+
| `email_rule_run_logs` | Execution history with per-rule stats | 90 days TTL |
|
|
423
|
+
| `email_throttle_config` | Throttle settings (singleton document) | — |
|
|
424
|
+
|
|
425
|
+
## Throttle Configuration
|
|
426
|
+
|
|
427
|
+
Default throttle settings (configurable via `PATCH /settings/throttle`):
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"maxPerUserPerDay": 2,
|
|
432
|
+
"maxPerUserPerWeek": 5,
|
|
433
|
+
"minGapDays": 1,
|
|
434
|
+
"window": "rolling"
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Rules with `bypassThrottle: true` or `emailType: 'transactional'` skip throttle checks.
|
|
439
|
+
|
|
440
|
+
## TypeScript Exports
|
|
441
|
+
|
|
442
|
+
The package exports everything you might need:
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
// Factory
|
|
446
|
+
import { createEmailRuleEngine } from '@astralibx/email-rule-engine';
|
|
447
|
+
|
|
448
|
+
// Types
|
|
449
|
+
import type {
|
|
450
|
+
EmailRuleEngineConfig,
|
|
451
|
+
SendEmailParams,
|
|
452
|
+
AgentSelection,
|
|
453
|
+
RecipientIdentifier,
|
|
454
|
+
LogAdapter,
|
|
455
|
+
EmailRule,
|
|
456
|
+
EmailTemplate,
|
|
457
|
+
RuleTarget,
|
|
458
|
+
RuleCondition,
|
|
459
|
+
RuleRunStats,
|
|
460
|
+
PerRuleStats,
|
|
461
|
+
CreateEmailRuleInput,
|
|
462
|
+
UpdateEmailRuleInput,
|
|
463
|
+
CreateEmailTemplateInput,
|
|
464
|
+
UpdateEmailTemplateInput,
|
|
465
|
+
} from '@astralibx/email-rule-engine';
|
|
466
|
+
|
|
467
|
+
// Enums
|
|
468
|
+
import {
|
|
469
|
+
TemplateAudience,
|
|
470
|
+
TemplateCategory,
|
|
471
|
+
RuleOperator,
|
|
472
|
+
EmailType,
|
|
473
|
+
RunTrigger,
|
|
474
|
+
} from '@astralibx/email-rule-engine';
|
|
475
|
+
|
|
476
|
+
// Services (for advanced usage)
|
|
477
|
+
import {
|
|
478
|
+
TemplateRenderService,
|
|
479
|
+
TemplateService,
|
|
480
|
+
RuleService,
|
|
481
|
+
RuleRunnerService,
|
|
482
|
+
RedisLock,
|
|
483
|
+
} from '@astralibx/email-rule-engine';
|
|
484
|
+
```
|
|
189
485
|
|
|
190
486
|
## License
|
|
191
487
|
|
package/dist/index.js
CHANGED
|
@@ -28,8 +28,8 @@ const routes_1 = require("./routes");
|
|
|
28
28
|
function createEmailRuleEngine(config) {
|
|
29
29
|
const conn = config.db.connection;
|
|
30
30
|
const prefix = config.db.collectionPrefix || '';
|
|
31
|
-
const EmailTemplate = conn.model(`${prefix}EmailTemplate`, (0, template_schema_1.createEmailTemplateSchema)(config.platforms));
|
|
32
|
-
const EmailRule = conn.model(`${prefix}EmailRule`, (0, rule_schema_1.createEmailRuleSchema)(config.platforms));
|
|
31
|
+
const EmailTemplate = conn.model(`${prefix}EmailTemplate`, (0, template_schema_1.createEmailTemplateSchema)(config.platforms, config.audiences));
|
|
32
|
+
const EmailRule = conn.model(`${prefix}EmailRule`, (0, rule_schema_1.createEmailRuleSchema)(config.platforms, config.audiences));
|
|
33
33
|
const EmailRuleSend = conn.model(`${prefix}EmailRuleSend`, (0, rule_send_schema_1.createEmailRuleSendSchema)());
|
|
34
34
|
const EmailRuleRunLog = conn.model(`${prefix}EmailRuleRunLog`, (0, run_log_schema_1.createEmailRuleRunLogSchema)());
|
|
35
35
|
const EmailThrottleConfig = conn.model(`${prefix}EmailThrottleConfig`, (0, throttle_config_schema_1.createEmailThrottleConfigSchema)());
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA0BA,sDAmDC;AA5ED,+DAA+F;AAC/F,uDAAmF;AACnF,iEAAgG;AAChG,6DAAkG;AAClG,6EAAkH;AAClH,kEAA8D;AAC9D,0DAAsD;AACtD,wEAAmE;AACnE,qCAAwC;AAiBxC,SAAgB,qBAAqB,CAAC,MAA6B;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAEhD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAC9B,GAAG,MAAM,eAAe,EACxB,IAAA,2CAAyB,EAAC,MAAM,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA0BA,sDAmDC;AA5ED,+DAA+F;AAC/F,uDAAmF;AACnF,iEAAgG;AAChG,6DAAkG;AAClG,6EAAkH;AAClH,kEAA8D;AAC9D,0DAAsD;AACtD,wEAAmE;AACnE,qCAAwC;AAiBxC,SAAgB,qBAAqB,CAAC,MAA6B;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAEhD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAC9B,GAAG,MAAM,eAAe,EACxB,IAAA,2CAAyB,EAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CACxC,CAAC;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAC1B,GAAG,MAAM,WAAW,EACpB,IAAA,mCAAqB,EAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CACxC,CAAC;IAEpB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAC9B,GAAG,MAAM,eAAe,EACxB,IAAA,4CAAyB,GAAE,CACN,CAAC;IAExB,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAChC,GAAG,MAAM,iBAAiB,EAC1B,IAAA,4CAA2B,GAAE,CACN,CAAC;IAE1B,MAAM,mBAAmB,GAAG,IAAI,CAAC,KAAK,CACpC,GAAG,MAAM,qBAAqB,EAC9B,IAAA,wDAA+B,GAAE,CACN,CAAC;IAE9B,MAAM,eAAe,GAAG,IAAI,kCAAe,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACnE,MAAM,WAAW,GAAG,IAAI,0BAAW,CAAC,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;IACvF,MAAM,aAAa,GAAG,IAAI,uCAAiB,CACzC,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,CACtF,CAAC;IAEF,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC;QAC1B,eAAe;QACf,WAAW;QACX,aAAa;QACb,eAAe;QACf,mBAAmB;QACnB,cAAc,EAAE,MAAM,CAAC,SAAS;KACjC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM;QACN,MAAM,EAAE,aAAa;QACrB,eAAe;QACf,WAAW;QACX,MAAM,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE;KAC1F,CAAC;AACJ,CAAC;AAED,0CAAwB;AACxB,4CAA0B;AAC1B,8EAAqH;AAA5G,gIAAA,qBAAqB,OAAA;AAC9B,gEAA8D;AAArD,mHAAA,eAAe,OAAA;AACxB,wDAAsD;AAA7C,2GAAA,WAAW,OAAA;AACpB,sEAAmE;AAA1D,wHAAA,iBAAiB,OAAA;AAC1B,iDAA+C;AAAtC,uGAAA,SAAS,OAAA"}
|
|
@@ -10,7 +10,7 @@ export interface EmailRuleStatics {
|
|
|
10
10
|
createRule(input: CreateEmailRuleInput): Promise<EmailRuleDocument>;
|
|
11
11
|
}
|
|
12
12
|
export type EmailRuleModel = Model<IEmailRule> & EmailRuleStatics;
|
|
13
|
-
export declare function createEmailRuleSchema(platformValues?: string[]): Schema<IEmailRule, Model<IEmailRule, any, any, any, import("mongoose").Document<unknown, any, IEmailRule, any, {}> & IEmailRule & {
|
|
13
|
+
export declare function createEmailRuleSchema(platformValues?: string[], audienceValues?: string[]): Schema<IEmailRule, Model<IEmailRule, any, any, any, import("mongoose").Document<unknown, any, IEmailRule, any, {}> & IEmailRule & {
|
|
14
14
|
_id: Types.ObjectId;
|
|
15
15
|
} & {
|
|
16
16
|
__v: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/rule.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAElE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3E,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,YAAY,CAAC;IACvE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC;CAC5B;AAED,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC3C,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACpF,UAAU,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACrE;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,gBAAgB,CAAC;AAElE,wBAAgB,qBAAqB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE;;;;;;;;
|
|
1
|
+
{"version":3,"file":"rule.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/rule.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAElE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3E,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,YAAY,CAAC;IACvE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC;CAC5B;AAED,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC3C,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACpF,UAAU,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACrE;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,gBAAgB,CAAC;AAElE,wBAAgB,qBAAqB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE;;;;;;;;GA0FzF"}
|
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createEmailRuleSchema = createEmailRuleSchema;
|
|
4
4
|
const mongoose_1 = require("mongoose");
|
|
5
5
|
const enums_1 = require("../types/enums");
|
|
6
|
-
function createEmailRuleSchema(platformValues) {
|
|
6
|
+
function createEmailRuleSchema(platformValues, audienceValues) {
|
|
7
7
|
const RuleConditionSchema = new mongoose_1.Schema({
|
|
8
8
|
field: { type: String, required: true },
|
|
9
9
|
operator: { type: String, enum: Object.values(enums_1.RuleOperator), required: true },
|
|
10
10
|
value: { type: mongoose_1.Schema.Types.Mixed }
|
|
11
11
|
}, { _id: false });
|
|
12
12
|
const RuleTargetSchema = new mongoose_1.Schema({
|
|
13
|
-
role: { type: String, enum: Object.values(enums_1.TemplateAudience), required: true },
|
|
13
|
+
role: { type: String, enum: audienceValues || Object.values(enums_1.TemplateAudience), required: true },
|
|
14
14
|
platform: {
|
|
15
15
|
type: String,
|
|
16
16
|
required: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.schema.js","sourceRoot":"","sources":["../../src/schemas/rule.schema.ts"],"names":[],"mappings":";;AAkBA,sDA0FC;AA5GD,uCAAkE;AAClE,0CAA2E;AAiB3E,SAAgB,qBAAqB,CAAC,cAAyB;
|
|
1
|
+
{"version":3,"file":"rule.schema.js","sourceRoot":"","sources":["../../src/schemas/rule.schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ export interface EmailTemplateStatics {
|
|
|
12
12
|
createTemplate(input: CreateEmailTemplateInput): Promise<EmailTemplateDocument>;
|
|
13
13
|
}
|
|
14
14
|
export type EmailTemplateModel = Model<IEmailTemplate> & EmailTemplateStatics;
|
|
15
|
-
export declare function createEmailTemplateSchema(platformValues?: string[]): Schema<IEmailTemplate, Model<IEmailTemplate, any, any, any, import("mongoose").Document<unknown, any, IEmailTemplate, any, {}> & IEmailTemplate & {
|
|
15
|
+
export declare function createEmailTemplateSchema(platformValues?: string[], audienceValues?: string[]): Schema<IEmailTemplate, Model<IEmailTemplate, any, any, any, import("mongoose").Document<unknown, any, IEmailTemplate, any, {}> & IEmailTemplate & {
|
|
16
16
|
_id: import("mongoose").Types.ObjectId;
|
|
17
17
|
} & {
|
|
18
18
|
__v: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/template.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEvF,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC;CAAG;AAErE,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAChE,UAAU,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC/C,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC7E,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC7E,cAAc,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACjF;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,oBAAoB,CAAC;AAE9E,wBAAgB,yBAAyB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE;;;;;;;;
|
|
1
|
+
{"version":3,"file":"template.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/template.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEvF,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC;CAAG;AAErE,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAChE,UAAU,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC/C,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC7E,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC7E,cAAc,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACjF;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,oBAAoB,CAAC;AAE9E,wBAAgB,yBAAyB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE;;;;;;;;GAsE7F"}
|
|
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createEmailTemplateSchema = createEmailTemplateSchema;
|
|
4
4
|
const mongoose_1 = require("mongoose");
|
|
5
5
|
const enums_1 = require("../types/enums");
|
|
6
|
-
function createEmailTemplateSchema(platformValues) {
|
|
6
|
+
function createEmailTemplateSchema(platformValues, audienceValues) {
|
|
7
7
|
const schema = new mongoose_1.Schema({
|
|
8
8
|
name: { type: String, required: true },
|
|
9
9
|
slug: { type: String, required: true, unique: true },
|
|
10
10
|
description: String,
|
|
11
11
|
category: { type: String, enum: Object.values(enums_1.TemplateCategory), required: true },
|
|
12
|
-
audience: { type: String, enum: Object.values(enums_1.TemplateAudience), required: true },
|
|
12
|
+
audience: { type: String, enum: audienceValues || Object.values(enums_1.TemplateAudience), required: true },
|
|
13
13
|
platform: {
|
|
14
14
|
type: String,
|
|
15
15
|
required: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.schema.js","sourceRoot":"","sources":["../../src/schemas/template.schema.ts"],"names":[],"mappings":";;AAkBA,8DAsEC;AAxFD,uCAA2D;AAC3D,0CAAoE;AAiBpE,SAAgB,yBAAyB,CAAC,cAAyB;
|
|
1
|
+
{"version":3,"file":"template.schema.js","sourceRoot":"","sources":["../../src/schemas/template.schema.ts"],"names":[],"mappings":";;AAkBA,8DAsEC;AAxFD,uCAA2D;AAC3D,0CAAoE;AAiBpE,SAAgB,yBAAyB,CAAC,cAAyB,EAAE,cAAyB;IAC5F,MAAM,MAAM,GAAG,IAAI,iBAAM,CACvB;QACE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACtC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACpD,WAAW,EAAE,MAAM;QACnB,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;QACjF,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;QACnG,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,IAAI;YACd,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD;QAED,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACzC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACtC,QAAQ,EAAE,MAAM;QAEhB,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC7B,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;QACrC,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;KACxD,EACD;QACE,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,iBAAiB;QAE7B,OAAO,EAAE;YACP,UAAU,CAAC,IAAY;gBACrB,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAChC,CAAC;YAED,UAAU;gBACR,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACtE,CAAC;YAED,cAAc,CAAC,QAA0B;gBACvC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACnE,CAAC;YAED,cAAc,CAAC,QAA0B;gBACvC,OAAO,IAAI,CAAC,IAAI,CAAC;oBACf,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,wBAAgB,CAAC,GAAG,EAAE,CAAC;oBACvD,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YAED,KAAK,CAAC,cAAc,CAAC,KAA+B;gBAClD,OAAO,IAAI,CAAC,MAAM,CAAC;oBACjB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;oBAChC,OAAO,EAAE,CAAC;oBACV,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC;YACL,CAAC;SACF;KACF,CACF,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAExD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.types.d.ts","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9D;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE;QACF,UAAU,EAAE,UAAU,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IAEF,KAAK,EAAE;QACL,UAAU,EAAE,KAAK,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,QAAQ,EAAE;QACR,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACtF,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACxE,SAAS,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACtD,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACtE,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;QACvE,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC5F,CAAC;IAEF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH"}
|
|
1
|
+
{"version":3,"file":"config.types.d.ts","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9D;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE;QACF,UAAU,EAAE,UAAU,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IAEF,KAAK,EAAE;QACL,UAAU,EAAE,KAAK,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,QAAQ,EAAE;QACR,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACtF,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACxE,SAAS,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACtD,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACtE,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;QACvE,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC5F,CAAC;IAEF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astralibx/email-rule-engine",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Rule-based email automation engine with MJML + Handlebars templates, throttling, and distributed locking",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|