@sonicjs-cms/core 2.16.1 → 2.17.1

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 (61) hide show
  1. package/dist/{app-D9L3mrC-.d.cts → app-C9esKLmh.d.cts} +2 -0
  2. package/dist/{app-D9L3mrC-.d.ts → app-C9esKLmh.d.ts} +2 -0
  3. package/dist/{chunk-7HHIZQNE.cjs → chunk-3TVMUQWG.cjs} +155 -17
  4. package/dist/chunk-3TVMUQWG.cjs.map +1 -0
  5. package/dist/{chunk-U6FOL6EO.cjs → chunk-47HKH3D6.cjs} +34 -6
  6. package/dist/chunk-47HKH3D6.cjs.map +1 -0
  7. package/dist/{chunk-V76ERLX6.cjs → chunk-5EBTBD2Z.cjs} +3 -3
  8. package/dist/{chunk-V76ERLX6.cjs.map → chunk-5EBTBD2Z.cjs.map} +1 -1
  9. package/dist/{chunk-MZS33LLH.cjs → chunk-5ITJB5ZT.cjs} +354 -180
  10. package/dist/chunk-5ITJB5ZT.cjs.map +1 -0
  11. package/dist/{chunk-JF5RQXPN.js → chunk-7D7SI5P7.js} +3 -3
  12. package/dist/{chunk-JF5RQXPN.js.map → chunk-7D7SI5P7.js.map} +1 -1
  13. package/dist/{chunk-W33MHOPA.js → chunk-EUFBU4T4.js} +34 -6
  14. package/dist/chunk-EUFBU4T4.js.map +1 -0
  15. package/dist/{chunk-HU4MN74Q.cjs → chunk-I6444XLU.cjs} +2 -2
  16. package/dist/{chunk-HU4MN74Q.cjs.map → chunk-I6444XLU.cjs.map} +1 -1
  17. package/dist/{chunk-KYAF33AF.js → chunk-P5IDHMOL.js} +149 -14
  18. package/dist/chunk-P5IDHMOL.js.map +1 -0
  19. package/dist/{chunk-TBJY2FF7.js → chunk-QFWHAFEO.js} +22 -2
  20. package/dist/chunk-QFWHAFEO.js.map +1 -0
  21. package/dist/{chunk-PUZMLXOJ.js → chunk-QZBZEUZF.js} +2 -2
  22. package/dist/{chunk-PUZMLXOJ.js.map → chunk-QZBZEUZF.js.map} +1 -1
  23. package/dist/{chunk-BAMJVG33.js → chunk-UDUHP4PA.js} +229 -55
  24. package/dist/chunk-UDUHP4PA.js.map +1 -0
  25. package/dist/{chunk-NZWFCUDA.cjs → chunk-WAEQXGCX.cjs} +22 -2
  26. package/dist/chunk-WAEQXGCX.cjs.map +1 -0
  27. package/dist/index.cjs +194 -186
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +30 -22
  32. package/dist/index.js.map +1 -1
  33. package/dist/middleware.cjs +41 -29
  34. package/dist/middleware.d.cts +38 -4
  35. package/dist/middleware.d.ts +38 -4
  36. package/dist/middleware.js +3 -3
  37. package/dist/migrations-3TVS3HU5.js +4 -0
  38. package/dist/{migrations-WCEBO5QQ.js.map → migrations-3TVS3HU5.js.map} +1 -1
  39. package/dist/migrations-VQ4UX4M4.cjs +13 -0
  40. package/dist/{migrations-MYQI2KAJ.cjs.map → migrations-VQ4UX4M4.cjs.map} +1 -1
  41. package/dist/routes.cjs +29 -29
  42. package/dist/routes.d.cts +1 -1
  43. package/dist/routes.d.ts +1 -1
  44. package/dist/routes.js +6 -6
  45. package/dist/services.cjs +39 -39
  46. package/dist/services.d.cts +12 -0
  47. package/dist/services.d.ts +12 -0
  48. package/dist/services.js +3 -3
  49. package/dist/utils.cjs +11 -11
  50. package/dist/utils.js +1 -1
  51. package/package.json +1 -1
  52. package/dist/chunk-7HHIZQNE.cjs.map +0 -1
  53. package/dist/chunk-BAMJVG33.js.map +0 -1
  54. package/dist/chunk-KYAF33AF.js.map +0 -1
  55. package/dist/chunk-MZS33LLH.cjs.map +0 -1
  56. package/dist/chunk-NZWFCUDA.cjs.map +0 -1
  57. package/dist/chunk-TBJY2FF7.js.map +0 -1
  58. package/dist/chunk-U6FOL6EO.cjs.map +0 -1
  59. package/dist/chunk-W33MHOPA.js.map +0 -1
  60. package/dist/migrations-MYQI2KAJ.cjs +0 -13
  61. package/dist/migrations-WCEBO5QQ.js +0 -4
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkNZWFCUDA_cjs = require('./chunk-NZWFCUDA.cjs');
4
- var chunk7HHIZQNE_cjs = require('./chunk-7HHIZQNE.cjs');
5
- var chunkU6FOL6EO_cjs = require('./chunk-U6FOL6EO.cjs');
6
- var chunkHU4MN74Q_cjs = require('./chunk-HU4MN74Q.cjs');
3
+ var chunkWAEQXGCX_cjs = require('./chunk-WAEQXGCX.cjs');
4
+ var chunk3TVMUQWG_cjs = require('./chunk-3TVMUQWG.cjs');
5
+ var chunk47HKH3D6_cjs = require('./chunk-47HKH3D6.cjs');
6
+ var chunkI6444XLU_cjs = require('./chunk-I6444XLU.cjs');
7
7
  var chunkOHYBNCVL_cjs = require('./chunk-OHYBNCVL.cjs');
8
8
  var chunkUYJ6TJHX_cjs = require('./chunk-UYJ6TJHX.cjs');
9
9
  var chunk635JAMSE_cjs = require('./chunk-635JAMSE.cjs');
10
- var chunkV76ERLX6_cjs = require('./chunk-V76ERLX6.cjs');
10
+ var chunk5EBTBD2Z_cjs = require('./chunk-5EBTBD2Z.cjs');
11
11
  var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
12
12
  var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
13
13
  var hono = require('hono');
@@ -189,7 +189,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
189
189
  }, 500);
190
190
  }
191
191
  });
192
- apiContentCrudRoutes.post("/", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
192
+ apiContentCrudRoutes.post("/", chunk3TVMUQWG_cjs.requireAuth(), chunk3TVMUQWG_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
193
193
  try {
194
194
  const db = c.env.DB;
195
195
  const user = c.get("user");
@@ -230,7 +230,7 @@ apiContentCrudRoutes.post("/", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_cj
230
230
  now,
231
231
  now
232
232
  ).run();
233
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
233
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
234
234
  await cache.invalidate(`content:list:${collectionId}:*`);
235
235
  await cache.invalidate("content-filtered:*");
236
236
  const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
@@ -255,7 +255,7 @@ apiContentCrudRoutes.post("/", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_cj
255
255
  }, 500);
256
256
  }
257
257
  });
