@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.
@@ -1,8 +1,64 @@
1
1
  // src/backend/routes/index.js
2
- import { Hono as Hono3 } from "hono";
2
+ import { Hono as Hono5 } from "hono";
3
3
 
4
- // src/backend/routes/templates.js
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 createTemplateRoutes(env, config = {}, cacheProvider = null) {
1065
- const app = new Hono();
1066
- const emailService = new EmailService(env, config, cacheProvider);
1067
- app.get("/templates", async (c) => {
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({ success: true, templates });
1145
+ return c.json(templates);
1071
1146
  } catch (err) {
1072
- return c.json({ success: false, error: err.message }, 500);
1147
+ return c.json({ error: err.message }, 500);
1073
1148
  }
1074
1149
  });
1075
- app.get("/templates/:id", async (c) => {
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({ success: false, error: "Template not found" }, 404);
1079
- return c.json({ success: true, template });
1154
+ if (!template) return c.json({ error: "Template not found" }, 404);
1155
+ return c.json(template);
1080
1156
  } catch (err) {
1081
- return c.json({ success: false, error: err.message }, 500);
1157
+ return c.json({ error: err.message }, 500);
1082
1158
  }
1083
1159
  });
1084
- app.post("/templates", async (c) => {
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
- await emailService.saveTemplate(data, "admin");
1088
- return c.json({ success: true, message: "Template saved" });
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({ success: false, error: err.message }, 500);
1173
+ return c.json({ error: err.message }, 500);
1091
1174
  }
1092
1175
  });
1093
- app.delete("/templates/:id", async (c) => {
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({ success: false, error: err.message }, 500);
1202
+ return c.json({ error: err.message }, 500);
1099
1203
  }
1100
1204
  });
1101
- app.post("/templates/:id/preview", async (c) => {
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({ success: false, error: err.message }, 500);
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 Hono2 } from "hono";
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 Hono2();
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(env, config = {}, cacheProvider = null) {
1311
- const app = new Hono3();
1312
- app.route("/api/email", createTemplateRoutes(env, config, cacheProvider));
1313
- app.route("/email", createTrackingRoutes(env, config));
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
- createTemplateRoutes,
1441
+ createLogRoutes2 as createLogRoutes,
1442
+ createSettingsRoutes,
1443
+ createTemplateRoutes2 as createTemplateRoutes,
1319
1444
  createTrackingRoutes
1320
1445
  };
1321
1446
  //# sourceMappingURL=index.js.map