@sonicjs-cms/core 2.0.4 → 2.0.5

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 (44) hide show
  1. package/dist/{chunk-LEG4KNFP.cjs → chunk-3JMOWGUU.cjs} +20 -2
  2. package/dist/chunk-3JMOWGUU.cjs.map +1 -0
  3. package/dist/{chunk-LH4Z7QID.js → chunk-6FR25MPC.js} +111 -3
  4. package/dist/chunk-6FR25MPC.js.map +1 -0
  5. package/dist/{chunk-3NVJ6W27.cjs → chunk-DOR2IU73.cjs} +111 -2
  6. package/dist/chunk-DOR2IU73.cjs.map +1 -0
  7. package/dist/{chunk-M6FPVS7E.js → chunk-G5KY3WJV.js} +16 -29
  8. package/dist/chunk-G5KY3WJV.js.map +1 -0
  9. package/dist/{chunk-CDBVZEWR.js → chunk-HSRPDEQQ.js} +20 -2
  10. package/dist/chunk-HSRPDEQQ.js.map +1 -0
  11. package/dist/{chunk-4BJGEGX5.cjs → chunk-IM5SDXOE.cjs} +19 -32
  12. package/dist/chunk-IM5SDXOE.cjs.map +1 -0
  13. package/dist/{chunk-CQ2VMJQO.js → chunk-LGC3TNCY.js} +252 -84
  14. package/dist/chunk-LGC3TNCY.js.map +1 -0
  15. package/dist/{chunk-RZW752PE.cjs → chunk-NPWWR6RI.cjs} +359 -191
  16. package/dist/chunk-NPWWR6RI.cjs.map +1 -0
  17. package/dist/{chunk-BRPONFW6.cjs → chunk-TRSHFTF6.cjs} +3 -3
  18. package/dist/{chunk-BRPONFW6.cjs.map → chunk-TRSHFTF6.cjs.map} +1 -1
  19. package/dist/{chunk-WKGONLHK.js → chunk-VSLEA22M.js} +3 -3
  20. package/dist/{chunk-WKGONLHK.js.map → chunk-VSLEA22M.js.map} +1 -1
  21. package/dist/index.cjs +876 -127
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.js +759 -9
  24. package/dist/index.js.map +1 -1
  25. package/dist/middleware.cjs +23 -23
  26. package/dist/middleware.js +2 -2
  27. package/dist/routes.cjs +25 -25
  28. package/dist/routes.js +5 -5
  29. package/dist/services.cjs +25 -21
  30. package/dist/services.js +2 -2
  31. package/dist/utils.cjs +11 -11
  32. package/dist/utils.js +1 -1
  33. package/migrations/006_plugin_system.sql +2 -2
  34. package/migrations/011_config_managed_collections.sql +1 -0
  35. package/migrations/018_settings_table.sql +23 -0
  36. package/package.json +1 -1
  37. package/dist/chunk-3NVJ6W27.cjs.map +0 -1
  38. package/dist/chunk-4BJGEGX5.cjs.map +0 -1
  39. package/dist/chunk-CDBVZEWR.js.map +0 -1
  40. package/dist/chunk-CQ2VMJQO.js.map +0 -1
  41. package/dist/chunk-LEG4KNFP.cjs.map +0 -1
  42. package/dist/chunk-LH4Z7QID.js.map +0 -1
  43. package/dist/chunk-M6FPVS7E.js.map +0 -1
  44. package/dist/chunk-RZW752PE.cjs.map +0 -1
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunk3NVJ6W27_cjs = require('./chunk-3NVJ6W27.cjs');
4
- var chunk4BJGEGX5_cjs = require('./chunk-4BJGEGX5.cjs');
5
- var chunkLEG4KNFP_cjs = require('./chunk-LEG4KNFP.cjs');
3
+ var chunkDOR2IU73_cjs = require('./chunk-DOR2IU73.cjs');
4
+ var chunkIM5SDXOE_cjs = require('./chunk-IM5SDXOE.cjs');
5
+ var chunk3JMOWGUU_cjs = require('./chunk-3JMOWGUU.cjs');
6
6
  var chunk3SPQ3J4N_cjs = require('./chunk-3SPQ3J4N.cjs');
7
- var chunkBRPONFW6_cjs = require('./chunk-BRPONFW6.cjs');
7
+ var chunkTRSHFTF6_cjs = require('./chunk-TRSHFTF6.cjs');
8
8
  var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
9
9
  var hono = require('hono');
10
10
  var cors = require('hono/cors');
@@ -43,7 +43,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
43
43
  }, 500);
44
44
  }
45
45
  });
46
- apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
46
+ apiContentCrudRoutes.post("/", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
47
47
  try {
48
48
  const db = c.env.DB;
49
49
  const user = c.get("user");
@@ -80,11 +80,11 @@ apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
80
80
  title,
81
81
  JSON.stringify(data || {}),
82
82
  status || "draft",
83
- user?.userId || "unknown",
83
+ user?.userId || "system",
84
84
  now,
85
85
  now
86
86
  ).run();
87
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
87
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
88
88
  await cache.invalidate(`content:list:${collectionId}:*`);
89
89
  await cache.invalidate("content-filtered:*");
90
90
  const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
@@ -109,7 +109,7 @@ apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
109
109
  }, 500);
110
110
  }
111
111
  });