258
- apiContentCrudRoutes.put("/:id", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
258
+ apiContentCrudRoutes.put("/:id", chunk3TVMUQWG_cjs.requireAuth(), chunk3TVMUQWG_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
259
259
  try {
260
260
  const id = c.req.param("id");
261
261
  const db = c.env.DB;
@@ -293,7 +293,7 @@ apiContentCrudRoutes.put("/:id", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_
293
293
  WHERE id = ?
294
294
  `);
295
295
  await updateStmt.bind(...params).run();
296
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
296
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
297
297
  await cache.delete(cache.generateKey("content", id));
298
298
  await cache.invalidate(`content:list:${existing.collection_id}:*`);
299
299
  await cache.invalidate("content-filtered:*");
@@ -319,7 +319,7 @@ apiContentCrudRoutes.put("/:id", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_
319
319
  }, 500);
320
320
  }
321
321
  });
322
- apiContentCrudRoutes.delete("/:id", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQNE_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
322
+ apiContentCrudRoutes.delete("/:id", chunk3TVMUQWG_cjs.requireAuth(), chunk3TVMUQWG_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
323
323
  try {
324
324
  const id = c.req.param("id");
325
325
  const db = c.env.DB;
@@ -330,7 +330,7 @@ apiContentCrudRoutes.delete("/:id", chunk7HHIZQNE_cjs.requireAuth(), chunk7HHIZQ
330
330
  }
331
331
  const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
332
332
  await deleteStmt.bind(id).run();
333
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
333
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
334
334
  await cache.delete(cache.generateKey("content", id));
335
335
  await cache.invalidate(`content:list:${existing.collection_id}:*`);
336
336
  await cache.invalidate("content-filtered:*");
@@ -355,7 +355,7 @@ apiRoutes.use("*", async (c, next) => {
355
355
  c.header("X-Response-Time", `${totalTime}ms`);
356
356
  });
357
357
  apiRoutes.use("*", async (c, next) => {
358
- const cacheEnabled = await chunk7HHIZQNE_cjs.isPluginActive(c.env.DB, "core-cache");
358
+ const cacheEnabled = await chunk3TVMUQWG_cjs.isPluginActive(c.env.DB, "core-cache");
359
359
  c.set("cacheEnabled", cacheEnabled);
360
360
  await next();
361
361
  });
@@ -792,7 +792,7 @@ apiRoutes.get("/collections", async (c) => {
792
792
  try {
793
793
  const db = c.env.DB;
794
794
  const cacheEnabled = c.get("cacheEnabled");
795
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
795
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
796
796
  const cacheKey = cache.generateKey("collections", "all");
797
797
  if (cacheEnabled) {
798
798
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -846,7 +846,7 @@ apiRoutes.get("/collections", async (c) => {
846
846
  return c.json({ error: "Failed to fetch collections" }, 500);
847
847
  }
848
848
  });
849
- apiRoutes.get("/content", chunk7HHIZQNE_cjs.optionalAuth(), async (c) => {
849
+ apiRoutes.get("/content", chunk3TVMUQWG_cjs.optionalAuth(), async (c) => {
850
850
  const executionStart = Date.now();
851
851
  try {
852
852
  const db = c.env.DB;
@@ -869,13 +869,13 @@ apiRoutes.get("/content", chunk7HHIZQNE_cjs.optionalAuth(), async (c) => {
869
869
  });
870
870
  }
871
871
  }
872
- const filter = chunkV76ERLX6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
872
+ const filter = chunk5EBTBD2Z_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
873
873
  const normalizedFilter = normalizePublicContentFilter(filter, c.get("user")?.role);
874
874
  if (!normalizedFilter.limit) {
875
875
  normalizedFilter.limit = 50;
876
876
  }
877
877
  normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
878
- const builder3 = new chunkV76ERLX6_cjs.QueryFilterBuilder();
878
+ const builder3 = new chunk5EBTBD2Z_cjs.QueryFilterBuilder();
879
879
  const queryResult = builder3.build("content", normalizedFilter);
880
880
  if (queryResult.errors.length > 0) {
881
881
  return c.json({
@@ -884,7 +884,7 @@ apiRoutes.get("/content", chunk7HHIZQNE_cjs.optionalAuth(), async (c) => {
884
884
  }, 400);
885
885
  }
886
886
  const cacheEnabled = c.get("cacheEnabled");
887
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
887
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
888
888
  const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter: normalizedFilter, query: queryResult.sql }));
889
889
  if (cacheEnabled) {
890
890
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -947,7 +947,7 @@ apiRoutes.get("/content", chunk7HHIZQNE_cjs.optionalAuth(), async (c) => {
947
947
  }, 500);
948
948
  }
949
949
  });
950
- apiRoutes.get("/collections/:collection/content", chunk7HHIZQNE_cjs.optionalAuth(), async (c) => {
950
+ apiRoutes.get("/collections/:collection/content", chunk3TVMUQWG_cjs.optionalAuth(), async (c) => {
951
951
  const executionStart = Date.now();
952
952
  try {
953
953
  const collection = c.req.param("collection");
@@ -958,7 +958,7 @@ apiRoutes.get("/collections/:collection/content", chunk7HHIZQNE_cjs.optionalAuth
958
958
  if (!collectionResult) {
959
959
  return c.json({ error: "Collection not found" }, 404);
960
960
  }
961
- const filter = chunkV76ERLX6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
961
+ const filter = chunk5EBTBD2Z_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
962
962
  const normalizedFilter = normalizePublicContentFilter(filter, c.get("user")?.role);
963
963
  if (!normalizedFilter.where) {
964
964
  normalizedFilter.where = { and: [] };
@@ -975,7 +975,7 @@ apiRoutes.get("/collections/:collection/content", chunk7HHIZQNE_cjs.optionalAuth
975
975
  normalizedFilter.limit = 50;
976
976
  }
977
977
  normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
978
- const builder3 = new chunkV76ERLX6_cjs.QueryFilterBuilder();
978
+ const builder3 = new chunk5EBTBD2Z_cjs.QueryFilterBuilder();
979
979
  const queryResult = builder3.build("content", normalizedFilter);
980
980
  if (queryResult.errors.length > 0) {
981
981
  return c.json({
@@ -984,7 +984,7 @@ apiRoutes.get("/collections/:collection/content", chunk7HHIZQNE_cjs.optionalAuth
984
984
  }, 400);
985
985
  }
986
986
  const cacheEnabled = c.get("cacheEnabled");
987
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.api);
987
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.api);
988
988
  const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql })}`);
989
989
  if (cacheEnabled) {
990
990
  const cacheResult = await cache.getWithSource(cacheKey);
@@ -1096,7 +1096,7 @@ var fileValidationSchema = zod.z.object({
1096
1096
  // 50MB max
1097
1097
  });
1098
1098
  var apiMediaRoutes = new hono.Hono();
1099
- apiMediaRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
1099
+ apiMediaRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
1100
1100
  apiMediaRoutes.post("/upload", async (c) => {
1101
1101
  try {
1102
1102
  const user = c.get("user");
@@ -1840,8 +1840,8 @@ apiSystemRoutes.get("/env", (c) => {
1840
1840
  });
1841
1841
  var api_system_default = apiSystemRoutes;
1842
1842
  var adminApiRoutes = new hono.Hono();
1843
- adminApiRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
1844
- adminApiRoutes.use("*", chunk7HHIZQNE_cjs.requireRole(["admin", "editor"]));
1843
+ adminApiRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
1844
+ adminApiRoutes.use("*", chunk3TVMUQWG_cjs.requireRole(["admin", "editor"]));
1845
1845
  adminApiRoutes.get("/stats", async (c) => {
1846
1846
  try {
1847
1847
  const db = c.env.DB;
@@ -2353,7 +2353,7 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
2353
2353
  });
2354
2354
  adminApiRoutes.get("/migrations/status", async (c) => {
2355
2355
  try {
2356
- const { MigrationService: MigrationService2 } = await import('./migrations-MYQI2KAJ.cjs');
2356
+ const { MigrationService: MigrationService2 } = await import('./migrations-VQ4UX4M4.cjs');
2357
2357
  const db = c.env.DB;
2358
2358
  const migrationService = new MigrationService2(db);
2359
2359
  const status = await migrationService.getMigrationStatus();
@@ -2378,7 +2378,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
2378
2378
  error: "Unauthorized. Admin access required."
2379
2379
  }, 403);
2380
2380
  }
2381
- const { MigrationService: MigrationService2 } = await import('./migrations-MYQI2KAJ.cjs');
2381
+ const { MigrationService: MigrationService2 } = await import('./migrations-VQ4UX4M4.cjs');
2382
2382
  const db = c.env.DB;
2383
2383
  const migrationService = new MigrationService2(db);
2384
2384
  const result = await migrationService.runPendingMigrations();
@@ -2400,7 +2400,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
2400
2400
  });
2401
2401
  adminApiRoutes.get("/migrations/validate", async (c) => {
2402
2402
  try {
2403
- const { MigrationService: MigrationService2 } = await import('./migrations-MYQI2KAJ.cjs');
2403
+ const { MigrationService: MigrationService2 } = await import('./migrations-VQ4UX4M4.cjs');
2404
2404
  const db = c.env.DB;
2405
2405
  const migrationService = new MigrationService2(db);
2406
2406
  const validation = await migrationService.validateSchema();
@@ -5150,16 +5150,17 @@ var userProfilesPlugin = createUserProfilesPlugin();
5150
5150
 
5151
5151
  // src/routes/auth.ts
5152
5152
  var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
5153
- async function setCsrfCookie(c) {
5153
+ async function setCsrfCookie(c, maxAge) {
5154
5154
  const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK;
5155
5155
  const isDev = c.env?.ENVIRONMENT === "development" || !c.env?.ENVIRONMENT;
5156
- const csrfToken = await chunk7HHIZQNE_cjs.generateCsrfToken(secret);
5156
+ const csrfToken = await chunk3TVMUQWG_cjs.generateCsrfToken(secret);
5157
+ const cookieMaxAge = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env?.DB, c.env);
5157
5158
  cookie.setCookie(c, "csrf_token", csrfToken, {
5158
5159
  httpOnly: false,
5159
5160
  secure: !isDev,
5160
5161
  sameSite: "Strict",
5161
5162
  path: "/",
5162
- maxAge: 86400
5163
+ maxAge: cookieMaxAge
5163
5164
  });
5164
5165
  }
5165
5166
  function clearCsrfCookie(c) {
@@ -5210,7 +5211,7 @@ var loginSchema = zod.z.object({
5210
5211
  });
5211
5212
  authRoutes.post(
5212
5213
  "/register",
5213
- chunk7HHIZQNE_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
5214
+ chunk3TVMUQWG_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
5214
5215
  async (c) => {
5215
5216
  try {
5216
5217
  const db = c.env.DB;
@@ -5247,7 +5248,7 @@ authRoutes.post(
5247
5248
  if (existingUser) {
5248
5249
  return c.json({ error: "User with this email or username already exists" }, 400);
5249
5250
  }
5250
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
5251
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
5251
5252
  const userId = crypto.randomUUID();
5252
5253
  const now = /* @__PURE__ */ new Date();
5253
5254
  await db.prepare(`
@@ -5281,13 +5282,13 @@ authRoutes.post(
5281
5282
  await saveCustomData(db, userId, sanitized);
5282
5283
  }
5283
5284
  }
5284
- const token = await chunk7HHIZQNE_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET);
5285
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
5286
+ const token = await chunk3TVMUQWG_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET, tokenTtl);
5285
5287
  cookie.setCookie(c, "auth_token", token, {
5286
5288
  httpOnly: true,
5287
5289
  secure: true,
5288
5290
  sameSite: "Strict",
5289
- maxAge: 60 * 60 * 24
5290
- // 24 hours
5291
+ maxAge: tokenTtl
5291
5292
  });
5292
5293
  await setCsrfCookie(c);
5293
5294
  return c.json({
@@ -5315,7 +5316,7 @@ authRoutes.post(
5315
5316
  );
5316
5317
  authRoutes.post(
5317
5318
  "/login",
5318
- chunk7HHIZQNE_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
5319
+ chunk3TVMUQWG_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
5319
5320
  async (c) => {
5320
5321
  try {
5321
5322
  const body = await c.req.json();
@@ -5326,7 +5327,7 @@ authRoutes.post(
5326
5327
  const { email, password } = validation.data;
5327
5328
  const db = c.env.DB;
5328
5329
  const normalizedEmail = email.toLowerCase();
5329
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.user);
5330
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.user);
5330
5331
  let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
5331
5332
  if (!user) {
5332
5333
  user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
@@ -5338,25 +5339,25 @@ authRoutes.post(
5338
5339
  if (!user) {
5339
5340
  return c.json({ error: "Invalid email or password" }, 401);
5340
5341
  }
5341
- const isValidPassword = await chunk7HHIZQNE_cjs.AuthManager.verifyPassword(password, user.password_hash);
5342
+ const isValidPassword = await chunk3TVMUQWG_cjs.AuthManager.verifyPassword(password, user.password_hash);
5342
5343
  if (!isValidPassword) {
5343
5344
  return c.json({ error: "Invalid email or password" }, 401);
5344
5345
  }
5345
- if (chunk7HHIZQNE_cjs.AuthManager.isLegacyHash(user.password_hash)) {
5346
+ if (chunk3TVMUQWG_cjs.AuthManager.isLegacyHash(user.password_hash)) {
5346
5347
  try {
5347
- const newHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
5348
+ const newHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
5348
5349
  await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(newHash, Date.now(), user.id).run();
5349
5350
  } catch (rehashError) {
5350
5351
  console.error("Password rehash failed (non-fatal):", rehashError);
5351
5352
  }
5352
5353
  }
5353
- const token = await chunk7HHIZQNE_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET);
5354
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
5355
+ const token = await chunk3TVMUQWG_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET, tokenTtl);
5354
5356
  cookie.setCookie(c, "auth_token", token, {
5355
5357
  httpOnly: true,
5356
5358
  secure: true,
5357
5359
  sameSite: "Strict",
5358
- maxAge: 60 * 60 * 24
5359
- // 24 hours
5360
+ maxAge: tokenTtl
5360
5361
  });
5361
5362
  await setCsrfCookie(c);
5362
5363
  await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
@@ -5403,7 +5404,7 @@ authRoutes.get("/logout", (c) => {
5403
5404
  clearCsrfCookie(c);
5404
5405
  return c.redirect("/auth/login?message=You have been logged out successfully");
5405
5406
  });
5406
- authRoutes.get("/me", chunk7HHIZQNE_cjs.requireAuth(), async (c) => {
5407
+ authRoutes.get("/me", chunk3TVMUQWG_cjs.requireAuth(), async (c) => {
5407
5408
  try {
5408
5409
  const user = c.get("user");
5409
5410
  if (!user) {
@@ -5420,30 +5421,48 @@ authRoutes.get("/me", chunk7HHIZQNE_cjs.requireAuth(), async (c) => {
5420
5421
  return c.json({ error: "Failed to get user" }, 500);
5421
5422
  }
5422
5423
  });
5423
- authRoutes.post("/refresh", chunk7HHIZQNE_cjs.requireAuth(), async (c) => {
5424
- try {
5425
- const user = c.get("user");
5426
- if (!user) {
5427
- return c.json({ error: "Not authenticated" }, 401);
5424
+ authRoutes.post(
5425
+ "/refresh",
5426
+ chunk3TVMUQWG_cjs.rateLimit({ max: 60, windowMs: 60 * 1e3, keyPrefix: "refresh" }),
5427
+ async (c) => {
5428
+ try {
5429
+ let token = c.req.header("Authorization")?.replace("Bearer ", "");
5430
+ if (!token) token = cookie.getCookie(c, "auth_token");
5431
+ if (!token) {
5432
+ return c.json({ error: "Authentication required" }, 401);
5433
+ }
5434
+ const db = c.env.DB;
5435
+ const grace = await chunk3TVMUQWG_cjs.getJwtRefreshGraceSecondsFromDb(db, c.env);
5436
+ const payload = await chunk3TVMUQWG_cjs.AuthManager.verifyToken(token, c.env.JWT_SECRET, grace);
5437
+ if (!payload) {
5438
+ return c.json({ error: "Invalid or expired token" }, 401);
5439
+ }
5440
+ const row = await db.prepare("SELECT id, email, role, is_active FROM users WHERE id = ?").bind(payload.userId).first();
5441
+ if (!row || !row.is_active) {
5442
+ return c.json({ error: "User is not active" }, 401);
5443
+ }
5444
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(db, c.env);
5445
+ const newToken = await chunk3TVMUQWG_cjs.AuthManager.generateToken(row.id, row.email, row.role, c.env.JWT_SECRET, tokenTtl);
5446
+ cookie.setCookie(c, "auth_token", newToken, {
5447
+ httpOnly: true,
5448
+ secure: true,
5449
+ sameSite: "Strict",
5450
+ maxAge: tokenTtl
5451
+ });
5452
+ await setCsrfCookie(c);
5453
+ return c.json({
5454
+ token: newToken,
5455
+ expiresIn: tokenTtl
5456
+ });
5457
+ } catch (error) {
5458
+ console.error("Token refresh error:", error);
5459
+ return c.json({ error: "Token refresh failed" }, 500);
5428
5460
  }
5429
- const token = await chunk7HHIZQNE_cjs.AuthManager.generateToken(user.userId, user.email, user.role, c.env.JWT_SECRET);
5430
- cookie.setCookie(c, "auth_token", token, {
5431
- httpOnly: true,
5432
- secure: true,
5433
- sameSite: "Strict",
5434
- maxAge: 60 * 60 * 24
5435
- // 24 hours
5436
- });
5437
- await setCsrfCookie(c);
5438
- return c.json({ token });
5439
- } catch (error) {
5440
- console.error("Token refresh error:", error);
5441
- return c.json({ error: "Token refresh failed" }, 500);
5442
5461
  }
5443
- });
5462
+ );
5444
5463
  authRoutes.post(
5445
5464
  "/register/form",
5446
- chunk7HHIZQNE_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
5465
+ chunk3TVMUQWG_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
5447
5466
  async (c) => {
5448
5467
  try {
5449
5468
  const db = c.env.DB;
@@ -5490,7 +5509,7 @@ authRoutes.post(
5490
5509
  </div>
5491
5510
  `);
5492
5511
  }
5493
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
5512
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
5494
5513
  const role = isFirstUser ? "admin" : "viewer";
5495
5514
  const userId = crypto.randomUUID();
5496
5515
  const now = /* @__PURE__ */ new Date();
@@ -5525,14 +5544,14 @@ authRoutes.post(
5525
5544
  await saveCustomData(db, userId, sanitized);
5526
5545
  }
5527
5546
  }
5528
- const token = await chunk7HHIZQNE_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET);
5547
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
5548
+ const token = await chunk3TVMUQWG_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET, tokenTtl);
5529
5549
  cookie.setCookie(c, "auth_token", token, {
5530
5550
  httpOnly: true,
5531
5551
  secure: false,
5532
5552
  // Set to true in production with HTTPS
5533
5553
  sameSite: "Strict",
5534
- maxAge: 60 * 60 * 24
5535
- // 24 hours
5554
+ maxAge: tokenTtl
5536
5555
  });
5537
5556
  await setCsrfCookie(c);
5538
5557
  const redirectUrl = role === "admin" ? "/admin/dashboard" : "/admin/dashboard";
@@ -5558,7 +5577,7 @@ authRoutes.post(
5558
5577
  );
5559
5578
  authRoutes.post(
5560
5579
  "/login/form",
5561
- chunk7HHIZQNE_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
5580
+ chunk3TVMUQWG_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
5562
5581
  async (c) => {
5563
5582
  try {
5564
5583
  const formData = await c.req.formData();
@@ -5582,7 +5601,7 @@ authRoutes.post(
5582
5601
  </div>
5583
5602
  `);
5584
5603
  }
5585
- const isValidPassword = await chunk7HHIZQNE_cjs.AuthManager.verifyPassword(password, user.password_hash);
5604
+ const isValidPassword = await chunk3TVMUQWG_cjs.AuthManager.verifyPassword(password, user.password_hash);
5586
5605
  if (!isValidPassword) {
5587
5606
  return c.html(html.html`
5588
5607
  <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
@@ -5590,22 +5609,22 @@ authRoutes.post(
5590
5609
  </div>
5591
5610
  `);
5592
5611
  }
5593
- if (chunk7HHIZQNE_cjs.AuthManager.isLegacyHash(user.password_hash)) {
5612
+ if (chunk3TVMUQWG_cjs.AuthManager.isLegacyHash(user.password_hash)) {
5594
5613
  try {
5595
- const newHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
5614
+ const newHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
5596
5615
  await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(newHash, Date.now(), user.id).run();
5597
5616
  } catch (rehashError) {
5598
5617
  console.error("Password rehash failed (non-fatal):", rehashError);
5599
5618
  }
5600
5619
  }
5601
- const token = await chunk7HHIZQNE_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET);
5620
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
5621
+ const token = await chunk3TVMUQWG_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET, tokenTtl);
5602
5622
  cookie.setCookie(c, "auth_token", token, {
5603
5623
  httpOnly: true,
5604
5624
  secure: false,
5605
5625
  // Set to true in production with HTTPS
5606
5626
  sameSite: "Strict",
5607
- maxAge: 60 * 60 * 24
5608
- // 24 hours
5627
+ maxAge: tokenTtl
5609
5628
  });
5610
5629
  await setCsrfCookie(c);
5611
5630
  await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
@@ -5640,7 +5659,7 @@ authRoutes.post(
5640
5659
  );
5641
5660
  authRoutes.post(
5642
5661
  "/seed-admin",
5643
- chunk7HHIZQNE_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
5662
+ chunk3TVMUQWG_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
5644
5663
  async (c) => {
5645
5664
  try {
5646
5665
  const db = c.env.DB;
@@ -5662,7 +5681,7 @@ authRoutes.post(
5662
5681
  `).run();
5663
5682
  const existingAdmin = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
5664
5683
  if (existingAdmin) {
5665
- const passwordHash2 = await chunk7HHIZQNE_cjs.AuthManager.hashPassword("sonicjs!");
5684
+ const passwordHash2 = await chunk3TVMUQWG_cjs.AuthManager.hashPassword("sonicjs!");
5666
5685
  await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
5667
5686
  return c.json({
5668
5687
  message: "Admin user already exists (password updated)",
@@ -5674,7 +5693,7 @@ authRoutes.post(
5674
5693
  }
5675
5694
  });
5676
5695
  }
5677
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword("sonicjs!");
5696
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword("sonicjs!");
5678
5697
  const userId = "admin-user-id";
5679
5698
  const now = Date.now();
5680
5699
  const adminEmail = "admin@sonicjs.com".toLowerCase();
@@ -5895,7 +5914,7 @@ authRoutes.post("/accept-invitation", async (c) => {
5895
5914
  if (existingUsername) {
5896
5915
  return c.json({ error: "Username is already taken" }, 400);
5897
5916
  }
5898
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
5917
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
5899
5918
  const updateStmt = db.prepare(`
5900
5919
  UPDATE users SET
5901
5920
  username = ?,
@@ -5914,13 +5933,13 @@ authRoutes.post("/accept-invitation", async (c) => {
5914
5933
  Date.now(),
5915
5934
  invitedUser.id
5916
5935
  ).run();
5917
- const authToken = await chunk7HHIZQNE_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET);
5936
+ const tokenTtl = await chunk3TVMUQWG_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
5937
+ const authToken = await chunk3TVMUQWG_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET, tokenTtl);
5918
5938
  cookie.setCookie(c, "auth_token", authToken, {
5919
5939
  httpOnly: true,
5920
5940
  secure: true,
5921
5941
  sameSite: "Strict",
5922
- maxAge: 60 * 60 * 24
5923
- // 24 hours
5942
+ maxAge: tokenTtl
5924
5943
  });
5925
5944
  await setCsrfCookie(c);
5926
5945
  return c.redirect("/admin/dashboard?welcome=true");
@@ -5931,7 +5950,7 @@ authRoutes.post("/accept-invitation", async (c) => {
5931
5950
  });
5932
5951
  authRoutes.post(
5933
5952
  "/request-password-reset",
5934
- chunk7HHIZQNE_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
5953
+ chunk3TVMUQWG_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
5935
5954
  async (c) => {
5936
5955
  try {
5937
5956
  const formData = await c.req.formData();
@@ -6149,7 +6168,7 @@ authRoutes.post("/reset-password", async (c) => {
6149
6168
  if (Date.now() > user.password_reset_expires) {
6150
6169
  return c.json({ error: "Reset token has expired" }, 400);
6151
6170
  }
6152
- const newPasswordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
6171
+ const newPasswordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
6153
6172
  try {
6154
6173
  const historyStmt = db.prepare(`
6155
6174
  INSERT INTO password_history (id, user_id, password_hash, created_at)
@@ -9525,9 +9544,9 @@ function parseFieldValue(field, formData, options = {}) {
9525
9544
  const { skipValidation = false } = options;
9526
9545
  const value = formData.get(field.field_name);
9527
9546
  const errors = [];
9528
- const blocksConfig = chunkV76ERLX6_cjs.getBlocksFieldConfig(field.field_options);
9547
+ const blocksConfig = chunk5EBTBD2Z_cjs.getBlocksFieldConfig(field.field_options);
9529
9548
  if (blocksConfig) {
9530
- const parsed = chunkV76ERLX6_cjs.parseBlocksValue(value, blocksConfig);
9549
+ const parsed = chunk5EBTBD2Z_cjs.parseBlocksValue(value, blocksConfig);
9531
9550
  if (!skipValidation && field.is_required && parsed.value.length === 0) {
9532
9551
  parsed.errors.push(`${field.field_label} is required`);
9533
9552
  }
@@ -9637,9 +9656,9 @@ function extractFieldData(fields, formData, options = {}) {
9637
9656
  }
9638
9657
  return { data, errors };
9639
9658
  }
9640
- adminContentRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
9659
+ adminContentRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
9641
9660
  async function getCollectionFields(db, collectionId) {
9642
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.collection);
9661
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.collection);
9643
9662
  return cache.getOrSet(
9644
9663
  cache.generateKey("fields", collectionId),
9645
9664
  async () => {
@@ -9688,7 +9707,7 @@ async function getCollectionFields(db, collectionId) {
9688
9707
  );
9689
9708
  }
9690
9709
  async function getCollection(db, collectionId) {
9691
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.collection);
9710
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.collection);
9692
9711
  return cache.getOrSet(
9693
9712
  cache.generateKey("collection", collectionId),
9694
9713
  async () => {
@@ -9914,21 +9933,21 @@ adminContentRoutes.get("/new", async (c) => {
9914
9933
  const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
9915
9934
  let tinymceSettings;
9916
9935
  if (tinymceEnabled) {
9917
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
9936
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
9918
9937
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
9919
9938
  tinymceSettings = tinymcePlugin2?.settings;
9920
9939
  }
9921
9940
  const quillEnabled = await isPluginActive2(db, "quill-editor");
9922
9941
  let quillSettings;
9923
9942
  if (quillEnabled) {
9924
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
9943
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
9925
9944
  const quillPlugin = await pluginService.getPlugin("quill-editor");
9926
9945
  quillSettings = quillPlugin?.settings;
9927
9946
  }
9928
9947
  const mdxeditorEnabled = await isPluginActive2(db, "easy-mdx");
9929
9948
  let mdxeditorSettings;
9930
9949
  if (mdxeditorEnabled) {
9931
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
9950
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
9932
9951
  const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
9933
9952
  mdxeditorSettings = mdxeditorPlugin?.settings;
9934
9953
  }
@@ -9978,7 +9997,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
9978
9997
  const db = c.env.DB;
9979
9998
  const url = new URL(c.req.url);
9980
9999
  const referrerParams = url.searchParams.get("ref") || "";
9981
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.content);
10000
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.content);
9982
10001
  const content = await cache.getOrSet(
9983
10002
  cache.generateKey("content", id),
9984
10003
  async () => {
@@ -10019,21 +10038,21 @@ adminContentRoutes.get("/:id/edit", async (c) => {
10019
10038
  const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
10020
10039
  let tinymceSettings;
10021
10040
  if (tinymceEnabled) {
10022
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
10041
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
10023
10042
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
10024
10043
  tinymceSettings = tinymcePlugin2?.settings;
10025
10044
  }
10026
10045
  const quillEnabled = await isPluginActive2(db, "quill-editor");
10027
10046
  let quillSettings;
10028
10047
  if (quillEnabled) {
10029
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
10048
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
10030
10049
  const quillPlugin = await pluginService.getPlugin("quill-editor");
10031
10050
  quillSettings = quillPlugin?.settings;
10032
10051
  }
10033
10052
  const mdxeditorEnabled = await isPluginActive2(db, "easy-mdx");
10034
10053
  let mdxeditorSettings;
10035
10054
  if (mdxeditorEnabled) {
10036
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
10055
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
10037
10056
  const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
10038
10057
  mdxeditorSettings = mdxeditorPlugin?.settings;
10039
10058
  }
@@ -10154,7 +10173,7 @@ adminContentRoutes.post("/", async (c) => {
10154
10173
  now,
10155
10174
  now
10156
10175
  ).run();
10157
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.content);
10176
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.content);
10158
10177
  await cache.invalidate(`content:list:${collectionId}:*`);
10159
10178
  const versionStmt = db.prepare(`
10160
10179
  INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
@@ -10273,7 +10292,7 @@ adminContentRoutes.put("/:id", async (c) => {
10273
10292
  now,
10274
10293
  id
10275
10294
  ).run();
10276
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.content);
10295
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.content);
10277
10296
  await cache.delete(cache.generateKey("content", id));
10278
10297
  await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
10279
10298
  const existingData = JSON.parse(existingContent.data || "{}");
@@ -10328,7 +10347,7 @@ adminContentRoutes.put("/:id", async (c) => {
10328
10347
  `);
10329
10348
  }
10330
10349
  });
10331
- adminContentRoutes.post("/preview", chunk7HHIZQNE_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
10350
+ adminContentRoutes.post("/preview", chunk3TVMUQWG_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
10332
10351
  try {
10333
10352
  const formData = await c.req.formData();
10334
10353
  const collectionId = formData.get("collection_id");
@@ -10550,7 +10569,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
10550
10569
  } else {
10551
10570
  return c.json({ success: false, error: "Invalid action" });
10552
10571
  }
10553
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.content);
10572
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.content);
10554
10573
  for (const contentId of ids) {
10555
10574
  await cache.delete(cache.generateKey("content", contentId));
10556
10575
  }
@@ -10578,7 +10597,7 @@ adminContentRoutes.delete("/:id", async (c) => {
10578
10597
  WHERE id = ?
10579
10598
  `);
10580
10599
  await deleteStmt.bind(now, id).run();
10581
- const cache = chunkNZWFCUDA_cjs.getCacheService(chunkNZWFCUDA_cjs.CACHE_CONFIGS.content);
10600
+ const cache = chunkWAEQXGCX_cjs.getCacheService(chunkWAEQXGCX_cjs.CACHE_CONFIGS.content);
10582
10601
  await cache.delete(cache.generateKey("content", id));
10583
10602
  await cache.invalidate("content:list:*");
10584
10603
  return c.html(`
@@ -10706,7 +10725,7 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
10706
10725
  return c.json({ success: false, error: "Failed to restore version" });
10707
10726
  }
10708
10727
  });
10709
- adminContentRoutes.get("/:id/version/:version/preview", chunk7HHIZQNE_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
10728
+ adminContentRoutes.get("/:id/version/:version/preview", chunk3TVMUQWG_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
10710
10729
  try {
10711
10730
  const id = c.req.param("id");
10712
10731
  const version = parseInt(c.req.param("version") || "0");
@@ -11629,7 +11648,6 @@ function renderUserEditPage(data) {
11629
11648
  type="text"
11630
11649
  name="first_name"
11631
11650
  value="${chunkMNWKYY5E_cjs.escapeHtml(data.userToEdit.firstName || "")}"
11632
- required
11633
11651
  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"
11634
11652
  />
11635
11653
  </div>
@@ -11640,7 +11658,6 @@ function renderUserEditPage(data) {
11640
11658
  type="text"
11641
11659
  name="last_name"
11642
11660
  value="${chunkMNWKYY5E_cjs.escapeHtml(data.userToEdit.lastName || "")}"
11643
- required
11644
11661
  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"
11645
11662
  />
11646
11663
  </div>
@@ -12707,14 +12724,14 @@ function renderUsersListPage(data) {
12707
12724
 
12708
12725
  // src/routes/admin-users.ts
12709
12726
  var userRoutes = new hono.Hono();
12710
- userRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
12711
- userRoutes.use("/users/*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12712
- userRoutes.use("/users", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12713
- userRoutes.use("/invite-user", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12714
- userRoutes.use("/resend-invitation/*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12715
- userRoutes.use("/cancel-invitation/*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12716
- userRoutes.use("/activity-logs", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12717
- userRoutes.use("/activity-logs/*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
12727
+ userRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
12728
+ userRoutes.use("/users/*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12729
+ userRoutes.use("/users", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12730
+ userRoutes.use("/invite-user", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12731
+ userRoutes.use("/resend-invitation/*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12732
+ userRoutes.use("/cancel-invitation/*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12733
+ userRoutes.use("/activity-logs", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12734
+ userRoutes.use("/activity-logs/*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
12718
12735
  userRoutes.get("/", (c) => {
12719
12736
  return c.redirect("/admin/dashboard");
12720
12737
  });
@@ -12884,7 +12901,7 @@ userRoutes.put("/profile", async (c) => {
12884
12901
  }
12885
12902
  await saveCustomData(db, user.userId, sanitized);
12886
12903
  }
12887
- await chunk7HHIZQNE_cjs.logActivity(
12904
+ await chunk3TVMUQWG_cjs.logActivity(
12888
12905
  db,
12889
12906
  user.userId,
12890
12907
  "profile.update",
@@ -12947,7 +12964,7 @@ userRoutes.post("/profile/avatar", async (c) => {
12947
12964
  SELECT first_name, last_name FROM users WHERE id = ?
12948
12965
  `);
12949
12966
  const userData = await userStmt.bind(user.userId).first();
12950
- await chunk7HHIZQNE_cjs.logActivity(
12967
+ await chunk3TVMUQWG_cjs.logActivity(
12951
12968
  db,
12952
12969
  user.userId,
12953
12970
  "profile.avatar_update",
@@ -13018,7 +13035,7 @@ userRoutes.post("/profile/password", async (c) => {
13018
13035
  dismissible: true
13019
13036
  }));
13020
13037
  }
13021
- const validPassword = await chunk7HHIZQNE_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
13038
+ const validPassword = await chunk3TVMUQWG_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
13022
13039
  if (!validPassword) {
13023
13040
  return c.html(renderAlert2({
13024
13041
  type: "error",
@@ -13026,7 +13043,7 @@ userRoutes.post("/profile/password", async (c) => {
13026
13043
  dismissible: true
13027
13044
  }));
13028
13045
  }
13029
- const newPasswordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(newPassword);
13046
+ const newPasswordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(newPassword);
13030
13047
  const historyStmt = db.prepare(`
13031
13048
  INSERT INTO password_history (id, user_id, password_hash, created_at)
13032
13049
  VALUES (?, ?, ?, ?)
@@ -13042,7 +13059,7 @@ userRoutes.post("/profile/password", async (c) => {
13042
13059
  WHERE id = ?
13043
13060
  `);
13044
13061
  await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
13045
- await chunk7HHIZQNE_cjs.logActivity(
13062
+ await chunk3TVMUQWG_cjs.logActivity(
13046
13063
  db,
13047
13064
  user.userId,
13048
13065
  "profile.password_change",
@@ -13109,7 +13126,7 @@ userRoutes.get("/users", async (c) => {
13109
13126
  `);
13110
13127
  const countResult = await countStmt.bind(...params).first();
13111
13128
  const totalUsers = countResult?.total || 0;
13112
- await chunk7HHIZQNE_cjs.logActivity(
13129
+ await chunk3TVMUQWG_cjs.logActivity(
13113
13130
  db,
13114
13131
  user.userId,
13115
13132
  "users.list_view",
@@ -13267,7 +13284,7 @@ userRoutes.post("/users/new", async (c) => {
13267
13284
  dismissible: true
13268
13285
  }));
13269
13286
  }
13270
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(password);
13287
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(password);
13271
13288
  const userId = crypto.randomUUID();
13272
13289
  const createStmt = db.prepare(`
13273
13290
  INSERT INTO users (
@@ -13290,7 +13307,7 @@ userRoutes.post("/users/new", async (c) => {
13290
13307
  Date.now(),
13291
13308
  Date.now()
13292
13309
  ).run();
13293
- await chunk7HHIZQNE_cjs.logActivity(
13310
+ await chunk3TVMUQWG_cjs.logActivity(
13294
13311
  db,
13295
13312
  user.userId,
13296
13313
  "user!.create",
@@ -13329,7 +13346,7 @@ userRoutes.get("/users/:id", async (c) => {
13329
13346
  if (!userRecord) {
13330
13347
  return c.json({ error: "User not found" }, 404);
13331
13348
  }
13332
- await chunk7HHIZQNE_cjs.logActivity(
13349
+ await chunk3TVMUQWG_cjs.logActivity(
13333
13350
  db,
13334
13351
  user.userId,
13335
13352
  "user!.view",
@@ -13481,10 +13498,10 @@ userRoutes.put("/users/:id", async (c) => {
13481
13498
  const merged = { ...existingCustom, ...sanitized };
13482
13499
  customDataJson = JSON.stringify(merged);
13483
13500
  }
13484
- if (!firstName || !lastName || !username || !email) {
13501
+ if (!username || !email) {
13485
13502
  return c.html(renderAlert2({
13486
13503
  type: "error",
13487
- message: "First name, last name, username, and email are required.",
13504
+ message: "Username and email are required.",
13488
13505
  dismissible: true
13489
13506
  }));
13490
13507
  }
@@ -13555,7 +13572,7 @@ userRoutes.put("/users/:id", async (c) => {
13555
13572
  userId
13556
13573
  ).run();
13557
13574
  if (newPassword) {
13558
- const passwordHash = await chunk7HHIZQNE_cjs.AuthManager.hashPassword(newPassword);
13575
+ const passwordHash = await chunk3TVMUQWG_cjs.AuthManager.hashPassword(newPassword);
13559
13576
  const updatePasswordStmt = db.prepare(`
13560
13577
  UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?
13561
13578
  `);
@@ -13609,7 +13626,7 @@ userRoutes.put("/users/:id", async (c) => {
13609
13626
  ).run();
13610
13627
  }
13611
13628
  }
13612
- await chunk7HHIZQNE_cjs.logActivity(
13629
+ await chunk3TVMUQWG_cjs.logActivity(
13613
13630
  db,
13614
13631
  user.userId,
13615
13632
  "user.update",
@@ -13654,7 +13671,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
13654
13671
  UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?
13655
13672
  `);
13656
13673
  await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
13657
- await chunk7HHIZQNE_cjs.logActivity(
13674
+ await chunk3TVMUQWG_cjs.logActivity(
13658
13675
  db,
13659
13676
  user.userId,
13660
13677
  active ? "user.activate" : "user.deactivate",
@@ -13695,7 +13712,7 @@ userRoutes.delete("/users/:id", async (c) => {
13695
13712
  DELETE FROM users WHERE id = ?
13696
13713
  `);
13697
13714
  await deleteStmt.bind(userId).run();
13698
- await chunk7HHIZQNE_cjs.logActivity(
13715
+ await chunk3TVMUQWG_cjs.logActivity(
13699
13716
  db,
13700
13717
  user.userId,
13701
13718
  "user!.hard_delete",
@@ -13714,7 +13731,7 @@ userRoutes.delete("/users/:id", async (c) => {
13714
13731
  UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
13715
13732
  `);
13716
13733
  await deleteStmt.bind(Date.now(), userId).run();
13717
- await chunk7HHIZQNE_cjs.logActivity(
13734
+ await chunk3TVMUQWG_cjs.logActivity(
13718
13735
  db,
13719
13736
  user.userId,
13720
13737
  "user!.soft_delete",
@@ -13780,7 +13797,7 @@ userRoutes.post("/invite-user", async (c) => {
13780
13797
  Date.now(),
13781
13798
  Date.now()
13782
13799
  ).run();
13783
- await chunk7HHIZQNE_cjs.logActivity(
13800
+ await chunk3TVMUQWG_cjs.logActivity(
13784
13801
  db,
13785
13802
  user.userId,
13786
13803
  "user!.invite_sent",
@@ -13837,7 +13854,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
13837
13854
  Date.now(),
13838
13855
  userId
13839
13856
  ).run();
13840
- await chunk7HHIZQNE_cjs.logActivity(
13857
+ await chunk3TVMUQWG_cjs.logActivity(
13841
13858
  db,
13842
13859
  user.userId,
13843
13860
  "user!.invitation_resent",
@@ -13873,7 +13890,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
13873
13890
  }
13874
13891
  const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
13875
13892
  await deleteStmt.bind(userId).run();
13876
- await chunk7HHIZQNE_cjs.logActivity(
13893
+ await chunk3TVMUQWG_cjs.logActivity(
13877
13894
  db,
13878
13895
  user.userId,
13879
13896
  "user!.invitation_cancelled",
@@ -13956,7 +13973,7 @@ userRoutes.get("/activity-logs", async (c) => {
13956
13973
  ...log,
13957
13974
  details: log.details ? JSON.parse(log.details) : null
13958
13975
  }));
13959
- await chunk7HHIZQNE_cjs.logActivity(
13976
+ await chunk3TVMUQWG_cjs.logActivity(
13960
13977
  db,
13961
13978
  user.userId,
13962
13979
  "activity.logs_viewed",
@@ -14063,7 +14080,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
14063
14080
  csvRows.push(row.join(","));
14064
14081
  }
14065
14082
  const csvContent = csvRows.join("\n");
14066
- await chunk7HHIZQNE_cjs.logActivity(
14083
+ await chunk3TVMUQWG_cjs.logActivity(
14067
14084
  db,
14068
14085
  user.userId,
14069
14086
  "activity.logs_exported",
@@ -15402,7 +15419,7 @@ var fileValidationSchema2 = zod.z.object({
15402
15419
  // 50MB max
15403
15420
  });
15404
15421
  var adminMediaRoutes = new hono.Hono();
15405
- adminMediaRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
15422
+ adminMediaRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
15406
15423
  adminMediaRoutes.get("/", async (c) => {
15407
15424
  try {
15408
15425
  const user = c.get("user");
@@ -15988,7 +16005,7 @@ adminMediaRoutes.put("/:id", async (c) => {
15988
16005
  `);
15989
16006
  }
15990
16007
  });
15991
- adminMediaRoutes.delete("/cleanup", chunk7HHIZQNE_cjs.requireRole("admin"), async (c) => {
16008
+ adminMediaRoutes.delete("/cleanup", chunk3TVMUQWG_cjs.requireRole("admin"), async (c) => {
15992
16009
  try {
15993
16010
  const db = c.env.DB;
15994
16011
  const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
@@ -18213,8 +18230,8 @@ function renderEmailSettingsContent(plugin, settings) {
18213
18230
 
18214
18231
  // src/routes/admin-plugins.ts
18215
18232
  var adminPluginRoutes = new hono.Hono();
18216
- adminPluginRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
18217
- var AVAILABLE_PLUGINS = Object.values(chunkU6FOL6EO_cjs.PLUGIN_REGISTRY).map((p) => ({
18233
+ adminPluginRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
18234
+ var AVAILABLE_PLUGINS = Object.values(chunk47HKH3D6_cjs.PLUGIN_REGISTRY).map((p) => ({
18218
18235
  id: p.id,
18219
18236
  name: p.codeName,
18220
18237
  display_name: p.displayName,
@@ -18234,7 +18251,7 @@ adminPluginRoutes.get("/", async (c) => {
18234
18251
  if (user?.role !== "admin") {
18235
18252
  return c.text("Access denied", 403);
18236
18253
  }
18237
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18254
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18238
18255
  let installedPlugins = [];
18239
18256
  let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
18240
18257
  try {
@@ -18306,7 +18323,7 @@ adminPluginRoutes.get("/:id", async (c) => {
18306
18323
  if (user?.role !== "admin") {
18307
18324
  return c.redirect("/admin/plugins");
18308
18325
  }
18309
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18326
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18310
18327
  const plugin = await pluginService.getPlugin(pluginId);
18311
18328
  if (!plugin) {
18312
18329
  return c.text("Plugin not found", 404);
@@ -18314,7 +18331,7 @@ adminPluginRoutes.get("/:id", async (c) => {
18314
18331
  const activity = await pluginService.getPluginActivity(pluginId, 20);
18315
18332
  let enrichedSettings = plugin.settings || {};
18316
18333
  if (pluginId === "otp-login") {
18317
- const settingsService = new chunkNZWFCUDA_cjs.SettingsService(db);
18334
+ const settingsService = new chunkWAEQXGCX_cjs.SettingsService(db);
18318
18335
  const generalSettings = await settingsService.getGeneralSettings();
18319
18336
  const siteName = generalSettings.siteName || "SonicJS";
18320
18337
  const emailPlugin = await db.prepare(`
@@ -18382,7 +18399,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
18382
18399
  if (user?.role !== "admin") {
18383
18400
  return c.json({ error: "Access denied" }, 403);
18384
18401
  }
18385
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18402
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18386
18403
  await pluginService.activatePlugin(pluginId);
18387
18404
  return c.json({ success: true });
18388
18405
  } catch (error) {
@@ -18399,7 +18416,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
18399
18416
  if (user?.role !== "admin") {
18400
18417
  return c.json({ error: "Access denied" }, 403);
18401
18418
  }
18402
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18419
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18403
18420
  await pluginService.deactivatePlugin(pluginId);
18404
18421
  return c.json({ success: true });
18405
18422
  } catch (error) {
@@ -18416,8 +18433,8 @@ adminPluginRoutes.post("/install", async (c) => {
18416
18433
  return c.json({ error: "Access denied" }, 403);
18417
18434
  }
18418
18435
  const body = await c.req.json();
18419
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18420
- const registryEntry = chunkU6FOL6EO_cjs.findPluginByCodeName(body.name) || chunkU6FOL6EO_cjs.PLUGIN_REGISTRY[body.name] || chunkU6FOL6EO_cjs.PLUGIN_REGISTRY[body.id];
18436
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18437
+ const registryEntry = chunk47HKH3D6_cjs.findPluginByCodeName(body.name) || chunk47HKH3D6_cjs.PLUGIN_REGISTRY[body.name] || chunk47HKH3D6_cjs.PLUGIN_REGISTRY[body.id];
18421
18438
  if (!registryEntry) {
18422
18439
  return c.json({ error: "Plugin not found in registry" }, 404);
18423
18440
  }
@@ -18450,7 +18467,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
18450
18467
  if (user?.role !== "admin") {
18451
18468
  return c.json({ error: "Access denied" }, 403);
18452
18469
  }
18453
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18470
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18454
18471
  await pluginService.uninstallPlugin(pluginId);
18455
18472
  return c.json({ success: true });
18456
18473
  } catch (error) {
@@ -18468,7 +18485,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
18468
18485
  return c.json({ error: "Access denied" }, 403);
18469
18486
  }
18470
18487
  const settings = await c.req.json();
18471
- const pluginService = new chunkU6FOL6EO_cjs.PluginService(db);
18488
+ const pluginService = new chunk47HKH3D6_cjs.PluginService(db);
18472
18489
  await pluginService.updatePluginSettings(pluginId, settings);
18473
18490
  if (pluginId === "core-auth") {
18474
18491
  try {
@@ -19276,11 +19293,11 @@ function renderLogConfigPage(data) {
19276
19293
 
19277
19294
  // src/routes/admin-logs.ts
19278
19295
  var adminLogsRoutes = new hono.Hono();
19279
- adminLogsRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
19296
+ adminLogsRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
19280
19297
  adminLogsRoutes.get("/", async (c) => {
19281
19298
  try {
19282
19299
  const user = c.get("user");
19283
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19300
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19284
19301
  const query = c.req.query();
19285
19302
  const page = parseInt(query.page || "1");
19286
19303
  const limit = parseInt(query.limit || "50");
@@ -19360,7 +19377,7 @@ adminLogsRoutes.get("/:id", async (c) => {
19360
19377
  try {
19361
19378
  const id = c.req.param("id");
19362
19379
  const user = c.get("user");
19363
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19380
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19364
19381
  const { logs } = await logger.getLogs({
19365
19382
  limit: 1,
19366
19383
  offset: 0,
@@ -19397,7 +19414,7 @@ adminLogsRoutes.get("/:id", async (c) => {
19397
19414
  adminLogsRoutes.get("/config", async (c) => {
19398
19415
  try {
19399
19416
  const user = c.get("user");
19400
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19417
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19401
19418
  const configs = await logger.getAllConfigs();
19402
19419
  const pageData = {
19403
19420
  configs,
@@ -19421,7 +19438,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
19421
19438
  const level = formData.get("level");
19422
19439
  const retention = parseInt(formData.get("retention"));
19423
19440
  const maxSize = parseInt(formData.get("max_size"));
19424
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19441
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19425
19442
  await logger.updateConfig(category, {
19426
19443
  enabled,
19427
19444
  level,
@@ -19450,7 +19467,7 @@ adminLogsRoutes.get("/export", async (c) => {
19450
19467
  const category = query.category;
19451
19468
  const startDate = query.start_date;
19452
19469
  const endDate = query.end_date;
19453
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19470
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19454
19471
  const filter = {
19455
19472
  limit: 1e4,
19456
19473
  // Export up to 10k logs
@@ -19531,7 +19548,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
19531
19548
  error: "Unauthorized. Admin access required."
19532
19549
  }, 403);
19533
19550
  }
19534
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19551
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19535
19552
  await logger.cleanupByRetention();
19536
19553
  return c.html(html.html`
19537
19554
  <div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
@@ -19553,7 +19570,7 @@ adminLogsRoutes.post("/search", async (c) => {
19553
19570
  const search = formData.get("search");
19554
19571
  const level = formData.get("level");
19555
19572
  const category = formData.get("category");
19556
- const logger = chunkNZWFCUDA_cjs.getLogger(c.env.DB);
19573
+ const logger = chunkWAEQXGCX_cjs.getLogger(c.env.DB);
19557
19574
  const filter = {
19558
19575
  limit: 20,
19559
19576
  offset: 0,
@@ -21604,9 +21621,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
21604
21621
  }
21605
21622
 
21606
21623
  // src/routes/admin-dashboard.ts
21607
- var VERSION = chunkV76ERLX6_cjs.getCoreVersion();
21624
+ var VERSION = chunk5EBTBD2Z_cjs.getCoreVersion();
21608
21625
  var router = new hono.Hono();
21609
- router.use("*", chunk7HHIZQNE_cjs.requireAuth());
21626
+ router.use("*", chunk3TVMUQWG_cjs.requireAuth());
21610
21627
  router.get("/", async (c) => {
21611
21628
  const user = c.get("user");
21612
21629
  try {
@@ -23425,10 +23442,10 @@ function renderCollectionFormPage(data) {
23425
23442
 
23426
23443
  // src/routes/admin-collections.ts
23427
23444
  var adminCollectionsRoutes = new hono.Hono();
23428
- adminCollectionsRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
23429
- adminCollectionsRoutes.post("*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
23430
- adminCollectionsRoutes.put("*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
23431
- adminCollectionsRoutes.delete("*", chunk7HHIZQNE_cjs.requireRole(["admin"]));
23445
+ adminCollectionsRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
23446
+ adminCollectionsRoutes.post("*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
23447
+ adminCollectionsRoutes.put("*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
23448
+ adminCollectionsRoutes.delete("*", chunk3TVMUQWG_cjs.requireRole(["admin"]));
23432
23449
  adminCollectionsRoutes.get("/", async (c) => {
23433
23450
  try {
23434
23451
  const user = c.get("user");
@@ -24241,6 +24258,43 @@ function renderSettingsPage(data) {
24241
24258
  }
24242
24259
  }
24243
24260
 
24261
+ async function saveSecuritySettings() {
24262
+ const formData = new FormData();
24263
+ const expiry = document.getElementById('jwtExpiresIn');
24264
+ const grace = document.getElementById('jwtRefreshGraceSeconds');
24265
+ if (expiry) formData.append('jwtExpiresIn', expiry.value);
24266
+ if (grace) formData.append('jwtRefreshGraceSeconds', grace.value);
24267
+
24268
+ const saveBtn = document.querySelector('button[onclick="saveSecuritySettings()"]');
24269
+ const originalText = saveBtn ? saveBtn.innerHTML : '';
24270
+ if (saveBtn) {
24271
+ 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...';
24272
+ saveBtn.disabled = true;
24273
+ }
24274
+
24275
+ try {
24276
+ const response = await fetch('/admin/settings/security', {
24277
+ method: 'POST',
24278
+ body: formData
24279
+ });
24280
+ const result = await response.json();
24281
+ if (result.success) {
24282
+ showNotification(result.message || 'Security settings saved successfully!', 'success');
24283
+ } else {
24284
+ showNotification(result.error || 'Failed to save security settings', 'error');
24285
+ }
24286
+ } catch (error) {
24287
+ console.error('Error saving security settings:', error);
24288
+ showNotification('Failed to save security settings. Please try again.', 'error');
24289
+ } finally {
24290
+ if (saveBtn) {
24291
+ saveBtn.innerHTML = originalText;
24292
+ saveBtn.disabled = false;
24293
+ }
24294
+ }
24295
+ }
24296
+ window.saveSecuritySettings = saveSecuritySettings;
24297
+
24244
24298
  // Migration functions
24245
24299
  window.refreshMigrationStatus = async function() {
24246
24300
  try {
@@ -24823,9 +24877,71 @@ function renderAppearanceSettings(settings) {
24823
24877
  `;
24824
24878
  }
24825
24879
  function renderSecuritySettings(settings) {
24880
+ const jwtExpiresIn = settings?.jwtExpiresIn ?? "30d";
24881
+ const jwtRefreshGraceSeconds = typeof settings?.jwtRefreshGraceSeconds === "number" ? settings.jwtRefreshGraceSeconds : 60 * 60 * 24 * 7;
24826
24882
  return `
24827
24883
  <div class="space-y-6">
24828
- <!-- WIP Notice -->
24884
+ <!-- Session / JWT card (live) -->
24885
+ <div class="rounded-lg bg-white dark:bg-white/5 p-6 ring-1 ring-inset ring-zinc-950/5 dark:ring-white/10">
24886
+ <h3 class="text-lg/7 font-semibold text-zinc-950 dark:text-white">Session / JWT</h3>
24887
+ <p class="mt-1 text-sm/6 text-zinc-500 dark:text-zinc-400">
24888
+ Configure how long a signed-in session lasts and how long an expired token can still be refreshed.
24889
+ The <code class="text-xs">JWT_EXPIRES_IN</code> and <code class="text-xs">JWT_REFRESH_GRACE_SECONDS</code>
24890
+ environment variables, when set, override the values below.
24891
+ </p>
24892
+
24893
+ <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
24894
+ <div>
24895
+ <label for="jwtExpiresIn" class="block text-sm/6 font-medium text-zinc-950 dark:text-white mb-2">
24896
+ JWT Expiration
24897
+ </label>
24898
+ <input
24899
+ type="text"
24900
+ id="jwtExpiresIn"
24901
+ name="jwtExpiresIn"
24902
+ value="${jwtExpiresIn}"
24903
+ placeholder="30d"
24904
+ class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm/6 text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
24905
+ />
24906
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
24907
+ Accepts <code>30d</code>, <code>12h</code>, <code>3600s</code>, or bare seconds. Default: 30 days.
24908
+ </p>
24909
+ </div>
24910
+
24911
+ <div>
24912
+ <label for="jwtRefreshGraceSeconds" class="block text-sm/6 font-medium text-zinc-950 dark:text-white mb-2">
24913
+ Refresh Grace Window (seconds)
24914
+ </label>
24915
+ <input
24916
+ type="number"
24917
+ id="jwtRefreshGraceSeconds"
24918
+ name="jwtRefreshGraceSeconds"
24919
+ value="${jwtRefreshGraceSeconds}"
24920
+ min="0"
24921
+ max="7776000"
24922
+ class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm/6 text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
24923
+ />
24924
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
24925
+ How long an expired token can still be exchanged at <code>/auth/refresh</code>. Default: 604800 (7 days).
24926
+ </p>
24927
+ </div>
24928
+ </div>
24929
+
24930
+ <div class="mt-6 pt-4 border-t border-zinc-950/5 dark:border-white/10 flex justify-end">
24931
+ <button
24932
+ type="button"
24933
+ onclick="saveSecuritySettings()"
24934
+ 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"
24935
+ >
24936
+ <svg class="-ml-0.5 mr-1.5 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
24937
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
24938
+ </svg>
24939
+ Save Session Settings
24940
+ </button>
24941
+ </div>
24942
+ </div>
24943
+
24944
+ <!-- WIP Notice for remaining fields -->
24829
24945
  <div class="rounded-lg bg-blue-50 dark:bg-blue-950/20 p-6 ring-1 ring-inset ring-blue-600/20 dark:ring-blue-500/30">
24830
24946
  <div class="flex items-start space-x-3">
24831
24947
  <svg class="w-6 h-6 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -24834,7 +24950,7 @@ function renderSecuritySettings(settings) {
24834
24950
  <div class="flex-1">
24835
24951
  <h4 class="text-base/7 font-semibold text-blue-900 dark:text-blue-300">Work in Progress</h4>
24836
24952
  <p class="mt-1 text-sm/6 text-blue-700 dark:text-blue-200">
24837
- This settings section is currently under development and provided for reference and design feedback only. Changes made here will not be saved.
24953
+ The fields below are under development and provided for reference and design feedback only. Changes made here will not be saved.
24838
24954
  </p>
24839
24955
  </div>
24840
24956
  </div>
@@ -25624,7 +25740,7 @@ function renderDatabaseToolsSettings(settings) {
25624
25740
 
25625
25741
  // src/routes/admin-settings.ts
25626
25742
  var adminSettingsRoutes = new hono.Hono();
25627
- adminSettingsRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
25743
+ adminSettingsRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
25628
25744
  function getMockSettings(user) {
25629
25745
  return {
25630
25746
  general: {
@@ -25689,7 +25805,7 @@ adminSettingsRoutes.get("/", (c) => {
25689
25805
  adminSettingsRoutes.get("/general", async (c) => {
25690
25806
  const user = c.get("user");
25691
25807
  const db = c.env.DB;
25692
- const settingsService = new chunkNZWFCUDA_cjs.SettingsService(db);
25808
+ const settingsService = new chunkWAEQXGCX_cjs.SettingsService(db);
25693
25809
  const generalSettings = await settingsService.getGeneralSettings(user?.email);
25694
25810
  const mockSettings = getMockSettings(user);
25695
25811
  mockSettings.general = generalSettings;
@@ -25719,15 +25835,24 @@ adminSettingsRoutes.get("/appearance", (c) => {
25719
25835
  };
25720
25836
  return c.html(renderSettingsPage(pageData));
25721
25837
  });
25722
- adminSettingsRoutes.get("/security", (c) => {
25838
+ adminSettingsRoutes.get("/security", async (c) => {
25723
25839
  const user = c.get("user");
25840
+ const db = c.env.DB;
25841
+ const settingsService = new chunkWAEQXGCX_cjs.SettingsService(db);
25842
+ const persisted = await settingsService.getSecuritySettings();
25843
+ const mockSettings = getMockSettings(user);
25844
+ mockSettings.security = {
25845
+ ...mockSettings.security,
25846
+ jwtExpiresIn: persisted.jwtExpiresIn,
25847
+ jwtRefreshGraceSeconds: persisted.jwtRefreshGraceSeconds
25848
+ };
25724
25849
  const pageData = {
25725
25850
  user: user ? {
25726
25851
  name: user.email,
25727
25852
  email: user.email,
25728
25853
  role: user.role
25729
25854
  } : void 0,
25730
- settings: getMockSettings(user),
25855
+ settings: mockSettings,
25731
25856
  activeTab: "security",
25732
25857
  version: c.get("appVersion")
25733
25858
  };
@@ -25792,7 +25917,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
25792
25917
  adminSettingsRoutes.get("/api/migrations/status", async (c) => {
25793
25918
  try {
25794
25919
  const db = c.env.DB;
25795
- const migrationService = new chunkHU4MN74Q_cjs.MigrationService(db);
25920
+ const migrationService = new chunkI6444XLU_cjs.MigrationService(db);
25796
25921
  const status = await migrationService.getMigrationStatus();
25797
25922
  return c.json({
25798
25923
  success: true,
@@ -25816,7 +25941,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
25816
25941
  }, 403);
25817
25942
  }
25818
25943
  const db = c.env.DB;
25819
- const migrationService = new chunkHU4MN74Q_cjs.MigrationService(db);
25944
+ const migrationService = new chunkI6444XLU_cjs.MigrationService(db);
25820
25945
  const result = await migrationService.runPendingMigrations();
25821
25946
  return c.json({
25822
25947
  success: result.success,
@@ -25834,7 +25959,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
25834
25959
  adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
25835
25960
  try {
25836
25961
  const db = c.env.DB;
25837
- const migrationService = new chunkHU4MN74Q_cjs.MigrationService(db);
25962
+ const migrationService = new chunkI6444XLU_cjs.MigrationService(db);
25838
25963
  const validation = await migrationService.validateSchema();
25839
25964
  return c.json({
25840
25965
  success: true,
@@ -26003,7 +26128,7 @@ adminSettingsRoutes.post("/general", async (c) => {
26003
26128
  }
26004
26129
  const formData = await c.req.formData();
26005
26130
  const db = c.env.DB;
26006
- const settingsService = new chunkNZWFCUDA_cjs.SettingsService(db);
26131
+ const settingsService = new chunkWAEQXGCX_cjs.SettingsService(db);
26007
26132
  const settings = {
26008
26133
  siteName: formData.get("siteName"),
26009
26134
  siteDescription: formData.get("siteDescription"),
@@ -26038,6 +26163,55 @@ adminSettingsRoutes.post("/general", async (c) => {
26038
26163
  }, 500);
26039
26164
  }
26040
26165
  });
26166
+ adminSettingsRoutes.post("/security", async (c) => {
26167
+ try {
26168
+ const user = c.get("user");
26169
+ if (!user || user.role !== "admin") {
26170
+ return c.json({
26171
+ success: false,
26172
+ error: "Unauthorized. Admin access required."
26173
+ }, 403);
26174
+ }
26175
+ const formData = await c.req.formData();
26176
+ const db = c.env.DB;
26177
+ const settingsService = new chunkWAEQXGCX_cjs.SettingsService(db);
26178
+ const jwtExpiresInRaw = formData.get("jwtExpiresIn")?.trim() || "";
26179
+ const graceRaw = formData.get("jwtRefreshGraceSeconds")?.trim() || "";
26180
+ if (!/^\d+(?:s|m|h|d)?$/i.test(jwtExpiresInRaw)) {
26181
+ return c.json({
26182
+ success: false,
26183
+ error: "JWT expiration must be a number optionally suffixed with s/m/h/d (e.g. 30d, 12h, 3600)."
26184
+ }, 400);
26185
+ }
26186
+ const graceSeconds = Number.parseInt(graceRaw, 10);
26187
+ if (!Number.isFinite(graceSeconds) || graceSeconds < 0 || graceSeconds > 60 * 60 * 24 * 90) {
26188
+ return c.json({
26189
+ success: false,
26190
+ error: "Refresh grace must be an integer between 0 and 7776000 seconds (90 days)."
26191
+ }, 400);
26192
+ }
26193
+ const success = await settingsService.saveSecuritySettings({
26194
+ jwtExpiresIn: jwtExpiresInRaw,
26195
+ jwtRefreshGraceSeconds: graceSeconds
26196
+ });
26197
+ if (success) {
26198
+ return c.json({
26199
+ success: true,
26200
+ message: "Security settings saved successfully!"
26201
+ });
26202
+ }
26203
+ return c.json({
26204
+ success: false,
26205
+ error: "Failed to save settings"
26206
+ }, 500);
26207
+ } catch (error) {
26208
+ console.error("Error saving security settings:", error);
26209
+ return c.json({
26210
+ success: false,
26211
+ error: "Failed to save settings. Please try again."
26212
+ }, 500);
26213
+ }
26214
+ });
26041
26215
  adminSettingsRoutes.post("/", async (c) => {
26042
26216
  return c.redirect("/admin/settings/general");
26043
26217
  });
@@ -27724,7 +27898,7 @@ function renderFormCreatePage(data) {
27724
27898
 
27725
27899
  // src/routes/admin-forms.ts
27726
27900
  var adminFormsRoutes = new hono.Hono();
27727
- adminFormsRoutes.use("*", chunk7HHIZQNE_cjs.requireAuth());
27901
+ adminFormsRoutes.use("*", chunk3TVMUQWG_cjs.requireAuth());
27728
27902
  adminFormsRoutes.get("/", async (c) => {
27729
27903
  try {
27730
27904
  const user = c.get("user");
@@ -28529,7 +28703,7 @@ publicFormsRoutes.post("/:identifier/submit", async (c) => {
28529
28703
  `).bind(now, form.id).run();
28530
28704
  let contentId = null;
28531
28705
  try {
28532
- contentId = await chunkU6FOL6EO_cjs.createContentFromSubmission(
28706
+ contentId = await chunk47HKH3D6_cjs.createContentFromSubmission(
28533
28707
  db,
28534
28708
  sanitizedData,
28535
28709
  { id: form.id, name: form.name, display_name: form.display_name },
@@ -28703,7 +28877,7 @@ function renderAPIReferencePage(data) {
28703
28877
  >
28704
28878
  <option value="">All Categories</option>
28705
28879
  ${categories.map((category) => {
28706
- const info = chunkNZWFCUDA_cjs.CATEGORY_INFO[category];
28880
+ const info = chunkWAEQXGCX_cjs.CATEGORY_INFO[category];
28707
28881
  const title = info ? info.title : category;
28708
28882
  return `<option value="${category}">${title}</option>`;
28709
28883
  }).join("\n ")}
@@ -28720,7 +28894,7 @@ function renderAPIReferencePage(data) {
28720
28894
  <!-- API Categories -->
28721
28895
  <div class="space-y-6">
28722
28896
  ${Object.entries(endpointsByCategory).map(([category, endpoints]) => {
28723
- const info = chunkNZWFCUDA_cjs.CATEGORY_INFO[category] || { title: category, description: "", icon: "&#x1f4cb;" };
28897
+ const info = chunkWAEQXGCX_cjs.CATEGORY_INFO[category] || { title: category, description: "", icon: "&#x1f4cb;" };
28724
28898
  return `
28725
28899
  <div class="api-category" data-category="${category}">
28726
28900
  <div class="rounded-lg bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden">
@@ -28897,14 +29071,14 @@ function renderAPIReferencePage(data) {
28897
29071
  }
28898
29072
 
28899
29073
  // src/routes/admin-api-reference.ts
28900
- var VERSION2 = chunkV76ERLX6_cjs.getCoreVersion();
29074
+ var VERSION2 = chunk5EBTBD2Z_cjs.getCoreVersion();
28901
29075
  var router2 = new hono.Hono();
28902
- router2.use("*", chunk7HHIZQNE_cjs.requireAuth());
29076
+ router2.use("*", chunk3TVMUQWG_cjs.requireAuth());
28903
29077
  router2.get("/", async (c) => {
28904
29078
  const user = c.get("user");
28905
29079
  try {
28906
- const app2 = chunkNZWFCUDA_cjs.getAppInstance();
28907
- const endpoints = chunkNZWFCUDA_cjs.buildRouteList(app2);
29080
+ const app2 = chunkWAEQXGCX_cjs.getAppInstance();
29081
+ const endpoints = chunkWAEQXGCX_cjs.buildRouteList(app2);
28908
29082
  const pageData = {
28909
29083
  endpoints,
28910
29084
  user: user ? {
@@ -28990,5 +29164,5 @@ exports.router2 = router2;
28990
29164
  exports.test_cleanup_default = test_cleanup_default;
28991
29165
  exports.userProfilesPlugin = userProfilesPlugin;
28992
29166
  exports.userRoutes = userRoutes;
28993
- //# sourceMappingURL=chunk-MZS33LLH.cjs.map
28994
- //# sourceMappingURL=chunk-MZS33LLH.cjs.map
29167
+ //# sourceMappingURL=chunk-5ITJB5ZT.cjs.map
29168
+ //# sourceMappingURL=chunk-5ITJB5ZT.cjs.map