@contentgrowth/content-emailing 0.7.5 → 0.7.7
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/backend/EmailService.cjs +19 -0
- package/dist/backend/EmailService.cjs.map +1 -1
- package/dist/backend/EmailService.d.cts +2 -0
- package/dist/backend/EmailService.d.ts +2 -0
- package/dist/backend/EmailService.js +19 -0
- package/dist/backend/EmailService.js.map +1 -1
- package/dist/backend/index.cjs +139 -46
- package/dist/backend/index.cjs.map +1 -1
- package/dist/backend/index.d.cts +1 -0
- package/dist/backend/index.d.ts +1 -0
- package/dist/backend/index.js +139 -46
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/routes/index.cjs +174 -47
- package/dist/backend/routes/index.cjs.map +1 -1
- package/dist/backend/routes/index.d.cts +23 -6
- package/dist/backend/routes/index.d.ts +23 -6
- package/dist/backend/routes/index.js +172 -47
- package/dist/backend/routes/index.js.map +1 -1
- package/dist/index.cjs +139 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +139 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,64 @@
|
|
|
1
1
|
// src/backend/routes/index.js
|
|
2
|
-
import { Hono as
|
|
2
|
+
import { Hono as Hono5 } from "hono";
|
|
3
3
|
|
|
4
|
-
// src/backend/routes/
|
|
4
|
+
// src/backend/routes/settings.js
|
|
5
5
|
import { Hono } from "hono";
|
|
6
|
+
function createSettingsRoutes(config = {}) {
|
|
7
|
+
const app = new Hono();
|
|
8
|
+
const tableName = config.tableName || "system_settings";
|
|
9
|
+
const keyPrefix = config.keyPrefix || "system_email.";
|
|
10
|
+
const getSettings = async (db) => {
|
|
11
|
+
try {
|
|
12
|
+
const { results } = await db.prepare(`SELECT * FROM ${tableName} WHERE key LIKE ?`).bind(`${keyPrefix}%`).all();
|
|
13
|
+
const settings = {};
|
|
14
|
+
for (const row of results) {
|
|
15
|
+
const cleanKey = row.key.slice(keyPrefix.length);
|
|
16
|
+
settings[cleanKey] = row.value;
|
|
17
|
+
}
|
|
18
|
+
return settings;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
console.warn(`[Settings] Failed to fetch from ${tableName}:`, e.message);
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
app.get("/", async (c) => {
|
|
25
|
+
try {
|
|
26
|
+
const settings = await getSettings(c.env.DB);
|
|
27
|
+
return c.json(settings);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error("Failed to fetch settings:", error);
|
|
30
|
+
return c.json({ error: error.message }, 500);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
app.post("/", async (c) => {
|
|
34
|
+
try {
|
|
35
|
+
const body = await c.req.json();
|
|
36
|
+
const db = c.env.DB;
|
|
37
|
+
const updates = Object.entries(body).map(([k, v]) => ({
|
|
38
|
+
key: `${keyPrefix}${k}`,
|
|
39
|
+
value: v
|
|
40
|
+
}));
|
|
41
|
+
if (updates.length === 0) return c.json({ success: true });
|
|
42
|
+
const stmt = db.prepare(`
|
|
43
|
+
INSERT INTO ${tableName} (key, value, updated_at)
|
|
44
|
+
VALUES (?, ?, strftime('%s', 'now'))
|
|
45
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
46
|
+
value = excluded.value,
|
|
47
|
+
updated_at = excluded.updated_at
|
|
48
|
+
`);
|
|
49
|
+
const batch = updates.map((u) => stmt.bind(u.key, u.value === void 0 || u.value === null ? "" : String(u.value)));
|
|
50
|
+
await db.batch(batch);
|
|
51
|
+
return c.json({ success: true });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Failed to save settings:", error);
|
|
54
|
+
return c.json({ error: error.message }, 500);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return app;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/backend/routes/templates.js
|
|
61
|
+
import { Hono as Hono2 } from "hono";
|
|
6
62
|
|
|
7
63
|
// src/backend/EmailService.js
|
|
8
64
|
import { marked } from "marked";
|
|
@@ -483,6 +539,9 @@ var EmailService = class {
|
|
|
483
539
|
// Updater function to save settings to backend
|
|
484
540
|
// Signature: async (profile, tenantId, settings) => void
|
|
485
541
|
settingsUpdater: config.settingsUpdater || null,
|
|
542
|
+
// Settings configuration
|
|
543
|
+
settingsTableName: config.settingsTableName || "system_settings",
|
|
544
|
+
settingsKeyPrefix: config.settingsKeyPrefix || "system_email.",
|
|
486
545
|
// Branding configuration for email templates
|
|
487
546
|
branding: {
|
|
488
547
|
brandName: config.branding?.brandName || "Your App",
|
|
@@ -531,6 +590,22 @@ var EmailService = class {
|
|
|
531
590
|
console.warn("[EmailService] settingsLoader failed:", e);
|
|
532
591
|
}
|
|
533
592
|
}
|
|
593
|
+
if (!settings && profile === "system" && this.db) {
|
|
594
|
+
try {
|
|
595
|
+
const tableName = this.config.settingsTableName;
|
|
596
|
+
const prefix = this.config.settingsKeyPrefix;
|
|
597
|
+
const { results } = await this.db.prepare(`SELECT * FROM ${tableName} WHERE key LIKE ?`).bind(`${prefix}%`).all();
|
|
598
|
+
if (results && results.length > 0) {
|
|
599
|
+
settings = {};
|
|
600
|
+
for (const row of results) {
|
|
601
|
+
const cleanKey = row.key.slice(prefix.length);
|
|
602
|
+
settings[cleanKey] = row.value;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
} catch (e) {
|
|
606
|
+
console.warn("[EmailService] Failed to load settings from DB:", e.message);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
534
609
|
if (settings) {
|
|
535
610
|
if (this.cache && this.cache.putSettings) {
|
|
536
611
|
try {
|
|
@@ -1061,78 +1136,88 @@ var EmailService = class {
|
|
|
1061
1136
|
};
|
|
1062
1137
|
|
|
1063
1138
|
// src/backend/routes/templates.js
|
|
1064
|
-
function
|
|
1065
|
-
const app = new
|
|
1066
|
-
|
|
1067
|
-
|
|
1139
|
+
function createTemplateRoutes2(config = {}) {
|
|
1140
|
+
const app = new Hono2();
|
|
1141
|
+
app.get("/", async (c) => {
|
|
1142
|
+
const emailService = new EmailService(c.env, config);
|
|
1068
1143
|
try {
|
|
1069
1144
|
const templates = await emailService.getAllTemplates();
|
|
1070
|
-
return c.json(
|
|
1145
|
+
return c.json(templates);
|
|
1071
1146
|
} catch (err) {
|
|
1072
|
-
return c.json({
|
|
1147
|
+
return c.json({ error: err.message }, 500);
|
|
1073
1148
|
}
|
|
1074
1149
|
});
|
|
1075
|
-
app.get("
|
|
1150
|
+
app.get("/:id", async (c) => {
|
|
1151
|
+
const emailService = new EmailService(c.env, config);
|
|
1076
1152
|
try {
|
|
1077
1153
|
const template = await emailService.getTemplate(c.req.param("id"));
|
|
1078
|
-
if (!template) return c.json({
|
|
1079
|
-
return c.json(
|
|
1154
|
+
if (!template) return c.json({ error: "Template not found" }, 404);
|
|
1155
|
+
return c.json(template);
|
|
1080
1156
|
} catch (err) {
|
|
1081
|
-
return c.json({
|
|
1157
|
+
return c.json({ error: err.message }, 500);
|
|
1082
1158
|
}
|
|
1083
1159
|
});
|
|
1084
|
-
app.post("/
|
|
1160
|
+
app.post("/", async (c) => {
|
|
1161
|
+
const emailService = new EmailService(c.env, config);
|
|
1085
1162
|
try {
|
|
1086
1163
|
const data = await c.req.json();
|
|
1087
|
-
|
|
1088
|
-
|
|
1164
|
+
let userId = "admin";
|
|
1165
|
+
const user = c.get("dbUser") || c.get("user");
|
|
1166
|
+
if (user && user.id) userId = user.id;
|
|
1167
|
+
if (!data.template_id || !data.subject_template) {
|
|
1168
|
+
return c.json({ error: "Missing required fields (template_id, subject_template)" }, 400);
|
|
1169
|
+
}
|
|
1170
|
+
const result = await emailService.saveTemplate(data, userId);
|
|
1171
|
+
return c.json({ success: true, message: "Template saved", result });
|
|
1089
1172
|
} catch (err) {
|
|
1090
|
-
return c.json({
|
|
1173
|
+
return c.json({ error: err.message }, 500);
|
|
1091
1174
|
}
|
|
1092
1175
|
});
|
|
1093
|
-
app.
|
|
1176
|
+
app.post("/send-test", async (c) => {
|
|
1177
|
+
const emailService = new EmailService(c.env, config);
|
|
1178
|
+
try {
|
|
1179
|
+
const { template_id, to, variables } = await c.req.json();
|
|
1180
|
+
let tid = template_id;
|
|
1181
|
+
if (!tid || !to) {
|
|
1182
|
+
return c.json({ error: "Missing required fields (template_id, to)" }, 400);
|
|
1183
|
+
}
|
|
1184
|
+
const user = c.get("dbUser") || c.get("user");
|
|
1185
|
+
const recipientUserId = user?.id || null;
|
|
1186
|
+
const result = await emailService.sendViaTemplate(tid, variables || {}, {
|
|
1187
|
+
to,
|
|
1188
|
+
profile: "test",
|
|
1189
|
+
recipientUserId
|
|
1190
|
+
});
|
|
1191
|
+
return c.json({ success: true, result });
|
|
1192
|
+
} catch (err) {
|
|
1193
|
+
return c.json({ error: `Failed to send test email: ${err.message}` }, 500);
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
app.delete("/:id", async (c) => {
|
|
1197
|
+
const emailService = new EmailService(c.env, config);
|
|
1094
1198
|
try {
|
|
1095
1199
|
await emailService.deleteTemplate(c.req.param("id"));
|
|
1096
1200
|
return c.json({ success: true, message: "Template deleted" });
|
|
1097
1201
|
} catch (err) {
|
|
1098
|
-
return c.json({
|
|
1202
|
+
return c.json({ error: err.message }, 500);
|
|
1099
1203
|
}
|
|
1100
1204
|
});
|
|
1101
|
-
app.post("
|
|
1205
|
+
app.post("/:id/preview", async (c) => {
|
|
1206
|
+
const emailService = new EmailService(c.env, config);
|
|
1102
1207
|
try {
|
|
1103
1208
|
const id = c.req.param("id");
|
|
1104
1209
|
const data = await c.req.json();
|
|
1105
1210
|
const result = await emailService.renderTemplate(id, data);
|
|
1106
1211
|
return c.json({ success: true, preview: result });
|
|
1107
1212
|
} catch (err) {
|
|
1108
|
-
return c.json({
|
|
1109
|
-
}
|
|
1110
|
-
});
|
|
1111
|
-
app.post("/templates/:id/test", async (c) => {
|
|
1112
|
-
try {
|
|
1113
|
-
const id = c.req.param("id");
|
|
1114
|
-
const { to, data } = await c.req.json();
|
|
1115
|
-
const { subject, html, plainText } = await emailService.renderTemplate(id, data);
|
|
1116
|
-
const result = await emailService.sendEmail({
|
|
1117
|
-
to,
|
|
1118
|
-
subject: `[TEST] ${subject}`,
|
|
1119
|
-
html,
|
|
1120
|
-
text: plainText
|
|
1121
|
-
});
|
|
1122
|
-
if (result.success) {
|
|
1123
|
-
return c.json({ success: true, message: "Test email sent" });
|
|
1124
|
-
} else {
|
|
1125
|
-
return c.json({ success: false, error: result.error }, 500);
|
|
1126
|
-
}
|
|
1127
|
-
} catch (err) {
|
|
1128
|
-
return c.json({ success: false, error: err.message }, 500);
|
|
1213
|
+
return c.json({ error: err.message }, 500);
|
|
1129
1214
|
}
|
|
1130
1215
|
});
|
|
1131
1216
|
return app;
|
|
1132
1217
|
}
|
|
1133
1218
|
|
|
1134
1219
|
// src/backend/routes/tracking.js
|
|
1135
|
-
import { Hono as
|
|
1220
|
+
import { Hono as Hono3 } from "hono";
|
|
1136
1221
|
var TRACKING_PIXEL = new Uint8Array([
|
|
1137
1222
|
71,
|
|
1138
1223
|
73,
|
|
@@ -1178,7 +1263,7 @@ var TRACKING_PIXEL = new Uint8Array([
|
|
|
1178
1263
|
59
|
|
1179
1264
|
]);
|
|
1180
1265
|
function createTrackingRoutes(env, config = {}) {
|
|
1181
|
-
const app = new
|
|
1266
|
+
const app = new Hono3();
|
|
1182
1267
|
const db = env.DB;
|
|
1183
1268
|
const tablePrefix = config.emailTablePrefix || config.tableNamePrefix || "system_email_";
|
|
1184
1269
|
app.get("/track/open/:token", async (c) => {
|
|
@@ -1306,16 +1391,56 @@ function createTrackingRoutes(env, config = {}) {
|
|
|
1306
1391
|
return app;
|
|
1307
1392
|
}
|
|
1308
1393
|
|
|
1394
|
+
// src/backend/routes/logs.js
|
|
1395
|
+
import { Hono as Hono4 } from "hono";
|
|
1396
|
+
function createLogRoutes2(config = {}) {
|
|
1397
|
+
const app = new Hono4();
|
|
1398
|
+
app.get("/", async (c) => {
|
|
1399
|
+
const limit = Math.min(parseInt(c.req.query("limit") || "50"), 100);
|
|
1400
|
+
const offset = parseInt(c.req.query("offset") || "0");
|
|
1401
|
+
const env = c.env;
|
|
1402
|
+
try {
|
|
1403
|
+
const table = `${config.emailTablePrefix || "system_email_"}logs`;
|
|
1404
|
+
const { results } = await env.DB.prepare(`
|
|
1405
|
+
SELECT * FROM ${table}
|
|
1406
|
+
ORDER BY created_at DESC
|
|
1407
|
+
LIMIT ? OFFSET ?
|
|
1408
|
+
`).bind(limit, offset).all();
|
|
1409
|
+
const countResult = await env.DB.prepare(`SELECT COUNT(*) as exact_count FROM ${table}`).first();
|
|
1410
|
+
return c.json({
|
|
1411
|
+
logs: results.map((row) => ({
|
|
1412
|
+
...row,
|
|
1413
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
|
1414
|
+
})),
|
|
1415
|
+
total: countResult.exact_count,
|
|
1416
|
+
limit,
|
|
1417
|
+
offset
|
|
1418
|
+
});
|
|
1419
|
+
} catch (error) {
|
|
1420
|
+
console.error("Failed to fetch logs:", error);
|
|
1421
|
+
return c.json({ error: "Failed to fetch logs" }, 500);
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
return app;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1309
1427
|
// src/backend/routes/index.js
|
|
1310
|
-
function createEmailRoutes(
|
|
1311
|
-
const app = new
|
|
1312
|
-
app.route("/
|
|
1313
|
-
app.route("/
|
|
1428
|
+
function createEmailRoutes(config = {}, cacheProvider = null) {
|
|
1429
|
+
const app = new Hono5();
|
|
1430
|
+
app.route("/templates", createTemplateRoutes(config, cacheProvider));
|
|
1431
|
+
app.route("/logs", createLogRoutes(config));
|
|
1432
|
+
app.route("/settings", createSettingsRoutes({
|
|
1433
|
+
...config,
|
|
1434
|
+
tableName: config.settingsTableName || "system_settings",
|
|
1435
|
+
keyPrefix: config.settingsKeyPrefix || "system_email."
|
|
1436
|
+
}));
|
|
1314
1437
|
return app;
|
|
1315
1438
|
}
|
|
1316
1439
|
export {
|
|
1317
1440
|
createEmailRoutes,
|
|
1318
|
-
|
|
1441
|
+
createLogRoutes2 as createLogRoutes,
|
|
1442
|
+
createSettingsRoutes,
|
|
1443
|
+
createTemplateRoutes2 as createTemplateRoutes,
|
|
1319
1444
|
createTrackingRoutes
|
|
1320
1445
|
};
|
|
1321
1446
|
//# sourceMappingURL=index.js.map
|