112
- apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
112
+ apiContentCrudRoutes.put("/:id", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
113
113
  try {
114
114
  const id = c.req.param("id");
115
115
  const db = c.env.DB;
@@ -147,7 +147,7 @@ apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
147
147
  WHERE id = ?
148
148
  `);
149
149
  await updateStmt.bind(...params).run();
150
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
150
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
151
151
  await cache.delete(cache.generateKey("content", id));
152
152
  await cache.invalidate(`content:list:${existing.collection_id}:*`);
153
153
  await cache.invalidate("content-filtered:*");
@@ -173,7 +173,7 @@ apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
173
173
  }, 500);
174
174
  }
175
175
  });
176
- apiContentCrudRoutes.delete("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
176
+ apiContentCrudRoutes.delete("/:id", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
177
177
  try {
178
178
  const id = c.req.param("id");
179
179
  const db = c.env.DB;
@@ -184,7 +184,7 @@ apiContentCrudRoutes.delete("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) =
184
184
  }
185
185
  const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
186
186
  await deleteStmt.bind(id).run();
187
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
187
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
188
188
  await cache.delete(cache.generateKey("content", id));
189
189
  await cache.invalidate(`content:list:${existing.collection_id}:*`);
190
190
  await cache.invalidate("content-filtered:*");
@@ -209,7 +209,7 @@ apiRoutes.use("*", async (c, next) => {
209
209
  c.header("X-Response-Time", `${totalTime}ms`);
210
210
  });
211
211
  apiRoutes.use("*", async (c, next) => {
212
- const cacheEnabled = await chunk4BJGEGX5_cjs.isPluginActive(c.env.DB, "core-cache");
212
+ const cacheEnabled = await chunkIM5SDXOE_cjs.isPluginActive(c.env.DB, "core-cache");
213
213
  c.set("cacheEnabled", cacheEnabled);
214
214
  await next();
215
215
  });
@@ -257,7 +257,7 @@ apiRoutes.get("/collections", async (c) => {
257
257
  try {
258
258
  const db = c.env.DB;
259
259
  const cacheEnabled = c.get("cacheEnabled");
260
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
260
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
261
261
  const cacheKey = cache.generateKey("collections", "all");
262
262
  if (cacheEnabled) {
263
263
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -334,12 +334,12 @@ apiRoutes.get("/content", async (c) => {
334
334
  });
335
335
  }
336
336
  }
337
- const filter = chunkBRPONFW6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
337
+ const filter = chunkTRSHFTF6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
338
338
  if (!filter.limit) {
339
339
  filter.limit = 50;
340
340
  }
341
341
  filter.limit = Math.min(filter.limit, 1e3);
342
- const builder = new chunkBRPONFW6_cjs.QueryFilterBuilder();
342
+ const builder = new chunkTRSHFTF6_cjs.QueryFilterBuilder();
343
343
  const queryResult = builder.build("content", filter);
344
344
  if (queryResult.errors.length > 0) {
345
345
  return c.json({
@@ -348,7 +348,7 @@ apiRoutes.get("/content", async (c) => {
348
348
  }, 400);
349
349
  }
350
350
  const cacheEnabled = c.get("cacheEnabled");
351
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
351
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
352
352
  const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
353
353
  if (cacheEnabled) {
354
354
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -426,7 +426,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
426
426
  if (!collectionResult) {
427
427
  return c.json({ error: "Collection not found" }, 404);
428
428
  }
429
- const filter = chunkBRPONFW6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
429
+ const filter = chunkTRSHFTF6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
430
430
  if (!filter.where) {
431
431
  filter.where = { and: [] };
432
432
  }
@@ -442,7 +442,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
442
442
  filter.limit = 50;
443
443
  }
444
444
  filter.limit = Math.min(filter.limit, 1e3);
445
- const builder = new chunkBRPONFW6_cjs.QueryFilterBuilder();
445
+ const builder = new chunkTRSHFTF6_cjs.QueryFilterBuilder();
446
446
  const queryResult = builder.build("content", filter);
447
447
  if (queryResult.errors.length > 0) {
448
448
  return c.json({
@@ -451,7 +451,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
451
451
  }, 400);
452
452
  }
453
453
  const cacheEnabled = c.get("cacheEnabled");
454
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
454
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
455
455
  const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
456
456
  if (cacheEnabled) {
457
457
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -567,7 +567,7 @@ var fileValidationSchema = zod.z.object({
567
567
  // 50MB max
568
568
  });
569
569
  var apiMediaRoutes = new hono.Hono();
570
- apiMediaRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
570
+ apiMediaRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
571
571
  apiMediaRoutes.post("/upload", async (c) => {
572
572
  try {
573
573
  const user = c.get("user");
@@ -673,6 +673,7 @@ apiMediaRoutes.post("/upload", async (c) => {
673
673
  size: mediaRecord.size,
674
674
  width: mediaRecord.width,
675
675
  height: mediaRecord.height,
676
+ r2_key: mediaRecord.r2_key,
676
677
  publicUrl: mediaRecord.public_url,
677
678
  thumbnailUrl: mediaRecord.thumbnail_url,
678
679
  uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
@@ -799,6 +800,7 @@ apiMediaRoutes.post("/upload-multiple", async (c) => {
799
800
  size: mediaRecord.size,
800
801
  width: mediaRecord.width,
801
802
  height: mediaRecord.height,
803
+ r2_key: mediaRecord.r2_key,
802
804
  publicUrl: mediaRecord.public_url,
803
805
  thumbnailUrl: mediaRecord.thumbnail_url,
804
806
  uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
@@ -1309,8 +1311,8 @@ apiSystemRoutes.get("/env", (c) => {
1309
1311
  });
1310
1312
  var api_system_default = apiSystemRoutes;
1311
1313
  var adminApiRoutes = new hono.Hono();
1312
- adminApiRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
1313
- adminApiRoutes.use("*", chunk4BJGEGX5_cjs.requireRole(["admin", "editor"]));
1314
+ adminApiRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
1315
+ adminApiRoutes.use("*", chunkIM5SDXOE_cjs.requireRole(["admin", "editor"]));
1314
1316
  adminApiRoutes.get("/stats", async (c) => {
1315
1317
  try {
1316
1318
  const db = c.env.DB;
@@ -1442,8 +1444,12 @@ adminApiRoutes.get("/activity", async (c) => {
1442
1444
  });
1443
1445
  var createCollectionSchema = zod.z.object({
1444
1446
  name: zod.z.string().min(1).max(255).regex(/^[a-z0-9_]+$/, "Must contain only lowercase letters, numbers, and underscores"),
1445
- display_name: zod.z.string().min(1).max(255),
1447
+ displayName: zod.z.string().min(1).max(255).optional(),
1448
+ display_name: zod.z.string().min(1).max(255).optional(),
1446
1449
  description: zod.z.string().optional()
1450
+ }).refine((data) => data.displayName || data.display_name, {
1451
+ message: "Either displayName or display_name is required",
1452
+ path: ["displayName"]
1447
1453
  });
1448
1454
  var updateCollectionSchema = zod.z.object({
1449
1455
  display_name: zod.z.string().min(1).max(255).optional(),
@@ -1530,15 +1536,16 @@ adminApiRoutes.get("/collections/:id", async (c) => {
1530
1536
  updated_at: Number(row.updated_at)
1531
1537
  }));
1532
1538
  return c.json({
1533
- data: {
1534
- ...collection,
1535
- is_active: collection.is_active === 1,
1536
- managed: collection.managed === 1,
1537
- schema: collection.schema ? JSON.parse(collection.schema) : null,
1538
- created_at: Number(collection.created_at),
1539
- updated_at: Number(collection.updated_at),
1540
- fields
1541
- }
1539
+ id: collection.id,
1540
+ name: collection.name,
1541
+ display_name: collection.display_name,
1542
+ description: collection.description,
1543
+ is_active: collection.is_active === 1,
1544
+ managed: collection.managed === 1,
1545
+ schema: collection.schema ? JSON.parse(collection.schema) : null,
1546
+ created_at: Number(collection.created_at),
1547
+ updated_at: Number(collection.updated_at),
1548
+ fields
1542
1549
  });
1543
1550
  } catch (error) {
1544
1551
  console.error("Error fetching collection:", error);
@@ -1547,7 +1554,16 @@ adminApiRoutes.get("/collections/:id", async (c) => {
1547
1554
  });
1548
1555
  adminApiRoutes.post("/collections", async (c) => {
1549
1556
  try {
1550
- const body = await c.req.json();
1557
+ const contentType = c.req.header("Content-Type");
1558
+ if (!contentType || !contentType.includes("application/json")) {
1559
+ return c.json({ error: "Content-Type must be application/json" }, 400);
1560
+ }
1561
+ let body;
1562
+ try {
1563
+ body = await c.req.json();
1564
+ } catch (e) {
1565
+ return c.json({ error: "Invalid JSON in request body" }, 400);
1566
+ }
1551
1567
  const validation = createCollectionSchema.safeParse(body);
1552
1568
  if (!validation.success) {
1553
1569
  return c.json({ error: "Validation failed", details: validation.error.errors }, 400);
@@ -1555,6 +1571,7 @@ adminApiRoutes.post("/collections", async (c) => {
1555
1571
  const validatedData = validation.data;
1556
1572
  const db = c.env.DB;
1557
1573
  const user = c.get("user");
1574
+ const displayName = validatedData.displayName || validatedData.display_name || "";
1558
1575
  const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
1559
1576
  const existing = await existingStmt.bind(validatedData.name).first();
1560
1577
  if (existing) {
@@ -1591,7 +1608,7 @@ adminApiRoutes.post("/collections", async (c) => {
1591
1608
  await insertStmt.bind(
1592
1609
  collectionId,
1593
1610
  validatedData.name,
1594
- validatedData.display_name,
1611
+ displayName,
1595
1612
  validatedData.description || null,
1596
1613
  JSON.stringify(basicSchema),
1597
1614
  1,
@@ -1606,13 +1623,11 @@ adminApiRoutes.post("/collections", async (c) => {
1606
1623
  console.error("Error clearing cache:", e);
1607
1624
  }
1608
1625
  return c.json({
1609
- data: {
1610
- id: collectionId,
1611
- name: validatedData.name,
1612
- display_name: validatedData.display_name,
1613
- description: validatedData.description,
1614
- created_at: now
1615
- }
1626
+ id: collectionId,
1627
+ name: validatedData.name,
1628
+ displayName,
1629
+ description: validatedData.description,
1630
+ created_at: now
1616
1631
  }, 201);
1617
1632
  } catch (error) {
1618
1633
  console.error("Error creating collection:", error);
@@ -1676,6 +1691,11 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
1676
1691
  try {
1677
1692
  const id = c.req.param("id");
1678
1693
  const db = c.env.DB;
1694
+ const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
1695
+ const collection = await collectionStmt.bind(id).first();
1696
+ if (!collection) {
1697
+ return c.json({ error: "Collection not found" }, 404);
1698
+ }
1679
1699
  const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
1680
1700
  const contentResult = await contentStmt.bind(id).first();
1681
1701
  if (contentResult && contentResult.count > 0) {
@@ -1683,17 +1703,13 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
1683
1703
  error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
1684
1704
  }, 400);
1685
1705
  }
1686
- const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
1687
- const collection = await collectionStmt.bind(id).first();
1688
1706
  const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
1689
1707
  await deleteFieldsStmt.bind(id).run();
1690
1708
  const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
1691
1709
  await deleteStmt.bind(id).run();
1692
1710
  try {
1693
1711
  await c.env.CACHE_KV.delete("cache:collections:all");
1694
- if (collection) {
1695
- await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
1696
- }
1712
+ await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
1697
1713
  } catch (e) {
1698
1714
  console.error("Error clearing cache:", e);
1699
1715
  }
@@ -2126,7 +2142,7 @@ authRoutes.post(
2126
2142
  if (existingUser) {
2127
2143
  return c.json({ error: "User with this email or username already exists" }, 400);
2128
2144
  }
2129
- const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
2145
+ const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
2130
2146
  const userId = crypto.randomUUID();
2131
2147
  const now = /* @__PURE__ */ new Date();
2132
2148
  await db.prepare(`
@@ -2146,7 +2162,7 @@ authRoutes.post(
2146
2162
  now.getTime(),
2147
2163
  now.getTime()
2148
2164
  ).run();
2149
- const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
2165
+ const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
2150
2166
  cookie.setCookie(c, "auth_token", token, {
2151
2167
  httpOnly: true,
2152
2168
  secure: true,
@@ -2181,7 +2197,7 @@ authRoutes.post("/login", async (c) => {
2181
2197
  const { email, password } = validation.data;
2182
2198
  const db = c.env.DB;
2183
2199
  const normalizedEmail = email.toLowerCase();
2184
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.user);
2200
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.user);
2185
2201
  let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
2186
2202
  if (!user) {
2187
2203
  user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
@@ -2193,11 +2209,11 @@ authRoutes.post("/login", async (c) => {
2193
2209
  if (!user) {
2194
2210
  return c.json({ error: "Invalid email or password" }, 401);
2195
2211
  }
2196
- const isValidPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(password, user.password_hash);
2212
+ const isValidPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(password, user.password_hash);
2197
2213
  if (!isValidPassword) {
2198
2214
  return c.json({ error: "Invalid email or password" }, 401);
2199
2215
  }
2200
- const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.id, user.email, user.role);
2216
+ const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.id, user.email, user.role);
2201
2217
  cookie.setCookie(c, "auth_token", token, {
2202
2218
  httpOnly: true,
2203
2219
  secure: true,
@@ -2246,7 +2262,7 @@ authRoutes.get("/logout", (c) => {
2246
2262
  });
2247
2263
  return c.redirect("/auth/login?message=You have been logged out successfully");
2248
2264
  });
2249
- authRoutes.get("/me", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
2265
+ authRoutes.get("/me", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
2250
2266
  try {
2251
2267
  const user = c.get("user");
2252
2268
  if (!user) {
@@ -2263,13 +2279,13 @@ authRoutes.get("/me", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
2263
2279
  return c.json({ error: "Failed to get user" }, 500);
2264
2280
  }
2265
2281
  });
2266
- authRoutes.post("/refresh", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
2282
+ authRoutes.post("/refresh", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
2267
2283
  try {
2268
2284
  const user = c.get("user");
2269
2285
  if (!user) {
2270
2286
  return c.json({ error: "Not authenticated" }, 401);
2271
2287
  }
2272
- const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
2288
+ const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
2273
2289
  cookie.setCookie(c, "auth_token", token, {
2274
2290
  httpOnly: true,
2275
2291
  secure: true,
@@ -2319,7 +2335,7 @@ authRoutes.post("/register/form", async (c) => {
2319
2335
  </div>
2320
2336
  `);
2321
2337
  }
2322
- const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
2338
+ const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
2323
2339
  const userId = crypto.randomUUID();
2324
2340
  const now = /* @__PURE__ */ new Date();
2325
2341
  await db.prepare(`
@@ -2339,7 +2355,7 @@ authRoutes.post("/register/form", async (c) => {
2339
2355
  now.getTime(),
2340
2356
  now.getTime()
2341
2357
  ).run();
2342
- const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
2358
+ const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
2343
2359
  cookie.setCookie(c, "auth_token", token, {
2344
2360
  httpOnly: true,
2345
2361
  secure: false,
@@ -2390,7 +2406,7 @@ authRoutes.post("/login/form", async (c) => {
2390
2406
  </div>
2391
2407
  `);
2392
2408
  }
2393
- const isValidPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(password, user.password_hash);
2409
+ const isValidPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(password, user.password_hash);
2394
2410
  if (!isValidPassword) {
2395
2411
  return c.html(html.html`
2396
2412
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -2398,7 +2414,7 @@ authRoutes.post("/login/form", async (c) => {
2398
2414
  </div>
2399
2415
  `);
2400
2416
  }
2401
- const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.id, user.email, user.role);
2417
+ const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.id, user.email, user.role);
2402
2418
  cookie.setCookie(c, "auth_token", token, {
2403
2419
  httpOnly: true,
2404
2420
  secure: false,
@@ -2467,7 +2483,7 @@ authRoutes.post("/seed-admin", async (c) => {
2467
2483
  }
2468
2484
  });
2469
2485
  }
2470
- const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword("admin123");
2486
+ const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword("admin123");
2471
2487
  const userId = "admin-user-id";
2472
2488
  const now = Date.now();
2473
2489
  const adminEmail = "admin@sonicjs.com".toLowerCase();
@@ -2687,7 +2703,7 @@ authRoutes.post("/accept-invitation", async (c) => {
2687
2703
  if (existingUsername) {
2688
2704
  return c.json({ error: "Username is already taken" }, 400);
2689
2705
  }
2690
- const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
2706
+ const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
2691
2707
  const updateStmt = db.prepare(`
2692
2708
  UPDATE users SET
2693
2709
  username = ?,
@@ -2706,7 +2722,7 @@ authRoutes.post("/accept-invitation", async (c) => {
2706
2722
  Date.now(),
2707
2723
  invitedUser.id
2708
2724
  ).run();
2709
- const authToken = await chunk4BJGEGX5_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
2725
+ const authToken = await chunkIM5SDXOE_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
2710
2726
  cookie.setCookie(c, "auth_token", authToken, {
2711
2727
  httpOnly: true,
2712
2728
  secure: true,
@@ -2936,7 +2952,7 @@ authRoutes.post("/reset-password", async (c) => {
2936
2952
  if (Date.now() > user.password_reset_expires) {
2937
2953
  return c.json({ error: "Reset token has expired" }, 400);
2938
2954
  }
2939
- const newPasswordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
2955
+ const newPasswordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
2940
2956
  try {
2941
2957
  const historyStmt = db.prepare(`
2942
2958
  INSERT INTO password_history (id, user_id, password_hash, created_at)
@@ -4741,9 +4757,9 @@ var isPluginActive2 = () => false;
4741
4757
 
4742
4758
  // src/routes/admin-content.ts
4743
4759
  var adminContentRoutes = new hono.Hono();
4744
- adminContentRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
4760
+ adminContentRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
4745
4761
  async function getCollectionFields(db, collectionId) {
4746
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.collection);
4762
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.collection);
4747
4763
  return cache.getOrSet(
4748
4764
  cache.generateKey("fields", collectionId),
4749
4765
  async () => {
@@ -4767,7 +4783,7 @@ async function getCollectionFields(db, collectionId) {
4767
4783
  );
4768
4784
  }
4769
4785
  async function getCollection(db, collectionId) {
4770
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.collection);
4786
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.collection);
4771
4787
  return cache.getOrSet(
4772
4788
  cache.generateKey("collection", collectionId),
4773
4789
  async () => {
@@ -5023,7 +5039,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
5023
5039
  const db = c.env.DB;
5024
5040
  const url = new URL(c.req.url);
5025
5041
  const referrerParams = url.searchParams.get("ref") || "";
5026
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
5042
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
5027
5043
  const content = await cache.getOrSet(
5028
5044
  cache.generateKey("content", id),
5029
5045
  async () => {
@@ -5192,11 +5208,11 @@ adminContentRoutes.post("/", async (c) => {
5192
5208
  const now = Date.now();
5193
5209
  const insertStmt = db.prepare(`
5194
5210
  INSERT INTO content (
5195
- id, collection_id, slug, title, data, status,
5211
+ id, collection_id, slug, title, data, status,
5196
5212
  scheduled_publish_at, scheduled_unpublish_at,
5197
- meta_title, meta_description, author_id, created_at, updated_at
5213
+ meta_title, meta_description, author_id, created_by, created_at, updated_at
5198
5214
  )
5199
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5215
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5200
5216
  `);
5201
5217
  await insertStmt.bind(
5202
5218
  contentId,
@@ -5210,10 +5226,11 @@ adminContentRoutes.post("/", async (c) => {
5210
5226
  data.meta_title || null,
5211
5227
  data.meta_description || null,
5212
5228
  user?.userId || "unknown",
5229
+ user?.userId || "unknown",
5213
5230
  now,
5214
5231
  now
5215
5232
  ).run();
5216
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
5233
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
5217
5234
  await cache.invalidate(`content:list:${collectionId}:*`);
5218
5235
  const versionStmt = db.prepare(`
5219
5236
  INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
@@ -5361,7 +5378,7 @@ adminContentRoutes.put("/:id", async (c) => {
5361
5378
  now,
5362
5379
  id
5363
5380
  ).run();
5364
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
5381
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
5365
5382
  await cache.delete(cache.generateKey("content", id));
5366
5383
  await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
5367
5384
  const existingData = JSON.parse(existingContent.data || "{}");
@@ -5511,10 +5528,10 @@ adminContentRoutes.post("/duplicate", async (c) => {
5511
5528
  originalData.title = `${originalData.title || "Untitled"} (Copy)`;
5512
5529
  const insertStmt = db.prepare(`
5513
5530
  INSERT INTO content (
5514
- id, collection_id, slug, title, data, status,
5515
- author_id, created_at, updated_at
5531
+ id, collection_id, slug, title, data, status,
5532
+ author_id, created_by, created_at, updated_at
5516
5533
  )
5517
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
5534
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5518
5535
  `);
5519
5536
  await insertStmt.bind(
5520
5537
  newId,
@@ -5525,6 +5542,7 @@ adminContentRoutes.post("/duplicate", async (c) => {
5525
5542
  "draft",
5526
5543
  // Always start as draft
5527
5544
  user?.userId || "unknown",
5545
+ user?.userId || "unknown",
5528
5546
  now,
5529
5547
  now
5530
5548
  ).run();
@@ -5654,7 +5672,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
5654
5672
  } else {
5655
5673
  return c.json({ success: false, error: "Invalid action" });
5656
5674
  }
5657
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
5675
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
5658
5676
  for (const contentId of ids) {
5659
5677
  await cache.delete(cache.generateKey("content", contentId));
5660
5678
  }
@@ -5682,7 +5700,7 @@ adminContentRoutes.delete("/:id", async (c) => {
5682
5700
  WHERE id = ?
5683
5701
  `);
5684
5702
  await deleteStmt.bind(now, id).run();
5685
- const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
5703
+ const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
5686
5704
  await cache.delete(cache.generateKey("content", id));
5687
5705
  await cache.invalidate("content:list:*");
5688
5706
  return c.html(`
@@ -5875,6 +5893,11 @@ var admin_content_default = adminContentRoutes;
5875
5893
 
5876
5894
  // src/templates/pages/admin-profile.template.ts
5877
5895
  chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
5896
+ function renderAvatarImage(avatarUrl, firstName, lastName) {
5897
+ return `<div id="avatar-image-container" class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-cyan-400 to-purple-400 flex items-center justify-center ring-4 ring-zinc-950/5 dark:ring-white/10">
5898
+ ${avatarUrl ? `<img src="${avatarUrl}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${firstName.charAt(0)}${lastName.charAt(0)}</span>`}
5899
+ </div>`;
5900
+ }
5878
5901
  function renderProfilePage(data) {
5879
5902
  const pageContent = `
5880
5903
  <div class="space-y-8">
@@ -6073,9 +6096,7 @@ function renderProfilePage(data) {
6073
6096
  <h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Profile Picture</h3>
6074
6097
 
6075
6098
  <div class="text-center">
6076
- <div class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-cyan-400 to-purple-400 flex items-center justify-center ring-4 ring-zinc-950/5 dark:ring-white/10">
6077
- ${data.profile.avatar_url ? `<img src="${data.profile.avatar_url}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${data.profile.first_name.charAt(0)}${data.profile.last_name.charAt(0)}</span>`}
6078
- </div>
6099
+ ${renderAvatarImage(data.profile.avatar_url, data.profile.first_name, data.profile.last_name)}
6079
6100
 
6080
6101
  <form id="avatar-form" hx-post="/admin/profile/avatar" hx-target="#avatar-messages" hx-encoding="multipart/form-data">
6081
6102
  <input
@@ -6723,7 +6744,7 @@ function renderUserEditPage(data) {
6723
6744
  <input
6724
6745
  type="text"
6725
6746
  name="first_name"
6726
- value="${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.firstName || "")}"
6747
+ value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.firstName || "")}"
6727
6748
  required
6728
6749
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6729
6750
  />
@@ -6734,7 +6755,7 @@ function renderUserEditPage(data) {
6734
6755
  <input
6735
6756
  type="text"
6736
6757
  name="last_name"
6737
- value="${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.lastName || "")}"
6758
+ value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.lastName || "")}"
6738
6759
  required
6739
6760
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6740
6761
  />
@@ -6745,7 +6766,7 @@ function renderUserEditPage(data) {
6745
6766
  <input
6746
6767
  type="text"
6747
6768
  name="username"
6748
- value="${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.username || "")}"
6769
+ value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.username || "")}"
6749
6770
  required
6750
6771
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6751
6772
  />
@@ -6756,7 +6777,7 @@ function renderUserEditPage(data) {
6756
6777
  <input
6757
6778
  type="email"
6758
6779
  name="email"
6759
- value="${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.email || "")}"
6780
+ value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.email || "")}"
6760
6781
  required
6761
6782
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6762
6783
  />
@@ -6767,7 +6788,7 @@ function renderUserEditPage(data) {
6767
6788
  <input
6768
6789
  type="tel"
6769
6790
  name="phone"
6770
- value="${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.phone || "")}"
6791
+ value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.phone || "")}"
6771
6792
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6772
6793
  />
6773
6794
  </div>
@@ -6781,7 +6802,7 @@ function renderUserEditPage(data) {
6781
6802
  class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 dark:bg-white/5 py-1.5 pl-3 pr-8 text-base text-zinc-950 dark:text-white outline outline-1 -outline-offset-1 outline-zinc-500/30 dark:outline-zinc-400/30 *:bg-white dark:*:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-zinc-500 dark:focus-visible:outline-zinc-400 sm:text-sm/6"
6782
6803
  >
6783
6804
  ${data.roles.map((role) => `
6784
- <option value="${chunkBRPONFW6_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunkBRPONFW6_cjs.escapeHtml(role.label)}</option>
6805
+ <option value="${chunkTRSHFTF6_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunkTRSHFTF6_cjs.escapeHtml(role.label)}</option>
6785
6806
  `).join("")}
6786
6807
  </select>
6787
6808
  <svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-zinc-600 dark:text-zinc-400 sm:size-4">
@@ -6797,7 +6818,7 @@ function renderUserEditPage(data) {
6797
6818
  name="bio"
6798
6819
  rows="3"
6799
6820
  class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white 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"
6800
- >${chunkBRPONFW6_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
6821
+ >${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
6801
6822
  </div>
6802
6823
  </div>
6803
6824
 
@@ -7697,7 +7718,7 @@ function renderUsersListPage(data) {
7697
7718
 
7698
7719
  // src/routes/admin-users.ts
7699
7720
  var userRoutes = new hono.Hono();
7700
- userRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
7721
+ userRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
7701
7722
  userRoutes.get("/", (c) => {
7702
7723
  return c.redirect("/admin/dashboard");
7703
7724
  });
@@ -7796,12 +7817,12 @@ userRoutes.put("/profile", async (c) => {
7796
7817
  const db = c.env.DB;
7797
7818
  try {
7798
7819
  const formData = await c.req.formData();
7799
- const firstName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("first_name")?.toString());
7800
- const lastName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("last_name")?.toString());
7801
- const username = chunkBRPONFW6_cjs.sanitizeInput(formData.get("username")?.toString());
7820
+ const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
7821
+ const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
7822
+ const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
7802
7823
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
7803
- const phone = chunkBRPONFW6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
7804
- const bio = chunkBRPONFW6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
7824
+ const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
7825
+ const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
7805
7826
  const timezone = formData.get("timezone")?.toString() || "UTC";
7806
7827
  const language = formData.get("language")?.toString() || "en";
7807
7828
  const emailNotifications = formData.get("email_notifications") === "1";
@@ -7852,7 +7873,7 @@ userRoutes.put("/profile", async (c) => {
7852
7873
  Date.now(),
7853
7874
  user.userId
7854
7875
  ).run();
7855
- await chunk4BJGEGX5_cjs.logActivity(
7876
+ await chunkIM5SDXOE_cjs.logActivity(
7856
7877
  db,
7857
7878
  user.userId,
7858
7879
  "profile.update",
@@ -7911,7 +7932,11 @@ userRoutes.post("/profile/avatar", async (c) => {
7911
7932
  WHERE id = ?
7912
7933
  `);
7913
7934
  await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
7914
- await chunk4BJGEGX5_cjs.logActivity(
7935
+ const userStmt = db.prepare(`
7936
+ SELECT first_name, last_name FROM users WHERE id = ?
7937
+ `);
7938
+ const userData = await userStmt.bind(user.userId).first();
7939
+ await chunkIM5SDXOE_cjs.logActivity(
7915
7940
  db,
7916
7941
  user.userId,
7917
7942
  "profile.avatar_update",
@@ -7921,11 +7946,18 @@ userRoutes.post("/profile/avatar", async (c) => {
7921
7946
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
7922
7947
  c.req.header("user-agent")
7923
7948
  );
7924
- return c.html(renderAlert2({
7949
+ const alertHtml = renderAlert2({
7925
7950
  type: "success",
7926
7951
  message: "Profile picture updated successfully!",
7927
7952
  dismissible: true
7928
- }));
7953
+ });
7954
+ const avatarUrlWithCache = `${avatarUrl}?t=${Date.now()}`;
7955
+ const avatarImageHtml = renderAvatarImage(avatarUrlWithCache, userData.first_name, userData.last_name);
7956
+ const avatarImageWithOob = avatarImageHtml.replace(
7957
+ 'id="avatar-image-container"',
7958
+ 'id="avatar-image-container" hx-swap-oob="true"'
7959
+ );
7960
+ return c.html(alertHtml + avatarImageWithOob);
7929
7961
  } catch (error) {
7930
7962
  console.error("Avatar upload error:", error);
7931
7963
  return c.html(renderAlert2({
@@ -7975,7 +8007,7 @@ userRoutes.post("/profile/password", async (c) => {
7975
8007
  dismissible: true
7976
8008
  }));
7977
8009
  }
7978
- const validPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
8010
+ const validPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
7979
8011
  if (!validPassword) {
7980
8012
  return c.html(renderAlert2({
7981
8013
  type: "error",
@@ -7983,7 +8015,7 @@ userRoutes.post("/profile/password", async (c) => {
7983
8015
  dismissible: true
7984
8016
  }));
7985
8017
  }
7986
- const newPasswordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(newPassword);
8018
+ const newPasswordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(newPassword);
7987
8019
  const historyStmt = db.prepare(`
7988
8020
  INSERT INTO password_history (id, user_id, password_hash, created_at)
7989
8021
  VALUES (?, ?, ?, ?)
@@ -7999,7 +8031,7 @@ userRoutes.post("/profile/password", async (c) => {
7999
8031
  WHERE id = ?
8000
8032
  `);
8001
8033
  await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
8002
- await chunk4BJGEGX5_cjs.logActivity(
8034
+ await chunkIM5SDXOE_cjs.logActivity(
8003
8035
  db,
8004
8036
  user.userId,
8005
8037
  "profile.password_change",
@@ -8066,7 +8098,7 @@ userRoutes.get("/users", async (c) => {
8066
8098
  `);
8067
8099
  const countResult = await countStmt.bind(...params).first();
8068
8100
  const totalUsers = countResult?.total || 0;
8069
- await chunk4BJGEGX5_cjs.logActivity(
8101
+ await chunkIM5SDXOE_cjs.logActivity(
8070
8102
  db,
8071
8103
  user.userId,
8072
8104
  "users.list_view",
@@ -8168,12 +8200,12 @@ userRoutes.post("/users/new", async (c) => {
8168
8200
  const user = c.get("user");
8169
8201
  try {
8170
8202
  const formData = await c.req.formData();
8171
- const firstName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8172
- const lastName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8173
- const username = chunkBRPONFW6_cjs.sanitizeInput(formData.get("username")?.toString());
8203
+ const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8204
+ const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8205
+ const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
8174
8206
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
8175
- const phone = chunkBRPONFW6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
8176
- const bio = chunkBRPONFW6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
8207
+ const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
8208
+ const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
8177
8209
  const role = formData.get("role")?.toString() || "viewer";
8178
8210
  const password = formData.get("password")?.toString() || "";
8179
8211
  const confirmPassword = formData.get("confirm_password")?.toString() || "";
@@ -8220,7 +8252,7 @@ userRoutes.post("/users/new", async (c) => {
8220
8252
  dismissible: true
8221
8253
  }));
8222
8254
  }
8223
- const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
8255
+ const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
8224
8256
  const userId = globalThis.crypto.randomUUID();
8225
8257
  const createStmt = db.prepare(`
8226
8258
  INSERT INTO users (
@@ -8243,7 +8275,7 @@ userRoutes.post("/users/new", async (c) => {
8243
8275
  Date.now(),
8244
8276
  Date.now()
8245
8277
  ).run();
8246
- await chunk4BJGEGX5_cjs.logActivity(
8278
+ await chunkIM5SDXOE_cjs.logActivity(
8247
8279
  db,
8248
8280
  user.userId,
8249
8281
  "user!.create",
@@ -8281,7 +8313,7 @@ userRoutes.get("/users/:id", async (c) => {
8281
8313
  if (!userRecord) {
8282
8314
  return c.json({ error: "User not found" }, 404);
8283
8315
  }
8284
- await chunk4BJGEGX5_cjs.logActivity(
8316
+ await chunkIM5SDXOE_cjs.logActivity(
8285
8317
  db,
8286
8318
  user.userId,
8287
8319
  "user!.view",
@@ -8374,12 +8406,12 @@ userRoutes.put("/users/:id", async (c) => {
8374
8406
  const userId = c.req.param("id");
8375
8407
  try {
8376
8408
  const formData = await c.req.formData();
8377
- const firstName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8378
- const lastName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8379
- const username = chunkBRPONFW6_cjs.sanitizeInput(formData.get("username")?.toString());
8409
+ const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8410
+ const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8411
+ const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
8380
8412
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
8381
- const phone = chunkBRPONFW6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
8382
- const bio = chunkBRPONFW6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
8413
+ const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
8414
+ const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
8383
8415
  const role = formData.get("role")?.toString() || "viewer";
8384
8416
  const isActive = formData.get("is_active") === "1";
8385
8417
  const emailVerified = formData.get("email_verified") === "1";
@@ -8430,7 +8462,7 @@ userRoutes.put("/users/:id", async (c) => {
8430
8462
  Date.now(),
8431
8463
  userId
8432
8464
  ).run();
8433
- await chunk4BJGEGX5_cjs.logActivity(
8465
+ await chunkIM5SDXOE_cjs.logActivity(
8434
8466
  db,
8435
8467
  user.userId,
8436
8468
  "user!.update",
@@ -8476,7 +8508,7 @@ userRoutes.delete("/users/:id", async (c) => {
8476
8508
  DELETE FROM users WHERE id = ?
8477
8509
  `);
8478
8510
  await deleteStmt.bind(userId).run();
8479
- await chunk4BJGEGX5_cjs.logActivity(
8511
+ await chunkIM5SDXOE_cjs.logActivity(
8480
8512
  db,
8481
8513
  user.userId,
8482
8514
  "user!.hard_delete",
@@ -8495,7 +8527,7 @@ userRoutes.delete("/users/:id", async (c) => {
8495
8527
  UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
8496
8528
  `);
8497
8529
  await deleteStmt.bind(Date.now(), userId).run();
8498
- await chunk4BJGEGX5_cjs.logActivity(
8530
+ await chunkIM5SDXOE_cjs.logActivity(
8499
8531
  db,
8500
8532
  user.userId,
8501
8533
  "user!.soft_delete",
@@ -8522,8 +8554,8 @@ userRoutes.post("/invite-user", async (c) => {
8522
8554
  const formData = await c.req.formData();
8523
8555
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
8524
8556
  const role = formData.get("role")?.toString()?.trim() || "viewer";
8525
- const firstName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8526
- const lastName = chunkBRPONFW6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8557
+ const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
8558
+ const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
8527
8559
  if (!email || !firstName || !lastName) {
8528
8560
  return c.json({ error: "Email, first name, and last name are required" }, 400);
8529
8561
  }
@@ -8562,7 +8594,7 @@ userRoutes.post("/invite-user", async (c) => {
8562
8594
  Date.now(),
8563
8595
  Date.now()
8564
8596
  ).run();
8565
- await chunk4BJGEGX5_cjs.logActivity(
8597
+ await chunkIM5SDXOE_cjs.logActivity(
8566
8598
  db,
8567
8599
  user.userId,
8568
8600
  "user!.invite_sent",
@@ -8619,7 +8651,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
8619
8651
  Date.now(),
8620
8652
  userId
8621
8653
  ).run();
8622
- await chunk4BJGEGX5_cjs.logActivity(
8654
+ await chunkIM5SDXOE_cjs.logActivity(
8623
8655
  db,
8624
8656
  user.userId,
8625
8657
  "user!.invitation_resent",
@@ -8655,7 +8687,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
8655
8687
  }
8656
8688
  const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
8657
8689
  await deleteStmt.bind(userId).run();
8658
- await chunk4BJGEGX5_cjs.logActivity(
8690
+ await chunkIM5SDXOE_cjs.logActivity(
8659
8691
  db,
8660
8692
  user.userId,
8661
8693
  "user!.invitation_cancelled",
@@ -8738,7 +8770,7 @@ userRoutes.get("/activity-logs", async (c) => {
8738
8770
  ...log,
8739
8771
  details: log.details ? JSON.parse(log.details) : null
8740
8772
  }));
8741
- await chunk4BJGEGX5_cjs.logActivity(
8773
+ await chunkIM5SDXOE_cjs.logActivity(
8742
8774
  db,
8743
8775
  user.userId,
8744
8776
  "activity.logs_viewed",
@@ -8845,7 +8877,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
8845
8877
  csvRows.push(row.join(","));
8846
8878
  }
8847
8879
  const csvContent = csvRows.join("\n");
8848
- await chunk4BJGEGX5_cjs.logActivity(
8880
+ await chunkIM5SDXOE_cjs.logActivity(
8849
8881
  db,
8850
8882
  user.userId,
8851
8883
  "activity.logs_exported",
@@ -9157,8 +9189,10 @@ function renderMediaLibraryPage(data) {
9157
9189
  </button>
9158
9190
  <button
9159
9191
  class="w-full text-left px-3 py-2 text-sm text-zinc-700 dark:text-zinc-300 hover:text-zinc-950 dark:hover:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 rounded-lg transition-colors"
9160
- hx-delete="/media/cleanup"
9192
+ hx-delete="/admin/media/cleanup"
9161
9193
  hx-confirm="Delete unused files?"
9194
+ hx-target="body"
9195
+ hx-swap="beforeend"
9162
9196
  >
9163
9197
  Cleanup Unused
9164
9198
  </button>
@@ -10182,7 +10216,7 @@ var fileValidationSchema2 = zod.z.object({
10182
10216
  // 50MB max
10183
10217
  });
10184
10218
  var adminMediaRoutes = new hono.Hono();
10185
- adminMediaRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
10219
+ adminMediaRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
10186
10220
  adminMediaRoutes.get("/", async (c) => {
10187
10221
  try {
10188
10222
  const user = c.get("user");
@@ -10761,6 +10795,87 @@ adminMediaRoutes.put("/:id", async (c) => {
10761
10795
  `);
10762
10796
  }
10763
10797
  });
10798
+ adminMediaRoutes.delete("/cleanup", chunkIM5SDXOE_cjs.requireRole("admin"), async (c) => {
10799
+ try {
10800
+ const db = c.env.DB;
10801
+ const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
10802
+ const { results: allMedia } = await allMediaStmt.all();
10803
+ const contentStmt = db.prepare("SELECT data FROM content");
10804
+ const { results: contentRecords } = await contentStmt.all();
10805
+ const referencedUrls = /* @__PURE__ */ new Set();
10806
+ for (const record of contentRecords) {
10807
+ if (record.data) {
10808
+ const dataStr = typeof record.data === "string" ? record.data : JSON.stringify(record.data);
10809
+ const urlMatches = dataStr.matchAll(/\/files\/([^\s"',]+)/g);
10810
+ for (const match of urlMatches) {
10811
+ referencedUrls.add(match[1]);
10812
+ }
10813
+ }
10814
+ }
10815
+ const unusedFiles = allMedia.filter((file) => !referencedUrls.has(file.r2_key));
10816
+ if (unusedFiles.length === 0) {
10817
+ return c.html(html.html`
10818
+ <div class="bg-blue-100 border border-blue-400 text-blue-700 px-4 py-3 rounded">
10819
+ No unused media files found. All files are referenced in content.
10820
+ </div>
10821
+ <script>
10822
+ setTimeout(() => {
10823
+ window.location.href = '/admin/media?t=' + Date.now();
10824
+ }, 2000);
10825
+ </script>
10826
+ `);
10827
+ }
10828
+ let deletedCount = 0;
10829
+ const errors = [];
10830
+ for (const file of unusedFiles) {
10831
+ try {
10832
+ await c.env.MEDIA_BUCKET.delete(file.r2_key);
10833
+ const deleteStmt = db.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
10834
+ await deleteStmt.bind(Math.floor(Date.now() / 1e3), file.id).run();
10835
+ deletedCount++;
10836
+ } catch (error) {
10837
+ console.error(`Failed to delete ${file.filename}:`, error);
10838
+ errors.push({
10839
+ filename: file.filename,
10840
+ error: error instanceof Error ? error.message : "Unknown error"
10841
+ });
10842
+ }
10843
+ }
10844
+ return c.html(html.html`
10845
+ <div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
10846
+ Successfully cleaned up ${deletedCount} unused media file${deletedCount !== 1 ? "s" : ""}.
10847
+ ${errors.length > 0 ? html.html`
10848
+ <br><span class="text-sm">Failed to delete ${errors.length} file${errors.length !== 1 ? "s" : ""}.</span>
10849
+ ` : ""}
10850
+ </div>
10851
+
10852
+ ${errors.length > 0 ? html.html`
10853
+ <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
10854
+ <p class="font-medium">Cleanup errors:</p>
10855
+ <ul class="list-disc list-inside mt-2 text-sm">
10856
+ ${errors.map((error) => html.html`
10857
+ <li>${error.filename}: ${error.error}</li>
10858
+ `)}
10859
+ </ul>
10860
+ </div>
10861
+ ` : ""}
10862
+
10863
+ <script>
10864
+ // Refresh media library after cleanup
10865
+ setTimeout(() => {
10866
+ window.location.href = '/admin/media?t=' + Date.now();
10867
+ }, 2500);
10868
+ </script>
10869
+ `);
10870
+ } catch (error) {
10871
+ console.error("Cleanup error:", error);
10872
+ return c.html(html.html`
10873
+ <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
10874
+ Cleanup failed: ${error instanceof Error ? error.message : "Unknown error"}
10875
+ </div>
10876
+ `);
10877
+ }
10878
+ });
10764
10879
  adminMediaRoutes.delete("/:id", async (c) => {
10765
10880
  try {
10766
10881
  const user = c.get("user");
@@ -12216,7 +12331,7 @@ function formatTimestamp(timestamp) {
12216
12331
 
12217
12332
  // src/routes/admin-plugins.ts
12218
12333
  var adminPluginRoutes = new hono.Hono();
12219
- adminPluginRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
12334
+ adminPluginRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
12220
12335
  adminPluginRoutes.get("/", async (c) => {
12221
12336
  try {
12222
12337
  const user = c.get("user");
@@ -12224,7 +12339,7 @@ adminPluginRoutes.get("/", async (c) => {
12224
12339
  if (user?.role !== "admin") {
12225
12340
  return c.text("Access denied", 403);
12226
12341
  }
12227
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12342
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12228
12343
  let plugins = [];
12229
12344
  let stats = { total: 0, active: 0, inactive: 0, errors: 0 };
12230
12345
  try {
@@ -12274,7 +12389,7 @@ adminPluginRoutes.get("/:id", async (c) => {
12274
12389
  if (user?.role !== "admin") {
12275
12390
  return c.redirect("/admin/plugins");
12276
12391
  }
12277
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12392
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12278
12393
  const plugin = await pluginService.getPlugin(pluginId);
12279
12394
  if (!plugin) {
12280
12395
  return c.text("Plugin not found", 404);
@@ -12328,7 +12443,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
12328
12443
  if (user?.role !== "admin") {
12329
12444
  return c.json({ error: "Access denied" }, 403);
12330
12445
  }
12331
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12446
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12332
12447
  await pluginService.activatePlugin(pluginId);
12333
12448
  return c.json({ success: true });
12334
12449
  } catch (error) {
@@ -12345,7 +12460,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
12345
12460
  if (user?.role !== "admin") {
12346
12461
  return c.json({ error: "Access denied" }, 403);
12347
12462
  }
12348
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12463
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12349
12464
  await pluginService.deactivatePlugin(pluginId);
12350
12465
  return c.json({ success: true });
12351
12466
  } catch (error) {
@@ -12362,7 +12477,7 @@ adminPluginRoutes.post("/install", async (c) => {
12362
12477
  return c.json({ error: "Access denied" }, 403);
12363
12478
  }
12364
12479
  const body = await c.req.json();
12365
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12480
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12366
12481
  if (body.name === "faq-plugin") {
12367
12482
  const faqPlugin = await pluginService.installPlugin({
12368
12483
  id: "third-party-faq",
@@ -12512,7 +12627,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
12512
12627
  if (user?.role !== "admin") {
12513
12628
  return c.json({ error: "Access denied" }, 403);
12514
12629
  }
12515
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12630
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12516
12631
  await pluginService.uninstallPlugin(pluginId);
12517
12632
  return c.json({ success: true });
12518
12633
  } catch (error) {
@@ -12530,7 +12645,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
12530
12645
  return c.json({ error: "Access denied" }, 403);
12531
12646
  }
12532
12647
  const settings = await c.req.json();
12533
- const pluginService = new chunkLEG4KNFP_cjs.PluginService(db);
12648
+ const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
12534
12649
  await pluginService.updatePluginSettings(pluginId, settings);
12535
12650
  return c.json({ success: true });
12536
12651
  } catch (error) {
@@ -13326,11 +13441,11 @@ function renderLogConfigPage(data) {
13326
13441
 
13327
13442
  // src/routes/admin-logs.ts
13328
13443
  var adminLogsRoutes = new hono.Hono();
13329
- adminLogsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
13444
+ adminLogsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
13330
13445
  adminLogsRoutes.get("/", async (c) => {
13331
13446
  try {
13332
13447
  const user = c.get("user");
13333
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13448
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13334
13449
  const query = c.req.query();
13335
13450
  const page = parseInt(query.page || "1");
13336
13451
  const limit = parseInt(query.limit || "50");
@@ -13410,7 +13525,7 @@ adminLogsRoutes.get("/:id", async (c) => {
13410
13525
  try {
13411
13526
  const id = c.req.param("id");
13412
13527
  const user = c.get("user");
13413
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13528
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13414
13529
  const { logs } = await logger.getLogs({
13415
13530
  limit: 1,
13416
13531
  offset: 0,
@@ -13447,7 +13562,7 @@ adminLogsRoutes.get("/:id", async (c) => {
13447
13562
  adminLogsRoutes.get("/config", async (c) => {
13448
13563
  try {
13449
13564
  const user = c.get("user");
13450
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13565
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13451
13566
  const configs = await logger.getAllConfigs();
13452
13567
  const pageData = {
13453
13568
  configs,
@@ -13471,7 +13586,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
13471
13586
  const level = formData.get("level");
13472
13587
  const retention = parseInt(formData.get("retention"));
13473
13588
  const maxSize = parseInt(formData.get("max_size"));
13474
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13589
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13475
13590
  await logger.updateConfig(category, {
13476
13591
  enabled,
13477
13592
  level,
@@ -13500,7 +13615,7 @@ adminLogsRoutes.get("/export", async (c) => {
13500
13615
  const category = query.category;
13501
13616
  const startDate = query.start_date;
13502
13617
  const endDate = query.end_date;
13503
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13618
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13504
13619
  const filter = {
13505
13620
  limit: 1e4,
13506
13621
  // Export up to 10k logs
@@ -13581,7 +13696,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
13581
13696
  error: "Unauthorized. Admin access required."
13582
13697
  }, 403);
13583
13698
  }
13584
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13699
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13585
13700
  await logger.cleanupByRetention();
13586
13701
  return c.html(html.html`
13587
13702
  <div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
@@ -13603,7 +13718,7 @@ adminLogsRoutes.post("/search", async (c) => {
13603
13718
  const search = formData.get("search");
13604
13719
  const level = formData.get("level");
13605
13720
  const category = formData.get("category");
13606
- const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
13721
+ const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
13607
13722
  const filter = {
13608
13723
  limit: 20,
13609
13724
  offset: 0,
@@ -16259,9 +16374,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
16259
16374
  }
16260
16375
 
16261
16376
  // src/routes/admin-dashboard.ts
16262
- var VERSION = chunkBRPONFW6_cjs.getCoreVersion();
16377
+ var VERSION = chunkTRSHFTF6_cjs.getCoreVersion();
16263
16378
  var router = new hono.Hono();
16264
- router.use("*", chunk4BJGEGX5_cjs.requireAuth());
16379
+ router.use("*", chunkIM5SDXOE_cjs.requireAuth());
16265
16380
  router.get("/", async (c) => {
16266
16381
  const user = c.get("user");
16267
16382
  try {
@@ -16324,14 +16439,14 @@ router.get("/stats", async (c) => {
16324
16439
  } catch (error) {
16325
16440
  console.error("Error fetching users count:", error);
16326
16441
  }
16327
- const html9 = renderStatsCards({
16442
+ const html8 = renderStatsCards({
16328
16443
  collections: collectionsCount,
16329
16444
  contentItems: contentCount,
16330
16445
  mediaFiles: mediaCount,
16331
16446
  users: usersCount,
16332
16447
  mediaSize
16333
16448
  });
16334
- return c.html(html9);
16449
+ return c.html(html8);
16335
16450
  } catch (error) {
16336
16451
  console.error("Error fetching stats:", error);
16337
16452
  return c.html('<div class="text-red-500">Failed to load statistics</div>');
@@ -16355,8 +16470,8 @@ router.get("/storage", async (c) => {
16355
16470
  } catch (error) {
16356
16471
  console.error("Error fetching media size:", error);
16357
16472
  }
16358
- const html9 = renderStorageUsage(databaseSize, mediaSize);
16359
- return c.html(html9);
16473
+ const html8 = renderStorageUsage(databaseSize, mediaSize);
16474
+ return c.html(html8);
16360
16475
  } catch (error) {
16361
16476
  console.error("Error fetching storage usage:", error);
16362
16477
  return c.html('<div class="text-red-500">Failed to load storage information</div>');
@@ -16405,12 +16520,12 @@ router.get("/recent-activity", async (c) => {
16405
16520
  user: userName
16406
16521
  };
16407
16522
  });
16408
- const html9 = renderRecentActivity(activities);
16409
- return c.html(html9);
16523
+ const html8 = renderRecentActivity(activities);
16524
+ return c.html(html8);
16410
16525
  } catch (error) {
16411
16526
  console.error("Error fetching recent activity:", error);
16412
- const html9 = renderRecentActivity([]);
16413
- return c.html(html9);
16527
+ const html8 = renderRecentActivity([]);
16528
+ return c.html(html8);
16414
16529
  }
16415
16530
  });
16416
16531
  router.get("/api/metrics", async (c) => {
@@ -16423,7 +16538,7 @@ router.get("/api/metrics", async (c) => {
16423
16538
  });
16424
16539
  router.get("/system-status", async (c) => {
16425
16540
  try {
16426
- const html9 = `
16541
+ const html8 = `
16427
16542
  <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
16428
16543
  <div class="relative group">
16429
16544
  <div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-cyan-500/20 dark:from-blue-500/10 dark:to-cyan-500/10 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
@@ -16478,7 +16593,7 @@ router.get("/system-status", async (c) => {
16478
16593
  </div>
16479
16594
  </div>
16480
16595
  `;
16481
- return c.html(html9);
16596
+ return c.html(html8);
16482
16597
  } catch (error) {
16483
16598
  console.error("Error fetching system status:", error);
16484
16599
  return c.html('<div class="text-red-500">Failed to load system status</div>');
@@ -17742,7 +17857,7 @@ function renderCollectionFormPage(data) {
17742
17857
 
17743
17858
  // src/routes/admin-collections.ts
17744
17859
  var adminCollectionsRoutes = new hono.Hono();
17745
- adminCollectionsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
17860
+ adminCollectionsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
17746
17861
  adminCollectionsRoutes.get("/", async (c) => {
17747
17862
  try {
17748
17863
  const user = c.get("user");
@@ -18234,31 +18349,52 @@ function renderSettingsPage(data) {
18234
18349
  // Initialize tab-specific features on page load
18235
18350
  const currentTab = '${activeTab}';
18236
18351
 
18237
- function saveAllSettings() {
18352
+ async function saveAllSettings() {
18238
18353
  // Collect all form data
18239
18354
  const formData = new FormData();
18240
-
18241
- // Get all form inputs
18242
- document.querySelectorAll('input, select, textarea').forEach(input => {
18355
+
18356
+ // Get all form inputs in the settings content area
18357
+ document.querySelectorAll('#settings-content input, #settings-content select, #settings-content textarea').forEach(input => {
18243
18358
  if (input.type === 'checkbox') {
18244
- formData.append(input.name, input.checked);
18359
+ formData.append(input.name, input.checked ? 'true' : 'false');
18245
18360
  } else if (input.name) {
18246
18361
  formData.append(input.name, input.value);
18247
18362
  }
18248
18363
  });
18249
-
18364
+
18250
18365
  // Show loading state
18251
18366
  const saveBtn = document.querySelector('button[onclick="saveAllSettings()"]');
18252
18367
  const originalText = saveBtn.innerHTML;
18253
- saveBtn.innerHTML = 'Saving...';
18368
+ saveBtn.innerHTML = '<svg class="animate-spin -ml-0.5 mr-1.5 h-5 w-5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg>Saving...';
18254
18369
  saveBtn.disabled = true;
18255
-
18256
- // Simulate save (replace with actual API call)
18257
- setTimeout(() => {
18370
+
18371
+ try {
18372
+ // Determine which endpoint to call based on current tab
18373
+ let endpoint = '/admin/settings/general';
18374
+ if (currentTab === 'general') {
18375
+ endpoint = '/admin/settings/general';
18376
+ }
18377
+ // Add more endpoints for other tabs when implemented
18378
+
18379
+ const response = await fetch(endpoint, {
18380
+ method: 'POST',
18381
+ body: formData
18382
+ });
18383
+
18384
+ const result = await response.json();
18385
+
18386
+ if (result.success) {
18387
+ showNotification(result.message || 'Settings saved successfully!', 'success');
18388
+ } else {
18389
+ showNotification(result.error || 'Failed to save settings', 'error');
18390
+ }
18391
+ } catch (error) {
18392
+ console.error('Error saving settings:', error);
18393
+ showNotification('Failed to save settings. Please try again.', 'error');
18394
+ } finally {
18258
18395
  saveBtn.innerHTML = originalText;
18259
18396
  saveBtn.disabled = false;
18260
- showNotification('Settings saved successfully!', 'success');
18261
- }, 1000);
18397
+ }
18262
18398
  }
18263
18399
 
18264
18400
  function resetSettings() {
@@ -19601,7 +19737,7 @@ function renderDatabaseToolsSettings(settings) {
19601
19737
 
19602
19738
  // src/routes/admin-settings.ts
19603
19739
  var adminSettingsRoutes = new hono.Hono();
19604
- adminSettingsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
19740
+ adminSettingsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
19605
19741
  function getMockSettings(user) {
19606
19742
  return {
19607
19743
  general: {
@@ -19663,15 +19799,20 @@ function getMockSettings(user) {
19663
19799
  adminSettingsRoutes.get("/", (c) => {
19664
19800
  return c.redirect("/admin/settings/general");
19665
19801
  });
19666
- adminSettingsRoutes.get("/general", (c) => {
19802
+ adminSettingsRoutes.get("/general", async (c) => {
19667
19803
  const user = c.get("user");
19804
+ const db = c.env.DB;
19805
+ const settingsService = new chunkDOR2IU73_cjs.SettingsService(db);
19806
+ const generalSettings = await settingsService.getGeneralSettings(user?.email);
19807
+ const mockSettings = getMockSettings(user);
19808
+ mockSettings.general = generalSettings;
19668
19809
  const pageData = {
19669
19810
  user: user ? {
19670
19811
  name: user.email,
19671
19812
  email: user.email,
19672
19813
  role: user.role
19673
19814
  } : void 0,
19674
- settings: getMockSettings(user),
19815
+ settings: mockSettings,
19675
19816
  activeTab: "general",
19676
19817
  version: c.get("appVersion")
19677
19818
  };
@@ -19764,7 +19905,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
19764
19905
  adminSettingsRoutes.get("/api/migrations/status", async (c) => {
19765
19906
  try {
19766
19907
  const db = c.env.DB;
19767
- const migrationService = new chunkLEG4KNFP_cjs.MigrationService(db);
19908
+ const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
19768
19909
  const status = await migrationService.getMigrationStatus();
19769
19910
  return c.json({
19770
19911
  success: true,
@@ -19788,7 +19929,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
19788
19929
  }, 403);
19789
19930
  }
19790
19931
  const db = c.env.DB;
19791
- const migrationService = new chunkLEG4KNFP_cjs.MigrationService(db);
19932
+ const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
19792
19933
  const result = await migrationService.runPendingMigrations();
19793
19934
  return c.json({
19794
19935
  success: result.success,
@@ -19806,7 +19947,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
19806
19947
  adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
19807
19948
  try {
19808
19949
  const db = c.env.DB;
19809
- const migrationService = new chunkLEG4KNFP_cjs.MigrationService(db);
19950
+ const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
19810
19951
  const validation = await migrationService.validateSchema();
19811
19952
  return c.json({
19812
19953
  success: true,
@@ -19952,28 +20093,55 @@ adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
19952
20093
  }, 500);
19953
20094
  }
19954
20095
  });
19955
- adminSettingsRoutes.post("/", async (c) => {
20096
+ adminSettingsRoutes.post("/general", async (c) => {
19956
20097
  try {
20098
+ const user = c.get("user");
20099
+ if (!user || user.role !== "admin") {
20100
+ return c.json({
20101
+ success: false,
20102
+ error: "Unauthorized. Admin access required."
20103
+ }, 403);
20104
+ }
19957
20105
  const formData = await c.req.formData();
19958
- return c.html(html.html`
19959
- <div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
19960
- Settings saved successfully!
19961
- <script>
19962
- setTimeout(() => {
19963
- showNotification('Settings saved successfully!', 'success');
19964
- }, 100);
19965
- </script>
19966
- </div>
19967
- `);
20106
+ const db = c.env.DB;
20107
+ const settingsService = new chunkDOR2IU73_cjs.SettingsService(db);
20108
+ const settings = {
20109
+ siteName: formData.get("siteName"),
20110
+ siteDescription: formData.get("siteDescription"),
20111
+ adminEmail: formData.get("adminEmail"),
20112
+ timezone: formData.get("timezone"),
20113
+ language: formData.get("language"),
20114
+ maintenanceMode: formData.get("maintenanceMode") === "true"
20115
+ };
20116
+ if (!settings.siteName || !settings.siteDescription) {
20117
+ return c.json({
20118
+ success: false,
20119
+ error: "Site name and description are required"
20120
+ }, 400);
20121
+ }
20122
+ const success = await settingsService.saveGeneralSettings(settings);
20123
+ if (success) {
20124
+ return c.json({
20125
+ success: true,
20126
+ message: "General settings saved successfully!"
20127
+ });
20128
+ } else {
20129
+ return c.json({
20130
+ success: false,
20131
+ error: "Failed to save settings"
20132
+ }, 500);
20133
+ }
19968
20134
  } catch (error) {
19969
- console.error("Error saving settings:", error);
19970
- return c.html(html.html`
19971
- <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
19972
- Failed to save settings. Please try again.
19973
- </div>
19974
- `);
20135
+ console.error("Error saving general settings:", error);
20136
+ return c.json({
20137
+ success: false,
20138
+ error: "Failed to save settings. Please try again."
20139
+ }, 500);
19975
20140
  }
19976
20141
  });
20142
+ adminSettingsRoutes.post("/", async (c) => {
20143
+ return c.redirect("/admin/settings/general");
20144
+ });
19977
20145
 
19978
20146
  // src/routes/index.ts
19979
20147
  var ROUTES_INFO = {
@@ -20023,5 +20191,5 @@ exports.api_system_default = api_system_default;
20023
20191
  exports.auth_default = auth_default;
20024
20192
  exports.router = router;
20025
20193
  exports.userRoutes = userRoutes;
20026
- //# sourceMappingURL=chunk-RZW752PE.cjs.map
20027
- //# sourceMappingURL=chunk-RZW752PE.cjs.map
20194
+ //# sourceMappingURL=chunk-NPWWR6RI.cjs.map
20195
+ //# sourceMappingURL=chunk-NPWWR6RI.cjs.map