@sonicjs-cms/core 2.0.11 → 2.0.13

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.
Files changed (72) hide show
  1. package/README.md +75 -1
  2. package/dist/{chunk-AMSTLQFI.cjs → chunk-22EFGHAX.cjs} +4 -4
  3. package/dist/chunk-22EFGHAX.cjs.map +1 -0
  4. package/dist/{chunk-IM2LGCYD.cjs → chunk-2CP6535T.cjs} +905 -565
  5. package/dist/chunk-2CP6535T.cjs.map +1 -0
  6. package/dist/{chunk-HKEK7UNV.js → chunk-CPXAVWCU.js} +3 -3
  7. package/dist/{chunk-HKEK7UNV.js.map → chunk-CPXAVWCU.js.map} +1 -1
  8. package/dist/{chunk-F5ESJXI2.cjs → chunk-DTLB6UIH.cjs} +3 -3
  9. package/dist/{chunk-F5ESJXI2.cjs.map → chunk-DTLB6UIH.cjs.map} +1 -1
  10. package/dist/chunk-HFFNEGZB.cjs +70 -0
  11. package/dist/chunk-HFFNEGZB.cjs.map +1 -0
  12. package/dist/chunk-I3R77LQC.js +1550 -0
  13. package/dist/chunk-I3R77LQC.js.map +1 -0
  14. package/dist/chunk-JQIQRMPA.cjs +1552 -0
  15. package/dist/chunk-JQIQRMPA.cjs.map +1 -0
  16. package/dist/{chunk-I5ZPYKNX.js → chunk-LWMMMW43.js} +4 -4
  17. package/dist/chunk-LWMMMW43.js.map +1 -0
  18. package/dist/chunk-MOWI4WYE.js +61 -0
  19. package/dist/chunk-MOWI4WYE.js.map +1 -0
  20. package/dist/{chunk-FYWJMETG.js → chunk-PFNUOW6W.js} +4 -4
  21. package/dist/{chunk-FYWJMETG.js.map → chunk-PFNUOW6W.js.map} +1 -1
  22. package/dist/{chunk-CLLJFZ5U.js → chunk-QWIXOMHW.js} +805 -466
  23. package/dist/chunk-QWIXOMHW.js.map +1 -0
  24. package/dist/{chunk-DOR2IU73.cjs → chunk-U2WYUO32.cjs} +249 -2
  25. package/dist/chunk-U2WYUO32.cjs.map +1 -0
  26. package/dist/{chunk-NNXPAPUD.cjs → chunk-WFHLBYNA.cjs} +7 -4
  27. package/dist/chunk-WFHLBYNA.cjs.map +1 -0
  28. package/dist/{chunk-X2VADBA4.cjs → chunk-WML2ZMHH.cjs} +7 -7
  29. package/dist/{chunk-X2VADBA4.cjs.map → chunk-WML2ZMHH.cjs.map} +1 -1
  30. package/dist/{chunk-DU7JJZN7.js → chunk-ZALNKBLS.js} +7 -4
  31. package/dist/chunk-ZALNKBLS.js.map +1 -0
  32. package/dist/{chunk-6FR25MPC.js → chunk-ZNESOOF2.js} +246 -3
  33. package/dist/chunk-ZNESOOF2.js.map +1 -0
  34. package/dist/index.cjs +139 -137
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.js +13 -11
  37. package/dist/index.js.map +1 -1
  38. package/dist/middleware.cjs +24 -24
  39. package/dist/middleware.js +3 -3
  40. package/dist/migrations-GVG73ZJC.js +4 -0
  41. package/dist/{migrations-IHERIQVD.js.map → migrations-GVG73ZJC.js.map} +1 -1
  42. package/dist/migrations-S52MEE4J.cjs +13 -0
  43. package/dist/{migrations-POFD5KNG.cjs.map → migrations-S52MEE4J.cjs.map} +1 -1
  44. package/dist/plugins.cjs +7 -7
  45. package/dist/plugins.js +1 -1
  46. package/dist/routes.cjs +30 -25
  47. package/dist/routes.js +7 -6
  48. package/dist/services.cjs +41 -24
  49. package/dist/services.js +4 -3
  50. package/dist/utils.cjs +44 -11
  51. package/dist/utils.js +2 -1
  52. package/migrations/001_initial_schema.sql +1 -1
  53. package/migrations/{023_add_mdxeditor_plugin.sql → 023_add_easy_mdx_plugin.sql} +7 -7
  54. package/migrations/025_rename_mdxeditor_to_easy_mdx.sql +22 -0
  55. package/package.json +5 -2
  56. package/dist/chunk-6FR25MPC.js.map +0 -1
  57. package/dist/chunk-AMSTLQFI.cjs.map +0 -1
  58. package/dist/chunk-CLLJFZ5U.js.map +0 -1
  59. package/dist/chunk-DOR2IU73.cjs.map +0 -1
  60. package/dist/chunk-DU7JJZN7.js.map +0 -1
  61. package/dist/chunk-I5ZPYKNX.js.map +0 -1
  62. package/dist/chunk-IM2LGCYD.cjs.map +0 -1
  63. package/dist/chunk-NNXPAPUD.cjs.map +0 -1
  64. package/dist/chunk-T7IYBGGO.cjs +0 -746
  65. package/dist/chunk-T7IYBGGO.cjs.map +0 -1
  66. package/dist/chunk-ZPMFT2JW.js +0 -744
  67. package/dist/chunk-ZPMFT2JW.js.map +0 -1
  68. package/dist/migrations-IHERIQVD.js +0 -4
  69. package/dist/migrations-POFD5KNG.cjs +0 -13
  70. package/migrations/013_code_examples_plugin.sql +0 -177
  71. package/migrations/025_add_easymde_plugin.sql +0 -25
  72. /package/migrations/{021_add_otp_login.sql → 026_add_otp_login.sql} +0 -0
@@ -1,9 +1,9 @@
1
- import { getCacheService, CACHE_CONFIGS, getLogger, SettingsService } from './chunk-6FR25MPC.js';
2
- import { requireAuth, isPluginActive, requireRole, AuthManager, logActivity } from './chunk-FYWJMETG.js';
3
- import { PluginService } from './chunk-I5ZPYKNX.js';
4
- import { MigrationService } from './chunk-ZPMFT2JW.js';
1
+ import { getCacheService, CACHE_CONFIGS, getLogger, SettingsService } from './chunk-ZNESOOF2.js';
2
+ import { requireAuth, isPluginActive, requireRole, AuthManager, logActivity } from './chunk-PFNUOW6W.js';
3
+ import { PluginService } from './chunk-LWMMMW43.js';
4
+ import { MigrationService } from './chunk-I3R77LQC.js';
5
5
  import { init_admin_layout_catalyst_template, renderDesignPage, renderCheckboxPage, renderTestimonialsList, renderCodeExamplesList, renderAlert, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayoutCatalyst, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-5RKQB2JG.js';
6
- import { QueryFilterBuilder, sanitizeInput, getCoreVersion, escapeHtml } from './chunk-DU7JJZN7.js';
6
+ import { QueryFilterBuilder, sanitizeInput, getCoreVersion, escapeHtml } from './chunk-ZALNKBLS.js';
7
7
  import { metricsTracker } from './chunk-FICTAGD4.js';
8
8
  import { Hono } from 'hono';
9
9
  import { cors } from 'hono/cors';
@@ -17,8 +17,8 @@ var apiContentCrudRoutes = new Hono();
17
17
  apiContentCrudRoutes.get("/:id", async (c) => {
18
18
  try {
19
19
  const id = c.req.param("id");
20
- const db = c.env.DB;
21
- const stmt = db.prepare("SELECT * FROM content WHERE id = ?");
20
+ const db2 = c.env.DB;
21
+ const stmt = db2.prepare("SELECT * FROM content WHERE id = ?");
22
22
  const content = await stmt.bind(id).first();
23
23
  if (!content) {
24
24
  return c.json({ error: "Content not found" }, 404);
@@ -44,7 +44,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
44
44
  });
45
45
  apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
46
46
  try {
47
- const db = c.env.DB;
47
+ const db2 = c.env.DB;
48
48
  const user = c.get("user");
49
49
  const body = await c.req.json();
50
50
  const { collectionId, title, slug, status, data } = body;
@@ -56,7 +56,7 @@ apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
56
56
  }
57
57
  let finalSlug = slug || title;
58
58
  finalSlug = finalSlug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
59
- const duplicateCheck = db.prepare(
59
+ const duplicateCheck = db2.prepare(
60
60
  "SELECT id FROM content WHERE collection_id = ? AND slug = ?"
61
61
  );
62
62
  const existing = await duplicateCheck.bind(collectionId, finalSlug).first();
@@ -65,7 +65,7 @@ apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
65
65
  }
66
66
  const contentId = crypto.randomUUID();
67
67
  const now = Date.now();
68
- const insertStmt = db.prepare(`
68
+ const insertStmt = db2.prepare(`
69
69
  INSERT INTO content (
70
70
  id, collection_id, slug, title, data, status,
71
71
  author_id, created_at, updated_at
@@ -86,7 +86,7 @@ apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
86
86
  const cache = getCacheService(CACHE_CONFIGS.api);
87
87
  await cache.invalidate(`content:list:${collectionId}:*`);
88
88
  await cache.invalidate("content-filtered:*");
89
- const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
89
+ const getStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
90
90
  const createdContent = await getStmt.bind(contentId).first();
91
91
  return c.json({
92
92
  data: {
@@ -111,9 +111,9 @@ apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
111
111
  apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
112
112
  try {
113
113
  const id = c.req.param("id");
114
- const db = c.env.DB;
114
+ const db2 = c.env.DB;
115
115
  const body = await c.req.json();
116
- const existingStmt = db.prepare("SELECT * FROM content WHERE id = ?");
116
+ const existingStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
117
117
  const existing = await existingStmt.bind(id).first();
118
118
  if (!existing) {
119
119
  return c.json({ error: "Content not found" }, 404);
@@ -141,7 +141,7 @@ apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
141
141
  updates.push("updated_at = ?");
142
142
  params.push(now);
143
143
  params.push(id);
144
- const updateStmt = db.prepare(`
144
+ const updateStmt = db2.prepare(`
145
145
  UPDATE content SET ${updates.join(", ")}
146
146
  WHERE id = ?
147
147
  `);
@@ -150,7 +150,7 @@ apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
150
150
  await cache.delete(cache.generateKey("content", id));
151
151
  await cache.invalidate(`content:list:${existing.collection_id}:*`);
152
152
  await cache.invalidate("content-filtered:*");
153
- const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
153
+ const getStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
154
154
  const updatedContent = await getStmt.bind(id).first();
155
155
  return c.json({
156
156
  data: {
@@ -175,13 +175,13 @@ apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
175
175
  apiContentCrudRoutes.delete("/:id", requireAuth(), async (c) => {
176
176
  try {
177
177
  const id = c.req.param("id");
178
- const db = c.env.DB;
179
- const existingStmt = db.prepare("SELECT collection_id FROM content WHERE id = ?");
178
+ const db2 = c.env.DB;
179
+ const existingStmt = db2.prepare("SELECT collection_id FROM content WHERE id = ?");
180
180
  const existing = await existingStmt.bind(id).first();
181
181
  if (!existing) {
182
182
  return c.json({ error: "Content not found" }, 404);
183
183
  }
184
- const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
184
+ const deleteStmt = db2.prepare("DELETE FROM content WHERE id = ?");
185
185
  await deleteStmt.bind(id).run();
186
186
  const cache = getCacheService(CACHE_CONFIGS.api);
187
187
  await cache.delete(cache.generateKey("content", id));
@@ -254,7 +254,7 @@ apiRoutes.get("/health", (c) => {
254
254
  apiRoutes.get("/collections", async (c) => {
255
255
  const executionStart = Date.now();
256
256
  try {
257
- const db = c.env.DB;
257
+ const db2 = c.env.DB;
258
258
  const cacheEnabled = c.get("cacheEnabled");
259
259
  const cache = getCacheService(CACHE_CONFIGS.api);
260
260
  const cacheKey = cache.generateKey("collections", "all");
@@ -282,7 +282,7 @@ apiRoutes.get("/collections", async (c) => {
282
282
  }
283
283
  c.header("X-Cache-Status", "MISS");
284
284
  c.header("X-Cache-Source", "database");
285
- const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1");
285
+ const stmt = db2.prepare("SELECT * FROM collections WHERE is_active = 1");
286
286
  const { results } = await stmt.all();
287
287
  const transformedResults = results.map((row) => ({
288
288
  ...row,
@@ -313,11 +313,11 @@ apiRoutes.get("/collections", async (c) => {
313
313
  apiRoutes.get("/content", async (c) => {
314
314
  const executionStart = Date.now();
315
315
  try {
316
- const db = c.env.DB;
316
+ const db2 = c.env.DB;
317
317
  const queryParams = c.req.query();
318
318
  if (queryParams.collection) {
319
319
  const collectionName = queryParams.collection;
320
- const collectionStmt = db.prepare("SELECT id FROM collections WHERE name = ? AND is_active = 1");
320
+ const collectionStmt = db2.prepare("SELECT id FROM collections WHERE name = ? AND is_active = 1");
321
321
  const collectionResult = await collectionStmt.bind(collectionName).first();
322
322
  if (collectionResult) {
323
323
  queryParams.collection_id = collectionResult.id;
@@ -373,7 +373,7 @@ apiRoutes.get("/content", async (c) => {
373
373
  }
374
374
  c.header("X-Cache-Status", "MISS");
375
375
  c.header("X-Cache-Source", "database");
376
- const stmt = db.prepare(queryResult.sql);
376
+ const stmt = db2.prepare(queryResult.sql);
377
377
  const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
378
378
  const { results } = await boundStmt.all();
379
379
  const transformedResults = results.map((row) => ({
@@ -418,9 +418,9 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
418
418
  const executionStart = Date.now();
419
419
  try {
420
420
  const collection = c.req.param("collection");
421
- const db = c.env.DB;
421
+ const db2 = c.env.DB;
422
422
  const queryParams = c.req.query();
423
- const collectionStmt = db.prepare("SELECT * FROM collections WHERE name = ? AND is_active = 1");
423
+ const collectionStmt = db2.prepare("SELECT * FROM collections WHERE name = ? AND is_active = 1");
424
424
  const collectionResult = await collectionStmt.bind(collection).first();
425
425
  if (!collectionResult) {
426
426
  return c.json({ error: "Collection not found" }, 404);
@@ -476,7 +476,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
476
476
  }
477
477
  c.header("X-Cache-Status", "MISS");
478
478
  c.header("X-Cache-Source", "database");
479
- const stmt = db.prepare(queryResult.sql);
479
+ const stmt = db2.prepare(queryResult.sql);
480
480
  const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
481
481
  const { results } = await boundStmt.all();
482
482
  const transformedResults = results.map((row) => ({
@@ -1240,20 +1240,20 @@ apiSystemRoutes.get("/info", (c) => {
1240
1240
  });
1241
1241
  apiSystemRoutes.get("/stats", async (c) => {
1242
1242
  try {
1243
- const db = c.env.DB;
1244
- const contentStats = await db.prepare(`
1243
+ const db2 = c.env.DB;
1244
+ const contentStats = await db2.prepare(`
1245
1245
  SELECT COUNT(*) as total_content
1246
1246
  FROM content
1247
1247
  WHERE deleted_at IS NULL
1248
1248
  `).first();
1249
- const mediaStats = await db.prepare(`
1249
+ const mediaStats = await db2.prepare(`
1250
1250
  SELECT
1251
1251
  COUNT(*) as total_files,
1252
1252
  SUM(size) as total_size
1253
1253
  FROM media
1254
1254
  WHERE deleted_at IS NULL
1255
1255
  `).first();
1256
- const userStats = await db.prepare(`
1256
+ const userStats = await db2.prepare(`
1257
1257
  SELECT COUNT(*) as total_users
1258
1258
  FROM users
1259
1259
  `).first();
@@ -1314,10 +1314,10 @@ adminApiRoutes.use("*", requireAuth());
1314
1314
  adminApiRoutes.use("*", requireRole(["admin", "editor"]));
1315
1315
  adminApiRoutes.get("/stats", async (c) => {
1316
1316
  try {
1317
- const db = c.env.DB;
1317
+ const db2 = c.env.DB;
1318
1318
  let collectionsCount = 0;
1319
1319
  try {
1320
- const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
1320
+ const collectionsStmt = db2.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
1321
1321
  const collectionsResult = await collectionsStmt.first();
1322
1322
  collectionsCount = collectionsResult?.count || 0;
1323
1323
  } catch (error) {
@@ -1325,7 +1325,7 @@ adminApiRoutes.get("/stats", async (c) => {
1325
1325
  }
1326
1326
  let contentCount = 0;
1327
1327
  try {
1328
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
1328
+ const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
1329
1329
  const contentResult = await contentStmt.first();
1330
1330
  contentCount = contentResult?.count || 0;
1331
1331
  } catch (error) {
@@ -1334,7 +1334,7 @@ adminApiRoutes.get("/stats", async (c) => {
1334
1334
  let mediaCount = 0;
1335
1335
  let mediaSize = 0;
1336
1336
  try {
1337
- const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
1337
+ const mediaStmt = db2.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
1338
1338
  const mediaResult = await mediaStmt.first();
1339
1339
  mediaCount = mediaResult?.count || 0;
1340
1340
  mediaSize = mediaResult?.total_size || 0;
@@ -1343,7 +1343,7 @@ adminApiRoutes.get("/stats", async (c) => {
1343
1343
  }
1344
1344
  let usersCount = 0;
1345
1345
  try {
1346
- const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
1346
+ const usersStmt = db2.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
1347
1347
  const usersResult = await usersStmt.first();
1348
1348
  usersCount = usersResult?.count || 0;
1349
1349
  } catch (error) {
@@ -1364,17 +1364,17 @@ adminApiRoutes.get("/stats", async (c) => {
1364
1364
  });
1365
1365
  adminApiRoutes.get("/storage", async (c) => {
1366
1366
  try {
1367
- const db = c.env.DB;
1367
+ const db2 = c.env.DB;
1368
1368
  let databaseSize = 0;
1369
1369
  try {
1370
- const result = await db.prepare("SELECT 1").run();
1370
+ const result = await db2.prepare("SELECT 1").run();
1371
1371
  databaseSize = result?.meta?.size_after || 0;
1372
1372
  } catch (error) {
1373
1373
  console.error("Error fetching database size:", error);
1374
1374
  }
1375
1375
  let mediaSize = 0;
1376
1376
  try {
1377
- const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
1377
+ const mediaStmt = db2.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
1378
1378
  const mediaResult = await mediaStmt.first();
1379
1379
  mediaSize = mediaResult?.total_size || 0;
1380
1380
  } catch (error) {
@@ -1393,9 +1393,9 @@ adminApiRoutes.get("/storage", async (c) => {
1393
1393
  });
1394
1394
  adminApiRoutes.get("/activity", async (c) => {
1395
1395
  try {
1396
- const db = c.env.DB;
1396
+ const db2 = c.env.DB;
1397
1397
  const limit = parseInt(c.req.query("limit") || "10");
1398
- const activityStmt = db.prepare(`
1398
+ const activityStmt = db2.prepare(`
1399
1399
  SELECT
1400
1400
  a.id,
1401
1401
  a.action,
@@ -1457,13 +1457,13 @@ var updateCollectionSchema = z.object({
1457
1457
  });
1458
1458
  adminApiRoutes.get("/collections", async (c) => {
1459
1459
  try {
1460
- const db = c.env.DB;
1460
+ const db2 = c.env.DB;
1461
1461
  const search = c.req.query("search") || "";
1462
1462
  const includeInactive = c.req.query("includeInactive") === "true";
1463
1463
  let stmt;
1464
1464
  let results;
1465
1465
  if (search) {
1466
- stmt = db.prepare(`
1466
+ stmt = db2.prepare(`
1467
1467
  SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
1468
1468
  FROM collections
1469
1469
  WHERE ${includeInactive ? "1=1" : "is_active = 1"}
@@ -1474,7 +1474,7 @@ adminApiRoutes.get("/collections", async (c) => {
1474
1474
  const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
1475
1475
  results = queryResults.results;
1476
1476
  } else {
1477
- stmt = db.prepare(`
1477
+ stmt = db2.prepare(`
1478
1478
  SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
1479
1479
  FROM collections
1480
1480
  ${includeInactive ? "" : "WHERE is_active = 1"}
@@ -1483,7 +1483,7 @@ adminApiRoutes.get("/collections", async (c) => {
1483
1483
  const queryResults = await stmt.all();
1484
1484
  results = queryResults.results;
1485
1485
  }
1486
- const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
1486
+ const fieldCountStmt = db2.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
1487
1487
  const { results: fieldCountResults } = await fieldCountStmt.all();
1488
1488
  const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
1489
1489
  const collections = (results || []).map((row) => ({
@@ -1510,13 +1510,13 @@ adminApiRoutes.get("/collections", async (c) => {
1510
1510
  adminApiRoutes.get("/collections/:id", async (c) => {
1511
1511
  try {
1512
1512
  const id = c.req.param("id");
1513
- const db = c.env.DB;
1514
- const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
1513
+ const db2 = c.env.DB;
1514
+ const stmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
1515
1515
  const collection = await stmt.bind(id).first();
1516
1516
  if (!collection) {
1517
1517
  return c.json({ error: "Collection not found" }, 404);
1518
1518
  }
1519
- const fieldsStmt = db.prepare(`
1519
+ const fieldsStmt = db2.prepare(`
1520
1520
  SELECT * FROM content_fields
1521
1521
  WHERE collection_id = ?
1522
1522
  ORDER BY field_order ASC
@@ -1565,13 +1565,13 @@ adminApiRoutes.post("/collections", async (c) => {
1565
1565
  }
1566
1566
  const validation = createCollectionSchema.safeParse(body);
1567
1567
  if (!validation.success) {
1568
- return c.json({ error: "Validation failed", details: validation.error.errors }, 400);
1568
+ return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
1569
1569
  }
1570
1570
  const validatedData = validation.data;
1571
- const db = c.env.DB;
1571
+ const db2 = c.env.DB;
1572
1572
  const ____user = c.get("user");
1573
1573
  const displayName = validatedData.displayName || validatedData.display_name || "";
1574
- const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
1574
+ const existingStmt = db2.prepare("SELECT id FROM collections WHERE name = ?");
1575
1575
  const existing = await existingStmt.bind(validatedData.name).first();
1576
1576
  if (existing) {
1577
1577
  return c.json({ error: "A collection with this name already exists" }, 400);
@@ -1600,7 +1600,7 @@ adminApiRoutes.post("/collections", async (c) => {
1600
1600
  };
1601
1601
  const collectionId = crypto.randomUUID();
1602
1602
  const now = Date.now();
1603
- const insertStmt = db.prepare(`
1603
+ const insertStmt = db2.prepare(`
1604
1604
  INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
1605
1605
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
1606
1606
  `);
@@ -1639,11 +1639,11 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
1639
1639
  const body = await c.req.json();
1640
1640
  const validation = updateCollectionSchema.safeParse(body);
1641
1641
  if (!validation.success) {
1642
- return c.json({ error: "Validation failed", details: validation.error.errors }, 400);
1642
+ return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
1643
1643
  }
1644
1644
  const validatedData = validation.data;
1645
- const db = c.env.DB;
1646
- const checkStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
1645
+ const db2 = c.env.DB;
1646
+ const checkStmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
1647
1647
  const existing = await checkStmt.bind(id).first();
1648
1648
  if (!existing) {
1649
1649
  return c.json({ error: "Collection not found" }, 404);
@@ -1668,7 +1668,7 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
1668
1668
  updateFields.push("updated_at = ?");
1669
1669
  updateParams.push(Date.now());
1670
1670
  updateParams.push(id);
1671
- const updateStmt = db.prepare(`
1671
+ const updateStmt = db2.prepare(`
1672
1672
  UPDATE collections
1673
1673
  SET ${updateFields.join(", ")}
1674
1674
  WHERE id = ?
@@ -1689,22 +1689,22 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
1689
1689
  adminApiRoutes.delete("/collections/:id", async (c) => {
1690
1690
  try {
1691
1691
  const id = c.req.param("id");
1692
- const db = c.env.DB;
1693
- const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
1692
+ const db2 = c.env.DB;
1693
+ const collectionStmt = db2.prepare("SELECT name FROM collections WHERE id = ?");
1694
1694
  const collection = await collectionStmt.bind(id).first();
1695
1695
  if (!collection) {
1696
1696
  return c.json({ error: "Collection not found" }, 404);
1697
1697
  }
1698
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
1698
+ const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
1699
1699
  const contentResult = await contentStmt.bind(id).first();
1700
1700
  if (contentResult && contentResult.count > 0) {
1701
1701
  return c.json({
1702
1702
  error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
1703
1703
  }, 400);
1704
1704
  }
1705
- const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
1705
+ const deleteFieldsStmt = db2.prepare("DELETE FROM content_fields WHERE collection_id = ?");
1706
1706
  await deleteFieldsStmt.bind(id).run();
1707
- const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
1707
+ const deleteStmt = db2.prepare("DELETE FROM collections WHERE id = ?");
1708
1708
  await deleteStmt.bind(id).run();
1709
1709
  try {
1710
1710
  await c.env.CACHE_KV.delete("cache:collections:all");
@@ -1720,9 +1720,9 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
1720
1720
  });
1721
1721
  adminApiRoutes.get("/migrations/status", async (c) => {
1722
1722
  try {
1723
- const { MigrationService: MigrationService2 } = await import('./migrations-IHERIQVD.js');
1724
- const db = c.env.DB;
1725
- const migrationService = new MigrationService2(db);
1723
+ const { MigrationService: MigrationService2 } = await import('./migrations-GVG73ZJC.js');
1724
+ const db2 = c.env.DB;
1725
+ const migrationService = new MigrationService2(db2);
1726
1726
  const status = await migrationService.getMigrationStatus();
1727
1727
  return c.json({
1728
1728
  success: true,
@@ -1745,9 +1745,9 @@ adminApiRoutes.post("/migrations/run", async (c) => {
1745
1745
  error: "Unauthorized. Admin access required."
1746
1746
  }, 403);
1747
1747
  }
1748
- const { MigrationService: MigrationService2 } = await import('./migrations-IHERIQVD.js');
1749
- const db = c.env.DB;
1750
- const migrationService = new MigrationService2(db);
1748
+ const { MigrationService: MigrationService2 } = await import('./migrations-GVG73ZJC.js');
1749
+ const db2 = c.env.DB;
1750
+ const migrationService = new MigrationService2(db2);
1751
1751
  const result = await migrationService.runPendingMigrations();
1752
1752
  return c.json({
1753
1753
  success: result.success,
@@ -1764,9 +1764,9 @@ adminApiRoutes.post("/migrations/run", async (c) => {
1764
1764
  });
1765
1765
  adminApiRoutes.get("/migrations/validate", async (c) => {
1766
1766
  try {
1767
- const { MigrationService: MigrationService2 } = await import('./migrations-IHERIQVD.js');
1768
- const db = c.env.DB;
1769
- const migrationService = new MigrationService2(db);
1767
+ const { MigrationService: MigrationService2 } = await import('./migrations-GVG73ZJC.js');
1768
+ const db2 = c.env.DB;
1769
+ const migrationService = new MigrationService2(db2);
1770
1770
  const validation = await migrationService.validateSchema();
1771
1771
  return c.json({
1772
1772
  success: true,
@@ -2158,10 +2158,10 @@ authRoutes.get("/login", async (c) => {
2158
2158
  message: message || void 0,
2159
2159
  version: c.get("appVersion")
2160
2160
  };
2161
- const db = c.env.DB;
2161
+ const db2 = c.env.DB;
2162
2162
  let demoLoginActive = false;
2163
2163
  try {
2164
- const plugin = await db.prepare("SELECT * FROM plugins WHERE id = ? AND status = ?").bind("demo-login-prefill", "active").first();
2164
+ const plugin = await db2.prepare("SELECT * FROM plugins WHERE id = ? AND status = ?").bind("demo-login-prefill", "active").first();
2165
2165
  demoLoginActive = !!plugin;
2166
2166
  } catch (error2) {
2167
2167
  }
@@ -2182,21 +2182,21 @@ authRoutes.post(
2182
2182
  "/register",
2183
2183
  async (c) => {
2184
2184
  try {
2185
- const db = c.env.DB;
2185
+ const db2 = c.env.DB;
2186
2186
  let requestData;
2187
2187
  try {
2188
2188
  requestData = await c.req.json();
2189
2189
  } catch (parseError) {
2190
2190
  return c.json({ error: "Invalid JSON in request body" }, 400);
2191
2191
  }
2192
- const validationSchema = await authValidationService.buildRegistrationSchema(db);
2192
+ const validationSchema = await authValidationService.buildRegistrationSchema(db2);
2193
2193
  let validatedData;
2194
2194
  try {
2195
2195
  validatedData = await validationSchema.parseAsync(requestData);
2196
2196
  } catch (validationError) {
2197
2197
  return c.json({
2198
2198
  error: "Validation failed",
2199
- details: validationError.errors?.map((e) => e.message) || [validationError.message || "Invalid request data"]
2199
+ details: validationError.issues?.map((e) => e.message) || [validationError.message || "Invalid request data"]
2200
2200
  }, 400);
2201
2201
  }
2202
2202
  const email = validatedData.email;
@@ -2205,14 +2205,14 @@ authRoutes.post(
2205
2205
  const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
2206
2206
  const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
2207
2207
  const normalizedEmail = email.toLowerCase();
2208
- const existingUser = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
2208
+ const existingUser = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
2209
2209
  if (existingUser) {
2210
2210
  return c.json({ error: "User with this email or username already exists" }, 400);
2211
2211
  }
2212
2212
  const passwordHash = await AuthManager.hashPassword(password);
2213
2213
  const userId = crypto.randomUUID();
2214
2214
  const now = /* @__PURE__ */ new Date();
2215
- await db.prepare(`
2215
+ await db2.prepare(`
2216
2216
  INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
2217
2217
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2218
2218
  `).bind(
@@ -2265,15 +2265,15 @@ authRoutes.post("/login", async (c) => {
2265
2265
  const body = await c.req.json();
2266
2266
  const validation = loginSchema.safeParse(body);
2267
2267
  if (!validation.success) {
2268
- return c.json({ error: "Validation failed", details: validation.error.errors }, 400);
2268
+ return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
2269
2269
  }
2270
2270
  const { email, password } = validation.data;
2271
- const db = c.env.DB;
2271
+ const db2 = c.env.DB;
2272
2272
  const normalizedEmail = email.toLowerCase();
2273
2273
  const cache = getCacheService(CACHE_CONFIGS.user);
2274
2274
  let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
2275
2275
  if (!user) {
2276
- user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
2276
+ user = await db2.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
2277
2277
  if (user) {
2278
2278
  await cache.set(cache.generateKey("user", `email:${normalizedEmail}`), user);
2279
2279
  await cache.set(cache.generateKey("user", user.id), user);
@@ -2294,7 +2294,7 @@ authRoutes.post("/login", async (c) => {
2294
2294
  maxAge: 60 * 60 * 24
2295
2295
  // 24 hours
2296
2296
  });
2297
- await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
2297
+ await db2.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
2298
2298
  await cache.delete(cache.generateKey("user", user.id));
2299
2299
  await cache.delete(cache.generateKey("user", `email:${normalizedEmail}`));
2300
2300
  return c.json({
@@ -2341,8 +2341,8 @@ authRoutes.get("/me", requireAuth(), async (c) => {
2341
2341
  if (!user) {
2342
2342
  return c.json({ error: "Not authenticated" }, 401);
2343
2343
  }
2344
- const db = c.env.DB;
2345
- const userData = await db.prepare("SELECT id, email, username, first_name, last_name, role, created_at FROM users WHERE id = ?").bind(user.userId).first();
2344
+ const db2 = c.env.DB;
2345
+ const userData = await db2.prepare("SELECT id, email, username, first_name, last_name, role, created_at FROM users WHERE id = ?").bind(user.userId).first();
2346
2346
  if (!userData) {
2347
2347
  return c.json({ error: "User not found" }, 404);
2348
2348
  }
@@ -2374,7 +2374,7 @@ authRoutes.post("/refresh", requireAuth(), async (c) => {
2374
2374
  });
2375
2375
  authRoutes.post("/register/form", async (c) => {
2376
2376
  try {
2377
- const db = c.env.DB;
2377
+ const db2 = c.env.DB;
2378
2378
  const formData = await c.req.formData();
2379
2379
  const requestData = {
2380
2380
  email: formData.get("email"),
@@ -2385,12 +2385,12 @@ authRoutes.post("/register/form", async (c) => {
2385
2385
  };
2386
2386
  const normalizedEmail = requestData.email?.toLowerCase();
2387
2387
  requestData.email = normalizedEmail;
2388
- const validationSchema = await authValidationService.buildRegistrationSchema(db);
2388
+ const validationSchema = await authValidationService.buildRegistrationSchema(db2);
2389
2389
  const validation = await validationSchema.safeParseAsync(requestData);
2390
2390
  if (!validation.success) {
2391
2391
  return c.html(html`
2392
2392
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
2393
- ${validation.error.errors.map((err) => err.message).join(", ")}
2393
+ ${validation.error.issues.map((err) => err.message).join(", ")}
2394
2394
  </div>
2395
2395
  `);
2396
2396
  }
@@ -2399,7 +2399,7 @@ authRoutes.post("/register/form", async (c) => {
2399
2399
  const username = validatedData.username || authValidationService.generateDefaultValue("username", validatedData);
2400
2400
  const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
2401
2401
  const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
2402
- const existingUser = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
2402
+ const existingUser = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
2403
2403
  if (existingUser) {
2404
2404
  return c.html(html`
2405
2405
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -2410,7 +2410,7 @@ authRoutes.post("/register/form", async (c) => {
2410
2410
  const passwordHash = await AuthManager.hashPassword(password);
2411
2411
  const userId = crypto.randomUUID();
2412
2412
  const now = /* @__PURE__ */ new Date();
2413
- await db.prepare(`
2413
+ await db2.prepare(`
2414
2414
  INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
2415
2415
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2416
2416
  `).bind(
@@ -2465,12 +2465,12 @@ authRoutes.post("/login/form", async (c) => {
2465
2465
  if (!validation.success) {
2466
2466
  return c.html(html`
2467
2467
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
2468
- ${validation.error.errors.map((err) => err.message).join(", ")}
2468
+ ${validation.error.issues.map((err) => err.message).join(", ")}
2469
2469
  </div>
2470
2470
  `);
2471
2471
  }
2472
- const db = c.env.DB;
2473
- const user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
2472
+ const db2 = c.env.DB;
2473
+ const user = await db2.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
2474
2474
  if (!user) {
2475
2475
  return c.html(html`
2476
2476
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -2495,7 +2495,7 @@ authRoutes.post("/login/form", async (c) => {
2495
2495
  maxAge: 60 * 60 * 24
2496
2496
  // 24 hours
2497
2497
  });
2498
- await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
2498
+ await db2.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
2499
2499
  return c.html(html`
2500
2500
  <div id="form-response">
2501
2501
  <div class="rounded-lg bg-green-100 dark:bg-lime-500/10 p-4 ring-1 ring-green-400 dark:ring-lime-500/20">
@@ -2526,8 +2526,8 @@ authRoutes.post("/login/form", async (c) => {
2526
2526
  });
2527
2527
  authRoutes.post("/seed-admin", async (c) => {
2528
2528
  try {
2529
- const db = c.env.DB;
2530
- await db.prepare(`
2529
+ const db2 = c.env.DB;
2530
+ await db2.prepare(`
2531
2531
  CREATE TABLE IF NOT EXISTS users (
2532
2532
  id TEXT PRIMARY KEY,
2533
2533
  email TEXT NOT NULL UNIQUE,
@@ -2543,10 +2543,10 @@ authRoutes.post("/seed-admin", async (c) => {
2543
2543
  updated_at INTEGER NOT NULL
2544
2544
  )
2545
2545
  `).run();
2546
- const existingAdmin = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
2546
+ const existingAdmin = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
2547
2547
  if (existingAdmin) {
2548
2548
  const passwordHash2 = await AuthManager.hashPassword("sonicjs!");
2549
- await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
2549
+ await db2.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
2550
2550
  return c.json({
2551
2551
  message: "Admin user already exists (password updated)",
2552
2552
  user: {
@@ -2561,7 +2561,7 @@ authRoutes.post("/seed-admin", async (c) => {
2561
2561
  const userId = "admin-user-id";
2562
2562
  const now = Date.now();
2563
2563
  const adminEmail = "admin@sonicjs.com".toLowerCase();
2564
- await db.prepare(`
2564
+ await db2.prepare(`
2565
2565
  INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
2566
2566
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2567
2567
  `).bind(
@@ -2608,8 +2608,8 @@ authRoutes.get("/accept-invitation", async (c) => {
2608
2608
  </html>
2609
2609
  `);
2610
2610
  }
2611
- const db = c.env.DB;
2612
- const userStmt = db.prepare(`
2611
+ const db2 = c.env.DB;
2612
+ const userStmt = db2.prepare(`
2613
2613
  SELECT id, email, first_name, last_name, role, invited_at
2614
2614
  FROM users
2615
2615
  WHERE invitation_token = ? AND is_active = 0
@@ -2755,8 +2755,8 @@ authRoutes.post("/accept-invitation", async (c) => {
2755
2755
  if (password.length < 8) {
2756
2756
  return c.json({ error: "Password must be at least 8 characters long" }, 400);
2757
2757
  }
2758
- const db = c.env.DB;
2759
- const userStmt = db.prepare(`
2758
+ const db2 = c.env.DB;
2759
+ const userStmt = db2.prepare(`
2760
2760
  SELECT id, email, first_name, last_name, role, invited_at
2761
2761
  FROM users
2762
2762
  WHERE invitation_token = ? AND is_active = 0
@@ -2770,7 +2770,7 @@ authRoutes.post("/accept-invitation", async (c) => {
2770
2770
  if (invitationAge > maxAge) {
2771
2771
  return c.json({ error: "Invitation has expired" }, 400);
2772
2772
  }
2773
- const existingUsernameStmt = db.prepare(`
2773
+ const existingUsernameStmt = db2.prepare(`
2774
2774
  SELECT id FROM users WHERE username = ? AND id != ?
2775
2775
  `);
2776
2776
  const existingUsername = await existingUsernameStmt.bind(username, invitedUser.id).first();
@@ -2778,7 +2778,7 @@ authRoutes.post("/accept-invitation", async (c) => {
2778
2778
  return c.json({ error: "Username is already taken" }, 400);
2779
2779
  }
2780
2780
  const passwordHash = await AuthManager.hashPassword(password);
2781
- const updateStmt = db.prepare(`
2781
+ const updateStmt = db2.prepare(`
2782
2782
  UPDATE users SET
2783
2783
  username = ?,
2784
2784
  password_hash = ?,
@@ -2821,8 +2821,8 @@ authRoutes.post("/request-password-reset", async (c) => {
2821
2821
  if (!emailRegex.test(email)) {
2822
2822
  return c.json({ error: "Please enter a valid email address" }, 400);
2823
2823
  }
2824
- const db = c.env.DB;
2825
- const userStmt = db.prepare(`
2824
+ const db2 = c.env.DB;
2825
+ const userStmt = db2.prepare(`
2826
2826
  SELECT id, email, first_name, last_name FROM users
2827
2827
  WHERE email = ? AND is_active = 1
2828
2828
  `);
@@ -2835,7 +2835,7 @@ authRoutes.post("/request-password-reset", async (c) => {
2835
2835
  }
2836
2836
  const resetToken = crypto.randomUUID();
2837
2837
  const resetExpires = Date.now() + 60 * 60 * 1e3;
2838
- const updateStmt = db.prepare(`
2838
+ const updateStmt = db2.prepare(`
2839
2839
  UPDATE users SET
2840
2840
  password_reset_token = ?,
2841
2841
  password_reset_expires = ?,
@@ -2875,8 +2875,8 @@ authRoutes.get("/reset-password", async (c) => {
2875
2875
  </html>
2876
2876
  `);
2877
2877
  }
2878
- const db = c.env.DB;
2879
- const userStmt = db.prepare(`
2878
+ const db2 = c.env.DB;
2879
+ const userStmt = db2.prepare(`
2880
2880
  SELECT id, email, first_name, last_name, password_reset_expires
2881
2881
  FROM users
2882
2882
  WHERE password_reset_token = ? AND is_active = 1
@@ -3013,8 +3013,8 @@ authRoutes.post("/reset-password", async (c) => {
3013
3013
  if (password.length < 8) {
3014
3014
  return c.json({ error: "Password must be at least 8 characters long" }, 400);
3015
3015
  }
3016
- const db = c.env.DB;
3017
- const userStmt = db.prepare(`
3016
+ const db2 = c.env.DB;
3017
+ const userStmt = db2.prepare(`
3018
3018
  SELECT id, email, password_hash, password_reset_expires
3019
3019
  FROM users
3020
3020
  WHERE password_reset_token = ? AND is_active = 1
@@ -3028,7 +3028,7 @@ authRoutes.post("/reset-password", async (c) => {
3028
3028
  }
3029
3029
  const newPasswordHash = await AuthManager.hashPassword(password);
3030
3030
  try {
3031
- const historyStmt = db.prepare(`
3031
+ const historyStmt = db2.prepare(`
3032
3032
  INSERT INTO password_history (id, user_id, password_hash, created_at)
3033
3033
  VALUES (?, ?, ?, ?)
3034
3034
  `);
@@ -3041,7 +3041,7 @@ authRoutes.post("/reset-password", async (c) => {
3041
3041
  } catch (historyError) {
3042
3042
  console.warn("Could not store password history:", historyError);
3043
3043
  }
3044
- const updateStmt = db.prepare(`
3044
+ const updateStmt = db2.prepare(`
3045
3045
  UPDATE users SET
3046
3046
  password_hash = ?,
3047
3047
  password_reset_token = NULL,
@@ -3061,19 +3061,269 @@ authRoutes.post("/reset-password", async (c) => {
3061
3061
  }
3062
3062
  });
3063
3063
  var auth_default = authRoutes;
3064
+ var app = new Hono();
3065
+ app.post("/test-cleanup", async (c) => {
3066
+ const db2 = c.env.DB;
3067
+ if (c.env.ENVIRONMENT === "production") {
3068
+ return c.json({ error: "Cleanup endpoint not available in production" }, 403);
3069
+ }
3070
+ try {
3071
+ let deletedCount = 0;
3072
+ await db2.prepare(`
3073
+ DELETE FROM content_versions
3074
+ WHERE content_id IN (
3075
+ SELECT id FROM content
3076
+ WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
3077
+ )
3078
+ `).run();
3079
+ await db2.prepare(`
3080
+ DELETE FROM workflow_history
3081
+ WHERE content_id IN (
3082
+ SELECT id FROM content
3083
+ WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
3084
+ )
3085
+ `).run();
3086
+ try {
3087
+ await db2.prepare(`
3088
+ DELETE FROM content_data
3089
+ WHERE content_id IN (
3090
+ SELECT id FROM content
3091
+ WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
3092
+ )
3093
+ `).run();
3094
+ } catch (e) {
3095
+ }
3096
+ const contentResult = await db2.prepare(`
3097
+ DELETE FROM content
3098
+ WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
3099
+ `).run();
3100
+ deletedCount += contentResult.meta?.changes || 0;
3101
+ await db2.prepare(`
3102
+ DELETE FROM api_tokens
3103
+ WHERE user_id IN (
3104
+ SELECT id FROM users
3105
+ WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
3106
+ )
3107
+ `).run();
3108
+ await db2.prepare(`
3109
+ DELETE FROM media
3110
+ WHERE uploaded_by IN (
3111
+ SELECT id FROM users
3112
+ WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
3113
+ )
3114
+ `).run();
3115
+ const usersResult = await db2.prepare(`
3116
+ DELETE FROM users
3117
+ WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
3118
+ `).run();
3119
+ deletedCount += usersResult.meta?.changes || 0;
3120
+ try {
3121
+ await db2.prepare(`
3122
+ DELETE FROM collection_fields
3123
+ WHERE collection_id IN (
3124
+ SELECT id FROM collections
3125
+ WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
3126
+ )
3127
+ `).run();
3128
+ } catch (e) {
3129
+ }
3130
+ await db2.prepare(`
3131
+ DELETE FROM content
3132
+ WHERE collection_id IN (
3133
+ SELECT id FROM collections
3134
+ WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
3135
+ )
3136
+ `).run();
3137
+ const collectionsResult = await db2.prepare(`
3138
+ DELETE FROM collections
3139
+ WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
3140
+ `).run();
3141
+ deletedCount += collectionsResult.meta?.changes || 0;
3142
+ try {
3143
+ await db2.prepare(`
3144
+ DELETE FROM content_data WHERE content_id NOT IN (SELECT id FROM content)
3145
+ `).run();
3146
+ } catch (e) {
3147
+ }
3148
+ try {
3149
+ await db2.prepare(`
3150
+ DELETE FROM collection_fields WHERE collection_id NOT IN (SELECT id FROM collections)
3151
+ `).run();
3152
+ } catch (e) {
3153
+ }
3154
+ try {
3155
+ await db2.prepare(`
3156
+ DELETE FROM content_versions WHERE content_id NOT IN (SELECT id FROM content)
3157
+ `).run();
3158
+ } catch (e) {
3159
+ }
3160
+ try {
3161
+ await db2.prepare(`
3162
+ DELETE FROM workflow_history WHERE content_id NOT IN (SELECT id FROM content)
3163
+ `).run();
3164
+ } catch (e) {
3165
+ }
3166
+ await db2.prepare(`
3167
+ DELETE FROM activity_logs
3168
+ WHERE id NOT IN (
3169
+ SELECT id FROM activity_logs
3170
+ ORDER BY created_at DESC
3171
+ LIMIT 100
3172
+ )
3173
+ `).run();
3174
+ return c.json({
3175
+ success: true,
3176
+ deletedCount,
3177
+ message: "Test data cleaned up successfully"
3178
+ });
3179
+ } catch (error) {
3180
+ console.error("Test cleanup error:", error);
3181
+ return c.json({
3182
+ success: false,
3183
+ error: error instanceof Error ? error.message : "Unknown error"
3184
+ }, 500);
3185
+ }
3186
+ });
3187
+ app.post("/test-cleanup/users", async (c) => {
3188
+ const db2 = c.env.DB;
3189
+ if (c.env.ENVIRONMENT === "production") {
3190
+ return c.json({ error: "Cleanup endpoint not available in production" }, 403);
3191
+ }
3192
+ try {
3193
+ const result = await db2.prepare(`
3194
+ DELETE FROM users
3195
+ WHERE email != 'admin@sonicjs.com'
3196
+ AND (
3197
+ email LIKE '%test%'
3198
+ OR email LIKE '%example.com%'
3199
+ OR first_name = 'Test'
3200
+ )
3201
+ `).run();
3202
+ return c.json({
3203
+ success: true,
3204
+ deletedCount: result.meta?.changes || 0,
3205
+ message: "Test users cleaned up successfully"
3206
+ });
3207
+ } catch (error) {
3208
+ console.error("User cleanup error:", error);
3209
+ return c.json({
3210
+ success: false,
3211
+ error: error instanceof Error ? error.message : "Unknown error"
3212
+ }, 500);
3213
+ }
3214
+ });
3215
+ app.post("/test-cleanup/collections", async (c) => {
3216
+ const db2 = c.env.DB;
3217
+ if (c.env.ENVIRONMENT === "production") {
3218
+ return c.json({ error: "Cleanup endpoint not available in production" }, 403);
3219
+ }
3220
+ try {
3221
+ let deletedCount = 0;
3222
+ const collections = await db2.prepare(`
3223
+ SELECT id FROM collections
3224
+ WHERE name LIKE 'test_%'
3225
+ OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
3226
+ `).all();
3227
+ if (collections.results && collections.results.length > 0) {
3228
+ const collectionIds = collections.results.map((c2) => c2.id);
3229
+ for (const id of collectionIds) {
3230
+ await db2.prepare("DELETE FROM collection_fields WHERE collection_id = ?").bind(id).run();
3231
+ }
3232
+ for (const id of collectionIds) {
3233
+ await db2.prepare("DELETE FROM content WHERE collection_id = ?").bind(id).run();
3234
+ }
3235
+ const result = await db2.prepare(`
3236
+ DELETE FROM collections
3237
+ WHERE id IN (${collectionIds.map(() => "?").join(",")})
3238
+ `).bind(...collectionIds).run();
3239
+ deletedCount = result.meta?.changes || 0;
3240
+ }
3241
+ return c.json({
3242
+ success: true,
3243
+ deletedCount,
3244
+ message: "Test collections cleaned up successfully"
3245
+ });
3246
+ } catch (error) {
3247
+ console.error("Collection cleanup error:", error);
3248
+ return c.json({
3249
+ success: false,
3250
+ error: error instanceof Error ? error.message : "Unknown error"
3251
+ }, 500);
3252
+ }
3253
+ });
3254
+ app.post("/test-cleanup/content", async (c) => {
3255
+ const db2 = c.env.DB;
3256
+ if (c.env.ENVIRONMENT === "production") {
3257
+ return c.json({ error: "Cleanup endpoint not available in production" }, 403);
3258
+ }
3259
+ try {
3260
+ const result = await db2.prepare(`
3261
+ DELETE FROM content
3262
+ WHERE title LIKE 'Test %'
3263
+ OR title LIKE '%E2E%'
3264
+ OR title LIKE '%Playwright%'
3265
+ OR title LIKE '%Sample%'
3266
+ `).run();
3267
+ await db2.prepare(`
3268
+ DELETE FROM content_data
3269
+ WHERE content_id NOT IN (SELECT id FROM content)
3270
+ `).run();
3271
+ return c.json({
3272
+ success: true,
3273
+ deletedCount: result.meta?.changes || 0,
3274
+ message: "Test content cleaned up successfully"
3275
+ });
3276
+ } catch (error) {
3277
+ console.error("Content cleanup error:", error);
3278
+ return c.json({
3279
+ success: false,
3280
+ error: error instanceof Error ? error.message : "Unknown error"
3281
+ }, 500);
3282
+ }
3283
+ });
3284
+ var test_cleanup_default = app;
3064
3285
 
3065
3286
  // src/templates/pages/admin-content-form.template.ts
3066
3287
  init_admin_layout_catalyst_template();
3067
3288
 
3068
3289
  // src/templates/components/dynamic-field.template.ts
3069
3290
  function renderDynamicField(field, options = {}) {
3070
- const { value = "", errors = [], disabled = false, className = "" } = options;
3291
+ const { value = "", errors = [], disabled = false, className = "", pluginStatuses = {} } = options;
3071
3292
  const opts = field.field_options || {};
3072
3293
  const required = field.is_required ? "required" : "";
3073
3294
  const baseClasses = `w-full rounded-lg px-3 py-2 text-sm text-zinc-950 dark:text-white bg-white dark:bg-zinc-800 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow ${className}`;
3074
3295
  const errorClasses = errors.length > 0 ? "ring-pink-600 dark:ring-pink-500 focus:ring-pink-600 dark:focus:ring-pink-500" : "";
3075
3296
  const fieldId = `field-${field.field_name}`;
3076
3297
  const fieldName = field.field_name;
3298
+ let fallbackToTextarea = false;
3299
+ let fallbackWarning = "";
3300
+ if (field.field_type === "quill" && !pluginStatuses.quillEnabled) {
3301
+ fallbackToTextarea = true;
3302
+ fallbackWarning = "\u26A0\uFE0F Quill Editor plugin is inactive. Using textarea fallback.";
3303
+ } else if (field.field_type === "mdxeditor" && !pluginStatuses.mdxeditorEnabled) {
3304
+ fallbackToTextarea = true;
3305
+ fallbackWarning = "\u26A0\uFE0F MDXEditor plugin is inactive. Using textarea fallback.";
3306
+ } else if (field.field_type === "tinymce" && !pluginStatuses.tinymceEnabled) {
3307
+ fallbackToTextarea = true;
3308
+ fallbackWarning = "\u26A0\uFE0F TinyMCE plugin is inactive. Using textarea fallback.";
3309
+ }
3310
+ if (fallbackToTextarea) {
3311
+ return `
3312
+ <div>
3313
+ ${fallbackWarning ? `<div class="mb-2 px-3 py-2 bg-amber-50 dark:bg-amber-900/20 text-amber-900 dark:text-amber-200 text-xs rounded-lg border border-amber-200 dark:border-amber-800">${fallbackWarning}</div>` : ""}
3314
+ <textarea
3315
+ id="${fieldId}"
3316
+ name="${fieldName}"
3317
+ rows="${opts.rows || opts.height ? Math.floor(opts.height / 25) : 10}"
3318
+ placeholder="${opts.placeholder || ""}"
3319
+ maxlength="${opts.maxLength || ""}"
3320
+ class="${baseClasses} ${errorClasses} resize-y"
3321
+ ${required}
3322
+ ${disabled ? "disabled" : ""}
3323
+ >${escapeHtml2(value)}</textarea>
3324
+ </div>
3325
+ `;
3326
+ }
3077
3327
  let fieldHTML = "";
3078
3328
  switch (field.field_type) {
3079
3329
  case "text":
@@ -3996,9 +4246,9 @@ function createQuillEditorPlugin() {
3996
4246
  }
3997
4247
  createQuillEditorPlugin();
3998
4248
 
3999
- // src/plugins/available/mdxeditor-plugin/index.ts
4249
+ // src/plugins/available/easy-mdx/index.ts
4000
4250
  var builder2 = PluginBuilder.create({
4001
- name: "mdxeditor-plugin",
4251
+ name: "easy-mdx",
4002
4252
  version: "1.0.0",
4003
4253
  description: "Lightweight markdown editor with live preview"
4004
4254
  });
@@ -4214,17 +4464,25 @@ function renderContentFormPage(data) {
4214
4464
  if (fieldName === "slug") return data.slug || data.data?.[fieldName] || "";
4215
4465
  return data.data?.[fieldName] || "";
4216
4466
  };
4467
+ const pluginStatuses = {
4468
+ quillEnabled: data.quillEnabled || false,
4469
+ mdxeditorEnabled: data.mdxeditorEnabled || false,
4470
+ tinymceEnabled: data.tinymceEnabled || false
4471
+ };
4217
4472
  const coreFieldsHTML = coreFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
4218
4473
  value: getFieldValue(field.field_name),
4219
- errors: data.validationErrors?.[field.field_name] || []
4474
+ errors: data.validationErrors?.[field.field_name] || [],
4475
+ pluginStatuses
4220
4476
  }));
4221
4477
  const contentFieldsHTML = contentFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
4222
4478
  value: getFieldValue(field.field_name),
4223
- errors: data.validationErrors?.[field.field_name] || []
4479
+ errors: data.validationErrors?.[field.field_name] || [],
4480
+ pluginStatuses
4224
4481
  }));
4225
4482
  const metaFieldsHTML = metaFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
4226
4483
  value: getFieldValue(field.field_name),
4227
- errors: data.validationErrors?.[field.field_name] || []
4484
+ errors: data.validationErrors?.[field.field_name] || [],
4485
+ pluginStatuses
4228
4486
  }));
4229
4487
  const pageContent = `
4230
4488
  <div class="space-y-6">
@@ -5653,9 +5911,9 @@ function escapeHtml3(text) {
5653
5911
  }
5654
5912
 
5655
5913
  // src/middleware/plugin-middleware.ts
5656
- async function isPluginActive2(db, pluginId) {
5914
+ async function isPluginActive2(db2, pluginId) {
5657
5915
  try {
5658
- const result = await db.prepare("SELECT status FROM plugins WHERE id = ?").bind(pluginId).first();
5916
+ const result = await db2.prepare("SELECT status FROM plugins WHERE id = ?").bind(pluginId).first();
5659
5917
  return result?.status === "active";
5660
5918
  } catch (error) {
5661
5919
  console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error);
@@ -5666,12 +5924,12 @@ async function isPluginActive2(db, pluginId) {
5666
5924
  // src/routes/admin-content.ts
5667
5925
  var adminContentRoutes = new Hono();
5668
5926
  adminContentRoutes.use("*", requireAuth());
5669
- async function getCollectionFields(db, collectionId) {
5927
+ async function getCollectionFields(db2, collectionId) {
5670
5928
  const cache = getCacheService(CACHE_CONFIGS.collection);
5671
5929
  return cache.getOrSet(
5672
5930
  cache.generateKey("fields", collectionId),
5673
5931
  async () => {
5674
- const collectionStmt = db.prepare("SELECT schema FROM collections WHERE id = ?");
5932
+ const collectionStmt = db2.prepare("SELECT schema FROM collections WHERE id = ?");
5675
5933
  const collectionRow = await collectionStmt.bind(collectionId).first();
5676
5934
  if (collectionRow && collectionRow.schema) {
5677
5935
  try {
@@ -5702,7 +5960,7 @@ async function getCollectionFields(db, collectionId) {
5702
5960
  console.error("Error parsing collection schema:", e);
5703
5961
  }
5704
5962
  }
5705
- const stmt = db.prepare(`
5963
+ const stmt = db2.prepare(`
5706
5964
  SELECT * FROM content_fields
5707
5965
  WHERE collection_id = ?
5708
5966
  ORDER BY field_order ASC
@@ -5721,12 +5979,12 @@ async function getCollectionFields(db, collectionId) {
5721
5979
  }
5722
5980
  );
5723
5981
  }
5724
- async function getCollection(db, collectionId) {
5982
+ async function getCollection(db2, collectionId) {
5725
5983
  const cache = getCacheService(CACHE_CONFIGS.collection);
5726
5984
  return cache.getOrSet(
5727
5985
  cache.generateKey("collection", collectionId),
5728
5986
  async () => {
5729
- const stmt = db.prepare("SELECT * FROM collections WHERE id = ? AND is_active = 1");
5987
+ const stmt = db2.prepare("SELECT * FROM collections WHERE id = ? AND is_active = 1");
5730
5988
  const collection = await stmt.bind(collectionId).first();
5731
5989
  if (!collection) return null;
5732
5990
  return {
@@ -5743,14 +6001,14 @@ adminContentRoutes.get("/", async (c) => {
5743
6001
  try {
5744
6002
  const user = c.get("user");
5745
6003
  const url = new URL(c.req.url);
5746
- const db = c.env.DB;
6004
+ const db2 = c.env.DB;
5747
6005
  const page = parseInt(url.searchParams.get("page") || "1");
5748
6006
  const limit = parseInt(url.searchParams.get("limit") || "20");
5749
6007
  const modelName = url.searchParams.get("model") || "all";
5750
6008
  const status = url.searchParams.get("status") || "all";
5751
6009
  const search = url.searchParams.get("search") || "";
5752
6010
  const offset = (page - 1) * limit;
5753
- const collectionsStmt = db.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name");
6011
+ const collectionsStmt = db2.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name");
5754
6012
  const { results: collectionsResults } = await collectionsStmt.all();
5755
6013
  const models = (collectionsResults || []).map((row) => ({
5756
6014
  name: row.name,
@@ -5776,7 +6034,7 @@ adminContentRoutes.get("/", async (c) => {
5776
6034
  conditions.push("c.status = 'deleted'");
5777
6035
  }
5778
6036
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
5779
- const countStmt = db.prepare(`
6037
+ const countStmt = db2.prepare(`
5780
6038
  SELECT COUNT(*) as count
5781
6039
  FROM content c
5782
6040
  JOIN collections col ON c.collection_id = col.id
@@ -5784,7 +6042,7 @@ adminContentRoutes.get("/", async (c) => {
5784
6042
  `);
5785
6043
  const countResult = await countStmt.bind(...params).first();
5786
6044
  const totalItems = countResult?.count || 0;
5787
- const contentStmt = db.prepare(`
6045
+ const contentStmt = db2.prepare(`
5788
6046
  SELECT c.id, c.title, c.slug, c.status, c.created_at, c.updated_at,
5789
6047
  col.name as collection_name, col.display_name as collection_display_name,
5790
6048
  u.first_name, u.last_name, u.email as author_email
@@ -5885,8 +6143,8 @@ adminContentRoutes.get("/new", async (c) => {
5885
6143
  const url = new URL(c.req.url);
5886
6144
  const collectionId = url.searchParams.get("collection");
5887
6145
  if (!collectionId) {
5888
- const db2 = c.env.DB;
5889
- const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name");
6146
+ const db3 = c.env.DB;
6147
+ const collectionsStmt = db3.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name");
5890
6148
  const { results } = await collectionsStmt.all();
5891
6149
  const collections = (results || []).map((row) => ({
5892
6150
  id: row.id,
@@ -5927,8 +6185,8 @@ adminContentRoutes.get("/new", async (c) => {
5927
6185
  `;
5928
6186
  return c.html(selectionHTML);
5929
6187
  }
5930
- const db = c.env.DB;
5931
- const collection = await getCollection(db, collectionId);
6188
+ const db2 = c.env.DB;
6189
+ const collection = await getCollection(db2, collectionId);
5932
6190
  if (!collection) {
5933
6191
  const formData2 = {
5934
6192
  collection: { id: "", name: "", display_name: "Unknown", schema: {} },
@@ -5942,28 +6200,28 @@ adminContentRoutes.get("/new", async (c) => {
5942
6200
  };
5943
6201
  return c.html(renderContentFormPage(formData2));
5944
6202
  }
5945
- const fields = await getCollectionFields(db, collectionId);
5946
- const workflowEnabled = await isPluginActive2(db, "workflow");
5947
- const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
6203
+ const fields = await getCollectionFields(db2, collectionId);
6204
+ const workflowEnabled = await isPluginActive2(db2, "workflow");
6205
+ const tinymceEnabled = await isPluginActive2(db2, "tinymce-plugin");
5948
6206
  let tinymceSettings;
5949
6207
  if (tinymceEnabled) {
5950
- const pluginService = new PluginService(db);
6208
+ const pluginService = new PluginService(db2);
5951
6209
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
5952
6210
  tinymceSettings = tinymcePlugin2?.settings;
5953
6211
  }
5954
- const quillEnabled = await isPluginActive2(db, "quill-editor");
6212
+ const quillEnabled = await isPluginActive2(db2, "quill-editor");
5955
6213
  let quillSettings;
5956
6214
  if (quillEnabled) {
5957
- const pluginService = new PluginService(db);
6215
+ const pluginService = new PluginService(db2);
5958
6216
  const quillPlugin = await pluginService.getPlugin("quill-editor");
5959
6217
  quillSettings = quillPlugin?.settings;
5960
6218
  }
5961
- const mdxeditorEnabled = await isPluginActive2(db, "mdxeditor-plugin");
6219
+ const mdxeditorEnabled = await isPluginActive2(db2, "easy-mdx");
5962
6220
  let mdxeditorSettings;
5963
6221
  if (mdxeditorEnabled) {
5964
- const pluginService = new PluginService(db);
5965
- const mdxeditorPlugin2 = await pluginService.getPlugin("mdxeditor-plugin");
5966
- mdxeditorSettings = mdxeditorPlugin2?.settings;
6222
+ const pluginService = new PluginService(db2);
6223
+ const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
6224
+ mdxeditorSettings = mdxeditorPlugin?.settings;
5967
6225
  }
5968
6226
  console.log("[Content Form /new] Editor plugins status:", {
5969
6227
  tinymce: tinymceEnabled,
@@ -6008,14 +6266,14 @@ adminContentRoutes.get("/:id/edit", async (c) => {
6008
6266
  try {
6009
6267
  const id = c.req.param("id");
6010
6268
  const user = c.get("user");
6011
- const db = c.env.DB;
6269
+ const db2 = c.env.DB;
6012
6270
  const url = new URL(c.req.url);
6013
6271
  const referrerParams = url.searchParams.get("ref") || "";
6014
6272
  const cache = getCacheService(CACHE_CONFIGS.content);
6015
6273
  const content = await cache.getOrSet(
6016
6274
  cache.generateKey("content", id),
6017
6275
  async () => {
6018
- const contentStmt = db.prepare(`
6276
+ const contentStmt = db2.prepare(`
6019
6277
  SELECT c.*, col.id as collection_id, col.name as collection_name,
6020
6278
  col.display_name as collection_display_name, col.description as collection_description,
6021
6279
  col.schema as collection_schema
@@ -6046,29 +6304,29 @@ adminContentRoutes.get("/:id/edit", async (c) => {
6046
6304
  description: content.collection_description,
6047
6305
  schema: content.collection_schema ? JSON.parse(content.collection_schema) : {}
6048
6306
  };
6049
- const fields = await getCollectionFields(db, content.collection_id);
6307
+ const fields = await getCollectionFields(db2, content.collection_id);
6050
6308
  const contentData = content.data ? JSON.parse(content.data) : {};
6051
- const workflowEnabled = await isPluginActive2(db, "workflow");
6052
- const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
6309
+ const workflowEnabled = await isPluginActive2(db2, "workflow");
6310
+ const tinymceEnabled = await isPluginActive2(db2, "tinymce-plugin");
6053
6311
  let tinymceSettings;
6054
6312
  if (tinymceEnabled) {
6055
- const pluginService = new PluginService(db);
6313
+ const pluginService = new PluginService(db2);
6056
6314
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
6057
6315
  tinymceSettings = tinymcePlugin2?.settings;
6058
6316
  }
6059
- const quillEnabled = await isPluginActive2(db, "quill-editor");
6317
+ const quillEnabled = await isPluginActive2(db2, "quill-editor");
6060
6318
  let quillSettings;
6061
6319
  if (quillEnabled) {
6062
- const pluginService = new PluginService(db);
6320
+ const pluginService = new PluginService(db2);
6063
6321
  const quillPlugin = await pluginService.getPlugin("quill-editor");
6064
6322
  quillSettings = quillPlugin?.settings;
6065
6323
  }
6066
- const mdxeditorEnabled = await isPluginActive2(db, "mdxeditor-plugin");
6324
+ const mdxeditorEnabled = await isPluginActive2(db2, "easy-mdx");
6067
6325
  let mdxeditorSettings;
6068
6326
  if (mdxeditorEnabled) {
6069
- const pluginService = new PluginService(db);
6070
- const mdxeditorPlugin2 = await pluginService.getPlugin("mdxeditor-plugin");
6071
- mdxeditorSettings = mdxeditorPlugin2?.settings;
6327
+ const pluginService = new PluginService(db2);
6328
+ const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
6329
+ mdxeditorSettings = mdxeditorPlugin?.settings;
6072
6330
  }
6073
6331
  const formData = {
6074
6332
  id: content.id,
@@ -6128,8 +6386,8 @@ adminContentRoutes.post("/", async (c) => {
6128
6386
  </div>
6129
6387
  `);
6130
6388
  }
6131
- const db = c.env.DB;
6132
- const collection = await getCollection(db, collectionId);
6389
+ const db2 = c.env.DB;
6390
+ const collection = await getCollection(db2, collectionId);
6133
6391
  if (!collection) {
6134
6392
  return c.html(html`
6135
6393
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -6137,7 +6395,7 @@ adminContentRoutes.post("/", async (c) => {
6137
6395
  </div>
6138
6396
  `);
6139
6397
  }
6140
- const fields = await getCollectionFields(db, collectionId);
6398
+ const fields = await getCollectionFields(db2, collectionId);
6141
6399
  const data = {};
6142
6400
  const errors = {};
6143
6401
  for (const field of fields) {
@@ -6195,13 +6453,13 @@ adminContentRoutes.post("/", async (c) => {
6195
6453
  const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
6196
6454
  const contentId = crypto.randomUUID();
6197
6455
  const now = Date.now();
6198
- const insertStmt = db.prepare(`
6456
+ const insertStmt = db2.prepare(`
6199
6457
  INSERT INTO content (
6200
6458
  id, collection_id, slug, title, data, status,
6201
6459
  scheduled_publish_at, scheduled_unpublish_at,
6202
- meta_title, meta_description, author_id, created_at, updated_at
6460
+ meta_title, meta_description, author_id, created_by, created_at, updated_at
6203
6461
  )
6204
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6462
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6205
6463
  `);
6206
6464
  await insertStmt.bind(
6207
6465
  contentId,
@@ -6215,12 +6473,13 @@ adminContentRoutes.post("/", async (c) => {
6215
6473
  data.meta_title || null,
6216
6474
  data.meta_description || null,
6217
6475
  user?.userId || "unknown",
6476
+ user?.userId || "unknown",
6218
6477
  now,
6219
6478
  now
6220
6479
  ).run();
6221
6480
  const cache = getCacheService(CACHE_CONFIGS.content);
6222
6481
  await cache.invalidate(`content:list:${collectionId}:*`);
6223
- const versionStmt = db.prepare(`
6482
+ const versionStmt = db2.prepare(`
6224
6483
  INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
6225
6484
  VALUES (?, ?, ?, ?, ?, ?)
6226
6485
  `);
@@ -6232,7 +6491,7 @@ adminContentRoutes.post("/", async (c) => {
6232
6491
  user?.userId || "unknown",
6233
6492
  now
6234
6493
  ).run();
6235
- const workflowStmt = db.prepare(`
6494
+ const workflowStmt = db2.prepare(`
6236
6495
  INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
6237
6496
  VALUES (?, ?, ?, ?, ?, ?, ?)
6238
6497
  `);
@@ -6270,8 +6529,8 @@ adminContentRoutes.put("/:id", async (c) => {
6270
6529
  const user = c.get("user");
6271
6530
  const formData = await c.req.formData();
6272
6531
  const action = formData.get("action");
6273
- const db = c.env.DB;
6274
- const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
6532
+ const db2 = c.env.DB;
6533
+ const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
6275
6534
  const existingContent = await contentStmt.bind(id).first();
6276
6535
  if (!existingContent) {
6277
6536
  return c.html(html`
@@ -6280,7 +6539,7 @@ adminContentRoutes.put("/:id", async (c) => {
6280
6539
  </div>
6281
6540
  `);
6282
6541
  }
6283
- const collection = await getCollection(db, existingContent.collection_id);
6542
+ const collection = await getCollection(db2, existingContent.collection_id);
6284
6543
  if (!collection) {
6285
6544
  return c.html(html`
6286
6545
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -6288,7 +6547,7 @@ adminContentRoutes.put("/:id", async (c) => {
6288
6547
  </div>
6289
6548
  `);
6290
6549
  }
6291
- const fields = await getCollectionFields(db, existingContent.collection_id);
6550
+ const fields = await getCollectionFields(db2, existingContent.collection_id);
6292
6551
  const data = {};
6293
6552
  const errors = {};
6294
6553
  for (const field of fields) {
@@ -6347,7 +6606,7 @@ adminContentRoutes.put("/:id", async (c) => {
6347
6606
  const scheduledPublishAt = formData.get("scheduled_publish_at");
6348
6607
  const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
6349
6608
  const now = Date.now();
6350
- const updateStmt = db.prepare(`
6609
+ const updateStmt = db2.prepare(`
6351
6610
  UPDATE content SET
6352
6611
  slug = ?, title = ?, data = ?, status = ?,
6353
6612
  scheduled_publish_at = ?, scheduled_unpublish_at = ?,
@@ -6371,10 +6630,10 @@ adminContentRoutes.put("/:id", async (c) => {
6371
6630
  await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
6372
6631
  const existingData = JSON.parse(existingContent.data || "{}");
6373
6632
  if (JSON.stringify(existingData) !== JSON.stringify(data)) {
6374
- const versionCountStmt = db.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
6633
+ const versionCountStmt = db2.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
6375
6634
  const versionResult = await versionCountStmt.bind(id).first();
6376
6635
  const nextVersion = (versionResult?.max_version || 0) + 1;
6377
- const versionStmt = db.prepare(`
6636
+ const versionStmt = db2.prepare(`
6378
6637
  INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
6379
6638
  VALUES (?, ?, ?, ?, ?, ?)
6380
6639
  `);
@@ -6388,7 +6647,7 @@ adminContentRoutes.put("/:id", async (c) => {
6388
6647
  ).run();
6389
6648
  }
6390
6649
  if (status !== existingContent.status) {
6391
- const workflowStmt = db.prepare(`
6650
+ const workflowStmt = db2.prepare(`
6392
6651
  INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
6393
6652
  VALUES (?, ?, ?, ?, ?, ?, ?)
6394
6653
  `);
@@ -6425,12 +6684,12 @@ adminContentRoutes.post("/preview", async (c) => {
6425
6684
  try {
6426
6685
  const formData = await c.req.formData();
6427
6686
  const collectionId = formData.get("collection_id");
6428
- const db = c.env.DB;
6429
- const collection = await getCollection(db, collectionId);
6687
+ const db2 = c.env.DB;
6688
+ const collection = await getCollection(db2, collectionId);
6430
6689
  if (!collection) {
6431
6690
  return c.html("<p>Collection not found</p>");
6432
6691
  }
6433
- const fields = await getCollectionFields(db, collectionId);
6692
+ const fields = await getCollectionFields(db2, collectionId);
6434
6693
  const data = {};
6435
6694
  for (const field of fields) {
6436
6695
  const value = formData.get(field.field_name);
@@ -6504,8 +6763,8 @@ adminContentRoutes.post("/duplicate", async (c) => {
6504
6763
  if (!originalId) {
6505
6764
  return c.json({ success: false, error: "Content ID required" });
6506
6765
  }
6507
- const db = c.env.DB;
6508
- const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
6766
+ const db2 = c.env.DB;
6767
+ const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
6509
6768
  const original = await contentStmt.bind(originalId).first();
6510
6769
  if (!original) {
6511
6770
  return c.json({ success: false, error: "Content not found" });
@@ -6514,7 +6773,7 @@ adminContentRoutes.post("/duplicate", async (c) => {
6514
6773
  const now = Date.now();
6515
6774
  const originalData = JSON.parse(original.data || "{}");
6516
6775
  originalData.title = `${originalData.title || "Untitled"} (Copy)`;
6517
- const insertStmt = db.prepare(`
6776
+ const insertStmt = db2.prepare(`
6518
6777
  INSERT INTO content (
6519
6778
  id, collection_id, slug, title, data, status,
6520
6779
  author_id, created_at, updated_at
@@ -6637,11 +6896,11 @@ adminContentRoutes.post("/bulk-action", async (c) => {
6637
6896
  if (!action || !ids || ids.length === 0) {
6638
6897
  return c.json({ success: false, error: "Action and IDs required" });
6639
6898
  }
6640
- const db = c.env.DB;
6899
+ const db2 = c.env.DB;
6641
6900
  const now = Date.now();
6642
6901
  if (action === "delete") {
6643
6902
  const placeholders = ids.map(() => "?").join(",");
6644
- const stmt = db.prepare(`
6903
+ const stmt = db2.prepare(`
6645
6904
  UPDATE content
6646
6905
  SET status = 'deleted', updated_at = ?
6647
6906
  WHERE id IN (${placeholders})
@@ -6650,7 +6909,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
6650
6909
  } else if (action === "publish" || action === "draft") {
6651
6910
  const placeholders = ids.map(() => "?").join(",");
6652
6911
  const publishedAt = action === "publish" ? now : null;
6653
- const stmt = db.prepare(`
6912
+ const stmt = db2.prepare(`
6654
6913
  UPDATE content
6655
6914
  SET status = ?, published_at = ?, updated_at = ?
6656
6915
  WHERE id IN (${placeholders})
@@ -6673,15 +6932,15 @@ adminContentRoutes.post("/bulk-action", async (c) => {
6673
6932
  adminContentRoutes.delete("/:id", async (c) => {
6674
6933
  try {
6675
6934
  const id = c.req.param("id");
6676
- const db = c.env.DB;
6935
+ const db2 = c.env.DB;
6677
6936
  const user = c.get("user");
6678
- const contentStmt = db.prepare("SELECT id, title FROM content WHERE id = ?");
6937
+ const contentStmt = db2.prepare("SELECT id, title FROM content WHERE id = ?");
6679
6938
  const content = await contentStmt.bind(id).first();
6680
6939
  if (!content) {
6681
6940
  return c.json({ success: false, error: "Content not found" }, 404);
6682
6941
  }
6683
6942
  const now = Date.now();
6684
- const deleteStmt = db.prepare(`
6943
+ const deleteStmt = db2.prepare(`
6685
6944
  UPDATE content
6686
6945
  SET status = 'deleted', updated_at = ?
6687
6946
  WHERE id = ?
@@ -6710,13 +6969,13 @@ adminContentRoutes.delete("/:id", async (c) => {
6710
6969
  adminContentRoutes.get("/:id/versions", async (c) => {
6711
6970
  try {
6712
6971
  const id = c.req.param("id");
6713
- const db = c.env.DB;
6714
- const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
6972
+ const db2 = c.env.DB;
6973
+ const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
6715
6974
  const content = await contentStmt.bind(id).first();
6716
6975
  if (!content) {
6717
6976
  return c.html("<p>Content not found</p>");
6718
6977
  }
6719
- const versionsStmt = db.prepare(`
6978
+ const versionsStmt = db2.prepare(`
6720
6979
  SELECT cv.*, u.first_name, u.last_name, u.email
6721
6980
  FROM content_versions cv
6722
6981
  LEFT JOIN users u ON cv.author_id = u.id
@@ -6753,8 +7012,8 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
6753
7012
  const id = c.req.param("id");
6754
7013
  const version = parseInt(c.req.param("version"));
6755
7014
  const user = c.get("user");
6756
- const db = c.env.DB;
6757
- const versionStmt = db.prepare(`
7015
+ const db2 = c.env.DB;
7016
+ const versionStmt = db2.prepare(`
6758
7017
  SELECT * FROM content_versions
6759
7018
  WHERE content_id = ? AND version = ?
6760
7019
  `);
@@ -6762,14 +7021,14 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
6762
7021
  if (!versionData) {
6763
7022
  return c.json({ success: false, error: "Version not found" });
6764
7023
  }
6765
- const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
7024
+ const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
6766
7025
  const currentContent = await contentStmt.bind(id).first();
6767
7026
  if (!currentContent) {
6768
7027
  return c.json({ success: false, error: "Content not found" });
6769
7028
  }
6770
7029
  const restoredData = JSON.parse(versionData.data);
6771
7030
  const now = Date.now();
6772
- const updateStmt = db.prepare(`
7031
+ const updateStmt = db2.prepare(`
6773
7032
  UPDATE content SET
6774
7033
  title = ?, data = ?, updated_at = ?
6775
7034
  WHERE id = ?
@@ -6780,10 +7039,10 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
6780
7039
  now,
6781
7040
  id
6782
7041
  ).run();
6783
- const nextVersionStmt = db.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
7042
+ const nextVersionStmt = db2.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
6784
7043
  const nextVersionResult = await nextVersionStmt.bind(id).first();
6785
7044
  const nextVersion = (nextVersionResult?.max_version || 0) + 1;
6786
- const newVersionStmt = db.prepare(`
7045
+ const newVersionStmt = db2.prepare(`
6787
7046
  INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
6788
7047
  VALUES (?, ?, ?, ?, ?, ?)
6789
7048
  `);
@@ -6795,7 +7054,7 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
6795
7054
  user?.userId || "unknown",
6796
7055
  now
6797
7056
  ).run();
6798
- const workflowStmt = db.prepare(`
7057
+ const workflowStmt = db2.prepare(`
6799
7058
  INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, comment, created_at)
6800
7059
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
6801
7060
  `);
@@ -6819,8 +7078,8 @@ adminContentRoutes.get("/:id/version/:version/preview", async (c) => {
6819
7078
  try {
6820
7079
  const id = c.req.param("id");
6821
7080
  const version = parseInt(c.req.param("version"));
6822
- const db = c.env.DB;
6823
- const versionStmt = db.prepare(`
7081
+ const db2 = c.env.DB;
7082
+ const versionStmt = db2.prepare(`
6824
7083
  SELECT cv.*, c.collection_id, col.display_name as collection_name
6825
7084
  FROM content_versions cv
6826
7085
  JOIN content c ON cv.content_id = c.id
@@ -8741,9 +9000,9 @@ var ROLES = [
8741
9000
  ];
8742
9001
  userRoutes.get("/profile", async (c) => {
8743
9002
  const user = c.get("user");
8744
- const db = c.env.DB;
9003
+ const db2 = c.env.DB;
8745
9004
  try {
8746
- const userStmt = db.prepare(`
9005
+ const userStmt = db2.prepare(`
8747
9006
  SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
8748
9007
  timezone, language, theme, email_notifications, two_factor_enabled,
8749
9008
  role, created_at, last_login_at
@@ -8801,7 +9060,7 @@ userRoutes.get("/profile", async (c) => {
8801
9060
  });
8802
9061
  userRoutes.put("/profile", async (c) => {
8803
9062
  const user = c.get("user");
8804
- const db = c.env.DB;
9063
+ const db2 = c.env.DB;
8805
9064
  try {
8806
9065
  const formData = await c.req.formData();
8807
9066
  const firstName = sanitizeInput(formData.get("first_name")?.toString());
@@ -8828,7 +9087,7 @@ userRoutes.put("/profile", async (c) => {
8828
9087
  dismissible: true
8829
9088
  }));
8830
9089
  }
8831
- const checkStmt = db.prepare(`
9090
+ const checkStmt = db2.prepare(`
8832
9091
  SELECT id FROM users
8833
9092
  WHERE (username = ? OR email = ?) AND id != ? AND is_active = 1
8834
9093
  `);
@@ -8840,7 +9099,7 @@ userRoutes.put("/profile", async (c) => {
8840
9099
  dismissible: true
8841
9100
  }));
8842
9101
  }
8843
- const updateStmt = db.prepare(`
9102
+ const updateStmt = db2.prepare(`
8844
9103
  UPDATE users SET
8845
9104
  first_name = ?, last_name = ?, username = ?, email = ?,
8846
9105
  phone = ?, bio = ?, timezone = ?, language = ?,
@@ -8861,7 +9120,7 @@ userRoutes.put("/profile", async (c) => {
8861
9120
  user.userId
8862
9121
  ).run();
8863
9122
  await logActivity(
8864
- db,
9123
+ db2,
8865
9124
  user.userId,
8866
9125
  "profile.update",
8867
9126
  "users",
@@ -8886,7 +9145,7 @@ userRoutes.put("/profile", async (c) => {
8886
9145
  });
8887
9146
  userRoutes.post("/profile/avatar", async (c) => {
8888
9147
  const user = c.get("user");
8889
- const db = c.env.DB;
9148
+ const db2 = c.env.DB;
8890
9149
  try {
8891
9150
  const formData = await c.req.formData();
8892
9151
  const avatarFile = formData.get("avatar");
@@ -8914,17 +9173,17 @@ userRoutes.post("/profile/avatar", async (c) => {
8914
9173
  }));
8915
9174
  }
8916
9175
  const avatarUrl = `/uploads/avatars/${user.userId}-${Date.now()}.${avatarFile.type.split("/")[1]}`;
8917
- const updateStmt = db.prepare(`
9176
+ const updateStmt = db2.prepare(`
8918
9177
  UPDATE users SET avatar_url = ?, updated_at = ?
8919
9178
  WHERE id = ?
8920
9179
  `);
8921
9180
  await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
8922
- const userStmt = db.prepare(`
9181
+ const userStmt = db2.prepare(`
8923
9182
  SELECT first_name, last_name FROM users WHERE id = ?
8924
9183
  `);
8925
9184
  const userData = await userStmt.bind(user.userId).first();
8926
9185
  await logActivity(
8927
- db,
9186
+ db2,
8928
9187
  user.userId,
8929
9188
  "profile.avatar_update",
8930
9189
  "users",
@@ -8956,7 +9215,7 @@ userRoutes.post("/profile/avatar", async (c) => {
8956
9215
  });
8957
9216
  userRoutes.post("/profile/password", async (c) => {
8958
9217
  const user = c.get("user");
8959
- const db = c.env.DB;
9218
+ const db2 = c.env.DB;
8960
9219
  try {
8961
9220
  const formData = await c.req.formData();
8962
9221
  const currentPassword = formData.get("current_password")?.toString() || "";
@@ -8983,7 +9242,7 @@ userRoutes.post("/profile/password", async (c) => {
8983
9242
  dismissible: true
8984
9243
  }));
8985
9244
  }
8986
- const userStmt = db.prepare(`
9245
+ const userStmt = db2.prepare(`
8987
9246
  SELECT password_hash FROM users WHERE id = ? AND is_active = 1
8988
9247
  `);
8989
9248
  const userData = await userStmt.bind(user.userId).first();
@@ -9003,7 +9262,7 @@ userRoutes.post("/profile/password", async (c) => {
9003
9262
  }));
9004
9263
  }
9005
9264
  const newPasswordHash = await AuthManager.hashPassword(newPassword);
9006
- const historyStmt = db.prepare(`
9265
+ const historyStmt = db2.prepare(`
9007
9266
  INSERT INTO password_history (id, user_id, password_hash, created_at)
9008
9267
  VALUES (?, ?, ?, ?)
9009
9268
  `);
@@ -9013,13 +9272,13 @@ userRoutes.post("/profile/password", async (c) => {
9013
9272
  userData.password_hash,
9014
9273
  Date.now()
9015
9274
  ).run();
9016
- const updateStmt = db.prepare(`
9275
+ const updateStmt = db2.prepare(`
9017
9276
  UPDATE users SET password_hash = ?, updated_at = ?
9018
9277
  WHERE id = ?
9019
9278
  `);
9020
9279
  await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
9021
9280
  await logActivity(
9022
- db,
9281
+ db2,
9023
9282
  user.userId,
9024
9283
  "profile.password_change",
9025
9284
  "users",
@@ -9043,7 +9302,7 @@ userRoutes.post("/profile/password", async (c) => {
9043
9302
  }
9044
9303
  });
9045
9304
  userRoutes.get("/users", async (c) => {
9046
- const db = c.env.DB;
9305
+ const db2 = c.env.DB;
9047
9306
  const user = c.get("user");
9048
9307
  try {
9049
9308
  const page = parseInt(c.req.query("page") || "1");
@@ -9070,7 +9329,7 @@ userRoutes.get("/users", async (c) => {
9070
9329
  whereClause += " AND u.role = ?";
9071
9330
  params.push(roleFilter);
9072
9331
  }
9073
- const usersStmt = db.prepare(`
9332
+ const usersStmt = db2.prepare(`
9074
9333
  SELECT u.id, u.email, u.username, u.first_name, u.last_name,
9075
9334
  u.role, u.avatar_url, u.created_at, u.last_login_at, u.updated_at,
9076
9335
  u.email_verified, u.two_factor_enabled, u.is_active
@@ -9080,13 +9339,13 @@ userRoutes.get("/users", async (c) => {
9080
9339
  LIMIT ? OFFSET ?
9081
9340
  `);
9082
9341
  const { results: usersData } = await usersStmt.bind(...params, limit, offset).all();
9083
- const countStmt = db.prepare(`
9342
+ const countStmt = db2.prepare(`
9084
9343
  SELECT COUNT(*) as total FROM users u ${whereClause}
9085
9344
  `);
9086
9345
  const countResult = await countStmt.bind(...params).first();
9087
9346
  const totalUsers = countResult?.total || 0;
9088
9347
  await logActivity(
9089
- db,
9348
+ db2,
9090
9349
  user.userId,
9091
9350
  "users.list_view",
9092
9351
  "users",
@@ -9183,7 +9442,7 @@ userRoutes.get("/users/new", async (c) => {
9183
9442
  }
9184
9443
  });
9185
9444
  userRoutes.post("/users/new", async (c) => {
9186
- const db = c.env.DB;
9445
+ const db2 = c.env.DB;
9187
9446
  const user = c.get("user");
9188
9447
  try {
9189
9448
  const formData = await c.req.formData();
@@ -9227,7 +9486,7 @@ userRoutes.post("/users/new", async (c) => {
9227
9486
  dismissible: true
9228
9487
  }));
9229
9488
  }
9230
- const checkStmt = db.prepare(`
9489
+ const checkStmt = db2.prepare(`
9231
9490
  SELECT id FROM users
9232
9491
  WHERE username = ? OR email = ?
9233
9492
  `);
@@ -9241,7 +9500,7 @@ userRoutes.post("/users/new", async (c) => {
9241
9500
  }
9242
9501
  const passwordHash = await AuthManager.hashPassword(password);
9243
9502
  const userId = crypto.randomUUID();
9244
- const createStmt = db.prepare(`
9503
+ const createStmt = db2.prepare(`
9245
9504
  INSERT INTO users (
9246
9505
  id, email, username, first_name, last_name, phone, bio,
9247
9506
  password_hash, role, is_active, email_verified, created_at, updated_at
@@ -9263,7 +9522,7 @@ userRoutes.post("/users/new", async (c) => {
9263
9522
  Date.now()
9264
9523
  ).run();
9265
9524
  await logActivity(
9266
- db,
9525
+ db2,
9267
9526
  user.userId,
9268
9527
  "user!.create",
9269
9528
  "users",
@@ -9286,11 +9545,11 @@ userRoutes.get("/users/:id", async (c) => {
9286
9545
  if (c.req.path.endsWith("/edit")) {
9287
9546
  return c.notFound();
9288
9547
  }
9289
- const db = c.env.DB;
9548
+ const db2 = c.env.DB;
9290
9549
  const user = c.get("user");
9291
9550
  const userId = c.req.param("id");
9292
9551
  try {
9293
- const userStmt = db.prepare(`
9552
+ const userStmt = db2.prepare(`
9294
9553
  SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
9295
9554
  role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
9296
9555
  FROM users
@@ -9301,7 +9560,7 @@ userRoutes.get("/users/:id", async (c) => {
9301
9560
  return c.json({ error: "User not found" }, 404);
9302
9561
  }
9303
9562
  await logActivity(
9304
- db,
9563
+ db2,
9305
9564
  user.userId,
9306
9565
  "user!.view",
9307
9566
  "users",
@@ -9334,11 +9593,11 @@ userRoutes.get("/users/:id", async (c) => {
9334
9593
  }
9335
9594
  });
9336
9595
  userRoutes.get("/users/:id/edit", async (c) => {
9337
- const db = c.env.DB;
9596
+ const db2 = c.env.DB;
9338
9597
  const user = c.get("user");
9339
9598
  const userId = c.req.param("id");
9340
9599
  try {
9341
- const userStmt = db.prepare(`
9600
+ const userStmt = db2.prepare(`
9342
9601
  SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
9343
9602
  role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
9344
9603
  FROM users
@@ -9388,7 +9647,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
9388
9647
  }
9389
9648
  });
9390
9649
  userRoutes.put("/users/:id", async (c) => {
9391
- const db = c.env.DB;
9650
+ const db2 = c.env.DB;
9392
9651
  const user = c.get("user");
9393
9652
  const userId = c.req.param("id");
9394
9653
  try {
@@ -9417,7 +9676,7 @@ userRoutes.put("/users/:id", async (c) => {
9417
9676
  dismissible: true
9418
9677
  }));
9419
9678
  }
9420
- const checkStmt = db.prepare(`
9679
+ const checkStmt = db2.prepare(`
9421
9680
  SELECT id FROM users
9422
9681
  WHERE (username = ? OR email = ?) AND id != ?
9423
9682
  `);
@@ -9429,7 +9688,7 @@ userRoutes.put("/users/:id", async (c) => {
9429
9688
  dismissible: true
9430
9689
  }));
9431
9690
  }
9432
- const updateStmt = db.prepare(`
9691
+ const updateStmt = db2.prepare(`
9433
9692
  UPDATE users SET
9434
9693
  first_name = ?, last_name = ?, username = ?, email = ?,
9435
9694
  phone = ?, bio = ?, role = ?, is_active = ?, email_verified = ?,
@@ -9450,7 +9709,7 @@ userRoutes.put("/users/:id", async (c) => {
9450
9709
  userId
9451
9710
  ).run();
9452
9711
  await logActivity(
9453
- db,
9712
+ db2,
9454
9713
  user.userId,
9455
9714
  "user!.update",
9456
9715
  "users",
@@ -9474,7 +9733,7 @@ userRoutes.put("/users/:id", async (c) => {
9474
9733
  }
9475
9734
  });
9476
9735
  userRoutes.post("/users/:id/toggle", async (c) => {
9477
- const db = c.env.DB;
9736
+ const db2 = c.env.DB;
9478
9737
  const user = c.get("user");
9479
9738
  const userId = c.req.param("id");
9480
9739
  try {
@@ -9483,19 +9742,19 @@ userRoutes.post("/users/:id/toggle", async (c) => {
9483
9742
  if (userId === user.userId && !active) {
9484
9743
  return c.json({ error: "You cannot deactivate your own account" }, 400);
9485
9744
  }
9486
- const userStmt = db.prepare(`
9745
+ const userStmt = db2.prepare(`
9487
9746
  SELECT id, email FROM users WHERE id = ?
9488
9747
  `);
9489
9748
  const userToToggle = await userStmt.bind(userId).first();
9490
9749
  if (!userToToggle) {
9491
9750
  return c.json({ error: "User not found" }, 404);
9492
9751
  }
9493
- const toggleStmt = db.prepare(`
9752
+ const toggleStmt = db2.prepare(`
9494
9753
  UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?
9495
9754
  `);
9496
9755
  await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
9497
9756
  await logActivity(
9498
- db,
9757
+ db2,
9499
9758
  user.userId,
9500
9759
  active ? "user.activate" : "user.deactivate",
9501
9760
  "users",
@@ -9514,7 +9773,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
9514
9773
  }
9515
9774
  });
9516
9775
  userRoutes.delete("/users/:id", async (c) => {
9517
- const db = c.env.DB;
9776
+ const db2 = c.env.DB;
9518
9777
  const user = c.get("user");
9519
9778
  const userId = c.req.param("id");
9520
9779
  try {
@@ -9523,7 +9782,7 @@ userRoutes.delete("/users/:id", async (c) => {
9523
9782
  if (userId === user.userId) {
9524
9783
  return c.json({ error: "You cannot delete your own account" }, 400);
9525
9784
  }
9526
- const userStmt = db.prepare(`
9785
+ const userStmt = db2.prepare(`
9527
9786
  SELECT id, email FROM users WHERE id = ?
9528
9787
  `);
9529
9788
  const userToDelete = await userStmt.bind(userId).first();
@@ -9531,12 +9790,12 @@ userRoutes.delete("/users/:id", async (c) => {
9531
9790
  return c.json({ error: "User not found" }, 404);
9532
9791
  }
9533
9792
  if (hardDelete) {
9534
- const deleteStmt = db.prepare(`
9793
+ const deleteStmt = db2.prepare(`
9535
9794
  DELETE FROM users WHERE id = ?
9536
9795
  `);
9537
9796
  await deleteStmt.bind(userId).run();
9538
9797
  await logActivity(
9539
- db,
9798
+ db2,
9540
9799
  user.userId,
9541
9800
  "user!.hard_delete",
9542
9801
  "users",
@@ -9550,12 +9809,12 @@ userRoutes.delete("/users/:id", async (c) => {
9550
9809
  message: "User permanently deleted"
9551
9810
  });
9552
9811
  } else {
9553
- const deleteStmt = db.prepare(`
9812
+ const deleteStmt = db2.prepare(`
9554
9813
  UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
9555
9814
  `);
9556
9815
  await deleteStmt.bind(Date.now(), userId).run();
9557
9816
  await logActivity(
9558
- db,
9817
+ db2,
9559
9818
  user.userId,
9560
9819
  "user!.soft_delete",
9561
9820
  "users",
@@ -9575,7 +9834,7 @@ userRoutes.delete("/users/:id", async (c) => {
9575
9834
  }
9576
9835
  });
9577
9836
  userRoutes.post("/invite-user", async (c) => {
9578
- const db = c.env.DB;
9837
+ const db2 = c.env.DB;
9579
9838
  const user = c.get("user");
9580
9839
  try {
9581
9840
  const formData = await c.req.formData();
@@ -9590,7 +9849,7 @@ userRoutes.post("/invite-user", async (c) => {
9590
9849
  if (!emailRegex.test(email)) {
9591
9850
  return c.json({ error: "Please enter a valid email address" }, 400);
9592
9851
  }
9593
- const existingUserStmt = db.prepare(`
9852
+ const existingUserStmt = db2.prepare(`
9594
9853
  SELECT id FROM users WHERE email = ?
9595
9854
  `);
9596
9855
  const existingUser = await existingUserStmt.bind(email).first();
@@ -9599,7 +9858,7 @@ userRoutes.post("/invite-user", async (c) => {
9599
9858
  }
9600
9859
  const invitationToken = crypto.randomUUID();
9601
9860
  const userId = crypto.randomUUID();
9602
- const createUserStmt = db.prepare(`
9861
+ const createUserStmt = db2.prepare(`
9603
9862
  INSERT INTO users (
9604
9863
  id, email, first_name, last_name, role,
9605
9864
  invitation_token, invited_by, invited_at,
@@ -9621,7 +9880,7 @@ userRoutes.post("/invite-user", async (c) => {
9621
9880
  Date.now()
9622
9881
  ).run();
9623
9882
  await logActivity(
9624
- db,
9883
+ db2,
9625
9884
  user.userId,
9626
9885
  "user!.invite_sent",
9627
9886
  "users",
@@ -9650,11 +9909,11 @@ userRoutes.post("/invite-user", async (c) => {
9650
9909
  }
9651
9910
  });
9652
9911
  userRoutes.post("/resend-invitation/:id", async (c) => {
9653
- const db = c.env.DB;
9912
+ const db2 = c.env.DB;
9654
9913
  const user = c.get("user");
9655
9914
  const userId = c.req.param("id");
9656
9915
  try {
9657
- const userStmt = db.prepare(`
9916
+ const userStmt = db2.prepare(`
9658
9917
  SELECT id, email, first_name, last_name, role, invitation_token
9659
9918
  FROM users
9660
9919
  WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
@@ -9664,7 +9923,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
9664
9923
  return c.json({ error: "User not found or invitation not valid" }, 404);
9665
9924
  }
9666
9925
  const newInvitationToken = crypto.randomUUID();
9667
- const updateStmt = db.prepare(`
9926
+ const updateStmt = db2.prepare(`
9668
9927
  UPDATE users SET
9669
9928
  invitation_token = ?,
9670
9929
  invited_at = ?,
@@ -9678,7 +9937,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
9678
9937
  userId
9679
9938
  ).run();
9680
9939
  await logActivity(
9681
- db,
9940
+ db2,
9682
9941
  user.userId,
9683
9942
  "user!.invitation_resent",
9684
9943
  "users",
@@ -9699,11 +9958,11 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
9699
9958
  }
9700
9959
  });
9701
9960
  userRoutes.delete("/cancel-invitation/:id", async (c) => {
9702
- const db = c.env.DB;
9961
+ const db2 = c.env.DB;
9703
9962
  const user = c.get("user");
9704
9963
  const userId = c.req.param("id");
9705
9964
  try {
9706
- const userStmt = db.prepare(`
9965
+ const userStmt = db2.prepare(`
9707
9966
  SELECT id, email FROM users
9708
9967
  WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
9709
9968
  `);
@@ -9711,10 +9970,10 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
9711
9970
  if (!invitedUser) {
9712
9971
  return c.json({ error: "User not found or invitation not valid" }, 404);
9713
9972
  }
9714
- const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
9973
+ const deleteStmt = db2.prepare(`DELETE FROM users WHERE id = ?`);
9715
9974
  await deleteStmt.bind(userId).run();
9716
9975
  await logActivity(
9717
- db,
9976
+ db2,
9718
9977
  user.userId,
9719
9978
  "user!.invitation_cancelled",
9720
9979
  "users",
@@ -9733,7 +9992,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
9733
9992
  }
9734
9993
  });
9735
9994
  userRoutes.get("/activity-logs", async (c) => {
9736
- const db = c.env.DB;
9995
+ const db2 = c.env.DB;
9737
9996
  const user = c.get("user");
9738
9997
  try {
9739
9998
  const page = parseInt(c.req.query("page") || "1");
@@ -9771,7 +10030,7 @@ userRoutes.get("/activity-logs", async (c) => {
9771
10030
  params.push(toTimestamp);
9772
10031
  }
9773
10032
  const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
9774
- const logsStmt = db.prepare(`
10033
+ const logsStmt = db2.prepare(`
9775
10034
  SELECT
9776
10035
  al.id, al.user_id, al.action, al.resource_type, al.resource_id,
9777
10036
  al.details, al.ip_address, al.user_agent, al.created_at,
@@ -9784,7 +10043,7 @@ userRoutes.get("/activity-logs", async (c) => {
9784
10043
  LIMIT ? OFFSET ?
9785
10044
  `);
9786
10045
  const { results: logs } = await logsStmt.bind(...params, limit, offset).all();
9787
- const countStmt = db.prepare(`
10046
+ const countStmt = db2.prepare(`
9788
10047
  SELECT COUNT(*) as total
9789
10048
  FROM activity_logs al
9790
10049
  LEFT JOIN users u ON al.user_id = u.id
@@ -9797,7 +10056,7 @@ userRoutes.get("/activity-logs", async (c) => {
9797
10056
  details: log.details ? JSON.parse(log.details) : null
9798
10057
  }));
9799
10058
  await logActivity(
9800
- db,
10059
+ db2,
9801
10060
  user.userId,
9802
10061
  "activity.logs_viewed",
9803
10062
  void 0,
@@ -9839,7 +10098,7 @@ userRoutes.get("/activity-logs", async (c) => {
9839
10098
  }
9840
10099
  });
9841
10100
  userRoutes.get("/activity-logs/export", async (c) => {
9842
- const db = c.env.DB;
10101
+ const db2 = c.env.DB;
9843
10102
  const user = c.get("user");
9844
10103
  try {
9845
10104
  const filters = {
@@ -9874,7 +10133,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
9874
10133
  params.push(toTimestamp);
9875
10134
  }
9876
10135
  const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
9877
- const logsStmt = db.prepare(`
10136
+ const logsStmt = db2.prepare(`
9878
10137
  SELECT
9879
10138
  al.id, al.user_id, al.action, al.resource_type, al.resource_id,
9880
10139
  al.details, al.ip_address, al.user_agent, al.created_at,
@@ -9904,7 +10163,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
9904
10163
  }
9905
10164
  const csvContent = csvRows.join("\n");
9906
10165
  await logActivity(
9907
- db,
10166
+ db2,
9908
10167
  user.userId,
9909
10168
  "activity.logs_exported",
9910
10169
  void 0,
@@ -11254,7 +11513,7 @@ adminMediaRoutes.get("/", async (c) => {
11254
11513
  const ____cacheBust = searchParams.get("t");
11255
11514
  const limit = 24;
11256
11515
  const offset = (page - 1) * limit;
11257
- const db = c.env.DB;
11516
+ const db2 = c.env.DB;
11258
11517
  let query = "SELECT * FROM media";
11259
11518
  const params = [];
11260
11519
  const conditions = ["deleted_at IS NULL"];
@@ -11282,9 +11541,9 @@ adminMediaRoutes.get("/", async (c) => {
11282
11541
  query += ` WHERE ${conditions.join(" AND ")}`;
11283
11542
  }
11284
11543
  query += ` ORDER BY uploaded_at DESC LIMIT ${limit} OFFSET ${offset}`;
11285
- const stmt = db.prepare(query);
11544
+ const stmt = db2.prepare(query);
11286
11545
  const { results } = await stmt.bind(...params).all();
11287
- const foldersStmt = db.prepare(`
11546
+ const foldersStmt = db2.prepare(`
11288
11547
  SELECT folder, COUNT(*) as count, SUM(size) as totalSize
11289
11548
  FROM media
11290
11549
  WHERE deleted_at IS NULL
@@ -11292,7 +11551,7 @@ adminMediaRoutes.get("/", async (c) => {
11292
11551
  ORDER BY folder
11293
11552
  `);
11294
11553
  const { results: folders } = await foldersStmt.all();
11295
- const typesStmt = db.prepare(`
11554
+ const typesStmt = db2.prepare(`
11296
11555
  SELECT
11297
11556
  CASE
11298
11557
  WHEN mime_type LIKE 'image/%' THEN 'images'
@@ -11358,7 +11617,7 @@ adminMediaRoutes.get("/selector", async (c) => {
11358
11617
  try {
11359
11618
  const { searchParams } = new URL(c.req.url);
11360
11619
  const search = searchParams.get("search") || "";
11361
- const db = c.env.DB;
11620
+ const db2 = c.env.DB;
11362
11621
  let query = "SELECT * FROM media WHERE deleted_at IS NULL";
11363
11622
  const params = [];
11364
11623
  if (search.trim()) {
@@ -11367,7 +11626,7 @@ adminMediaRoutes.get("/selector", async (c) => {
11367
11626
  params.push(searchTerm, searchTerm, searchTerm);
11368
11627
  }
11369
11628
  query += " ORDER BY uploaded_at DESC LIMIT 24";
11370
- const stmt = db.prepare(query);
11629
+ const stmt = db2.prepare(query);
11371
11630
  const { results } = await stmt.bind(...params).all();
11372
11631
  const mediaFiles = results.map((row) => ({
11373
11632
  id: row.id,
@@ -11474,7 +11733,7 @@ adminMediaRoutes.get("/search", async (c) => {
11474
11733
  const search = searchParams.get("search") || "";
11475
11734
  const folder = searchParams.get("folder") || "all";
11476
11735
  const type = searchParams.get("type") || "all";
11477
- const db = c.env.DB;
11736
+ const db2 = c.env.DB;
11478
11737
  let query = "SELECT * FROM media";
11479
11738
  const params = [];
11480
11739
  const conditions = [];
@@ -11507,7 +11766,7 @@ adminMediaRoutes.get("/search", async (c) => {
11507
11766
  query += ` WHERE ${conditions.join(" AND ")}`;
11508
11767
  }
11509
11768
  query += ` ORDER BY uploaded_at DESC LIMIT 24`;
11510
- const stmt = db.prepare(query);
11769
+ const stmt = db2.prepare(query);
11511
11770
  const { results } = await stmt.bind(...params).all();
11512
11771
  const mediaFiles = results.map((row) => ({
11513
11772
  ...row,
@@ -11530,8 +11789,8 @@ adminMediaRoutes.get("/search", async (c) => {
11530
11789
  adminMediaRoutes.get("/:id/details", async (c) => {
11531
11790
  try {
11532
11791
  const id = c.req.param("id");
11533
- const db = c.env.DB;
11534
- const stmt = db.prepare("SELECT * FROM media WHERE id = ?");
11792
+ const db2 = c.env.DB;
11793
+ const stmt = db2.prepare("SELECT * FROM media WHERE id = ?");
11535
11794
  const result = await stmt.bind(id).first();
11536
11795
  if (!result) {
11537
11796
  return c.html('<div class="text-red-500">File not found</div>');
@@ -11604,7 +11863,7 @@ adminMediaRoutes.post("/upload", async (c) => {
11604
11863
  });
11605
11864
  continue;
11606
11865
  }
11607
- const fileId = globalThis.crypto.randomUUID();
11866
+ const fileId = crypto.randomUUID();
11608
11867
  const fileExtension = file.name.split(".").pop() || "";
11609
11868
  const filename = `${fileId}.${fileExtension}`;
11610
11869
  const folder = formData.get("folder") || "uploads";
@@ -11823,10 +12082,10 @@ adminMediaRoutes.put("/:id", async (c) => {
11823
12082
  });
11824
12083
  adminMediaRoutes.delete("/cleanup", requireRole("admin"), async (c) => {
11825
12084
  try {
11826
- const db = c.env.DB;
11827
- const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
12085
+ const db2 = c.env.DB;
12086
+ const allMediaStmt = db2.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
11828
12087
  const { results: allMedia } = await allMediaStmt.all();
11829
- const contentStmt = db.prepare("SELECT data FROM content");
12088
+ const contentStmt = db2.prepare("SELECT data FROM content");
11830
12089
  const { results: contentRecords } = await contentStmt.all();
11831
12090
  const referencedUrls = /* @__PURE__ */ new Set();
11832
12091
  for (const record of contentRecords) {
@@ -11856,7 +12115,7 @@ adminMediaRoutes.delete("/cleanup", requireRole("admin"), async (c) => {
11856
12115
  for (const file of unusedFiles) {
11857
12116
  try {
11858
12117
  await c.env.MEDIA_BUCKET.delete(file.r2_key);
11859
- const deleteStmt = db.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
12118
+ const deleteStmt = db2.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
11860
12119
  await deleteStmt.bind(Math.floor(Date.now() / 1e3), file.id).run();
11861
12120
  deletedCount++;
11862
12121
  } catch (error) {
@@ -12080,44 +12339,6 @@ function renderPluginsListPage(data) {
12080
12339
  <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Plugins</h1>
12081
12340
  <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">Manage and extend functionality with plugins</p>
12082
12341
  </div>
12083
- <div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
12084
- <div class="relative inline-block text-left">
12085
- <button onclick="toggleDropdown()" class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
12086
- <svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
12087
- <path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z" />
12088
- </svg>
12089
- Install Plugin
12090
- <svg class="-mr-1 ml-2 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
12091
- <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
12092
- </svg>
12093
- </button>
12094
- <div id="plugin-dropdown" class="hidden absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-xl bg-white dark:bg-zinc-900 shadow-xl ring-1 ring-zinc-950/5 dark:ring-white/10 focus:outline-none">
12095
- <div class="py-1">
12096
- <button onclick="installPlugin('faq-plugin')" class="block w-full text-left px-4 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors first:rounded-t-xl">
12097
- <div class="flex items-center">
12098
- <span class="text-lg mr-2">\u2753</span>
12099
- <div>
12100
- <div class="font-medium">FAQ System</div>
12101
- <div class="text-xs text-zinc-500 dark:text-zinc-400">Community FAQ management plugin</div>
12102
- </div>
12103
- </div>
12104
- </button>
12105
- <div class="border-t border-zinc-950/5 dark:border-white/10 my-1"></div>
12106
- <button onclick="showNotification('Plugin marketplace coming soon!', 'info')" class="block w-full text-left px-4 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors last:rounded-b-xl">
12107
- <div class="flex items-center">
12108
- <svg class="w-5 h-5 mr-2 text-zinc-500 dark:text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
12109
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
12110
- </svg>
12111
- <div>
12112
- <div class="font-medium">Browse Marketplace</div>
12113
- <div class="text-xs text-zinc-500 dark:text-zinc-400">Discover more plugins</div>
12114
- </div>
12115
- </div>
12116
- </button>
12117
- </div>
12118
- </div>
12119
- </div>
12120
- </div>
12121
12342
  </div>
12122
12343
 
12123
12344
  <!-- Experimental Notice -->
@@ -12448,16 +12669,11 @@ function renderPluginsListPage(data) {
12448
12669
  notification.className = \`fixed top-4 right-4 px-4 py-2 rounded-lg text-white z-50 \${bgColor}\`;
12449
12670
  notification.textContent = message;
12450
12671
  document.body.appendChild(notification);
12451
-
12672
+
12452
12673
  setTimeout(() => {
12453
12674
  notification.remove();
12454
12675
  }, 3000);
12455
12676
  }
12456
-
12457
- function toggleDropdown() {
12458
- const dropdown = document.getElementById('plugin-dropdown');
12459
- dropdown.classList.toggle('hidden');
12460
- }
12461
12677
 
12462
12678
  function filterPlugins() {
12463
12679
  const categoryFilter = document.getElementById('category-filter').value.toLowerCase();
@@ -12524,16 +12740,6 @@ function renderPluginsListPage(data) {
12524
12740
  noResultsMsg.style.display = 'none';
12525
12741
  }
12526
12742
  }
12527
-
12528
- // Close dropdown when clicking outside
12529
- document.addEventListener('click', (event) => {
12530
- const dropdown = document.getElementById('plugin-dropdown');
12531
- const button = event.target.closest('button[onclick="toggleDropdown()"]');
12532
-
12533
- if (!button && !dropdown.contains(event.target)) {
12534
- dropdown.classList.add('hidden');
12535
- }
12536
- });
12537
12743
  </script>
12538
12744
 
12539
12745
  <!-- Confirmation Dialogs -->
@@ -13557,16 +13763,29 @@ var AVAILABLE_PLUGINS = [
13557
13763
  permissions: [],
13558
13764
  dependencies: [],
13559
13765
  is_core: false
13766
+ },
13767
+ {
13768
+ id: "easy-mdx",
13769
+ name: "easy-mdx",
13770
+ display_name: "EasyMDE Markdown Editor",
13771
+ description: "Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.",
13772
+ version: "1.0.0",
13773
+ author: "SonicJS Team",
13774
+ category: "editor",
13775
+ icon: "\u{1F4DD}",
13776
+ permissions: [],
13777
+ dependencies: [],
13778
+ is_core: false
13560
13779
  }
13561
13780
  ];
13562
13781
  adminPluginRoutes.get("/", async (c) => {
13563
13782
  try {
13564
13783
  const user = c.get("user");
13565
- const db = c.env.DB;
13784
+ const db2 = c.env.DB;
13566
13785
  if (user?.role !== "admin") {
13567
13786
  return c.text("Access denied", 403);
13568
13787
  }
13569
- const pluginService = new PluginService(db);
13788
+ const pluginService = new PluginService(db2);
13570
13789
  let installedPlugins = [];
13571
13790
  let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
13572
13791
  try {
@@ -13633,12 +13852,12 @@ adminPluginRoutes.get("/", async (c) => {
13633
13852
  adminPluginRoutes.get("/:id", async (c) => {
13634
13853
  try {
13635
13854
  const user = c.get("user");
13636
- const db = c.env.DB;
13855
+ const db2 = c.env.DB;
13637
13856
  const pluginId = c.req.param("id");
13638
13857
  if (user?.role !== "admin") {
13639
13858
  return c.redirect("/admin/plugins");
13640
13859
  }
13641
- const pluginService = new PluginService(db);
13860
+ const pluginService = new PluginService(db2);
13642
13861
  const plugin = await pluginService.getPlugin(pluginId);
13643
13862
  if (!plugin) {
13644
13863
  return c.text("Plugin not found", 404);
@@ -13687,12 +13906,12 @@ adminPluginRoutes.get("/:id", async (c) => {
13687
13906
  adminPluginRoutes.post("/:id/activate", async (c) => {
13688
13907
  try {
13689
13908
  const user = c.get("user");
13690
- const db = c.env.DB;
13909
+ const db2 = c.env.DB;
13691
13910
  const pluginId = c.req.param("id");
13692
13911
  if (user?.role !== "admin") {
13693
13912
  return c.json({ error: "Access denied" }, 403);
13694
13913
  }
13695
- const pluginService = new PluginService(db);
13914
+ const pluginService = new PluginService(db2);
13696
13915
  await pluginService.activatePlugin(pluginId);
13697
13916
  return c.json({ success: true });
13698
13917
  } catch (error) {
@@ -13704,12 +13923,12 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
13704
13923
  adminPluginRoutes.post("/:id/deactivate", async (c) => {
13705
13924
  try {
13706
13925
  const user = c.get("user");
13707
- const db = c.env.DB;
13926
+ const db2 = c.env.DB;
13708
13927
  const pluginId = c.req.param("id");
13709
13928
  if (user?.role !== "admin") {
13710
13929
  return c.json({ error: "Access denied" }, 403);
13711
13930
  }
13712
- const pluginService = new PluginService(db);
13931
+ const pluginService = new PluginService(db2);
13713
13932
  await pluginService.deactivatePlugin(pluginId);
13714
13933
  return c.json({ success: true });
13715
13934
  } catch (error) {
@@ -13721,12 +13940,12 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
13721
13940
  adminPluginRoutes.post("/install", async (c) => {
13722
13941
  try {
13723
13942
  const user = c.get("user");
13724
- const db = c.env.DB;
13943
+ const db2 = c.env.DB;
13725
13944
  if (user?.role !== "admin") {
13726
13945
  return c.json({ error: "Access denied" }, 403);
13727
13946
  }
13728
13947
  const body = await c.req.json();
13729
- const pluginService = new PluginService(db);
13948
+ const pluginService = new PluginService(db2);
13730
13949
  if (body.name === "faq-plugin") {
13731
13950
  const faqPlugin = await pluginService.installPlugin({
13732
13951
  id: "third-party-faq",
@@ -13905,6 +14124,28 @@ adminPluginRoutes.post("/install", async (c) => {
13905
14124
  });
13906
14125
  return c.json({ success: true, plugin: tinymcePlugin2 });
13907
14126
  }
14127
+ if (body.name === "easy-mdx") {
14128
+ const easyMdxPlugin2 = await pluginService.installPlugin({
14129
+ id: "easy-mdx",
14130
+ name: "easy-mdx",
14131
+ display_name: "EasyMDE Markdown Editor",
14132
+ description: "Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.",
14133
+ version: "1.0.0",
14134
+ author: "SonicJS Team",
14135
+ category: "editor",
14136
+ icon: "\u{1F4DD}",
14137
+ permissions: [],
14138
+ dependencies: [],
14139
+ is_core: false,
14140
+ settings: {
14141
+ defaultHeight: 400,
14142
+ theme: "dark",
14143
+ toolbar: "full",
14144
+ placeholder: "Start writing your content..."
14145
+ }
14146
+ });
14147
+ return c.json({ success: true, plugin: easyMdxPlugin2 });
14148
+ }
13908
14149
  return c.json({ error: "Plugin not found in registry" }, 404);
13909
14150
  } catch (error) {
13910
14151
  console.error("Error installing plugin:", error);
@@ -13915,12 +14156,12 @@ adminPluginRoutes.post("/install", async (c) => {
13915
14156
  adminPluginRoutes.post("/:id/uninstall", async (c) => {
13916
14157
  try {
13917
14158
  const user = c.get("user");
13918
- const db = c.env.DB;
14159
+ const db2 = c.env.DB;
13919
14160
  const pluginId = c.req.param("id");
13920
14161
  if (user?.role !== "admin") {
13921
14162
  return c.json({ error: "Access denied" }, 403);
13922
14163
  }
13923
- const pluginService = new PluginService(db);
14164
+ const pluginService = new PluginService(db2);
13924
14165
  await pluginService.uninstallPlugin(pluginId);
13925
14166
  return c.json({ success: true });
13926
14167
  } catch (error) {
@@ -13932,13 +14173,13 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
13932
14173
  adminPluginRoutes.post("/:id/settings", async (c) => {
13933
14174
  try {
13934
14175
  const user = c.get("user");
13935
- const db = c.env.DB;
14176
+ const db2 = c.env.DB;
13936
14177
  const pluginId = c.req.param("id");
13937
14178
  if (user?.role !== "admin") {
13938
14179
  return c.json({ error: "Access denied" }, 403);
13939
14180
  }
13940
14181
  const settings = await c.req.json();
13941
- const pluginService = new PluginService(db);
14182
+ const pluginService = new PluginService(db2);
13942
14183
  await pluginService.updatePluginSettings(pluginId, settings);
13943
14184
  return c.json({ success: true });
13944
14185
  } catch (error) {
@@ -15399,8 +15640,8 @@ adminTestimonialsRoutes.get("/", async (c) => {
15399
15640
  const currentPage = parseInt(page, 10) || 1;
15400
15641
  const limit = 20;
15401
15642
  const offset = (currentPage - 1) * limit;
15402
- const db = c.env?.DB;
15403
- if (!db) {
15643
+ const db2 = c.env?.DB;
15644
+ if (!db2) {
15404
15645
  return c.html(renderTestimonialsList({
15405
15646
  testimonials: [],
15406
15647
  totalCount: 0,
@@ -15431,7 +15672,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
15431
15672
  params.push(searchTerm, searchTerm, searchTerm);
15432
15673
  }
15433
15674
  const countQuery = `SELECT COUNT(*) as count FROM testimonials ${whereClause}`;
15434
- const { results: countResults } = await db.prepare(countQuery).bind(...params).all();
15675
+ const { results: countResults } = await db2.prepare(countQuery).bind(...params).all();
15435
15676
  const totalCount = countResults?.[0]?.count || 0;
15436
15677
  const dataQuery = `
15437
15678
  SELECT * FROM testimonials
@@ -15439,7 +15680,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
15439
15680
  ORDER BY sortOrder ASC, created_at DESC
15440
15681
  LIMIT ? OFFSET ?
15441
15682
  `;
15442
- const { results: testimonials } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
15683
+ const { results: testimonials } = await db2.prepare(dataQuery).bind(...params, limit, offset).all();
15443
15684
  const totalPages = Math.ceil(totalCount / limit);
15444
15685
  return c.html(renderTestimonialsList({
15445
15686
  testimonials: testimonials || [],
@@ -15487,8 +15728,8 @@ adminTestimonialsRoutes.post("/", async (c) => {
15487
15728
  const data = Object.fromEntries(formData.entries());
15488
15729
  const validatedData = testimonialSchema.parse(data);
15489
15730
  const user = c.get("user");
15490
- const db = c.env?.DB;
15491
- if (!db) {
15731
+ const db2 = c.env?.DB;
15732
+ if (!db2) {
15492
15733
  return c.html(renderTestimonialsForm({
15493
15734
  isEdit: false,
15494
15735
  user: user ? {
@@ -15500,7 +15741,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
15500
15741
  messageType: "error"
15501
15742
  }));
15502
15743
  }
15503
- const { results } = await db.prepare(`
15744
+ const { results } = await db2.prepare(`
15504
15745
  INSERT INTO testimonials (author_name, author_title, author_company, testimonial_text, rating, isPublished, sortOrder)
15505
15746
  VALUES (?, ?, ?, ?, ?, ?, ?)
15506
15747
  RETURNING *
@@ -15532,7 +15773,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
15532
15773
  const user = c.get("user");
15533
15774
  if (error instanceof z.ZodError) {
15534
15775
  const errors = {};
15535
- error.errors.forEach((err) => {
15776
+ error.issues.forEach((err) => {
15536
15777
  const field = err.path[0];
15537
15778
  if (!errors[field]) errors[field] = [];
15538
15779
  errors[field].push(err.message);
@@ -15565,8 +15806,8 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
15565
15806
  try {
15566
15807
  const id = parseInt(c.req.param("id"));
15567
15808
  const user = c.get("user");
15568
- const db = c.env?.DB;
15569
- if (!db) {
15809
+ const db2 = c.env?.DB;
15810
+ if (!db2) {
15570
15811
  return c.html(renderTestimonialsForm({
15571
15812
  isEdit: true,
15572
15813
  user: user ? {
@@ -15578,7 +15819,7 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
15578
15819
  messageType: "error"
15579
15820
  }));
15580
15821
  }
15581
- const { results } = await db.prepare("SELECT * FROM testimonials WHERE id = ?").bind(id).all();
15822
+ const { results } = await db2.prepare("SELECT * FROM testimonials WHERE id = ?").bind(id).all();
15582
15823
  if (!results || results.length === 0) {
15583
15824
  return c.redirect("/admin/testimonials?message=Testimonial not found&type=error");
15584
15825
  }
@@ -15623,8 +15864,8 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
15623
15864
  const data = Object.fromEntries(formData.entries());
15624
15865
  const validatedData = testimonialSchema.parse(data);
15625
15866
  const user = c.get("user");
15626
- const db = c.env?.DB;
15627
- if (!db) {
15867
+ const db2 = c.env?.DB;
15868
+ if (!db2) {
15628
15869
  return c.html(renderTestimonialsForm({
15629
15870
  isEdit: true,
15630
15871
  user: user ? {
@@ -15636,7 +15877,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
15636
15877
  messageType: "error"
15637
15878
  }));
15638
15879
  }
15639
- const { results } = await db.prepare(`
15880
+ const { results } = await db2.prepare(`
15640
15881
  UPDATE testimonials
15641
15882
  SET author_name = ?, author_title = ?, author_company = ?, testimonial_text = ?, rating = ?, isPublished = ?, sortOrder = ?
15642
15883
  WHERE id = ?
@@ -15681,7 +15922,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
15681
15922
  const id = parseInt(c.req.param("id"));
15682
15923
  if (error instanceof z.ZodError) {
15683
15924
  const errors = {};
15684
- error.errors.forEach((err) => {
15925
+ error.issues.forEach((err) => {
15685
15926
  const field = err.path[0];
15686
15927
  if (!errors[field]) errors[field] = [];
15687
15928
  errors[field].push(err.message);
@@ -15733,11 +15974,11 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
15733
15974
  adminTestimonialsRoutes.delete("/:id", async (c) => {
15734
15975
  try {
15735
15976
  const id = parseInt(c.req.param("id"));
15736
- const db = c.env?.DB;
15737
- if (!db) {
15977
+ const db2 = c.env?.DB;
15978
+ if (!db2) {
15738
15979
  return c.json({ error: "Database not available" }, 500);
15739
15980
  }
15740
- const { changes } = await db.prepare("DELETE FROM testimonials WHERE id = ?").bind(id).run();
15981
+ const { changes } = await db2.prepare("DELETE FROM testimonials WHERE id = ?").bind(id).run();
15741
15982
  if (changes === 0) {
15742
15983
  return c.json({ error: "Testimonial not found" }, 404);
15743
15984
  }
@@ -16069,8 +16310,8 @@ adminCodeExamplesRoutes.get("/", async (c) => {
16069
16310
  const currentPage = parseInt(page, 10) || 1;
16070
16311
  const limit = 20;
16071
16312
  const offset = (currentPage - 1) * limit;
16072
- const db = c.env?.DB;
16073
- if (!db) {
16313
+ const db2 = c.env?.DB;
16314
+ if (!db2) {
16074
16315
  return c.html(renderCodeExamplesList({
16075
16316
  codeExamples: [],
16076
16317
  totalCount: 0,
@@ -16101,7 +16342,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
16101
16342
  params.push(searchTerm, searchTerm, searchTerm, searchTerm);
16102
16343
  }
16103
16344
  const countQuery = `SELECT COUNT(*) as count FROM code_examples ${whereClause}`;
16104
- const { results: countResults } = await db.prepare(countQuery).bind(...params).all();
16345
+ const { results: countResults } = await db2.prepare(countQuery).bind(...params).all();
16105
16346
  const totalCount = countResults?.[0]?.count || 0;
16106
16347
  const dataQuery = `
16107
16348
  SELECT * FROM code_examples
@@ -16109,7 +16350,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
16109
16350
  ORDER BY sortOrder ASC, created_at DESC
16110
16351
  LIMIT ? OFFSET ?
16111
16352
  `;
16112
- const { results: codeExamples } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
16353
+ const { results: codeExamples } = await db2.prepare(dataQuery).bind(...params, limit, offset).all();
16113
16354
  const totalPages = Math.ceil(totalCount / limit);
16114
16355
  return c.html(renderCodeExamplesList({
16115
16356
  codeExamples: codeExamples || [],
@@ -16157,8 +16398,8 @@ adminCodeExamplesRoutes.post("/", async (c) => {
16157
16398
  const data = Object.fromEntries(formData.entries());
16158
16399
  const validatedData = codeExampleSchema.parse(data);
16159
16400
  const user = c.get("user");
16160
- const db = c.env?.DB;
16161
- if (!db) {
16401
+ const db2 = c.env?.DB;
16402
+ if (!db2) {
16162
16403
  return c.html(renderCodeExamplesForm({
16163
16404
  isEdit: false,
16164
16405
  user: user ? {
@@ -16170,7 +16411,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
16170
16411
  messageType: "error"
16171
16412
  }));
16172
16413
  }
16173
- const { results } = await db.prepare(`
16414
+ const { results } = await db2.prepare(`
16174
16415
  INSERT INTO code_examples (title, description, code, language, category, tags, isPublished, sortOrder)
16175
16416
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
16176
16417
  RETURNING *
@@ -16203,7 +16444,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
16203
16444
  const user = c.get("user");
16204
16445
  if (error instanceof z.ZodError) {
16205
16446
  const errors = {};
16206
- error.errors.forEach((err) => {
16447
+ error.issues.forEach((err) => {
16207
16448
  const field = err.path[0];
16208
16449
  if (!errors[field]) errors[field] = [];
16209
16450
  errors[field].push(err.message);
@@ -16236,8 +16477,8 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
16236
16477
  try {
16237
16478
  const id = parseInt(c.req.param("id"));
16238
16479
  const user = c.get("user");
16239
- const db = c.env?.DB;
16240
- if (!db) {
16480
+ const db2 = c.env?.DB;
16481
+ if (!db2) {
16241
16482
  return c.html(renderCodeExamplesForm({
16242
16483
  isEdit: true,
16243
16484
  user: user ? {
@@ -16249,7 +16490,7 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
16249
16490
  messageType: "error"
16250
16491
  }));
16251
16492
  }
16252
- const { results } = await db.prepare("SELECT * FROM code_examples WHERE id = ?").bind(id).all();
16493
+ const { results } = await db2.prepare("SELECT * FROM code_examples WHERE id = ?").bind(id).all();
16253
16494
  if (!results || results.length === 0) {
16254
16495
  return c.redirect("/admin/code-examples?message=Code example not found&type=error");
16255
16496
  }
@@ -16295,8 +16536,8 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
16295
16536
  const data = Object.fromEntries(formData.entries());
16296
16537
  const validatedData = codeExampleSchema.parse(data);
16297
16538
  const user = c.get("user");
16298
- const db = c.env?.DB;
16299
- if (!db) {
16539
+ const db2 = c.env?.DB;
16540
+ if (!db2) {
16300
16541
  return c.html(renderCodeExamplesForm({
16301
16542
  isEdit: true,
16302
16543
  user: user ? {
@@ -16308,7 +16549,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
16308
16549
  messageType: "error"
16309
16550
  }));
16310
16551
  }
16311
- const { results } = await db.prepare(`
16552
+ const { results } = await db2.prepare(`
16312
16553
  UPDATE code_examples
16313
16554
  SET title = ?, description = ?, code = ?, language = ?, category = ?, tags = ?, isPublished = ?, sortOrder = ?
16314
16555
  WHERE id = ?
@@ -16355,7 +16596,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
16355
16596
  const id = parseInt(c.req.param("id"));
16356
16597
  if (error instanceof z.ZodError) {
16357
16598
  const errors = {};
16358
- error.errors.forEach((err) => {
16599
+ error.issues.forEach((err) => {
16359
16600
  const field = err.path[0];
16360
16601
  if (!errors[field]) errors[field] = [];
16361
16602
  errors[field].push(err.message);
@@ -16409,11 +16650,11 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
16409
16650
  adminCodeExamplesRoutes.delete("/:id", async (c) => {
16410
16651
  try {
16411
16652
  const id = parseInt(c.req.param("id"));
16412
- const db = c.env?.DB;
16413
- if (!db) {
16653
+ const db2 = c.env?.DB;
16654
+ if (!db2) {
16414
16655
  return c.json({ error: "Database not available" }, 500);
16415
16656
  }
16416
- const { changes } = await db.prepare("DELETE FROM code_examples WHERE id = ?").bind(id).run();
16657
+ const { changes } = await db2.prepare("DELETE FROM code_examples WHERE id = ?").bind(id).run();
16417
16658
  if (changes === 0) {
16418
16659
  return c.json({ error: "Code example not found" }, 404);
16419
16660
  }
@@ -17092,10 +17333,10 @@ router.get("/", async (c) => {
17092
17333
  });
17093
17334
  router.get("/stats", async (c) => {
17094
17335
  try {
17095
- const db = c.env.DB;
17336
+ const db2 = c.env.DB;
17096
17337
  let collectionsCount = 0;
17097
17338
  try {
17098
- const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
17339
+ const collectionsStmt = db2.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
17099
17340
  const collectionsResult = await collectionsStmt.first();
17100
17341
  collectionsCount = collectionsResult?.count || 0;
17101
17342
  } catch (error) {
@@ -17103,7 +17344,7 @@ router.get("/stats", async (c) => {
17103
17344
  }
17104
17345
  let contentCount = 0;
17105
17346
  try {
17106
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content");
17347
+ const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content");
17107
17348
  const contentResult = await contentStmt.first();
17108
17349
  contentCount = contentResult?.count || 0;
17109
17350
  } catch (error) {
@@ -17112,7 +17353,7 @@ router.get("/stats", async (c) => {
17112
17353
  let mediaCount = 0;
17113
17354
  let mediaSize = 0;
17114
17355
  try {
17115
- const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
17356
+ const mediaStmt = db2.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
17116
17357
  const mediaResult = await mediaStmt.first();
17117
17358
  mediaCount = mediaResult?.count || 0;
17118
17359
  mediaSize = mediaResult?.total_size || 0;
@@ -17121,7 +17362,7 @@ router.get("/stats", async (c) => {
17121
17362
  }
17122
17363
  let usersCount = 0;
17123
17364
  try {
17124
- const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
17365
+ const usersStmt = db2.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
17125
17366
  const usersResult = await usersStmt.first();
17126
17367
  usersCount = usersResult?.count || 0;
17127
17368
  } catch (error) {
@@ -17142,17 +17383,17 @@ router.get("/stats", async (c) => {
17142
17383
  });
17143
17384
  router.get("/storage", async (c) => {
17144
17385
  try {
17145
- const db = c.env.DB;
17386
+ const db2 = c.env.DB;
17146
17387
  let databaseSize = 0;
17147
17388
  try {
17148
- const result = await db.prepare("SELECT 1").run();
17389
+ const result = await db2.prepare("SELECT 1").run();
17149
17390
  databaseSize = result?.meta?.size_after || 0;
17150
17391
  } catch (error) {
17151
17392
  console.error("Error fetching database size:", error);
17152
17393
  }
17153
17394
  let mediaSize = 0;
17154
17395
  try {
17155
- const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
17396
+ const mediaStmt = db2.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
17156
17397
  const mediaResult = await mediaStmt.first();
17157
17398
  mediaSize = mediaResult?.total_size || 0;
17158
17399
  } catch (error) {
@@ -17167,9 +17408,9 @@ router.get("/storage", async (c) => {
17167
17408
  });
17168
17409
  router.get("/recent-activity", async (c) => {
17169
17410
  try {
17170
- const db = c.env.DB;
17411
+ const db2 = c.env.DB;
17171
17412
  const limit = parseInt(c.req.query("limit") || "5");
17172
- const activityStmt = db.prepare(`
17413
+ const activityStmt = db2.prepare(`
17173
17414
  SELECT
17174
17415
  a.id,
17175
17416
  a.action,
@@ -17773,7 +18014,7 @@ function getFieldTypeBadge(fieldType) {
17773
18014
  "text": "Text",
17774
18015
  "richtext": "Rich Text (TinyMCE)",
17775
18016
  "quill": "Rich Text (Quill)",
17776
- "mdxeditor": "Rich Text (MDXEditor)",
18017
+ "mdxeditor": "EasyMDX",
17777
18018
  "number": "Number",
17778
18019
  "boolean": "Boolean",
17779
18020
  "date": "Date",
@@ -17796,6 +18037,7 @@ function getFieldTypeBadge(fieldType) {
17796
18037
  return `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${color} ring-1 ring-inset">${label}</span>`;
17797
18038
  }
17798
18039
  function renderCollectionFormPage(data) {
18040
+ console.log("[renderCollectionFormPage] editorPlugins:", data.editorPlugins);
17799
18041
  const isEdit = data.isEdit || !!data.id;
17800
18042
  const title = isEdit ? "Edit Collection" : "Create New Collection";
17801
18043
  const subtitle = isEdit ? `Update collection: ${data.display_name}` : "Define a new content collection with custom fields and settings.";
@@ -18260,7 +18502,7 @@ function renderCollectionFormPage(data) {
18260
18502
  <option value="text">Text</option>
18261
18503
  ${data.editorPlugins?.tinymce ? '<option value="richtext">Rich Text (TinyMCE)</option>' : ""}
18262
18504
  ${data.editorPlugins?.quill ? '<option value="quill">Rich Text (Quill)</option>' : ""}
18263
- ${data.editorPlugins?.mdxeditor ? '<option value="mdxeditor">Rich Text (MDXEditor)</option>' : ""}
18505
+ ${data.editorPlugins?.easyMdx ? '<option value="mdxeditor">EasyMDX</option>' : ""}
18264
18506
  <option value="number">Number</option>
18265
18507
  <option value="boolean">Boolean</option>
18266
18508
  <option value="date">Date</option>
@@ -18482,12 +18724,13 @@ function renderCollectionFormPage(data) {
18482
18724
 
18483
18725
  // Check if it's a schema field with field_options that might indicate the actual type
18484
18726
  if (field.field_options && typeof field.field_options === 'object') {
18485
- // Check for richtext format
18486
- if (field.field_options.format === 'richtext') {
18727
+ // Only convert to richtext if type is explicitly 'string' and format is richtext
18728
+ // Don't convert if it's already a specific editor type like 'mdxeditor', 'quill', etc.
18729
+ if (field.field_options.format === 'richtext' && uiFieldType === 'string') {
18487
18730
  uiFieldType = 'richtext';
18488
18731
  }
18489
18732
  // Check for other format indicators
18490
- else if (field.field_options.type) {
18733
+ else if (field.field_options.type && !uiFieldType) {
18491
18734
  uiFieldType = field.field_options.type;
18492
18735
  }
18493
18736
  }
@@ -18503,8 +18746,60 @@ function renderCollectionFormPage(data) {
18503
18746
  uiFieldType = typeMapping[uiFieldType];
18504
18747
  }
18505
18748
 
18749
+ // Log all available options
18750
+ const availableOptions = Array.from(fieldTypeSelect.options).map(opt => ({ value: opt.value, text: opt.text }));
18751
+ console.log('Available dropdown options:', availableOptions);
18752
+ console.log('Trying to set field-type to:', uiFieldType);
18753
+
18754
+ // Clear any existing selections first
18755
+ Array.from(fieldTypeSelect.options).forEach(opt => opt.selected = false);
18756
+
18757
+ // Try multiple approaches to set the value
18758
+ let selectionSucceeded = false;
18759
+
18760
+ // Approach 1: Direct value assignment
18506
18761
  fieldTypeSelect.value = uiFieldType;
18507
- console.log('Set field-type to:', fieldTypeSelect.value, '(original:', field.field_type, ')');
18762
+ if (fieldTypeSelect.value === uiFieldType) {
18763
+ selectionSucceeded = true;
18764
+ console.log('\u2713 Approach 1 (direct value) succeeded');
18765
+ }
18766
+
18767
+ // Approach 2: Find and select the specific option
18768
+ if (!selectionSucceeded) {
18769
+ console.log('Approach 1 failed, trying approach 2 (direct option selection)');
18770
+ const optionToSelect = Array.from(fieldTypeSelect.options).find(opt => opt.value === uiFieldType);
18771
+ if (optionToSelect) {
18772
+ optionToSelect.selected = true;
18773
+ // Trigger change event
18774
+ fieldTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
18775
+ if (fieldTypeSelect.value === uiFieldType) {
18776
+ selectionSucceeded = true;
18777
+ console.log('\u2713 Approach 2 (option.selected) succeeded');
18778
+ }
18779
+ }
18780
+ }
18781
+
18782
+ // Approach 3: Set selectedIndex
18783
+ if (!selectionSucceeded) {
18784
+ console.log('Approach 2 failed, trying approach 3 (selectedIndex)');
18785
+ const optionIndex = Array.from(fieldTypeSelect.options).findIndex(opt => opt.value === uiFieldType);
18786
+ if (optionIndex !== -1) {
18787
+ fieldTypeSelect.selectedIndex = optionIndex;
18788
+ if (fieldTypeSelect.value === uiFieldType) {
18789
+ selectionSucceeded = true;
18790
+ console.log('\u2713 Approach 3 (selectedIndex) succeeded');
18791
+ }
18792
+ }
18793
+ }
18794
+
18795
+ console.log('Final field-type value:', fieldTypeSelect.value, '(wanted:', uiFieldType, ')');
18796
+
18797
+ if (!selectionSucceeded) {
18798
+ console.error('\u274C All approaches failed to set field-type!');
18799
+ console.error('Wanted:', uiFieldType);
18800
+ console.error('Got:', fieldTypeSelect.value);
18801
+ console.error('Available options:', availableOptions);
18802
+ }
18508
18803
  } else {
18509
18804
  console.error('field-type select not found!');
18510
18805
  }
@@ -18575,9 +18870,15 @@ function renderCollectionFormPage(data) {
18575
18870
  setTimeout(() => {
18576
18871
  isEditingField = false;
18577
18872
  console.log('Cleared isEditingField flag');
18578
- }, 100);
18579
18873
 
18580
- }, 10); // Small delay to ensure modal is fully rendered
18874
+ // Double-check the field-type value after the flag is cleared
18875
+ const finalCheck = document.getElementById('field-type');
18876
+ if (finalCheck) {
18877
+ console.log('Post-flag-clear check - field-type value:', finalCheck.value);
18878
+ }
18879
+ }, 200); // Increased delay
18880
+
18881
+ }, 50); // Increased delay to ensure modal is fully rendered
18581
18882
  }
18582
18883
 
18583
18884
  function closeFieldModal() {
@@ -18762,13 +19063,13 @@ adminCollectionsRoutes.use("*", requireAuth());
18762
19063
  adminCollectionsRoutes.get("/", async (c) => {
18763
19064
  try {
18764
19065
  const user = c.get("user");
18765
- const db = c.env.DB;
19066
+ const db2 = c.env.DB;
18766
19067
  const url = new URL(c.req.url);
18767
19068
  const search = url.searchParams.get("search") || "";
18768
19069
  let stmt;
18769
19070
  let results;
18770
19071
  if (search) {
18771
- stmt = db.prepare(`
19072
+ stmt = db2.prepare(`
18772
19073
  SELECT id, name, display_name, description, created_at, managed, schema
18773
19074
  FROM collections
18774
19075
  WHERE is_active = 1
@@ -18779,11 +19080,11 @@ adminCollectionsRoutes.get("/", async (c) => {
18779
19080
  const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
18780
19081
  results = queryResults.results;
18781
19082
  } else {
18782
- stmt = db.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC");
19083
+ stmt = db2.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC");
18783
19084
  const queryResults = await stmt.all();
18784
19085
  results = queryResults.results;
18785
19086
  }
18786
- const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
19087
+ const fieldCountStmt = db2.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
18787
19088
  const { results: fieldCountResults } = await fieldCountStmt.all();
18788
19089
  const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
18789
19090
  const collections = (results || []).filter((row) => row && row.id).map((row) => {
@@ -18824,21 +19125,22 @@ adminCollectionsRoutes.get("/", async (c) => {
18824
19125
  return c.html(renderCollectionsListPage(pageData));
18825
19126
  } catch (error) {
18826
19127
  console.error("Error fetching collections:", error);
18827
- return c.html(html`<p>Error loading collections</p>`);
19128
+ const errorMessage = error instanceof Error ? error.message : String(error);
19129
+ return c.html(html`<p>Error loading collections: ${errorMessage}</p>`);
18828
19130
  }
18829
19131
  });
18830
19132
  adminCollectionsRoutes.get("/new", async (c) => {
18831
19133
  const user = c.get("user");
18832
- const db = c.env.DB;
19134
+ const db2 = c.env.DB;
18833
19135
  const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
18834
- isPluginActive2(db, "tinymce-plugin"),
18835
- isPluginActive2(db, "quill-editor"),
18836
- isPluginActive2(db, "mdxeditor-plugin")
19136
+ isPluginActive2(db2, "tinymce-plugin"),
19137
+ isPluginActive2(db2, "quill-editor"),
19138
+ isPluginActive2(db2, "easy-mdx")
18837
19139
  ]);
18838
19140
  console.log("[Collections /new] Editor plugins status:", {
18839
19141
  tinymce: tinymceActive,
18840
19142
  quill: quillActive,
18841
- mdxeditor: mdxeditorActive
19143
+ easyMdx: mdxeditorActive
18842
19144
  });
18843
19145
  const formData = {
18844
19146
  isEdit: false,
@@ -18851,7 +19153,7 @@ adminCollectionsRoutes.get("/new", async (c) => {
18851
19153
  editorPlugins: {
18852
19154
  tinymce: tinymceActive,
18853
19155
  quill: quillActive,
18854
- mdxeditor: mdxeditorActive
19156
+ easyMdx: mdxeditorActive
18855
19157
  }
18856
19158
  };
18857
19159
  return c.html(renderCollectionFormPage(formData));
@@ -18887,8 +19189,8 @@ adminCollectionsRoutes.post("/", async (c) => {
18887
19189
  return c.redirect("/admin/collections/new");
18888
19190
  }
18889
19191
  }
18890
- const db = c.env.DB;
18891
- const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
19192
+ const db2 = c.env.DB;
19193
+ const existingStmt = db2.prepare("SELECT id FROM collections WHERE name = ?");
18892
19194
  const existing = await existingStmt.bind(name).first();
18893
19195
  if (existing) {
18894
19196
  const errorMsg = "A collection with this name already exists.";
@@ -18924,9 +19226,9 @@ adminCollectionsRoutes.post("/", async (c) => {
18924
19226
  },
18925
19227
  required: ["title"]
18926
19228
  };
18927
- const collectionId = globalThis.crypto.randomUUID();
19229
+ const collectionId = crypto.randomUUID();
18928
19230
  const now = Date.now();
18929
- const insertStmt = db.prepare(`
19231
+ const insertStmt = db2.prepare(`
18930
19232
  INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
18931
19233
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
18932
19234
  `);
@@ -18981,10 +19283,15 @@ adminCollectionsRoutes.get("/:id", async (c) => {
18981
19283
  try {
18982
19284
  const id = c.req.param("id");
18983
19285
  const user = c.get("user");
18984
- const db = c.env.DB;
18985
- const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
19286
+ const db2 = c.env.DB;
19287
+ const stmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
18986
19288
  const collection = await stmt.bind(id).first();
18987
19289
  if (!collection) {
19290
+ const [tinymceActive2, quillActive2, mdxeditorActive2] = await Promise.all([
19291
+ isPluginActive2(db2, "tinymce-plugin"),
19292
+ isPluginActive2(db2, "quill-editor"),
19293
+ isPluginActive2(db2, "easy-mdx")
19294
+ ]);
18988
19295
  const formData2 = {
18989
19296
  isEdit: true,
18990
19297
  error: "Collection not found.",
@@ -18993,7 +19300,12 @@ adminCollectionsRoutes.get("/:id", async (c) => {
18993
19300
  email: user.email,
18994
19301
  role: user.role
18995
19302
  } : void 0,
18996
- version: c.get("appVersion")
19303
+ version: c.get("appVersion"),
19304
+ editorPlugins: {
19305
+ tinymce: tinymceActive2,
19306
+ quill: quillActive2,
19307
+ easyMdx: mdxeditorActive2
19308
+ }
18997
19309
  };
18998
19310
  return c.html(renderCollectionFormPage(formData2));
18999
19311
  }
@@ -19019,28 +19331,44 @@ adminCollectionsRoutes.get("/:id", async (c) => {
19019
19331
  }
19020
19332
  }
19021
19333
  if (fields.length === 0) {
19022
- const fieldsStmt = db.prepare(`
19334
+ const fieldsStmt = db2.prepare(`
19023
19335
  SELECT * FROM content_fields
19024
19336
  WHERE collection_id = ?
19025
19337
  ORDER BY field_order ASC
19026
19338
  `);
19027
19339
  const { results: fieldsResults } = await fieldsStmt.bind(id).all();
19028
- fields = (fieldsResults || []).map((row) => ({
19029
- id: row.id,
19030
- field_name: row.field_name,
19031
- field_type: row.field_type,
19032
- field_label: row.field_label,
19033
- field_options: row.field_options ? JSON.parse(row.field_options) : {},
19034
- field_order: row.field_order,
19035
- is_required: row.is_required === 1,
19036
- is_searchable: row.is_searchable === 1
19037
- }));
19340
+ fields = (fieldsResults || []).map((row) => {
19341
+ let fieldOptions = {};
19342
+ if (row.field_options) {
19343
+ try {
19344
+ fieldOptions = typeof row.field_options === "string" ? JSON.parse(row.field_options) : row.field_options;
19345
+ } catch (e) {
19346
+ console.error("Error parsing field_options for field:", row.field_name, e);
19347
+ fieldOptions = {};
19348
+ }
19349
+ }
19350
+ return {
19351
+ id: row.id,
19352
+ field_name: row.field_name,
19353
+ field_type: row.field_type,
19354
+ field_label: row.field_label,
19355
+ field_options: fieldOptions,
19356
+ field_order: row.field_order,
19357
+ is_required: row.is_required === 1,
19358
+ is_searchable: row.is_searchable === 1
19359
+ };
19360
+ });
19038
19361
  }
19039
19362
  const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
19040
- isPluginActive2(db, "tinymce-plugin"),
19041
- isPluginActive2(db, "quill-editor"),
19042
- isPluginActive2(db, "mdxeditor-plugin")
19363
+ isPluginActive2(db2, "tinymce-plugin"),
19364
+ isPluginActive2(db2, "quill-editor"),
19365
+ isPluginActive2(db2, "easy-mdx")
19043
19366
  ]);
19367
+ console.log("[Collections /:id] Editor plugins status:", {
19368
+ tinymce: tinymceActive,
19369
+ quill: quillActive,
19370
+ easyMdx: mdxeditorActive
19371
+ });
19044
19372
  const formData = {
19045
19373
  id: collection.id,
19046
19374
  name: collection.name,
@@ -19058,13 +19386,18 @@ adminCollectionsRoutes.get("/:id", async (c) => {
19058
19386
  editorPlugins: {
19059
19387
  tinymce: tinymceActive,
19060
19388
  quill: quillActive,
19061
- mdxeditor: mdxeditorActive
19389
+ easyMdx: mdxeditorActive
19062
19390
  }
19063
19391
  };
19064
19392
  return c.html(renderCollectionFormPage(formData));
19065
19393
  } catch (error) {
19066
19394
  console.error("Error fetching collection:", error);
19067
19395
  const user = c.get("user");
19396
+ const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
19397
+ isPluginActive2(db, "tinymce-plugin"),
19398
+ isPluginActive2(db, "quill-editor"),
19399
+ isPluginActive2(db, "easy-mdx")
19400
+ ]);
19068
19401
  const formData = {
19069
19402
  isEdit: true,
19070
19403
  error: "Failed to load collection.",
@@ -19073,7 +19406,12 @@ adminCollectionsRoutes.get("/:id", async (c) => {
19073
19406
  email: user.email,
19074
19407
  role: user.role
19075
19408
  } : void 0,
19076
- version: c.get("appVersion")
19409
+ version: c.get("appVersion"),
19410
+ editorPlugins: {
19411
+ tinymce: tinymceActive,
19412
+ quill: quillActive,
19413
+ easyMdx: mdxeditorActive
19414
+ }
19077
19415
  };
19078
19416
  return c.html(renderCollectionFormPage(formData));
19079
19417
  }
@@ -19091,8 +19429,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
19091
19429
  </div>
19092
19430
  `);
19093
19431
  }
19094
- const db = c.env.DB;
19095
- const updateStmt = db.prepare(`
19432
+ const db2 = c.env.DB;
19433
+ const updateStmt = db2.prepare(`
19096
19434
  UPDATE collections
19097
19435
  SET display_name = ?, description = ?, updated_at = ?
19098
19436
  WHERE id = ?
@@ -19115,8 +19453,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
19115
19453
  adminCollectionsRoutes.delete("/:id", async (c) => {
19116
19454
  try {
19117
19455
  const id = c.req.param("id");
19118
- const db = c.env.DB;
19119
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
19456
+ const db2 = c.env.DB;
19457
+ const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
19120
19458
  const contentResult = await contentStmt.bind(id).first();
19121
19459
  if (contentResult && contentResult.count > 0) {
19122
19460
  return c.html(html`
@@ -19125,9 +19463,9 @@ adminCollectionsRoutes.delete("/:id", async (c) => {
19125
19463
  </div>
19126
19464
  `);
19127
19465
  }
19128
- const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
19466
+ const deleteFieldsStmt = db2.prepare("DELETE FROM content_fields WHERE collection_id = ?");
19129
19467
  await deleteFieldsStmt.bind(id).run();
19130
- const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
19468
+ const deleteStmt = db2.prepare("DELETE FROM collections WHERE id = ?");
19131
19469
  await deleteStmt.bind(id).run();
19132
19470
  return c.html(html`
19133
19471
  <script>
@@ -19159,18 +19497,18 @@ adminCollectionsRoutes.post("/:id/fields", async (c) => {
19159
19497
  if (!/^[a-z0-9_]+$/.test(fieldName)) {
19160
19498
  return c.json({ success: false, error: "Field name must contain only lowercase letters, numbers, and underscores." });
19161
19499
  }
19162
- const db = c.env.DB;
19163
- const existingStmt = db.prepare("SELECT id FROM content_fields WHERE collection_id = ? AND field_name = ?");
19500
+ const db2 = c.env.DB;
19501
+ const existingStmt = db2.prepare("SELECT id FROM content_fields WHERE collection_id = ? AND field_name = ?");
19164
19502
  const existing = await existingStmt.bind(collectionId, fieldName).first();
19165
19503
  if (existing) {
19166
19504
  return c.json({ success: false, error: "A field with this name already exists." });
19167
19505
  }
19168
- const orderStmt = db.prepare("SELECT MAX(field_order) as max_order FROM content_fields WHERE collection_id = ?");
19506
+ const orderStmt = db2.prepare("SELECT MAX(field_order) as max_order FROM content_fields WHERE collection_id = ?");
19169
19507
  const orderResult = await orderStmt.bind(collectionId).first();
19170
19508
  const nextOrder = (orderResult?.max_order || 0) + 1;
19171
- const fieldId = globalThis.crypto.randomUUID();
19509
+ const fieldId = crypto.randomUUID();
19172
19510
  const now = Date.now();
19173
- const insertStmt = db.prepare(`
19511
+ const insertStmt = db2.prepare(`
19174
19512
  INSERT INTO content_fields (
19175
19513
  id, collection_id, field_name, field_type, field_label,
19176
19514
  field_options, field_order, is_required, is_searchable,
@@ -19219,11 +19557,11 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
19219
19557
  if (!fieldLabel) {
19220
19558
  return c.json({ success: false, error: "Field label is required." });
19221
19559
  }
19222
- const db = c.env.DB;
19560
+ const db2 = c.env.DB;
19223
19561
  if (fieldId.startsWith("schema-")) {
19224
19562
  const fieldName = fieldId.replace("schema-", "");
19225
19563
  console.log("[Field Update] Updating schema field:", fieldName);
19226
- const getCollectionStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
19564
+ const getCollectionStmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
19227
19565
  const collection = await getCollectionStmt.bind(collectionId).first();
19228
19566
  if (!collection) {
19229
19567
  return c.json({ success: false, error: "Collection not found." });
@@ -19268,7 +19606,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
19268
19606
  console.log("[Field Update] Final required array:", schema.required);
19269
19607
  console.log("[Field Update] Final field config:", schema.properties[fieldName]);
19270
19608
  }
19271
- const updateCollectionStmt = db.prepare(`
19609
+ const updateCollectionStmt = db2.prepare(`
19272
19610
  UPDATE collections
19273
19611
  SET schema = ?, updated_at = ?
19274
19612
  WHERE id = ?
@@ -19280,7 +19618,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
19280
19618
  });
19281
19619
  return c.json({ success: true });
19282
19620
  }
19283
- const updateStmt = db.prepare(`
19621
+ const updateStmt = db2.prepare(`
19284
19622
  UPDATE content_fields
19285
19623
  SET field_label = ?, field_type = ?, field_options = ?, is_required = ?, is_searchable = ?, updated_at = ?
19286
19624
  WHERE id = ?
@@ -19292,7 +19630,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
19292
19630
  changes: result.meta?.changes,
19293
19631
  last_row_id: result.meta?.last_row_id
19294
19632
  });
19295
- const verifyStmt = db.prepare("SELECT * FROM content_fields WHERE id = ?");
19633
+ const verifyStmt = db2.prepare("SELECT * FROM content_fields WHERE id = ?");
19296
19634
  const verifyResult = await verifyStmt.bind(fieldId).first();
19297
19635
  console.log("[Field Update] Verification - field after update:", verifyResult);
19298
19636
  console.log("[Field Update] Successfully updated field with type:", fieldType);
@@ -19305,8 +19643,8 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
19305
19643
  adminCollectionsRoutes.delete("/:collectionId/fields/:fieldId", async (c) => {
19306
19644
  try {
19307
19645
  const fieldId = c.req.param("fieldId");
19308
- const db = c.env.DB;
19309
- const deleteStmt = db.prepare("DELETE FROM content_fields WHERE id = ?");
19646
+ const db2 = c.env.DB;
19647
+ const deleteStmt = db2.prepare("DELETE FROM content_fields WHERE id = ?");
19310
19648
  await deleteStmt.bind(fieldId).run();
19311
19649
  return c.json({ success: true });
19312
19650
  } catch (error) {
@@ -19321,9 +19659,9 @@ adminCollectionsRoutes.post("/:collectionId/fields/reorder", async (c) => {
19321
19659
  if (!Array.isArray(fieldIds)) {
19322
19660
  return c.json({ success: false, error: "Invalid field order data." });
19323
19661
  }
19324
- const db = c.env.DB;
19662
+ const db2 = c.env.DB;
19325
19663
  for (let i = 0; i < fieldIds.length; i++) {
19326
- const updateStmt = db.prepare("UPDATE content_fields SET field_order = ?, updated_at = ? WHERE id = ?");
19664
+ const updateStmt = db2.prepare("UPDATE content_fields SET field_order = ?, updated_at = ? WHERE id = ?");
19327
19665
  await updateStmt.bind(i + 1, Date.now(), fieldIds[i]).run();
19328
19666
  }
19329
19667
  return c.json({ success: true });
@@ -20846,8 +21184,8 @@ adminSettingsRoutes.get("/", (c) => {
20846
21184
  });
20847
21185
  adminSettingsRoutes.get("/general", async (c) => {
20848
21186
  const user = c.get("user");
20849
- const db = c.env.DB;
20850
- const settingsService = new SettingsService(db);
21187
+ const db2 = c.env.DB;
21188
+ const settingsService = new SettingsService(db2);
20851
21189
  const generalSettings = await settingsService.getGeneralSettings(user?.email);
20852
21190
  const mockSettings = getMockSettings(user);
20853
21191
  mockSettings.general = generalSettings;
@@ -20949,8 +21287,8 @@ adminSettingsRoutes.get("/database-tools", (c) => {
20949
21287
  });
20950
21288
  adminSettingsRoutes.get("/api/migrations/status", async (c) => {
20951
21289
  try {
20952
- const db = c.env.DB;
20953
- const migrationService = new MigrationService(db);
21290
+ const db2 = c.env.DB;
21291
+ const migrationService = new MigrationService(db2);
20954
21292
  const status = await migrationService.getMigrationStatus();
20955
21293
  return c.json({
20956
21294
  success: true,
@@ -20973,8 +21311,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
20973
21311
  error: "Unauthorized. Admin access required."
20974
21312
  }, 403);
20975
21313
  }
20976
- const db = c.env.DB;
20977
- const migrationService = new MigrationService(db);
21314
+ const db2 = c.env.DB;
21315
+ const migrationService = new MigrationService(db2);
20978
21316
  const result = await migrationService.runPendingMigrations();
20979
21317
  return c.json({
20980
21318
  success: result.success,
@@ -20991,8 +21329,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
20991
21329
  });
20992
21330
  adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
20993
21331
  try {
20994
- const db = c.env.DB;
20995
- const migrationService = new MigrationService(db);
21332
+ const db2 = c.env.DB;
21333
+ const migrationService = new MigrationService(db2);
20996
21334
  const validation = await migrationService.validateSchema();
20997
21335
  return c.json({
20998
21336
  success: true,
@@ -21008,8 +21346,8 @@ adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
21008
21346
  });
21009
21347
  adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
21010
21348
  try {
21011
- const db = c.env.DB;
21012
- const tablesQuery = await db.prepare(`
21349
+ const db2 = c.env.DB;
21350
+ const tablesQuery = await db2.prepare(`
21013
21351
  SELECT name FROM sqlite_master
21014
21352
  WHERE type='table'
21015
21353
  AND name NOT LIKE 'sqlite_%'
@@ -21021,7 +21359,7 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
21021
21359
  const tableStats = await Promise.all(
21022
21360
  tables.map(async (table) => {
21023
21361
  try {
21024
- const countResult = await db.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first();
21362
+ const countResult = await db2.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first();
21025
21363
  const rowCount = countResult?.count || 0;
21026
21364
  totalRows += rowCount;
21027
21365
  return {
@@ -21058,8 +21396,8 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
21058
21396
  });
21059
21397
  adminSettingsRoutes.get("/api/database-tools/validate", async (c) => {
21060
21398
  try {
21061
- const db = c.env.DB;
21062
- const integrityResult = await db.prepare("PRAGMA integrity_check").first();
21399
+ const db2 = c.env.DB;
21400
+ const integrityResult = await db2.prepare("PRAGMA integrity_check").first();
21063
21401
  const isValid = integrityResult?.integrity_check === "ok";
21064
21402
  return c.json({
21065
21403
  success: true,
@@ -21114,11 +21452,11 @@ adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
21114
21452
  error: "No tables specified for truncation"
21115
21453
  }, 400);
21116
21454
  }
21117
- const db = c.env.DB;
21455
+ const db2 = c.env.DB;
21118
21456
  const results = [];
21119
21457
  for (const tableName of tablesToTruncate) {
21120
21458
  try {
21121
- await db.prepare(`DELETE FROM ${tableName}`).run();
21459
+ await db2.prepare(`DELETE FROM ${tableName}`).run();
21122
21460
  results.push({ table: tableName, success: true });
21123
21461
  } catch (error) {
21124
21462
  console.error(`Error truncating ${tableName}:`, error);
@@ -21148,8 +21486,8 @@ adminSettingsRoutes.post("/general", async (c) => {
21148
21486
  }, 403);
21149
21487
  }
21150
21488
  const formData = await c.req.formData();
21151
- const db = c.env.DB;
21152
- const settingsService = new SettingsService(db);
21489
+ const db2 = c.env.DB;
21490
+ const settingsService = new SettingsService(db2);
21153
21491
  const settings = {
21154
21492
  siteName: formData.get("siteName"),
21155
21493
  siteDescription: formData.get("siteDescription"),
@@ -21198,6 +21536,7 @@ var ROUTES_INFO = {
21198
21536
  "apiSystemRoutes",
21199
21537
  "adminApiRoutes",
21200
21538
  "authRoutes",
21539
+ "testCleanupRoutes",
21201
21540
  "adminContentRoutes",
21202
21541
  "adminUsersRoutes",
21203
21542
  "adminMediaRoutes",
@@ -21215,6 +21554,6 @@ var ROUTES_INFO = {
21215
21554
  reference: "https://github.com/sonicjs/sonicjs"
21216
21555
  };
21217
21556
 
21218
- export { PluginBuilder, ROUTES_INFO, adminCheckboxRoutes, adminCollectionsRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_code_examples_default, admin_content_default, admin_testimonials_default, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, router, userRoutes };
21219
- //# sourceMappingURL=chunk-CLLJFZ5U.js.map
21220
- //# sourceMappingURL=chunk-CLLJFZ5U.js.map
21557
+ export { PluginBuilder, ROUTES_INFO, adminCheckboxRoutes, adminCollectionsRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_code_examples_default, admin_content_default, admin_testimonials_default, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, router, test_cleanup_default, userRoutes };
21558
+ //# sourceMappingURL=chunk-QWIXOMHW.js.map
21559
+ //# sourceMappingURL=chunk-QWIXOMHW.js.map