@sonicjs-cms/core 3.0.0-beta.24 → 3.0.0-beta.25

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 (137) hide show
  1. package/bin/db-reset.js +39 -22
  2. package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
  3. package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
  4. package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
  6. package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
  7. package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
  8. package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
  9. package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
  10. package/dist/{chunk-RJ2O5IIE.js → chunk-2D3A4X52.js} +2 -2
  11. package/dist/{chunk-RJ2O5IIE.js.map → chunk-2D3A4X52.js.map} +1 -1
  12. package/dist/{chunk-FHPEM77Y.js → chunk-2OXFMMA3.js} +11 -10
  13. package/dist/chunk-2OXFMMA3.js.map +1 -0
  14. package/dist/{chunk-SOZUG52O.js → chunk-3KGY4IBW.js} +3 -3
  15. package/dist/{chunk-SOZUG52O.js.map → chunk-3KGY4IBW.js.map} +1 -1
  16. package/dist/{chunk-I767LVN7.cjs → chunk-6OA77UM7.cjs} +757 -471
  17. package/dist/chunk-6OA77UM7.cjs.map +1 -0
  18. package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
  19. package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
  20. package/dist/{chunk-VC5XVPLM.js → chunk-7P5OCUPS.js} +424 -138
  21. package/dist/chunk-7P5OCUPS.js.map +1 -0
  22. package/dist/{chunk-3TMTYJAJ.js → chunk-BDQ55MWV.js} +18 -2
  23. package/dist/chunk-BDQ55MWV.js.map +1 -0
  24. package/dist/{chunk-KKNEYIZJ.cjs → chunk-BJ6NJL2E.cjs} +7 -12
  25. package/dist/chunk-BJ6NJL2E.cjs.map +1 -0
  26. package/dist/{chunk-VGEZNFWH.js → chunk-C54MH5UI.js} +5 -4
  27. package/dist/chunk-C54MH5UI.js.map +1 -0
  28. package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
  29. package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
  30. package/dist/{chunk-LNI3FYSI.js → chunk-CWIGQYRR.js} +7 -12
  31. package/dist/chunk-CWIGQYRR.js.map +1 -0
  32. package/dist/{chunk-BP52BFIV.cjs → chunk-D6FWEYQE.cjs} +6 -5
  33. package/dist/chunk-D6FWEYQE.cjs.map +1 -0
  34. package/dist/{chunk-UIHIXTIS.js → chunk-D7RLBBHE.js} +2 -2
  35. package/dist/{chunk-UIHIXTIS.js.map → chunk-D7RLBBHE.js.map} +1 -1
  36. package/dist/{chunk-IXUHXTHW.cjs → chunk-DLTT7QZU.cjs} +17 -6
  37. package/dist/chunk-DLTT7QZU.cjs.map +1 -0
  38. package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
  39. package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
  40. package/dist/{chunk-37V3RET3.cjs → chunk-E7E3NL3Y.cjs} +24 -23
  41. package/dist/chunk-E7E3NL3Y.cjs.map +1 -0
  42. package/dist/{chunk-VYQVDL2M.js → chunk-F26HP3B6.js} +36 -5
  43. package/dist/chunk-F26HP3B6.js.map +1 -0
  44. package/dist/{chunk-QZGABF2M.js → chunk-FVAK4C6L.js} +17 -6
  45. package/dist/chunk-FVAK4C6L.js.map +1 -0
  46. package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
  47. package/dist/chunk-HSDJDWLV.js.map +1 -0
  48. package/dist/{chunk-QJUJNTIU.cjs → chunk-I7MIRRFJ.cjs} +43 -12
  49. package/dist/chunk-I7MIRRFJ.cjs.map +1 -0
  50. package/dist/{chunk-LTZ5WYOK.cjs → chunk-JCBDXEY2.cjs} +18 -2
  51. package/dist/chunk-JCBDXEY2.cjs.map +1 -0
  52. package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
  53. package/dist/chunk-MI2YXCK4.cjs.map +1 -0
  54. package/dist/{chunk-A2SN3RVL.cjs → chunk-MOGK3U4A.cjs} +2 -2
  55. package/dist/{chunk-A2SN3RVL.cjs.map → chunk-MOGK3U4A.cjs.map} +1 -1
  56. package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
  57. package/dist/chunk-OUBUS74I.cjs.map +1 -0
  58. package/dist/{chunk-GMMCCIQO.cjs → chunk-RSBZITK3.cjs} +3 -3
  59. package/dist/{chunk-GMMCCIQO.cjs.map → chunk-RSBZITK3.cjs.map} +1 -1
  60. package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
  61. package/dist/chunk-SXC4HPK6.js.map +1 -0
  62. package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
  63. package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
  64. package/dist/{chunk-QCJHCSOK.cjs → chunk-YAURVGUK.cjs} +2 -2
  65. package/dist/{chunk-QCJHCSOK.cjs.map → chunk-YAURVGUK.cjs.map} +1 -1
  66. package/dist/config-4TIHSNW6.js +6 -0
  67. package/dist/{config-6FB2BXMP.js.map → config-4TIHSNW6.js.map} +1 -1
  68. package/dist/{config-OCH7S4WK.cjs → config-XN2ETAJ3.cjs} +5 -5
  69. package/dist/{config-OCH7S4WK.cjs.map → config-XN2ETAJ3.cjs.map} +1 -1
  70. package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
  71. package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
  72. package/dist/index.cjs +408 -370
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.d.cts +10 -2
  75. package/dist/index.d.ts +10 -2
  76. package/dist/index.js +67 -29
  77. package/dist/index.js.map +1 -1
  78. package/dist/middleware.cjs +35 -35
  79. package/dist/middleware.d.cts +4 -1
  80. package/dist/middleware.d.ts +4 -1
  81. package/dist/middleware.js +6 -6
  82. package/dist/migrations-JAHMI5MK.js +4 -0
  83. package/dist/{migrations-Z6D27NAW.js.map → migrations-JAHMI5MK.js.map} +1 -1
  84. package/dist/migrations-KU4V6T73.cjs +13 -0
  85. package/dist/{migrations-FGXZPKDC.cjs.map → migrations-KU4V6T73.cjs.map} +1 -1
  86. package/dist/plugins.cjs +40 -40
  87. package/dist/plugins.d.cts +1 -1
  88. package/dist/plugins.d.ts +1 -1
  89. package/dist/plugins.js +3 -3
  90. package/dist/rbac-AORZ6O3N.cjs +14 -0
  91. package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-AORZ6O3N.cjs.map} +1 -1
  92. package/dist/rbac-P44772FP.js +5 -0
  93. package/dist/{rbac-Y43IEQOP.js.map → rbac-P44772FP.js.map} +1 -1
  94. package/dist/routes.cjs +31 -31
  95. package/dist/routes.js +11 -11
  96. package/dist/services.cjs +18 -18
  97. package/dist/services.d.cts +1 -1
  98. package/dist/services.d.ts +1 -1
  99. package/dist/services.js +2 -2
  100. package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
  101. package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
  102. package/dist/templates.cjs +17 -17
  103. package/dist/templates.js +3 -3
  104. package/dist/types.d.cts +1 -1
  105. package/dist/types.d.ts +1 -1
  106. package/dist/utils.cjs +12 -12
  107. package/dist/utils.d.cts +1 -1
  108. package/dist/utils.d.ts +1 -1
  109. package/dist/utils.js +2 -2
  110. package/package.json +5 -10
  111. package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
  112. package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
  113. package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
  114. package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
  115. package/dist/chunk-37V3RET3.cjs.map +0 -1
  116. package/dist/chunk-3TMTYJAJ.js.map +0 -1
  117. package/dist/chunk-BJROXF4N.js.map +0 -1
  118. package/dist/chunk-BP52BFIV.cjs.map +0 -1
  119. package/dist/chunk-E66UVONV.cjs.map +0 -1
  120. package/dist/chunk-FHPEM77Y.js.map +0 -1
  121. package/dist/chunk-I767LVN7.cjs.map +0 -1
  122. package/dist/chunk-IXUHXTHW.cjs.map +0 -1
  123. package/dist/chunk-KKNEYIZJ.cjs.map +0 -1
  124. package/dist/chunk-LNI3FYSI.js.map +0 -1
  125. package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
  126. package/dist/chunk-QJUJNTIU.cjs.map +0 -1
  127. package/dist/chunk-QZGABF2M.js.map +0 -1
  128. package/dist/chunk-THFZSDIU.js.map +0 -1
  129. package/dist/chunk-UYJQDDEE.cjs.map +0 -1
  130. package/dist/chunk-VC5XVPLM.js.map +0 -1
  131. package/dist/chunk-VGEZNFWH.js.map +0 -1
  132. package/dist/chunk-VYQVDL2M.js.map +0 -1
  133. package/dist/config-6FB2BXMP.js +0 -6
  134. package/dist/migrations-FGXZPKDC.cjs +0 -13
  135. package/dist/migrations-Z6D27NAW.js +0 -4
  136. package/dist/rbac-7QZ4JZ2E.cjs +0 -14
  137. package/dist/rbac-Y43IEQOP.js +0 -5
@@ -1,20 +1,20 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkXWVDSM2L_cjs = require('./chunk-XWVDSM2L.cjs');
4
- var chunkJMJM7DMM_cjs = require('./chunk-JMJM7DMM.cjs');
4
+ var chunkTT3TQSCZ_cjs = require('./chunk-TT3TQSCZ.cjs');
5
5
  var chunk36Z3AKX3_cjs = require('./chunk-36Z3AKX3.cjs');
6
- var chunk37V3RET3_cjs = require('./chunk-37V3RET3.cjs');
7
- var chunkLTZ5WYOK_cjs = require('./chunk-LTZ5WYOK.cjs');
6
+ var chunkE7E3NL3Y_cjs = require('./chunk-E7E3NL3Y.cjs');
7
+ var chunkJCBDXEY2_cjs = require('./chunk-JCBDXEY2.cjs');
8
8
  var chunkKIGVVO6N_cjs = require('./chunk-KIGVVO6N.cjs');
9
- var chunkQCJHCSOK_cjs = require('./chunk-QCJHCSOK.cjs');
10
- var chunkA2SN3RVL_cjs = require('./chunk-A2SN3RVL.cjs');
11
- var chunkE66UVONV_cjs = require('./chunk-E66UVONV.cjs');
12
- var chunkUYJQDDEE_cjs = require('./chunk-UYJQDDEE.cjs');
13
- var chunkBP52BFIV_cjs = require('./chunk-BP52BFIV.cjs');
9
+ var chunkYAURVGUK_cjs = require('./chunk-YAURVGUK.cjs');
10
+ var chunkMOGK3U4A_cjs = require('./chunk-MOGK3U4A.cjs');
11
+ var chunkOUBUS74I_cjs = require('./chunk-OUBUS74I.cjs');
12
+ var chunkMI2YXCK4_cjs = require('./chunk-MI2YXCK4.cjs');
13
+ var chunkD6FWEYQE_cjs = require('./chunk-D6FWEYQE.cjs');
14
14
  var chunkJ6JTWD2A_cjs = require('./chunk-J6JTWD2A.cjs');
15
- var chunkIXUHXTHW_cjs = require('./chunk-IXUHXTHW.cjs');
15
+ var chunkDLTT7QZU_cjs = require('./chunk-DLTT7QZU.cjs');
16
16
  var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
17
- var chunkKKNEYIZJ_cjs = require('./chunk-KKNEYIZJ.cjs');
17
+ var chunkBJ6NJL2E_cjs = require('./chunk-BJ6NJL2E.cjs');
18
18
  var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
19
19
  var hono = require('hono');
20
20
  var zod = require('zod');
@@ -47,6 +47,7 @@ var DocumentPermissionsService = class {
47
47
  const publicGrants = baseGrants["public"] ?? [];
48
48
  if (publicGrants.includes(permission)) return true;
49
49
  } else if (principal.type === "role") {
50
+ if (principal.id === "public") continue;
50
51
  const roleGrants = baseGrants[principal.id] ?? [];
51
52
  if (roleGrants.includes(permission)) return true;
52
53
  }
@@ -271,7 +272,7 @@ function getDocumentRequestContext(c) {
271
272
 
272
273
  // src/routes/api-documents.ts
273
274
  async function aclAllowsRead(db, tenantId, principalSet, row, preloadedType) {
274
- const docType = preloadedType ?? await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(row.type_id);
275
+ const docType = preloadedType ?? await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
275
276
  if (!docType) return false;
276
277
  return new DocumentRepository(db, tenantId).isAllowed(principalSet, row.root_id, "read", docType.settings);
277
278
  }
@@ -289,7 +290,7 @@ apiDocumentsRoutes.get("/", async (c) => {
289
290
  if (!typeId) {
290
291
  return c.json({ error: "type query parameter is required" }, 400);
291
292
  }
292
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
293
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
293
294
  const docType = await registry.findById(typeId);
294
295
  if (!docType || !docType.isActive) {
295
296
  return c.json({ error: "Unknown document type" }, 400);
@@ -371,7 +372,7 @@ apiDocumentsRoutes.get("/root/:rootId", async (c) => {
371
372
  AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
372
373
  ).bind(rootId, now, now).first();
373
374
  if (!row) return c.json({ error: "Not found" }, 404);
374
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(row.type_id);
375
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
375
376
  const effTenant = effectiveTenantForType(tenantId, docType?.settings);
376
377
  if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
377
378
  if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
@@ -407,7 +408,7 @@ apiDocumentsRoutes.get("/:id", async (c) => {
407
408
  AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
408
409
  ).bind(id, now, now).first();
409
410
  if (!row) return c.json({ error: "Not found" }, 404);
410
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(row.type_id);
411
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
411
412
  const effTenant = effectiveTenantForType(tenantId, docType?.settings);
412
413
  if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
413
414
  if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
@@ -477,17 +478,17 @@ async function resolveDocScope(c, db, by, opts = {}) {
477
478
  const draft = opts.currentDraftOnly ? " AND is_current_draft = 1" : "";
478
479
  const row = await db.prepare(`SELECT type_id, root_id, tenant_id FROM documents WHERE ${col} = ?${draft} LIMIT 1`).bind(val).first();
479
480
  if (!row) return null;
480
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(row.type_id);
481
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
481
482
  const tenantId = effectiveTenantForType(getRequestTenant(c), docType?.settings);
482
483
  if (row.tenant_id !== tenantId) return null;
483
484
  return { typeId: row.type_id, rootId: row.root_id, tenantId, docType };
484
485
  }
485
486
  var adminDocumentsRoutes = new hono.Hono();
486
- adminDocumentsRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
487
- adminDocumentsRoutes.use("*", chunk37V3RET3_cjs.requireRole(["admin", "editor"]));
487
+ adminDocumentsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
488
+ adminDocumentsRoutes.use("*", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor"]));
488
489
  adminDocumentsRoutes.get("/types", async (c) => {
489
490
  try {
490
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(c.env.DB);
491
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
491
492
  const types = await registry.findAll();
492
493
  return c.json({ data: types });
493
494
  } catch (error) {
@@ -515,7 +516,7 @@ adminDocumentsRoutes.get("/", async (c) => {
515
516
  if (!typeId) {
516
517
  return c.json({ error: "type query parameter is required" }, 400);
517
518
  }
518
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
519
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
519
520
  const docType = await registry.findById(typeId);
520
521
  if (!docType || !docType.isActive) {
521
522
  return c.json({ error: "Unknown document type" }, 400);
@@ -626,7 +627,7 @@ adminDocumentsRoutes.post("/", async (c) => {
626
627
  const input = validation.data;
627
628
  const db = c.env.DB;
628
629
  const user = c.get("user");
629
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
630
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
630
631
  const docType = await registry.findById(input.typeId);
631
632
  if (!docType || !docType.isActive) {
632
633
  return c.json({ error: "Unknown document type" }, 400);
@@ -634,7 +635,7 @@ adminDocumentsRoutes.post("/", async (c) => {
634
635
  const createDenied = await denyIfNotAllowed(c, db, "", "create", docType.settings);
635
636
  if (createDenied) return createDenied;
636
637
  const tenantId = effectiveTenantForType(getRequestTenant(c), docType.settings);
637
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
638
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
638
639
  queryableFields: docType.queryableFields,
639
640
  typeSchemaVersion: docType.schemaVersion,
640
641
  maxVersionsPerRoot: docType.settings.maxVersionsPerRoot,
@@ -672,7 +673,7 @@ adminDocumentsRoutes.put("/:rootId", async (c) => {
672
673
  const docType = scope.docType;
673
674
  const updateDenied = await denyIfNotAllowed(c, db, rootId, "update", docType?.settings, scope.tenantId);
674
675
  if (updateDenied) return updateDenied;
675
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
676
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
676
677
  queryableFields: docType?.queryableFields ?? [],
677
678
  typeSchemaVersion: docType?.schemaVersion,
678
679
  maxVersionsPerRoot: docType?.settings.maxVersionsPerRoot,
@@ -697,7 +698,7 @@ adminDocumentsRoutes.post("/:id/publish", async (c) => {
697
698
  const docType = scope.docType;
698
699
  const publishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
699
700
  if (publishDenied) return publishDenied;
700
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
701
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
701
702
  queryableFields: docType?.queryableFields ?? [],
702
703
  typeSchemaVersion: docType?.schemaVersion,
703
704
  tenantId: scope.tenantId,
@@ -720,7 +721,7 @@ adminDocumentsRoutes.post("/:id/unpublish", async (c) => {
720
721
  const docType = scope.docType;
721
722
  const unpublishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
722
723
  if (unpublishDenied) return unpublishDenied;
723
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
724
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
724
725
  queryableFields: docType?.queryableFields ?? [],
725
726
  tenantId: scope.tenantId
726
727
  });
@@ -742,7 +743,7 @@ adminDocumentsRoutes.delete("/:id", async (c) => {
742
743
  const docType = scope.docType;
743
744
  const deleteDenied = await denyIfNotAllowed(c, db, scope.rootId, "delete", docType?.settings, scope.tenantId);
744
745
  if (deleteDenied) return deleteDenied;
745
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], tenantId: scope.tenantId });
746
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], tenantId: scope.tenantId });
746
747
  if (docType?.settings.pii) {
747
748
  if (scope.rootId) await svc.erase(scope.rootId, scope.tenantId);
748
749
  } else {
@@ -758,7 +759,7 @@ adminDocumentsRoutes.post("/types/:typeId/reindex", async (c) => {
758
759
  try {
759
760
  const { typeId } = c.req.param();
760
761
  const db = c.env.DB;
761
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
762
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
762
763
  const docType = await registry.findById(typeId);
763
764
  if (!docType) return c.json({ error: "Unknown document type" }, 400);
764
765
  const reindexTenant = effectiveTenantForType(getRequestTenant(c), docType.settings);
@@ -912,13 +913,13 @@ async function resolveContentVariables(contentData, db) {
912
913
  // src/routes/api-content-crud.ts
913
914
  var apiContentCrudRoutes = new hono.Hono();
914
915
  async function resolveDocBacking(db, collectionIdOrName) {
915
- const registry = chunkQCJHCSOK_cjs.getCollectionRegistry();
916
+ const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
916
917
  const record = registry.getBySlugOrName(collectionIdOrName) ?? registry.getById(collectionIdOrName);
917
918
  if (record) {
918
- const docType2 = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(record.name);
919
+ const docType2 = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
919
920
  return docType2 ? { coll: { id: record.id, name: record.name }, docType: docType2 } : null;
920
921
  }
921
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(collectionIdOrName);
922
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(collectionIdOrName);
922
923
  if (docType) {
923
924
  return { coll: { id: collectionIdOrName, name: collectionIdOrName }, docType };
924
925
  }
@@ -961,7 +962,7 @@ apiContentCrudRoutes.get("/check-slug", async (c) => {
961
962
  }, 500);
962
963
  }
963
964
  });
964
- apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
965
+ apiContentCrudRoutes.get("/:id", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
965
966
  try {
966
967
  const id = c.req.param("id");
967
968
  const db = c.env.DB;
@@ -971,7 +972,7 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
971
972
  ).bind(id, getRequestTenant(c)).first();
972
973
  let transformedContent;
973
974
  if (docRow) {
974
- const coll = chunkQCJHCSOK_cjs.getCollectionRegistry().getByName(docRow.type_id);
975
+ const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
975
976
  transformedContent = {
976
977
  id: docRow.root_id,
977
978
  title: docRow.title,
@@ -980,8 +981,8 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
980
981
  collectionId: coll?.id ?? docRow.type_id,
981
982
  data: docRow.data ? JSON.parse(docRow.data) : {},
982
983
  // D29: document timestamps are SECONDS; legacy `content` API contract is MILLISECONDS.
983
- created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(docRow.created_at),
984
- updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(docRow.updated_at)
984
+ created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.created_at),
985
+ updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.updated_at)
985
986
  };
986
987
  } else {
987
988
  return c.json({ error: "Content not found" }, 404);
@@ -996,6 +997,32 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
996
997
  { collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data },
997
998
  "fire-and-forget"
998
999
  );
1000
+ const fieldsParam = c.req.query("fields");
1001
+ if (fieldsParam) {
1002
+ const projFields = fieldsParam.split(",").map((s) => s.trim()).filter(Boolean);
1003
+ if (projFields.length > 0) {
1004
+ const result = {};
1005
+ const dataSubFields = [];
1006
+ for (const f of projFields) {
1007
+ if (f === "data") {
1008
+ result.data = transformedContent.data;
1009
+ } else if (f.startsWith("data.")) {
1010
+ dataSubFields.push(f.slice(5));
1011
+ } else if (Object.prototype.hasOwnProperty.call(transformedContent, f)) {
1012
+ result[f] = transformedContent[f];
1013
+ }
1014
+ }
1015
+ if (dataSubFields.length > 0 && !result.data) {
1016
+ result.data = {};
1017
+ for (const sub of dataSubFields) {
1018
+ if (transformedContent.data && Object.prototype.hasOwnProperty.call(transformedContent.data, sub)) {
1019
+ result.data[sub] = transformedContent.data[sub];
1020
+ }
1021
+ }
1022
+ }
1023
+ return c.json({ data: result });
1024
+ }
1025
+ }
999
1026
  return c.json({ data: transformedContent });
1000
1027
  } catch (error) {
1001
1028
  console.error("Error fetching content:", error);
@@ -1005,7 +1032,7 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
1005
1032
  }, 500);
1006
1033
  }
1007
1034
  });
1008
- apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1035
+ apiContentCrudRoutes.post("/", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1009
1036
  try {
1010
1037
  const db = c.env.DB;
1011
1038
  const user = c.get("user");
@@ -1039,7 +1066,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
1039
1066
  return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
1040
1067
  }
1041
1068
  const tenantId = getRequestTenant(c);
1042
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
1069
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
1043
1070
  queryableFields: backing.docType.queryableFields ?? [],
1044
1071
  typeSchemaVersion: backing.docType.schemaVersion ?? 1,
1045
1072
  maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50,
@@ -1059,8 +1086,8 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
1059
1086
  user?.userId
1060
1087
  );
1061
1088
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1062
- await cache.invalidate("content-filtered:*");
1063
- await cache.invalidate("collection-content-filtered:*");
1089
+ await cache.invalidate("api:content-filtered:*");
1090
+ await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
1064
1091
  dispatchHookEvent(
1065
1092
  c,
1066
1093
  "content:after:create",
@@ -1068,7 +1095,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
1068
1095
  "fire-and-forget"
1069
1096
  );
1070
1097
  return c.json({
1071
- data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(doc.updatedAt) }
1098
+ data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.updatedAt) }
1072
1099
  }, 201);
1073
1100
  }
1074
1101
  return c.json({ error: "Collection is not document-backed" }, 400);
@@ -1080,7 +1107,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
1080
1107
  }, 500);
1081
1108
  }
1082
1109
  });
1083
- apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1110
+ apiContentCrudRoutes.put("/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1084
1111
  try {
1085
1112
  const id = c.req.param("id");
1086
1113
  const db = c.env.DB;
@@ -1102,8 +1129,8 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
1102
1129
  } catch (err) {
1103
1130
  return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
1104
1131
  }
1105
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
1106
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
1132
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
1133
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
1107
1134
  queryableFields: docType?.queryableFields ?? [],
1108
1135
  typeSchemaVersion: docType?.schemaVersion ?? 1,
1109
1136
  maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
@@ -1123,9 +1150,9 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
1123
1150
  await svc.unpublish(pub.id);
1124
1151
  }
1125
1152
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1126
- await cache.invalidate("content-filtered:*");
1127
- await cache.invalidate("collection-content-filtered:*");
1128
- const coll = chunkQCJHCSOK_cjs.getCollectionRegistry().getByName(docRow.type_id);
1153
+ await cache.invalidate("api:content-filtered:*");
1154
+ await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
1155
+ const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
1129
1156
  const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
1130
1157
  const savedData = saved?.data ? JSON.parse(saved.data) : {};
1131
1158
  dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
@@ -1134,7 +1161,7 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
1134
1161
  dispatchHookEvent(c, "content:after:publish", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
1135
1162
  }
1136
1163
  return c.json({
1137
- data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(saved.updated_at) }
1164
+ data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.updated_at) }
1138
1165
  });
1139
1166
  }
1140
1167
  return c.json({ error: "Content not found" }, 404);
@@ -1146,7 +1173,7 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
1146
1173
  }, 500);
1147
1174
  }
1148
1175
  });
1149
- apiContentCrudRoutes.delete("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1176
+ apiContentCrudRoutes.delete("/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
1150
1177
  try {
1151
1178
  const id = c.req.param("id");
1152
1179
  const db = c.env.DB;
@@ -1163,8 +1190,8 @@ apiContentCrudRoutes.delete("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RE
1163
1190
  const now = Math.floor(Date.now() / 1e3);
1164
1191
  await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now, now, id, tenantId).run();
1165
1192
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1166
- await cache.invalidate("content-filtered:*");
1167
- await cache.invalidate("collection-content-filtered:*");
1193
+ await cache.invalidate("api:content-filtered:*");
1194
+ await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
1168
1195
  dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
1169
1196
  return c.json({ success: true });
1170
1197
  }
@@ -1180,6 +1207,22 @@ apiContentCrudRoutes.delete("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RE
1180
1207
  var api_content_crud_default = apiContentCrudRoutes;
1181
1208
 
1182
1209
  // src/routes/api.ts
1210
+ function isAnonPrincipal(principalSet) {
1211
+ return principalSet.length === 1 && principalSet[0]?.type === "public";
1212
+ }
1213
+ async function typeReadAllowed(db, principalSet, docType, typeName) {
1214
+ const perms = new DocumentPermissionsService(db);
1215
+ if (perms.isAllowedSync(principalSet, [], "read", docType?.settings ?? {})) return true;
1216
+ const rbac = new chunkJCBDXEY2_cjs.RbacService(db);
1217
+ let anyRbacRoleFound = false;
1218
+ for (const p of principalSet) {
1219
+ if (p.type !== "role") continue;
1220
+ if (!await rbac.hasRbacRole(p.id)) continue;
1221
+ anyRbacRoleFound = true;
1222
+ if (await rbac.isGrantedForRole(p.id, `document_type:${typeName}`, "read")) return true;
1223
+ }
1224
+ return !anyRbacRoleFound;
1225
+ }
1183
1226
  var DOC_SORTABLE_COLUMNS = /* @__PURE__ */ new Set([
1184
1227
  "created_at",
1185
1228
  "updated_at",
@@ -1259,10 +1302,37 @@ function mapDocRowToContent(row, collectionId) {
1259
1302
  collectionId,
1260
1303
  data: row.data ? JSON.parse(row.data) : {},
1261
1304
  // D29: document timestamps are SECONDS; the legacy `content` API contract is MILLISECONDS.
1262
- created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(row.created_at),
1263
- updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(row.updated_at)
1305
+ created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(row.created_at),
1306
+ updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(row.updated_at)
1264
1307
  };
1265
1308
  }
1309
+ function projectFields(item, fields) {
1310
+ if (fields.length === 0) return item;
1311
+ const result = {};
1312
+ const dataSubFields = [];
1313
+ for (const f of fields) {
1314
+ if (f === "data") {
1315
+ result.data = item.data;
1316
+ } else if (f.startsWith("data.")) {
1317
+ dataSubFields.push(f.slice(5));
1318
+ } else if (Object.prototype.hasOwnProperty.call(item, f)) {
1319
+ result[f] = item[f];
1320
+ }
1321
+ }
1322
+ if (dataSubFields.length > 0 && !result.data) {
1323
+ result.data = {};
1324
+ for (const sub of dataSubFields) {
1325
+ if (item.data && Object.prototype.hasOwnProperty.call(item.data, sub)) {
1326
+ result.data[sub] = item.data[sub];
1327
+ }
1328
+ }
1329
+ }
1330
+ return result;
1331
+ }
1332
+ function parseFieldsParam(raw2) {
1333
+ if (!raw2) return [];
1334
+ return raw2.split(",").map((s) => s.trim()).filter(Boolean);
1335
+ }
1266
1336
  var apiRoutes = new hono.Hono();
1267
1337
  apiRoutes.use("*", async (c, next) => {
1268
1338
  const startTime = Date.now();
@@ -1272,7 +1342,7 @@ apiRoutes.use("*", async (c, next) => {
1272
1342
  c.header("X-Response-Time", `${totalTime}ms`);
1273
1343
  });
1274
1344
  apiRoutes.use("*", async (c, next) => {
1275
- const cacheEnabled = await chunk37V3RET3_cjs.isPluginActive(c.env.DB, "core-cache");
1345
+ const cacheEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(c.env.DB, "core-cache");
1276
1346
  c.set("cacheEnabled", cacheEnabled);
1277
1347
  await next();
1278
1348
  });
@@ -1295,7 +1365,7 @@ apiRoutes.get("/", (c) => {
1295
1365
  openapi: "3.0.0",
1296
1366
  info: {
1297
1367
  title: "SonicJS AI API",
1298
- version: chunkKKNEYIZJ_cjs.getCoreVersion(),
1368
+ version: chunkBJ6NJL2E_cjs.getCoreVersion(),
1299
1369
  description: "RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers",
1300
1370
  contact: {
1301
1371
  name: "SonicJS Support",
@@ -1725,8 +1795,8 @@ apiRoutes.get("/collections", async (c) => {
1725
1795
  }
1726
1796
  c.header("X-Cache-Status", "MISS");
1727
1797
  c.header("X-Cache-Source", "registry");
1728
- const records = chunkQCJHCSOK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
1729
- const transformedResults = records.map(chunkQCJHCSOK_cjs.collectionRecordToRow);
1798
+ const records = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
1799
+ const transformedResults = records.map(chunkYAURVGUK_cjs.collectionRecordToRow);
1730
1800
  const responseData = {
1731
1801
  data: transformedResults,
1732
1802
  meta: addTimingMeta(c, {
@@ -1747,16 +1817,21 @@ apiRoutes.get("/collections", async (c) => {
1747
1817
  return c.json({ error: "Failed to fetch collections" }, 500);
1748
1818
  }
1749
1819
  });
1750
- apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1820
+ apiRoutes.get("/content", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
1751
1821
  const executionStart = Date.now();
1752
1822
  try {
1753
1823
  const db = c.env.DB;
1754
1824
  const queryParams = c.req.query();
1825
+ const projFields = parseFieldsParam(queryParams.fields);
1826
+ if (queryParams.fields) delete queryParams.fields;
1755
1827
  const role = c.get("user")?.role;
1828
+ const { tenantId: cTenantId, principalSet: cPrincipalSet } = getDocumentRequestContext(c);
1829
+ const cAnon = isAnonPrincipal(cPrincipalSet);
1830
+ const cNeedsAcl = !cAnon && !canReadNonPublicContent(role);
1756
1831
  const collIdByName = /* @__PURE__ */ new Map();
1757
1832
  let typeId;
1758
1833
  let typeIds;
1759
- const registry = chunkQCJHCSOK_cjs.getCollectionRegistry();
1834
+ const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
1760
1835
  if (queryParams.collection) {
1761
1836
  const collectionName = queryParams.collection;
1762
1837
  const record = registry.getByName(collectionName);
@@ -1786,11 +1861,11 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1786
1861
  return r.name;
1787
1862
  });
1788
1863
  }
1789
- const filter = chunkIXUHXTHW_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
1864
+ const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
1790
1865
  const normalizedFilter = augmentFilterForDocuments(filter, { typeId, typeIds, role });
1791
1866
  if (!normalizedFilter.limit) normalizedFilter.limit = 50;
1792
1867
  normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
1793
- const builder = new chunkIXUHXTHW_cjs.QueryFilterBuilder();
1868
+ const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
1794
1869
  const queryResult = builder.build("documents", normalizedFilter);
1795
1870
  if (queryResult.errors.length > 0) {
1796
1871
  return c.json({
@@ -1798,7 +1873,7 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1798
1873
  details: queryResult.errors
1799
1874
  }, 400);
1800
1875
  }
1801
- const cacheEnabled = c.get("cacheEnabled");
1876
+ const cacheEnabled = c.get("cacheEnabled") && cAnon;
1802
1877
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1803
1878
  const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter: normalizedFilter, query: queryResult.sql }));
1804
1879
  if (cacheEnabled) {
@@ -1828,11 +1903,41 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1828
1903
  const stmt = db.prepare(queryResult.sql);
1829
1904
  const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
1830
1905
  const { results } = await boundStmt.all();
1831
- const transformedResults = results.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
1906
+ let aclResults = results;
1907
+ if (cNeedsAcl) {
1908
+ const typeReg = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
1909
+ const repo = new DocumentRepository(db, cTenantId);
1910
+ const uniqueTypeIds = [...new Set(results.map((r) => r.type_id))];
1911
+ const typeSettingsMap = /* @__PURE__ */ new Map();
1912
+ const typeRbacOnlyMap = /* @__PURE__ */ new Map();
1913
+ const typeDeniedMap = /* @__PURE__ */ new Map();
1914
+ await Promise.all(uniqueTypeIds.map(async (tid) => {
1915
+ const dt = await typeReg.findById(tid);
1916
+ const settings = dt?.settings ?? {};
1917
+ typeSettingsMap.set(tid, settings);
1918
+ const allowed2 = await typeReadAllowed(db, cPrincipalSet, dt, tid);
1919
+ if (!allowed2) {
1920
+ typeDeniedMap.set(tid, true);
1921
+ return;
1922
+ }
1923
+ const perms = new DocumentPermissionsService(db);
1924
+ typeRbacOnlyMap.set(tid, !perms.isAllowedSync(cPrincipalSet, [], "read", settings));
1925
+ }));
1926
+ const allowed = await Promise.all(
1927
+ results.map((row) => {
1928
+ const tid = row.type_id;
1929
+ if (typeDeniedMap.get(tid)) return Promise.resolve(false);
1930
+ if (typeRbacOnlyMap.get(tid)) return Promise.resolve(true);
1931
+ return repo.isAllowed(cPrincipalSet, row.root_id, "read", typeSettingsMap.get(tid) ?? {});
1932
+ })
1933
+ );
1934
+ aclResults = results.filter((_, i) => allowed[i]);
1935
+ }
1936
+ const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
1832
1937
  const responseData = {
1833
- data: transformedResults,
1938
+ data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
1834
1939
  meta: addTimingMeta(c, {
1835
- count: results.length,
1940
+ count: aclResults.length,
1836
1941
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1837
1942
  // D44: echo the caller's filter with the access policy applied (status=published forced for
1838
1943
  // anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
@@ -1843,7 +1948,7 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1843
1948
  }
1844
1949
  }, executionStart)
1845
1950
  };
1846
- if (cacheEnabled) {
1951
+ if (cacheEnabled && projFields.length === 0) {
1847
1952
  await cache.set(cacheKey, responseData);
1848
1953
  }
1849
1954
  return c.json(responseData);
@@ -1855,26 +1960,36 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1855
1960
  }, 500);
1856
1961
  }
1857
1962
  });
1858
- apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1963
+ apiRoutes.get("/collections/:collection/content", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
1859
1964
  const executionStart = Date.now();
1860
1965
  try {
1861
1966
  const collection = c.req.param("collection");
1862
1967
  const db = c.env.DB;
1863
1968
  const queryParams = c.req.query();
1864
- const record = chunkQCJHCSOK_cjs.getCollectionRegistry().getBySlugOrName(collection);
1969
+ const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
1865
1970
  if (!record || record.isActive === false) {
1866
1971
  return c.json({ error: "Collection not found" }, 404);
1867
1972
  }
1868
1973
  const collIdByName = /* @__PURE__ */ new Map();
1869
1974
  collIdByName.set(collection, record.id);
1870
1975
  const role = c.get("user")?.role;
1871
- const filter = chunkIXUHXTHW_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
1976
+ const { tenantId: ccTenantId, principalSet: ccPrincipalSet } = getDocumentRequestContext(c);
1977
+ const ccAnon = isAnonPrincipal(ccPrincipalSet);
1978
+ const ccNeedsAcl = !ccAnon && !canReadNonPublicContent(role);
1979
+ let ccDocType;
1980
+ if (ccNeedsAcl) {
1981
+ ccDocType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
1982
+ if (!await typeReadAllowed(db, ccPrincipalSet, ccDocType, record.name)) {
1983
+ return c.json({ error: "Forbidden" }, 403);
1984
+ }
1985
+ }
1986
+ const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
1872
1987
  const normalizedFilter = augmentFilterForDocuments(filter, { typeId: collection, role });
1873
1988
  if (!normalizedFilter.limit) {
1874
1989
  normalizedFilter.limit = 50;
1875
1990
  }
1876
1991
  normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
1877
- const builder = new chunkIXUHXTHW_cjs.QueryFilterBuilder();
1992
+ const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
1878
1993
  const queryResult = builder.build("documents", normalizedFilter);
1879
1994
  if (queryResult.errors.length > 0) {
1880
1995
  return c.json({
@@ -1882,7 +1997,7 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
1882
1997
  details: queryResult.errors
1883
1998
  }, 400);
1884
1999
  }
1885
- const cacheEnabled = c.get("cacheEnabled");
2000
+ const cacheEnabled = c.get("cacheEnabled") && ccAnon;
1886
2001
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1887
2002
  const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
1888
2003
  const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
@@ -1913,12 +2028,24 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
1913
2028
  const stmt = db.prepare(queryResult.sql);
1914
2029
  const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
1915
2030
  const { results } = await boundStmt.all();
1916
- const transformedResults = results.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
2031
+ let ccAclResults = results;
2032
+ if (ccNeedsAcl) {
2033
+ const ccPerms = new DocumentPermissionsService(db);
2034
+ const ccBaseGrantsPass = ccPerms.isAllowedSync(ccPrincipalSet, [], "read", ccDocType?.settings ?? {});
2035
+ if (ccBaseGrantsPass) {
2036
+ const repo = new DocumentRepository(db, ccTenantId);
2037
+ const allowed = await Promise.all(
2038
+ results.map((row) => repo.isAllowed(ccPrincipalSet, row.root_id, "read", ccDocType?.settings ?? {}))
2039
+ );
2040
+ ccAclResults = results.filter((_, i) => allowed[i]);
2041
+ }
2042
+ }
2043
+ const transformedResults = ccAclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
1917
2044
  const responseData = {
1918
2045
  data: transformedResults,
1919
2046
  meta: addTimingMeta(c, {
1920
- ...includeCollection ? { collection: chunkQCJHCSOK_cjs.collectionRecordToRow(record) } : {},
1921
- count: results.length,
2047
+ ...includeCollection ? { collection: chunkYAURVGUK_cjs.collectionRecordToRow(record) } : {},
2048
+ count: ccAclResults.length,
1922
2049
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1923
2050
  // D44: echo the caller's filter with the access policy applied (status=published forced for
1924
2051
  // anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
@@ -1942,31 +2069,43 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
1942
2069
  }
1943
2070
  });
1944
2071
  apiRoutes.route("/content", api_content_crud_default);
1945
- apiRoutes.get("/:collection", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
2072
+ apiRoutes.get("/:collection", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
1946
2073
  const executionStart = Date.now();
1947
2074
  try {
1948
2075
  const collection = c.req.param("collection");
1949
2076
  const db = c.env.DB;
1950
2077
  const queryParams = c.req.query();
1951
- const record = chunkQCJHCSOK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2078
+ const projFields = parseFieldsParam(queryParams.fields);
2079
+ if (queryParams.fields) delete queryParams.fields;
2080
+ const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
1952
2081
  if (!record || record.isActive === false) {
1953
2082
  return c.json({ error: "Collection not found" }, 404);
1954
2083
  }
1955
2084
  const collIdByName = /* @__PURE__ */ new Map();
1956
2085
  collIdByName.set(record.name, record.id);
1957
2086
  const role = c.get("user")?.role;
1958
- const filter = chunkIXUHXTHW_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
2087
+ const { tenantId, principalSet } = getDocumentRequestContext(c);
2088
+ const anon = isAnonPrincipal(principalSet);
2089
+ const needsAcl = !anon && !canReadNonPublicContent(role);
2090
+ let docTypeForCheck;
2091
+ if (needsAcl) {
2092
+ docTypeForCheck = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
2093
+ if (!await typeReadAllowed(db, principalSet, docTypeForCheck, record.name)) {
2094
+ return c.json({ error: "Forbidden" }, 403);
2095
+ }
2096
+ }
2097
+ const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
1959
2098
  const normalizedFilter = augmentFilterForDocuments(filter, { typeId: record.name, role });
1960
2099
  if (!normalizedFilter.limit) normalizedFilter.limit = 50;
1961
2100
  normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
1962
- const builder = new chunkIXUHXTHW_cjs.QueryFilterBuilder();
2101
+ const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
1963
2102
  const queryResult = builder.build("documents", normalizedFilter);
1964
2103
  if (queryResult.errors.length > 0) {
1965
2104
  return c.json({ error: "Invalid filter parameters", details: queryResult.errors }, 400);
1966
2105
  }
1967
2106
  const collectionCache = record.cache;
1968
2107
  const collectionCacheDisabled = collectionCache?.enabled === false;
1969
- const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled;
2108
+ const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled && projFields.length === 0 && anon;
1970
2109
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
1971
2110
  const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
1972
2111
  const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
@@ -1984,12 +2123,25 @@ apiRoutes.get("/:collection", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
1984
2123
  const stmt = db.prepare(queryResult.sql);
1985
2124
  const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
1986
2125
  const { results } = await boundStmt.all();
1987
- const transformedResults = results.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
2126
+ let aclResults = results;
2127
+ if (needsAcl) {
2128
+ const perms = new DocumentPermissionsService(db);
2129
+ const baseGrantsPass = perms.isAllowedSync(principalSet, [], "read", docTypeForCheck?.settings ?? {});
2130
+ if (!baseGrantsPass) {
2131
+ } else {
2132
+ const repo = new DocumentRepository(db, tenantId);
2133
+ const allowed = await Promise.all(
2134
+ results.map((row) => repo.isAllowed(principalSet, row.root_id, "read", docTypeForCheck?.settings ?? {}))
2135
+ );
2136
+ aclResults = results.filter((_, i) => allowed[i]);
2137
+ }
2138
+ }
2139
+ const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
1988
2140
  const responseData = {
1989
- data: transformedResults,
2141
+ data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
1990
2142
  meta: addTimingMeta(c, {
1991
- ...includeCollection ? { collection: chunkQCJHCSOK_cjs.collectionRecordToRow(record) } : {},
1992
- count: results.length,
2143
+ ...includeCollection ? { collection: chunkYAURVGUK_cjs.collectionRecordToRow(record) } : {},
2144
+ count: aclResults.length,
1993
2145
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1994
2146
  filter: normalizePublicContentFilter(filter, role),
1995
2147
  cache: { hit: false, source: "database" }
@@ -2006,12 +2158,12 @@ apiRoutes.get("/:collection", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
2006
2158
  return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
2007
2159
  }
2008
2160
  });
2009
- apiRoutes.get("/:collection/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
2161
+ apiRoutes.get("/:collection/:id", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
2010
2162
  try {
2011
2163
  const collection = c.req.param("collection");
2012
2164
  const id = c.req.param("id");
2013
2165
  const db = c.env.DB;
2014
- const record = chunkQCJHCSOK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2166
+ const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2015
2167
  if (!record || record.isActive === false) {
2016
2168
  return c.json({ error: "Collection not found" }, 404);
2017
2169
  }
@@ -2020,7 +2172,24 @@ apiRoutes.get("/:collection/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
2020
2172
  privileged ? "SELECT * FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL" : "SELECT * FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_published = 1 AND deleted_at IS NULL"
2021
2173
  ).bind(id, record.name).first();
2022
2174
  if (!docRow) return c.json({ error: "Content not found" }, 404);
2023
- const coll = chunkQCJHCSOK_cjs.getCollectionRegistry().getByName(docRow.type_id);
2175
+ const colRole = c.get("user")?.role;
2176
+ const { tenantId: colTenantId, principalSet: colPrincipalSet } = getDocumentRequestContext(c);
2177
+ const colNeedsAcl = !isAnonPrincipal(colPrincipalSet) && !canReadNonPublicContent(colRole);
2178
+ if (colNeedsAcl) {
2179
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
2180
+ if (!await typeReadAllowed(db, colPrincipalSet, docType, record.name)) {
2181
+ return c.json({ error: "Content not found" }, 404);
2182
+ }
2183
+ const perms = new DocumentPermissionsService(db);
2184
+ if (perms.isAllowedSync(colPrincipalSet, [], "read", docType?.settings ?? {})) {
2185
+ const repo = new DocumentRepository(db, colTenantId);
2186
+ if (!await repo.isAllowed(colPrincipalSet, docRow.root_id, "read", docType?.settings ?? {})) {
2187
+ return c.json({ error: "Content not found" }, 404);
2188
+ }
2189
+ }
2190
+ }
2191
+ const projFields = parseFieldsParam(c.req.query("fields"));
2192
+ const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
2024
2193
  const transformedContent = {
2025
2194
  id: docRow.root_id,
2026
2195
  title: docRow.title,
@@ -2028,17 +2197,17 @@ apiRoutes.get("/:collection/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
2028
2197
  status: docRow.status,
2029
2198
  collectionId: coll?.id ?? docRow.type_id,
2030
2199
  data: docRow.data ? JSON.parse(docRow.data) : {},
2031
- created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(docRow.created_at),
2032
- updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(docRow.updated_at)
2200
+ created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.created_at),
2201
+ updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.updated_at)
2033
2202
  };
2034
2203
  dispatchHookEvent(c, "content:read", { collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data }, "fire-and-forget");
2035
- return c.json({ data: transformedContent });
2204
+ return c.json({ data: projFields.length ? projectFields(transformedContent, projFields) : transformedContent });
2036
2205
  } catch (error) {
2037
2206
  console.error("Error fetching content:", error);
2038
2207
  return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
2039
2208
  }
2040
2209
  });
2041
- apiRoutes.post("/:collection", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2210
+ apiRoutes.post("/:collection", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2042
2211
  try {
2043
2212
  const collection = c.req.param("collection");
2044
2213
  const db = c.env.DB;
@@ -2059,26 +2228,26 @@ apiRoutes.post("/:collection", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
2059
2228
  } catch (err) {
2060
2229
  return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
2061
2230
  }
2062
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, { queryableFields: backing.docType.queryableFields ?? [], typeSchemaVersion: backing.docType.schemaVersion ?? 1, maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: backing.docType.settings?.versioning ?? false });
2231
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: backing.docType.queryableFields ?? [], typeSchemaVersion: backing.docType.schemaVersion ?? 1, maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: backing.docType.settings?.versioning ?? false });
2063
2232
  const doc = await svc.create(createDocumentSchema.parse({ typeId: backing.coll.name, tenantId: "default", locale: "default", title, slug: finalSlug, data: hookData, publishOnCreate: (status || "draft") === "published" }), user?.userId);
2064
2233
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
2065
- await cache.invalidate("content-filtered:*");
2066
- await cache.invalidate("collection-content-filtered:*");
2234
+ await cache.invalidate("api:content-filtered:*");
2235
+ await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
2067
2236
  dispatchHookEvent(c, "content:after:create", { collection: backing.coll.name, id: doc.rootId, data: doc.data ?? {}, user: actor }, "fire-and-forget");
2068
- return c.json({ data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(doc.updatedAt) } }, 201);
2237
+ return c.json({ data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.updatedAt) } }, 201);
2069
2238
  } catch (error) {
2070
2239
  console.error("Error creating content:", error);
2071
2240
  return c.json({ error: "Failed to create content", details: error instanceof Error ? error.message : String(error) }, 500);
2072
2241
  }
2073
2242
  });
2074
- apiRoutes.put("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2243
+ apiRoutes.put("/:collection/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2075
2244
  try {
2076
2245
  const collection = c.req.param("collection");
2077
2246
  const id = c.req.param("id");
2078
2247
  const db = c.env.DB;
2079
2248
  const user = c.get("user");
2080
2249
  const body = await c.req.json();
2081
- const collRecord = chunkQCJHCSOK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2250
+ const collRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2082
2251
  const typeName = collRecord?.name ?? collection;
2083
2252
  const docRow = await db.prepare("SELECT root_id, type_id FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").bind(id, typeName).first();
2084
2253
  if (!docRow) return c.json({ error: "Content not found" }, 404);
@@ -2090,8 +2259,8 @@ apiRoutes.put("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3
2090
2259
  } catch (err) {
2091
2260
  return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
2092
2261
  }
2093
- const docType = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
2094
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], typeSchemaVersion: docType?.schemaVersion ?? 1, maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: docType?.settings?.versioning ?? false });
2262
+ const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
2263
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], typeSchemaVersion: docType?.schemaVersion ?? 1, maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: docType?.settings?.versioning ?? false });
2095
2264
  const input = {};
2096
2265
  if (body.title !== void 0) input.title = body.title;
2097
2266
  if (body.slug !== void 0) input.slug = slugify(body.slug);
@@ -2105,27 +2274,27 @@ apiRoutes.put("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3
2105
2274
  await svc.unpublish(pub.id);
2106
2275
  }
2107
2276
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
2108
- await cache.invalidate("content-filtered:*");
2109
- await cache.invalidate("collection-content-filtered:*");
2110
- const coll = chunkQCJHCSOK_cjs.getCollectionRegistry().getByName(docRow.type_id);
2277
+ await cache.invalidate("api:content-filtered:*");
2278
+ await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
2279
+ const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
2111
2280
  const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
2112
2281
  const savedData = saved?.data ? JSON.parse(saved.data) : {};
2113
2282
  dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
2114
2283
  const nowPublished = body.status === "published" || body.status === void 0 && wasPublished;
2115
2284
  if (nowPublished && !wasPublished) dispatchHookEvent(c, "content:after:publish", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
2116
- return c.json({ data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkLTZ5WYOK_cjs.documentSecondsToMs(saved.updated_at) } });
2285
+ return c.json({ data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.updated_at) } });
2117
2286
  } catch (error) {
2118
2287
  console.error("Error updating content:", error);
2119
2288
  return c.json({ error: "Failed to update content", details: error instanceof Error ? error.message : String(error) }, 500);
2120
2289
  }
2121
2290
  });
2122
- apiRoutes.delete("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2291
+ apiRoutes.delete("/:collection/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
2123
2292
  try {
2124
2293
  const collection = c.req.param("collection");
2125
2294
  const id = c.req.param("id");
2126
2295
  const db = c.env.DB;
2127
2296
  const user = c.get("user");
2128
- const collRecord = chunkQCJHCSOK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2297
+ const collRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
2129
2298
  const typeName = collRecord?.name ?? collection;
2130
2299
  const docRow = await db.prepare("SELECT type_id FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND deleted_at IS NULL LIMIT 1").bind(id, typeName).first();
2131
2300
  if (!docRow) return c.json({ error: "Content not found" }, 404);
@@ -2138,8 +2307,8 @@ apiRoutes.delete("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3R
2138
2307
  const now = Math.floor(Date.now() / 1e3);
2139
2308
  await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = 'default'").bind(now, now, id).run();
2140
2309
  const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
2141
- await cache.invalidate("content-filtered:*");
2142
- await cache.invalidate("collection-content-filtered:*");
2310
+ await cache.invalidate("api:content-filtered:*");
2311
+ await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
2143
2312
  dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
2144
2313
  return c.json({ success: true });
2145
2314
  } catch (error) {
@@ -2212,7 +2381,7 @@ var MediaDocumentService = class {
2212
2381
  tenantId;
2213
2382
  /** Create a media_asset document from R2 upload metadata. Published-on-create (immediately usable). */
2214
2383
  async createFromUpload(meta, createdBy) {
2215
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
2384
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
2216
2385
  return svc.create(
2217
2386
  createDocumentSchema.parse({
2218
2387
  typeId: "media_asset",
@@ -2290,7 +2459,7 @@ var MediaDocumentService = class {
2290
2459
  }
2291
2460
  /** Update alt/caption/tags on a media_asset document (saveDraft + publish atomically). */
2292
2461
  async updateMetadata(rootId, meta, updatedBy) {
2293
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
2462
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
2294
2463
  const newDraft = await svc.saveDraft(rootId, { data: meta }, updatedBy);
2295
2464
  return svc.publish(newDraft.id, updatedBy);
2296
2465
  }
@@ -2347,7 +2516,7 @@ var fileValidationSchema = zod.z.object({
2347
2516
  // 50MB max
2348
2517
  });
2349
2518
  var apiMediaRoutes = new hono.Hono();
2350
- apiMediaRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
2519
+ apiMediaRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
2351
2520
  apiMediaRoutes.post("/upload", async (c) => {
2352
2521
  try {
2353
2522
  const user = c.get("user");
@@ -2701,9 +2870,13 @@ apiMediaRoutes.post("/create-folder", async (c) => {
2701
2870
  error: "Folder name can only contain lowercase letters, numbers, hyphens, and underscores"
2702
2871
  }, 400);
2703
2872
  }
2704
- const checkStmt = c.env.DB.prepare("SELECT COUNT(*) as count FROM media WHERE folder = ? AND deleted_at IS NULL");
2705
- const existingFolder = await checkStmt.bind(folderName).first();
2706
- if (existingFolder && existingFolder.count > 0) {
2873
+ let folderExists = false;
2874
+ try {
2875
+ const existing = await c.env.DB.prepare("SELECT COUNT(*) as count FROM documents WHERE type_id = 'media_asset' AND tenant_id = 'default' AND json_extract(data, '$.folder') = ? AND deleted_at IS NULL AND is_current_draft = 1").bind(folderName).first();
2876
+ folderExists = (existing?.count ?? 0) > 0;
2877
+ } catch {
2878
+ }
2879
+ if (folderExists) {
2707
2880
  return c.json({
2708
2881
  success: false,
2709
2882
  error: `Folder "${folderName}" already exists`
@@ -3045,7 +3218,7 @@ apiSystemRoutes.get("/info", (c) => {
3045
3218
  apiSystemRoutes.get("/stats", async (c) => {
3046
3219
  try {
3047
3220
  const db = c.env.DB;
3048
- const typeIds = chunkQCJHCSOK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal).map((r) => r.name);
3221
+ const typeIds = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal).map((r) => r.name);
3049
3222
  let contentStats = null;
3050
3223
  if (typeIds.length > 0) {
3051
3224
  const placeholders = typeIds.map(() => "?").join(",");
@@ -3120,12 +3293,12 @@ apiSystemRoutes.get("/env", (c) => {
3120
3293
  });
3121
3294
  var api_system_default = apiSystemRoutes;
3122
3295
  var adminApiRoutes = new hono.Hono();
3123
- adminApiRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
3124
- adminApiRoutes.use("*", chunk37V3RET3_cjs.requireRole(["admin", "editor"]));
3296
+ adminApiRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
3297
+ adminApiRoutes.use("*", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor"]));
3125
3298
  adminApiRoutes.get("/stats", async (c) => {
3126
3299
  try {
3127
3300
  const db = c.env.DB;
3128
- const userCollections = chunkQCJHCSOK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
3301
+ const userCollections = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
3129
3302
  const collectionsCount = userCollections.length;
3130
3303
  let contentCount = 0;
3131
3304
  if (userCollections.length > 0) {
@@ -3216,7 +3389,7 @@ adminApiRoutes.get("/collections", async (c) => {
3216
3389
  try {
3217
3390
  const search = c.req.query("search") || "";
3218
3391
  const includeInactive = c.req.query("includeInactive") === "true";
3219
- let records = chunkQCJHCSOK_cjs.getCollectionRegistry().list().filter((r) => !r.internal);
3392
+ let records = chunkYAURVGUK_cjs.getCollectionRegistry().list().filter((r) => !r.internal);
3220
3393
  if (!includeInactive) records = records.filter((r) => r.isActive !== false);
3221
3394
  if (search) {
3222
3395
  const needle = search.toLowerCase();
@@ -3248,7 +3421,7 @@ adminApiRoutes.get("/collections", async (c) => {
3248
3421
  adminApiRoutes.get("/collections/:id", async (c) => {
3249
3422
  try {
3250
3423
  const id = c.req.param("id");
3251
- const registry = chunkQCJHCSOK_cjs.getCollectionRegistry();
3424
+ const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
3252
3425
  const record = registry.getById(id) ?? registry.getByName(id);
3253
3426
  if (!record) {
3254
3427
  return c.json({ error: "Collection not found" }, 404);
@@ -3298,7 +3471,7 @@ adminApiRoutes.get("/references", async (c) => {
3298
3471
  if (collectionParams.length === 0) {
3299
3472
  return c.json({ error: "Collection is required" }, 400);
3300
3473
  }
3301
- const registry = chunkQCJHCSOK_cjs.getCollectionRegistry();
3474
+ const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
3302
3475
  const matched = collectionParams.map((param) => registry.getById(param) ?? registry.getByName(param)).filter((r) => !!r);
3303
3476
  const seen = /* @__PURE__ */ new Set();
3304
3477
  const collections = matched.filter((r) => {
@@ -3413,7 +3586,7 @@ adminApiRoutes.patch("/collections/:id", collectionsReadOnly);
3413
3586
  adminApiRoutes.delete("/collections/:id", collectionsReadOnly);
3414
3587
  adminApiRoutes.get("/migrations/status", async (c) => {
3415
3588
  try {
3416
- const { MigrationService: MigrationService2 } = await import('./migrations-FGXZPKDC.cjs');
3589
+ const { MigrationService: MigrationService2 } = await import('./migrations-KU4V6T73.cjs');
3417
3590
  const db = c.env.DB;
3418
3591
  const migrationService = new MigrationService2(db);
3419
3592
  const status = await migrationService.getMigrationStatus();
@@ -3456,7 +3629,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
3456
3629
  });
3457
3630
  adminApiRoutes.get("/migrations/validate", async (c) => {
3458
3631
  try {
3459
- const { MigrationService: MigrationService2 } = await import('./migrations-FGXZPKDC.cjs');
3632
+ const { MigrationService: MigrationService2 } = await import('./migrations-KU4V6T73.cjs');
3460
3633
  const db = c.env.DB;
3461
3634
  const migrationService = new MigrationService2(db);
3462
3635
  const validation = await migrationService.validateSchema();
@@ -3606,8 +3779,8 @@ function renderLoginPage(data, demoLoginActive = false) {
3606
3779
  <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
3607
3780
  <div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
3608
3781
  <!-- Alerts -->
3609
- ${data.error ? `<div class="mb-6">${chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
3610
- ${data.message ? `<div class="mb-6">${chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.message })}</div>` : ""}
3782
+ ${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
3783
+ ${data.message ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.message })}</div>` : ""}
3611
3784
 
3612
3785
  <!-- Form Response (HTMX target) -->
3613
3786
  <div id="form-response" class="mb-6"></div>
@@ -3615,6 +3788,8 @@ function renderLoginPage(data, demoLoginActive = false) {
3615
3788
  <!-- Form -->
3616
3789
  <form
3617
3790
  id="login-form"
3791
+ action="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
3792
+ method="post"
3618
3793
  hx-post="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
3619
3794
  hx-target="#form-response"
3620
3795
  hx-swap="innerHTML"
@@ -3771,7 +3946,7 @@ function renderRegisterPage(data) {
3771
3946
  <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
3772
3947
  <div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
3773
3948
  <!-- Alerts -->
3774
- ${data.error ? `<div class="mb-6">${chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
3949
+ ${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
3775
3950
 
3776
3951
  <!-- Form -->
3777
3952
  <form
@@ -3871,7 +4046,7 @@ function renderRegisterPage(data) {
3871
4046
  }
3872
4047
 
3873
4048
  // src/services/email/email-service-singleton.ts
3874
- var singleton = chunkBP52BFIV_cjs.createServiceSingleton("EmailService");
4049
+ var singleton = chunkD6FWEYQE_cjs.createServiceSingleton("EmailService");
3875
4050
  function setEmailService(service2) {
3876
4051
  singleton.set(service2);
3877
4052
  }
@@ -3915,7 +4090,7 @@ function emptyProfile() {
3915
4090
  return { custom: {} };
3916
4091
  }
3917
4092
  function service(db) {
3918
- return new chunkLTZ5WYOK_cjs.DocumentsService(db, { tenantId: "default", maxVersionsPerRoot: 1, queryableFields: [] });
4093
+ return new chunkJCBDXEY2_cjs.DocumentsService(db, { tenantId: "default", maxVersionsPerRoot: 1, queryableFields: [] });
3919
4094
  }
3920
4095
  async function readProfileData(db, userId) {
3921
4096
  const row = await db.prepare(
@@ -4679,7 +4854,7 @@ function getLexicalInitScript(settings = {}) {
4679
4854
  </script>
4680
4855
  `;
4681
4856
  }
4682
- var lexicalEditorPlugin = chunkBP52BFIV_cjs.definePlugin({
4857
+ var lexicalEditorPlugin = chunkD6FWEYQE_cjs.definePlugin({
4683
4858
  id: "lexical-editor",
4684
4859
  version: "1.0.0",
4685
4860
  name: "Lexical Editor",
@@ -5130,9 +5305,11 @@ function renderDynamicField(field, options = {}) {
5130
5305
  min="${opts.min || ""}"
5131
5306
  max="${opts.max || ""}"
5132
5307
  class="${baseClasses} ${errorClasses} !w-auto dark:[color-scheme:dark]"
5308
+ placeholder="YYYY-MM-DD"
5133
5309
  ${required}
5134
5310
  ${disabled ? "disabled" : ""}
5135
5311
  >
5312
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD</p>
5136
5313
  `;
5137
5314
  break;
5138
5315
  case "datetime":
@@ -5148,6 +5325,7 @@ function renderDynamicField(field, options = {}) {
5148
5325
  ${required}
5149
5326
  ${disabled ? "disabled" : ""}
5150
5327
  >
5328
+ <p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD HH:MM</p>
5151
5329
  `;
5152
5330
  break;
5153
5331
  case "slug":
@@ -7085,7 +7263,7 @@ api.put("/:userId", async (c) => {
7085
7263
  await saveCustomData(db, userId, sanitized);
7086
7264
  return c.json({ success: true });
7087
7265
  });
7088
- var userProfilesPlugin = chunkBP52BFIV_cjs.definePlugin({
7266
+ var userProfilesPlugin = chunkD6FWEYQE_cjs.definePlugin({
7089
7267
  id: "user-profiles",
7090
7268
  version: "1.0.0",
7091
7269
  name: "User Profiles",
@@ -7104,6 +7282,21 @@ function createUserProfilesPlugin() {
7104
7282
 
7105
7283
  // src/routes/auth.ts
7106
7284
  var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
7285
+ var DEMO_EMAIL = "admin@sonicjs.com";
7286
+ var STATS_EVENTS_ENDPOINT = "https://stats.sonicjs.com/v1/events";
7287
+ async function trackDemoLogin(kv) {
7288
+ try {
7289
+ const installationId = await kv?.get("_sonicjs_installation_id") ?? "demo-unknown";
7290
+ await fetch(STATS_EVENTS_ENDPOINT, {
7291
+ method: "POST",
7292
+ headers: { "Content-Type": "application/json" },
7293
+ body: JSON.stringify({
7294
+ data: { installation_id: installationId, event_type: "demo_login", properties: {}, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
7295
+ })
7296
+ });
7297
+ } catch {
7298
+ }
7299
+ }
7107
7300
  function renderPasswordResetEmail(resetLink, firstName) {
7108
7301
  const greeting = firstName ? `Hi ${firstName},` : "Hello,";
7109
7302
  return `<!DOCTYPE html>
@@ -7123,8 +7316,8 @@ function renderPasswordResetEmail(resetLink, firstName) {
7123
7316
  async function setCsrfCookie(c, maxAge) {
7124
7317
  const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK;
7125
7318
  const isDev = c.env?.ENVIRONMENT === "development" || !c.env?.ENVIRONMENT;
7126
- const csrfToken = await chunk37V3RET3_cjs.generateCsrfToken(secret);
7127
- const cookieMaxAge = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(c.env?.DB, c.env);
7319
+ const csrfToken = await chunkE7E3NL3Y_cjs.generateCsrfToken(secret);
7320
+ const cookieMaxAge = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env?.DB, c.env);
7128
7321
  cookie.setCookie(c, "csrf_token", csrfToken, {
7129
7322
  httpOnly: false,
7130
7323
  secure: !isDev,
@@ -7183,7 +7376,7 @@ var loginSchema = zod.z.object({
7183
7376
  });
7184
7377
  authRoutes.post(
7185
7378
  "/register",
7186
- chunk37V3RET3_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
7379
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
7187
7380
  async (c) => {
7188
7381
  try {
7189
7382
  const db = c.env.DB;
@@ -7219,7 +7412,7 @@ authRoutes.post(
7219
7412
  if (existingUser) {
7220
7413
  return c.json({ error: "User with this email already exists" }, 400);
7221
7414
  }
7222
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(password);
7415
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
7223
7416
  const userId = crypto.randomUUID();
7224
7417
  const now = /* @__PURE__ */ new Date();
7225
7418
  const nowSec = Math.floor(now.getTime() / 1e3);
@@ -7252,8 +7445,8 @@ authRoutes.post(
7252
7445
  { user: { id: userId, email: normalizedEmail, role: "viewer" } },
7253
7446
  "fire-and-forget"
7254
7447
  );
7255
- const tokenTtl = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7256
- const token = await chunk37V3RET3_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET, tokenTtl);
7448
+ const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7449
+ const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET, tokenTtl);
7257
7450
  cookie.setCookie(c, "auth_token", token, {
7258
7451
  httpOnly: true,
7259
7452
  secure: true,
@@ -7285,7 +7478,7 @@ authRoutes.post(
7285
7478
  );
7286
7479
  authRoutes.post(
7287
7480
  "/login",
7288
- chunk37V3RET3_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
7481
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
7289
7482
  async (c) => {
7290
7483
  try {
7291
7484
  const body = await c.req.json();
@@ -7295,8 +7488,8 @@ authRoutes.post(
7295
7488
  }
7296
7489
  const { email, password } = validation.data;
7297
7490
  const normalizedEmail = email.toLowerCase();
7298
- const { createAuth } = await import('./config-OCH7S4WK.cjs');
7299
- const auth = createAuth(c.env);
7491
+ const { createAuth } = await import('./config-XN2ETAJ3.cjs');
7492
+ const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
7300
7493
  const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
7301
7494
  method: "POST",
7302
7495
  headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
@@ -7306,19 +7499,21 @@ authRoutes.post(
7306
7499
  if (!baRes.ok) {
7307
7500
  return c.json({ error: "Invalid email or password" }, 401);
7308
7501
  }
7309
- const rawSetCookie = baRes.headers.get("set-cookie");
7310
- if (rawSetCookie) {
7311
- c.res.headers.append("Set-Cookie", rawSetCookie);
7312
- } else if (baRes.headers.getSetCookie) {
7502
+ if (baRes.headers.getSetCookie) {
7313
7503
  for (const sc of baRes.headers.getSetCookie()) {
7314
- c.res.headers.append("Set-Cookie", sc);
7504
+ c.header("Set-Cookie", sc, { append: true });
7505
+ }
7506
+ } else {
7507
+ const rawSetCookie = baRes.headers.get("set-cookie");
7508
+ if (rawSetCookie) {
7509
+ c.header("Set-Cookie", rawSetCookie, { append: true });
7315
7510
  }
7316
7511
  }
7317
7512
  await setCsrfCookie(c);
7318
7513
  const baBody = await baRes.json();
7319
7514
  const user = baBody.user ?? {};
7320
- const tokenTtl = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7321
- const token = await chunk37V3RET3_cjs.AuthManager.generateToken(
7515
+ const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7516
+ const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(
7322
7517
  user.id,
7323
7518
  user.email,
7324
7519
  user.role ?? "viewer",
@@ -7331,6 +7526,9 @@ authRoutes.post(
7331
7526
  sameSite: "Strict",
7332
7527
  maxAge: tokenTtl
7333
7528
  });
7529
+ if (normalizedEmail === DEMO_EMAIL) {
7530
+ c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
7531
+ }
7334
7532
  return c.json({
7335
7533
  user: {
7336
7534
  id: user.id,
@@ -7349,8 +7547,8 @@ authRoutes.post(
7349
7547
  );
7350
7548
  authRoutes.post("/logout", async (c) => {
7351
7549
  try {
7352
- const { createAuth } = await import('./config-OCH7S4WK.cjs');
7353
- const auth = createAuth(c.env);
7550
+ const { createAuth } = await import('./config-XN2ETAJ3.cjs');
7551
+ const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
7354
7552
  const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
7355
7553
  method: "POST",
7356
7554
  headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
@@ -7359,14 +7557,15 @@ authRoutes.post("/logout", async (c) => {
7359
7557
  await auth.handler(baReq);
7360
7558
  } catch {
7361
7559
  }
7362
- cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0 });
7560
+ const isSecure = new URL(c.req.url).protocol === "https:";
7561
+ cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
7363
7562
  clearCsrfCookie(c);
7364
7563
  return c.json({ message: "Logged out successfully" });
7365
7564
  });
7366
7565
  authRoutes.get("/logout", async (c) => {
7367
7566
  try {
7368
- const { createAuth } = await import('./config-OCH7S4WK.cjs');
7369
- const auth = createAuth(c.env);
7567
+ const { createAuth } = await import('./config-XN2ETAJ3.cjs');
7568
+ const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
7370
7569
  const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
7371
7570
  method: "POST",
7372
7571
  headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
@@ -7375,11 +7574,12 @@ authRoutes.get("/logout", async (c) => {
7375
7574
  await auth.handler(baReq);
7376
7575
  } catch {
7377
7576
  }
7378
- cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0 });
7577
+ const isSecure = new URL(c.req.url).protocol === "https:";
7578
+ cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
7379
7579
  clearCsrfCookie(c);
7380
7580
  return c.redirect("/auth/login?message=You have been logged out successfully");
7381
7581
  });
7382
- authRoutes.get("/me", chunk37V3RET3_cjs.requireAuth(), async (c) => {
7582
+ authRoutes.get("/me", chunkE7E3NL3Y_cjs.requireAuth(), async (c) => {
7383
7583
  try {
7384
7584
  const user = c.get("user");
7385
7585
  if (!user) {
@@ -7399,7 +7599,7 @@ authRoutes.get("/me", chunk37V3RET3_cjs.requireAuth(), async (c) => {
7399
7599
  });
7400
7600
  authRoutes.post(
7401
7601
  "/refresh",
7402
- chunk37V3RET3_cjs.rateLimit({ max: 60, windowMs: 60 * 1e3, keyPrefix: "refresh" }),
7602
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 60, windowMs: 60 * 1e3, keyPrefix: "refresh" }),
7403
7603
  async (c) => {
7404
7604
  try {
7405
7605
  let token = c.req.header("Authorization")?.replace("Bearer ", "");
@@ -7408,8 +7608,8 @@ authRoutes.post(
7408
7608
  return c.json({ error: "Authentication required" }, 401);
7409
7609
  }
7410
7610
  const db = c.env.DB;
7411
- const grace = await chunk37V3RET3_cjs.getJwtRefreshGraceSecondsFromDb(db, c.env);
7412
- const payload = await chunk37V3RET3_cjs.AuthManager.verifyToken(token, c.env.JWT_SECRET, grace);
7611
+ const grace = await chunkE7E3NL3Y_cjs.getJwtRefreshGraceSecondsFromDb(db, c.env);
7612
+ const payload = await chunkE7E3NL3Y_cjs.AuthManager.verifyToken(token, c.env.JWT_SECRET, grace);
7413
7613
  if (!payload) {
7414
7614
  return c.json({ error: "Invalid or expired token" }, 401);
7415
7615
  }
@@ -7417,8 +7617,8 @@ authRoutes.post(
7417
7617
  if (!row || !row.is_active) {
7418
7618
  return c.json({ error: "User is not active" }, 401);
7419
7619
  }
7420
- const tokenTtl = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(db, c.env);
7421
- const newToken = await chunk37V3RET3_cjs.AuthManager.generateToken(row.id, row.email, row.role, c.env.JWT_SECRET, tokenTtl);
7620
+ const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(db, c.env);
7621
+ const newToken = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(row.id, row.email, row.role, c.env.JWT_SECRET, tokenTtl);
7422
7622
  cookie.setCookie(c, "auth_token", newToken, {
7423
7623
  httpOnly: true,
7424
7624
  secure: true,
@@ -7438,7 +7638,7 @@ authRoutes.post(
7438
7638
  );
7439
7639
  authRoutes.post(
7440
7640
  "/register/form",
7441
- chunk37V3RET3_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
7641
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
7442
7642
  async (c) => {
7443
7643
  try {
7444
7644
  const db = c.env.DB;
@@ -7483,7 +7683,7 @@ authRoutes.post(
7483
7683
  </div>
7484
7684
  `);
7485
7685
  }
7486
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(password);
7686
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
7487
7687
  const role = isFirstUser ? "admin" : "viewer";
7488
7688
  const userId = crypto.randomUUID();
7489
7689
  const now = /* @__PURE__ */ new Date();
@@ -7517,7 +7717,7 @@ authRoutes.post(
7517
7717
  await saveCustomData(db, userId, sanitized);
7518
7718
  }
7519
7719
  }
7520
- const rbacService = new chunkLTZ5WYOK_cjs.RbacService(db);
7720
+ const rbacService = new chunkJCBDXEY2_cjs.RbacService(db);
7521
7721
  await rbacService.addUserRoleByName(userId, role);
7522
7722
  dispatchHookEvent(
7523
7723
  c,
@@ -7525,8 +7725,8 @@ authRoutes.post(
7525
7725
  { user: { id: userId, email: normalizedEmail, role } },
7526
7726
  "fire-and-forget"
7527
7727
  );
7528
- const tokenTtl = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7529
- const token = await chunk37V3RET3_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET, tokenTtl);
7728
+ const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7729
+ const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET, tokenTtl);
7530
7730
  cookie.setCookie(c, "auth_token", token, {
7531
7731
  httpOnly: true,
7532
7732
  secure: false,
@@ -7558,7 +7758,7 @@ authRoutes.post(
7558
7758
  );
7559
7759
  authRoutes.post(
7560
7760
  "/login/form",
7561
- chunk37V3RET3_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
7761
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
7562
7762
  async (c) => {
7563
7763
  try {
7564
7764
  const formData = await c.req.formData();
@@ -7572,8 +7772,8 @@ authRoutes.post(
7572
7772
  </div>
7573
7773
  `);
7574
7774
  }
7575
- const { createAuth } = await import('./config-OCH7S4WK.cjs');
7576
- const auth = createAuth(c.env);
7775
+ const { createAuth } = await import('./config-XN2ETAJ3.cjs');
7776
+ const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
7577
7777
  const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
7578
7778
  method: "POST",
7579
7779
  headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
@@ -7587,17 +7787,27 @@ authRoutes.post(
7587
7787
  </div>
7588
7788
  `);
7589
7789
  }
7590
- const rawSetCookie = baRes.headers.get("set-cookie");
7591
- if (rawSetCookie) {
7592
- c.res.headers.append("Set-Cookie", rawSetCookie);
7593
- } else if (baRes.headers.getSetCookie) {
7790
+ if (baRes.headers.getSetCookie) {
7594
7791
  for (const sc of baRes.headers.getSetCookie()) {
7595
- c.res.headers.append("Set-Cookie", sc);
7792
+ c.header("Set-Cookie", sc, { append: true });
7793
+ }
7794
+ } else {
7795
+ const rawSetCookie = baRes.headers.get("set-cookie");
7796
+ if (rawSetCookie) {
7797
+ c.header("Set-Cookie", rawSetCookie, { append: true });
7596
7798
  }
7597
7799
  }
7598
7800
  await setCsrfCookie(c);
7801
+ if (email === DEMO_EMAIL) {
7802
+ c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
7803
+ }
7599
7804
  const rawRedirect = c.req.query("redirect");
7600
7805
  const redirectUrl = rawRedirect && rawRedirect.startsWith("/") ? rawRedirect : "/admin/content";
7806
+ const isHtmx = c.req.header("HX-Request") === "true";
7807
+ if (isHtmx) {
7808
+ c.header("HX-Redirect", redirectUrl);
7809
+ return c.html(html.html`<div id="form-response"><p class="text-sm text-green-600">Login successful! Redirecting...</p></div>`);
7810
+ }
7601
7811
  return c.html(html.html`
7602
7812
  <div id="form-response">
7603
7813
  <div class="rounded-lg bg-green-100 dark:bg-lime-500/10 p-4 ring-1 ring-green-400 dark:ring-lime-500/20">
@@ -7627,14 +7837,14 @@ authRoutes.post(
7627
7837
  );
7628
7838
  authRoutes.post(
7629
7839
  "/seed-admin",
7630
- chunk37V3RET3_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
7840
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
7631
7841
  async (c) => {
7632
7842
  try {
7633
7843
  const db = c.env.DB;
7634
- const rbac = new chunkLTZ5WYOK_cjs.RbacService(db);
7844
+ const rbac = new chunkJCBDXEY2_cjs.RbacService(db);
7635
7845
  const results = [];
7636
7846
  const upsertSeedUser = async (opts) => {
7637
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(opts.password);
7847
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(opts.password);
7638
7848
  const nowMs = Date.now();
7639
7849
  const nowSec = Math.floor(nowMs / 1e3);
7640
7850
  const existing = await db.prepare("SELECT id FROM auth_user WHERE email = ?").bind(opts.email).first();
@@ -7859,7 +8069,7 @@ authRoutes.post("/accept-invitation", async (c) => {
7859
8069
  if (invitationAge > maxAge) {
7860
8070
  return c.json({ error: "Invitation has expired" }, 400);
7861
8071
  }
7862
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(password);
8072
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
7863
8073
  const updateStmt = db.prepare(`
7864
8074
  UPDATE auth_user SET
7865
8075
  password_hash = ?,
@@ -7876,8 +8086,8 @@ authRoutes.post("/accept-invitation", async (c) => {
7876
8086
  Date.now(),
7877
8087
  invitedUser.id
7878
8088
  ).run();
7879
- const tokenTtl = await chunk37V3RET3_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
7880
- const authToken = await chunk37V3RET3_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET, tokenTtl);
8089
+ const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
8090
+ const authToken = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET, tokenTtl);
7881
8091
  cookie.setCookie(c, "auth_token", authToken, {
7882
8092
  httpOnly: true,
7883
8093
  secure: true,
@@ -7893,7 +8103,7 @@ authRoutes.post("/accept-invitation", async (c) => {
7893
8103
  });
7894
8104
  authRoutes.post(
7895
8105
  "/request-password-reset",
7896
- chunk37V3RET3_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
8106
+ chunkE7E3NL3Y_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
7897
8107
  async (c) => {
7898
8108
  try {
7899
8109
  const formData = await c.req.formData();
@@ -8130,7 +8340,7 @@ authRoutes.post("/reset-password", async (c) => {
8130
8340
  if (Date.now() > user.password_reset_expires) {
8131
8341
  return c.json({ error: "Reset token has expired" }, 400);
8132
8342
  }
8133
- const newPasswordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(password);
8343
+ const newPasswordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
8134
8344
  try {
8135
8345
  const historyStmt = db.prepare(`
8136
8346
  INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
@@ -8344,7 +8554,7 @@ app.post("/test-seed-defaults", async (c) => {
8344
8554
  var test_cleanup_default = app;
8345
8555
 
8346
8556
  // src/plugins/available/easy-mdx/index.ts
8347
- chunkBP52BFIV_cjs.definePlugin({
8557
+ chunkD6FWEYQE_cjs.definePlugin({
8348
8558
  id: "easy-mdx",
8349
8559
  version: "1.0.0",
8350
8560
  name: "EasyMDE Markdown Editor",
@@ -8544,7 +8754,7 @@ function getMDXEditorInitScript(config) {
8544
8754
  }
8545
8755
 
8546
8756
  // src/plugins/available/tinymce-plugin/index.ts
8547
- chunkBP52BFIV_cjs.definePlugin({
8757
+ chunkD6FWEYQE_cjs.definePlugin({
8548
8758
  id: "tinymce-plugin",
8549
8759
  version: "1.0.0",
8550
8760
  name: "TinyMCE",
@@ -8814,7 +9024,7 @@ function getQuillCDN(version = "2.0.2") {
8814
9024
  </style>
8815
9025
  `;
8816
9026
  }
8817
- chunkBP52BFIV_cjs.definePlugin({
9027
+ chunkD6FWEYQE_cjs.definePlugin({
8818
9028
  id: "quill-editor",
8819
9029
  version: "1.0.0",
8820
9030
  name: "Quill Editor",
@@ -8826,7 +9036,7 @@ chunkBP52BFIV_cjs.definePlugin({
8826
9036
  });
8827
9037
 
8828
9038
  // src/templates/pages/admin-content-form.template.ts
8829
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
9039
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
8830
9040
  function renderContentFormPage(data, opts) {
8831
9041
  const isEdit = data.isEdit || !!data.id;
8832
9042
  const title = isEdit ? `Edit: ${data.title || "Content"}` : `New ${data.collection.display_name}`;
@@ -8908,8 +9118,8 @@ function renderContentFormPage(data, opts) {
8908
9118
  <!-- Form Content -->
8909
9119
  <div class="px-6 py-6">
8910
9120
  <div id="form-messages">
8911
- ${data.error ? chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
8912
- ${data.success ? chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
9121
+ ${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
9122
+ ${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
8913
9123
  </div>
8914
9124
 
8915
9125
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
@@ -9109,33 +9319,44 @@ function renderContentFormPage(data, opts) {
9109
9319
  </a>
9110
9320
 
9111
9321
  <div class="flex items-center gap-x-3">
9112
- ${data.versioningEnabled ? `
9113
- <button
9114
- type="submit"
9115
- form="content-form"
9116
- name="action"
9117
- value="save"
9118
- class="inline-flex items-center justify-center gap-x-1.5 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"
9119
- >
9120
- <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
9121
- <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
9122
- </svg>
9123
- ${isEdit ? "Update" : "Save"}
9124
- </button>
9125
- ` : ""}
9322
+ <button
9323
+ type="submit"
9324
+ form="content-form"
9325
+ name="action"
9326
+ value="save"
9327
+ class="inline-flex items-center justify-center gap-x-1.5 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"
9328
+ >
9329
+ <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
9330
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
9331
+ </svg>
9332
+ Save
9333
+ </button>
9126
9334
 
9127
- ${data.user?.role !== "viewer" ? `
9335
+ <button
9336
+ type="submit"
9337
+ form="content-form"
9338
+ name="action"
9339
+ value="save_and_close"
9340
+ class="inline-flex items-center justify-center gap-x-1.5 rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors shadow-sm"
9341
+ >
9342
+ <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
9343
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
9344
+ </svg>
9345
+ Save & close
9346
+ </button>
9347
+
9348
+ ${data.user?.role !== "viewer" && data.versioningEnabled ? `
9128
9349
  <button
9129
9350
  type="submit"
9130
9351
  form="content-form"
9131
9352
  name="action"
9132
9353
  value="save_and_publish"
9133
- class="inline-flex items-center justify-center gap-x-1.5 rounded-lg ${data.versioningEnabled ? "bg-lime-600 dark:bg-lime-500 hover:bg-lime-700 dark:hover:bg-lime-600" : "bg-zinc-950 dark:bg-white hover:bg-zinc-800 dark:hover:bg-zinc-100 text-white dark:text-zinc-950"} px-3.5 py-2.5 text-sm font-semibold text-white transition-colors shadow-sm"
9354
+ class="inline-flex items-center justify-center gap-x-1.5 rounded-lg bg-lime-600 dark:bg-lime-500 hover:bg-lime-700 dark:hover:bg-lime-600 px-3.5 py-2.5 text-sm font-semibold text-white transition-colors shadow-sm"
9134
9355
  >
9135
9356
  <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
9136
9357
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
9137
9358
  </svg>
9138
- ${data.versioningEnabled ? `${isEdit ? "Update" : "Save"} & Publish` : isEdit ? "Update" : "Save"}
9359
+ Publish
9139
9360
  </button>
9140
9361
  ` : ""}
9141
9362
  </div>
@@ -9145,7 +9366,7 @@ function renderContentFormPage(data, opts) {
9145
9366
  </div>
9146
9367
 
9147
9368
  <!-- Confirmation Dialogs -->
9148
- ${chunkE66UVONV_cjs.renderConfirmationDialog({
9369
+ ${chunkOUBUS74I_cjs.renderConfirmationDialog({
9149
9370
  id: "duplicate-content-confirm",
9150
9371
  title: "Duplicate Content",
9151
9372
  message: "Create a copy of this content?",
@@ -9156,7 +9377,7 @@ function renderContentFormPage(data, opts) {
9156
9377
  onConfirm: "performDuplicateContent()"
9157
9378
  })}
9158
9379
 
9159
- ${chunkE66UVONV_cjs.renderConfirmationDialog({
9380
+ ${chunkOUBUS74I_cjs.renderConfirmationDialog({
9160
9381
  id: "delete-content-confirm",
9161
9382
  title: "Delete Content",
9162
9383
  message: "Are you sure you want to delete this content? This action cannot be undone.",
@@ -9167,7 +9388,7 @@ function renderContentFormPage(data, opts) {
9167
9388
  onConfirm: `performDeleteContent('${data.id}')`
9168
9389
  })}
9169
9390
 
9170
- ${chunkE66UVONV_cjs.renderConfirmationDialog({
9391
+ ${chunkOUBUS74I_cjs.renderConfirmationDialog({
9171
9392
  id: "delete-repeater-item-confirm",
9172
9393
  title: "Delete Item",
9173
9394
  message: "Are you sure you want to delete this item? This action cannot be undone.",
@@ -9178,7 +9399,7 @@ function renderContentFormPage(data, opts) {
9178
9399
  onConfirm: "performRepeaterDelete()"
9179
9400
  })}
9180
9401
 
9181
- ${chunkE66UVONV_cjs.renderConfirmationDialog({
9402
+ ${chunkOUBUS74I_cjs.renderConfirmationDialog({
9182
9403
  id: "delete-block-confirm",
9183
9404
  title: "Delete Block",
9184
9405
  message: "Are you sure you want to delete this block? This action cannot be undone.",
@@ -9189,7 +9410,7 @@ function renderContentFormPage(data, opts) {
9189
9410
  onConfirm: "performRepeaterDelete()"
9190
9411
  })}
9191
9412
 
9192
- ${chunkE66UVONV_cjs.getConfirmationDialogScript()}
9413
+ ${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
9193
9414
 
9194
9415
  ${data.lexicalEnabled ? getLexicalStyles() : "<!-- Lexical plugin not active -->"}
9195
9416
 
@@ -10275,11 +10496,11 @@ function renderContentFormPage(data, opts) {
10275
10496
  content: pageContent,
10276
10497
  version: data.version
10277
10498
  };
10278
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
10499
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
10279
10500
  }
10280
10501
 
10281
10502
  // src/templates/pages/admin-content-list.template.ts
10282
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
10503
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
10283
10504
  function renderContentListPage(data) {
10284
10505
  const urlParams = new URLSearchParams();
10285
10506
  if (data.modelName && data.modelName !== "all") urlParams.set("model", data.modelName);
@@ -10713,8 +10934,8 @@ function renderContentListPage(data) {
10713
10934
 
10714
10935
  <!-- Content List -->
10715
10936
  <div id="content-list">
10716
- ${chunkE66UVONV_cjs.renderTable(tableData)}
10717
- ${chunkE66UVONV_cjs.renderPagination(paginationData)}
10937
+ ${chunkOUBUS74I_cjs.renderTable(tableData)}
10938
+ ${chunkOUBUS74I_cjs.renderPagination(paginationData)}
10718
10939
  </div>
10719
10940
 
10720
10941
  </div>
@@ -10924,7 +11145,7 @@ function renderContentListPage(data) {
10924
11145
  </script>
10925
11146
 
10926
11147
  <!-- Confirmation Dialog for Bulk Actions -->
10927
- ${chunkE66UVONV_cjs.renderConfirmationDialog({
11148
+ ${chunkOUBUS74I_cjs.renderConfirmationDialog({
10928
11149
  id: "bulk-action-confirm",
10929
11150
  title: "Confirm Bulk Action",
10930
11151
  message: "Are you sure you want to perform this action? This operation will affect multiple items.",
@@ -10936,7 +11157,7 @@ function renderContentListPage(data) {
10936
11157
  })}
10937
11158
 
10938
11159
  <!-- Confirmation Dialog Script -->
10939
- ${chunkE66UVONV_cjs.getConfirmationDialogScript()}
11160
+ ${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
10940
11161
 
10941
11162
  <!-- Advanced Search Modal -->
10942
11163
  <div id="advancedSearchModal" class="hidden fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
@@ -11233,7 +11454,7 @@ function renderContentListPage(data) {
11233
11454
  version: data.version,
11234
11455
  content: pageContent
11235
11456
  };
11236
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
11457
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
11237
11458
  }
11238
11459
 
11239
11460
  // src/routes/admin-content-field-types.ts
@@ -11276,9 +11497,9 @@ function parseFieldValue(field, formData, options = {}) {
11276
11497
  const { skipValidation = false } = options;
11277
11498
  const value = formData.get(field.field_name);
11278
11499
  const errors = [];
11279
- const blocksConfig = chunkIXUHXTHW_cjs.getBlocksFieldConfig(field.field_options);
11500
+ const blocksConfig = chunkDLTT7QZU_cjs.getBlocksFieldConfig(field.field_options);
11280
11501
  if (blocksConfig) {
11281
- const parsed = chunkIXUHXTHW_cjs.parseBlocksValue(value, blocksConfig);
11502
+ const parsed = chunkDLTT7QZU_cjs.parseBlocksValue(value, blocksConfig);
11282
11503
  if (!skipValidation && field.is_required && parsed.value.length === 0) {
11283
11504
  parsed.errors.push(`${field.field_label} is required`);
11284
11505
  }
@@ -11388,7 +11609,7 @@ function extractFieldData(fields, formData, options = {}) {
11388
11609
  }
11389
11610
  return { data, errors };
11390
11611
  }
11391
- adminContentRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
11612
+ adminContentRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
11392
11613
  async function getCollectionFields(db, collectionId) {
11393
11614
  console.log(`[getCollectionFields] Loading fields for collection: ${collectionId}`);
11394
11615
  const collectionStmt = db.prepare("SELECT schema, queryable_fields FROM document_types WHERE id = ?");
@@ -11415,7 +11636,7 @@ async function getCollectionFields(db, collectionId) {
11415
11636
  };
11416
11637
  });
11417
11638
  }
11418
- const codeCollections2 = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
11639
+ const codeCollections2 = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11419
11640
  const codeMatch = codeCollections2.find((c) => c.name === collectionId);
11420
11641
  if (codeMatch && codeMatch.schema?.properties) {
11421
11642
  console.log(`[getCollectionFields] DB doc type has no properties \u2014 using code collection schema`);
@@ -11447,7 +11668,7 @@ async function getCollectionFields(db, collectionId) {
11447
11668
  }
11448
11669
  }
11449
11670
  console.log(`[getCollectionFields] Not in database, checking code collections`);
11450
- const codeCollections = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
11671
+ const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11451
11672
  console.log(`[getCollectionFields] Found ${codeCollections.length} code collections`);
11452
11673
  const codeCollection = codeCollections.find((c) => c.name === collectionId);
11453
11674
  if (codeCollection && codeCollection.schema) {
@@ -11501,7 +11722,7 @@ async function getCollection(db, collectionId) {
11501
11722
  };
11502
11723
  }
11503
11724
  console.log(`[getCollection] Not in database, checking code collections`);
11504
- const codeCollections = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
11725
+ const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11505
11726
  const codeCollection = codeCollections.find((c) => c.name === collectionId);
11506
11727
  if (codeCollection) {
11507
11728
  console.log(`[getCollection] Found code collection: ${collectionId}`);
@@ -11520,7 +11741,7 @@ async function getCollection(db, collectionId) {
11520
11741
  }
11521
11742
  async function getDocBackingType(db, collectionName) {
11522
11743
  if (!collectionName) return null;
11523
- const dt = await new chunk37V3RET3_cjs.DocumentTypeRegistry(db).findById(collectionName);
11744
+ const dt = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(collectionName);
11524
11745
  return dt && dt.isActive ? dt : null;
11525
11746
  }
11526
11747
  async function getCollectionByName(db, name) {
@@ -11537,7 +11758,7 @@ async function getCollectionByName(db, name) {
11537
11758
  };
11538
11759
  }
11539
11760
  console.log(`[getCollectionByName] Not in database, checking code collections`);
11540
- const codeCollections = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
11761
+ const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11541
11762
  const codeCollection = codeCollections.find((c) => c.name === name);
11542
11763
  if (codeCollection) {
11543
11764
  console.log(`[getCollectionByName] Found code collection: ${name}`);
@@ -11553,7 +11774,7 @@ async function getCollectionByName(db, name) {
11553
11774
  return null;
11554
11775
  }
11555
11776
  async function loadContentEditorFlags(db) {
11556
- const flags = { workflowEnabled: await chunk37V3RET3_cjs.isPluginActive(db, "workflow") };
11777
+ const flags = { workflowEnabled: await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow") };
11557
11778
  const editors = [
11558
11779
  ["tinymce-plugin", "tinymce"],
11559
11780
  ["quill-editor", "quill"],
@@ -11561,10 +11782,10 @@ async function loadContentEditorFlags(db) {
11561
11782
  ["lexical-editor", "lexical"]
11562
11783
  ];
11563
11784
  for (const [plugin, key] of editors) {
11564
- const enabled = await chunk37V3RET3_cjs.isPluginActive(db, plugin);
11785
+ const enabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, plugin);
11565
11786
  flags[`${key}Enabled`] = enabled;
11566
11787
  if (enabled) {
11567
- const ps = new chunkQCJHCSOK_cjs.PluginService(db);
11788
+ const ps = new chunkYAURVGUK_cjs.PluginService(db);
11568
11789
  const p = await ps.getPlugin(plugin);
11569
11790
  flags[`${key}Settings`] = p?.settings;
11570
11791
  }
@@ -11572,7 +11793,7 @@ async function loadContentEditorFlags(db) {
11572
11793
  return flags;
11573
11794
  }
11574
11795
  function makeDocService(db, docType, tenantId) {
11575
- return new chunkLTZ5WYOK_cjs.DocumentsService(db, {
11796
+ return new chunkJCBDXEY2_cjs.DocumentsService(db, {
11576
11797
  queryableFields: docType.queryableFields ?? [],
11577
11798
  typeSchemaVersion: docType.schemaVersion ?? 1,
11578
11799
  maxVersionsPerRoot: docType.settings?.maxVersionsPerRoot ?? 50,
@@ -11600,9 +11821,9 @@ adminContentRoutes.get("/", async (c) => {
11600
11821
  const offset = (page - 1) * limit;
11601
11822
  const collectionsStmt = db.prepare("SELECT id, name, display_name FROM document_types WHERE is_active = 1 ORDER BY display_name");
11602
11823
  const { results: collectionsResults } = await collectionsStmt.all();
11603
- const codeCollections = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
11824
+ const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11604
11825
  const codeCollectionMap = new Map(codeCollections.map((c2) => [c2.name, c2]));
11605
- const docTypeRegistry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
11826
+ const docTypeRegistry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
11606
11827
  const docTypes = (await docTypeRegistry.findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth);
11607
11828
  const visibleTypeIds = new Set(docTypes.map((dt) => dt.id));
11608
11829
  const allCollections = [
@@ -11614,7 +11835,7 @@ adminContentRoutes.get("/", async (c) => {
11614
11835
  ...allCollections.map((c2) => ({ name: c2.name, displayName: c2.displayName })),
11615
11836
  ...docTypes.filter((dt) => !collectionNames.has(dt.id)).map((dt) => ({ name: `doc:${dt.id}`, displayName: dt.displayName }))
11616
11837
  ];
11617
- const newContentCollections = await chunkQCJHCSOK_cjs.getVisibleCollections(db);
11838
+ const newContentCollections = await chunkYAURVGUK_cjs.getVisibleCollections(db);
11618
11839
  const docBackedCollection = !modelName.startsWith("doc:") && modelName !== "all" ? docTypes.find((dt) => dt.id === modelName) : void 0;
11619
11840
  const isDocModel = modelName.startsWith("doc:") || !!docBackedCollection;
11620
11841
  if (isDocModel) {
@@ -11899,9 +12120,9 @@ adminContentRoutes.get("/new", async (c) => {
11899
12120
  const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM document_types WHERE is_active = 1 ORDER BY display_name");
11900
12121
  const { results } = await collectionsStmt.all();
11901
12122
  const visibleTypeIds = new Set(
11902
- (await new chunk37V3RET3_cjs.DocumentTypeRegistry(db2).findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth).map((dt) => dt.id)
12123
+ (await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db2).findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth).map((dt) => dt.id)
11903
12124
  );
11904
- const codeCollections = await chunkQCJHCSOK_cjs.loadCollectionConfigs();
12125
+ const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
11905
12126
  const dbCollectionNames = new Set((results || []).map((r) => r.name));
11906
12127
  const allCollections = [
11907
12128
  ...codeCollections.filter((c2) => !dbCollectionNames.has(c2.name)).map((c2) => ({
@@ -11967,32 +12188,32 @@ adminContentRoutes.get("/new", async (c) => {
11967
12188
  return c.html(renderContentFormPage(formData2));
11968
12189
  }
11969
12190
  const fields = await getCollectionFields(db, collection.id);
11970
- const workflowEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "workflow");
11971
- const tinymceEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "tinymce-plugin");
12191
+ const workflowEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow");
12192
+ const tinymceEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin");
11972
12193
  let tinymceSettings;
11973
12194
  if (tinymceEnabled) {
11974
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12195
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
11975
12196
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
11976
12197
  tinymceSettings = tinymcePlugin2?.settings;
11977
12198
  }
11978
- const quillEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "quill-editor");
12199
+ const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
11979
12200
  let quillSettings;
11980
12201
  if (quillEnabled) {
11981
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12202
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
11982
12203
  const quillPlugin = await pluginService.getPlugin("quill-editor");
11983
12204
  quillSettings = quillPlugin?.settings;
11984
12205
  }
11985
- const mdxeditorEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "easy-mdx");
12206
+ const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
11986
12207
  let mdxeditorSettings;
11987
12208
  if (mdxeditorEnabled) {
11988
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12209
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
11989
12210
  const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
11990
12211
  mdxeditorSettings = mdxeditorPlugin?.settings;
11991
12212
  }
11992
- const lexicalEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "lexical-editor");
12213
+ const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
11993
12214
  let lexicalSettings;
11994
12215
  if (lexicalEnabled) {
11995
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12216
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
11996
12217
  const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
11997
12218
  lexicalSettings = lexicalPlugin?.settings;
11998
12219
  }
@@ -12128,32 +12349,32 @@ adminContentRoutes.get("/:id/edit", async (c) => {
12128
12349
  };
12129
12350
  const fields = await getCollectionFields(db, content.collection_id);
12130
12351
  const contentData = content.data ? JSON.parse(content.data) : {};
12131
- const workflowEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "workflow");
12132
- const tinymceEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "tinymce-plugin");
12352
+ const workflowEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow");
12353
+ const tinymceEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin");
12133
12354
  let tinymceSettings;
12134
12355
  if (tinymceEnabled) {
12135
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12356
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
12136
12357
  const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
12137
12358
  tinymceSettings = tinymcePlugin2?.settings;
12138
12359
  }
12139
- const quillEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "quill-editor");
12360
+ const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
12140
12361
  let quillSettings;
12141
12362
  if (quillEnabled) {
12142
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12363
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
12143
12364
  const quillPlugin = await pluginService.getPlugin("quill-editor");
12144
12365
  quillSettings = quillPlugin?.settings;
12145
12366
  }
12146
- const mdxeditorEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "easy-mdx");
12367
+ const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
12147
12368
  let mdxeditorSettings;
12148
12369
  if (mdxeditorEnabled) {
12149
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12370
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
12150
12371
  const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
12151
12372
  mdxeditorSettings = mdxeditorPlugin?.settings;
12152
12373
  }
12153
- const lexicalEnabled = await chunk37V3RET3_cjs.isPluginActive(db, "lexical-editor");
12374
+ const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
12154
12375
  let lexicalSettings;
12155
12376
  if (lexicalEnabled) {
12156
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
12377
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
12157
12378
  const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
12158
12379
  lexicalSettings = lexicalPlugin?.settings;
12159
12380
  }
@@ -12278,6 +12499,9 @@ adminContentRoutes.post("/", async (c) => {
12278
12499
  }), user?.userId);
12279
12500
  const cache2 = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content);
12280
12501
  await cache2.invalidate(`content:list:${collectionId}:*`);
12502
+ const apiCacheCreate = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
12503
+ await apiCacheCreate.invalidate("api:content-filtered:*");
12504
+ await apiCacheCreate.invalidate(`api:collection-content-filtered:${createDocType.id}:*`);
12281
12505
  const redirectUrl2 = `/admin/content/${doc.rootId}/edit?success=Content created successfully!`;
12282
12506
  return c.req.header("HX-Request") === "true" ? c.text("", 200, { "HX-Redirect": redirectUrl2 }) : c.redirect(redirectUrl2);
12283
12507
  }
@@ -12396,8 +12620,28 @@ adminContentRoutes.put("/:id", async (c) => {
12396
12620
  if (status2 === "published") await svc.publish(newDraft.id, user?.userId);
12397
12621
  else if (pub) await svc.unpublish(pub.id);
12398
12622
  await chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content).invalidate(`content:list:*`);
12623
+ const apiCacheEdit = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
12624
+ await apiCacheEdit.invalidate("api:content-filtered:*");
12625
+ await apiCacheEdit.invalidate(`api:collection-content-filtered:${docRowU.type_id}:*`);
12626
+ const isHTMX2 = c.req.header("HX-Request") === "true";
12627
+ const referrerParams = formData.get("referrer_params");
12628
+ const listUrl = referrerParams ? `/admin/content?${referrerParams}` : `/admin/content?collection=${dcoll.id}`;
12629
+ if (action === "save_and_close") {
12630
+ return isHTMX2 ? c.text("", 200, { "HX-Redirect": listUrl }) : c.redirect(listUrl);
12631
+ }
12632
+ if (isHTMX2) {
12633
+ const label = status2 === "published" ? "Content published successfully!" : "Content saved successfully!";
12634
+ return c.html(html.html`<div id="form-messages">
12635
+ <div class="rounded-lg bg-green-50 dark:bg-green-900/20 p-4 mb-4 flex items-center gap-3 border border-green-200 dark:border-green-800">
12636
+ <svg class="h-5 w-5 text-green-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
12637
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
12638
+ </svg>
12639
+ <span class="text-sm font-medium text-green-800 dark:text-green-200">${label}</span>
12640
+ </div>
12641
+ </div>`);
12642
+ }
12399
12643
  const redirectUrl2 = `/admin/content/${id}/edit?success=Content updated successfully!`;
12400
- return c.req.header("HX-Request") === "true" ? c.text("", 200, { "HX-Redirect": redirectUrl2 }) : c.redirect(redirectUrl2);
12644
+ return c.redirect(redirectUrl2);
12401
12645
  }
12402
12646
  }
12403
12647
  return c.html(html.html`
@@ -12530,7 +12774,7 @@ adminContentRoutes.put("/:id", async (c) => {
12530
12774
  `);
12531
12775
  }
12532
12776
  });
12533
- adminContentRoutes.post("/preview", chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
12777
+ adminContentRoutes.post("/preview", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
12534
12778
  try {
12535
12779
  const formData = await c.req.formData();
12536
12780
  const collectionId = formData.get("collection_id");
@@ -12791,8 +13035,8 @@ adminContentRoutes.post("/bulk-action", async (c) => {
12791
13035
  }
12792
13036
  await cache.invalidate("content:list:*");
12793
13037
  const apiCache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
12794
- await apiCache.invalidate("content-filtered:*");
12795
- await apiCache.invalidate("collection-content-filtered:*");
13038
+ await apiCache.invalidate("api:content-filtered:*");
13039
+ await apiCache.invalidate("api:collection-content-filtered:*");
12796
13040
  return c.json({ success: true, count: ids.length });
12797
13041
  } catch (error) {
12798
13042
  console.error("Bulk action error:", error);
@@ -12810,6 +13054,9 @@ adminContentRoutes.delete("/:id", async (c) => {
12810
13054
  const now2 = Math.floor(Date.now() / 1e3);
12811
13055
  await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now2, now2, id, tenantId).run();
12812
13056
  await chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content).invalidate("content:list:*");
13057
+ const apiCacheDel = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
13058
+ await apiCacheDel.invalidate("api:content-filtered:*");
13059
+ await apiCacheDel.invalidate(`api:collection-content-filtered:${docDel.type_id}:*`);
12813
13060
  return c.html(`
12814
13061
  <div id="content-list" hx-get="/admin/content?model=${docDel.type_id}" hx-trigger="load" hx-swap="outerHTML">
12815
13062
  <div class="flex items-center justify-center p-8"><span class="text-zinc-500">Deleting\u2026</span></div>
@@ -12849,7 +13096,7 @@ adminContentRoutes.delete("/:id", async (c) => {
12849
13096
  return c.json({ success: false, error: "Failed to delete content" }, 500);
12850
13097
  }
12851
13098
  });
12852
- adminContentRoutes.get("/:id/version/:version/preview", chunk37V3RET3_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
13099
+ adminContentRoutes.get("/:id/version/:version/preview", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
12853
13100
  try {
12854
13101
  const id = c.req.param("id");
12855
13102
  const version = parseInt(c.req.param("version") || "0");
@@ -12945,9 +13192,9 @@ function parseDocFormData(formData, queryableFields = []) {
12945
13192
  return { title, slug, data };
12946
13193
  }
12947
13194
  async function getDocService(db, typeId, tenantId) {
12948
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
13195
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
12949
13196
  const docType = await registry.findById(typeId);
12950
- const svc = new chunkLTZ5WYOK_cjs.DocumentsService(db, {
13197
+ const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
12951
13198
  queryableFields: docType?.queryableFields ?? [],
12952
13199
  typeSchemaVersion: docType?.schemaVersion ?? 1,
12953
13200
  maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
@@ -12958,10 +13205,10 @@ async function getDocService(db, typeId, tenantId) {
12958
13205
  }
12959
13206
  adminContentRoutes.get("/documents/:typeId/new", async (c) => {
12960
13207
  const { typeId } = c.req.param();
12961
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(c.env.DB);
13208
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
12962
13209
  const docType = await registry.findById(typeId);
12963
13210
  if (!docType) return c.html("<p>Unknown document type.</p>", 404);
12964
- return c.html(chunkJMJM7DMM_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c) }));
13211
+ return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c) }));
12965
13212
  });
12966
13213
  adminContentRoutes.post("/documents/:typeId/new", async (c) => {
12967
13214
  const { typeId } = c.req.param();
@@ -12983,17 +13230,17 @@ adminContentRoutes.post("/documents/:typeId/new", async (c) => {
12983
13230
  }), user?.userId);
12984
13231
  return c.redirect(`/admin/content/documents/${typeId}/${doc.rootId}/edit?message=Created+successfully`);
12985
13232
  } catch (err) {
12986
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(c.env.DB);
13233
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
12987
13234
  const docType = await registry.findById(typeId);
12988
13235
  if (!docType) return c.html("<p>Unknown document type.</p>", 404);
12989
- return c.html(chunkJMJM7DMM_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c), message: err?.message ?? "Failed to create", messageType: "error" }));
13236
+ return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c), message: err?.message ?? "Failed to create", messageType: "error" }));
12990
13237
  }
12991
13238
  });
12992
13239
  adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
12993
13240
  const { typeId, rootId } = c.req.param();
12994
13241
  const db = c.env.DB;
12995
13242
  const message = c.req.query("message");
12996
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
13243
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
12997
13244
  const docType = await registry.findById(typeId);
12998
13245
  if (!docType) return c.html("<p>Unknown document type.</p>", 404);
12999
13246
  const tenantId = reqTenant(c);
@@ -13040,7 +13287,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
13040
13287
  createdAt: draftRow.created_at,
13041
13288
  updatedAt: draftRow.updated_at
13042
13289
  };
13043
- return c.html(chunkJMJM7DMM_cjs.renderDocumentFormPage({ docType, doc, publishedDoc, isEdit: true, message, user: userCtx(c), versioningEnabled: docType?.settings?.versioning === true }));
13290
+ return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, doc, publishedDoc, isEdit: true, message, user: userCtx(c), versioningEnabled: docType?.settings?.versioning === true }));
13044
13291
  });
13045
13292
  adminContentRoutes.post("/documents/:typeId/:rootId", async (c) => {
13046
13293
  const { typeId, rootId } = c.req.param();
@@ -13105,8 +13352,8 @@ adminContentRoutes.post("/documents/:typeId/:documentId/delete", async (c) => {
13105
13352
  adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
13106
13353
  const { typeId, rootId } = c.req.param();
13107
13354
  const db = c.env.DB;
13108
- const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-YNAVMJCV.cjs');
13109
- const registry = new chunk37V3RET3_cjs.DocumentTypeRegistry(db);
13355
+ const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-UWKGVAMW.cjs');
13356
+ const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
13110
13357
  const docType = await registry.findById(typeId);
13111
13358
  if (!docType) return c.html("<div>Unknown type.</div>", 404);
13112
13359
  const result = await db.prepare(
@@ -13126,7 +13373,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
13126
13373
  var admin_content_default = adminContentRoutes;
13127
13374
 
13128
13375
  // src/templates/pages/admin-profile.template.ts
13129
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
13376
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
13130
13377
  function renderAvatarImage(avatarUrl, firstName, lastName) {
13131
13378
  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">
13132
13379
  ${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>`}
@@ -13146,8 +13393,8 @@ function renderProfilePage(data) {
13146
13393
  </div>
13147
13394
 
13148
13395
  <!-- Alert Messages -->
13149
- ${data.error ? chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
13150
- ${data.success ? chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
13396
+ ${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
13397
+ ${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
13151
13398
 
13152
13399
  <!-- Profile Form -->
13153
13400
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
@@ -13524,7 +13771,7 @@ function renderProfilePage(data) {
13524
13771
  version: data.version,
13525
13772
  content: pageContent
13526
13773
  };
13527
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
13774
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
13528
13775
  }
13529
13776
 
13530
13777
  // src/templates/pages/admin-activity-logs.template.ts
@@ -13734,7 +13981,7 @@ function renderActivityLogsPage(data) {
13734
13981
  user: data.user,
13735
13982
  content: pageContent
13736
13983
  };
13737
- return chunkE66UVONV_cjs.renderAdminLayout(layoutData);
13984
+ return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
13738
13985
  }
13739
13986
  function getActionBadgeClass(action) {
13740
13987
  if (action.includes("login") || action.includes("logout")) {
@@ -13754,7 +14001,7 @@ function formatAction(action) {
13754
14001
  }
13755
14002
 
13756
14003
  // src/templates/pages/admin-user-edit.template.ts
13757
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
14004
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
13758
14005
 
13759
14006
  // src/templates/components/confirmation-dialog.template.ts
13760
14007
  function renderConfirmationDialog2(options) {
@@ -13950,8 +14197,8 @@ function renderUserEditPage(data) {
13950
14197
 
13951
14198
  <!-- Alert Messages -->
13952
14199
  <div id="form-messages" class="mb-6 empty:mb-0">
13953
- ${data.error ? chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
13954
- ${data.success ? chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
14200
+ ${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
14201
+ ${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
13955
14202
  </div>
13956
14203
 
13957
14204
  <!-- User Edit Form -->
@@ -14273,11 +14520,11 @@ function renderUserEditPage(data) {
14273
14520
  user: data.user,
14274
14521
  content: pageContent
14275
14522
  };
14276
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
14523
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
14277
14524
  }
14278
14525
 
14279
14526
  // src/templates/pages/admin-user-new.template.ts
14280
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
14527
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
14281
14528
  function renderUserNewPage(data) {
14282
14529
  const pageContent = `
14283
14530
  <div>
@@ -14316,8 +14563,8 @@ function renderUserNewPage(data) {
14316
14563
 
14317
14564
  <!-- Alert Messages -->
14318
14565
  <div id="form-messages">
14319
- ${data.error ? chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
14320
- ${data.success ? chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
14566
+ ${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
14567
+ ${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
14321
14568
  </div>
14322
14569
 
14323
14570
  <!-- User New Form -->
@@ -14547,11 +14794,11 @@ function renderUserNewPage(data) {
14547
14794
  user: data.user,
14548
14795
  content: pageContent
14549
14796
  };
14550
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
14797
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
14551
14798
  }
14552
14799
 
14553
14800
  // src/templates/pages/admin-users-list.template.ts
14554
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
14801
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
14555
14802
  function renderUsersListPage(data) {
14556
14803
  const columns = [
14557
14804
  {
@@ -14707,8 +14954,8 @@ function renderUsersListPage(data) {
14707
14954
  </div>
14708
14955
 
14709
14956
  <!-- Alert Messages -->
14710
- ${data.error ? chunkE66UVONV_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
14711
- ${data.success ? chunkE66UVONV_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
14957
+ ${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
14958
+ ${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
14712
14959
 
14713
14960
  <!-- Stats -->
14714
14961
  <div class="mb-6">
@@ -14885,10 +15132,10 @@ function renderUsersListPage(data) {
14885
15132
  </div>
14886
15133
 
14887
15134
  <!-- Users Table -->
14888
- ${chunkE66UVONV_cjs.renderTable(tableData)}
15135
+ ${chunkOUBUS74I_cjs.renderTable(tableData)}
14889
15136
 
14890
15137
  <!-- Pagination -->
14891
- ${data.pagination ? chunkE66UVONV_cjs.renderPagination(data.pagination) : ""}
15138
+ ${data.pagination ? chunkOUBUS74I_cjs.renderPagination(data.pagination) : ""}
14892
15139
  </div>
14893
15140
 
14894
15141
  <script>
@@ -14959,7 +15206,7 @@ function renderUsersListPage(data) {
14959
15206
  version: data.version,
14960
15207
  content: pageContent
14961
15208
  };
14962
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
15209
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
14963
15210
  }
14964
15211
 
14965
15212
  // src/plugins/core-plugins/multi-tenant-plugin/services/tenant-service.ts
@@ -15039,7 +15286,7 @@ var TenantService = class {
15039
15286
  SET name = ?, domain = ?, status = ?, notes = ?, updated_at = ?
15040
15287
  WHERE slug = ?
15041
15288
  `).bind(name, domain, status, notes, now, slug).run();
15042
- chunkQCJHCSOK_cjs.invalidateTenantCache();
15289
+ chunkYAURVGUK_cjs.invalidateTenantCache();
15043
15290
  const updated = await this.getTenantBySlug(slug);
15044
15291
  if (!updated) throw new Error("Tenant not found");
15045
15292
  return updated;
@@ -15057,7 +15304,7 @@ var TenantService = class {
15057
15304
  throw new Error(`Tenant '${slug}' still owns ${docCount} document(s). Delete or migrate its content first.`);
15058
15305
  }
15059
15306
  await this.db.prepare(`DELETE FROM auth_tenant WHERE slug = ?`).bind(slug).run();
15060
- chunkQCJHCSOK_cjs.invalidateTenantCache();
15307
+ chunkYAURVGUK_cjs.invalidateTenantCache();
15061
15308
  }
15062
15309
  // ─── Membership (auth_tenant_member) ───────────────────────────────────────
15063
15310
  // Tenant resolution and the admin switcher are gated on membership: an authed user may only
@@ -15301,7 +15548,7 @@ var TenantService = class {
15301
15548
  INSERT INTO auth_tenant (id, name, slug, status, domain, notes, metadata, created_at, updated_at)
15302
15549
  VALUES (?, ?, ?, 'active', ?, ?, '{}', ?, ?)
15303
15550
  `).bind(id, input.name, input.slug, input.domain, input.notes, now, now).run();
15304
- chunkQCJHCSOK_cjs.invalidateTenantCache();
15551
+ chunkYAURVGUK_cjs.invalidateTenantCache();
15305
15552
  const created = await this.getTenantBySlug(input.slug);
15306
15553
  if (!created) throw new Error("Failed to create tenant");
15307
15554
  return created;
@@ -15325,14 +15572,14 @@ function mapRowToTenant(row) {
15325
15572
 
15326
15573
  // src/routes/admin-users.ts
15327
15574
  var userRoutes = new hono.Hono();
15328
- userRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
15329
- userRoutes.use("/users/*", chunk37V3RET3_cjs.requireRole(["admin"]));
15330
- userRoutes.use("/users", chunk37V3RET3_cjs.requireRole(["admin"]));
15331
- userRoutes.use("/invite-user", chunk37V3RET3_cjs.requireRole(["admin"]));
15332
- userRoutes.use("/resend-invitation/*", chunk37V3RET3_cjs.requireRole(["admin"]));
15333
- userRoutes.use("/cancel-invitation/*", chunk37V3RET3_cjs.requireRole(["admin"]));
15334
- userRoutes.use("/activity-logs", chunk37V3RET3_cjs.requireRole(["admin"]));
15335
- userRoutes.use("/activity-logs/*", chunk37V3RET3_cjs.requireRole(["admin"]));
15575
+ userRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
15576
+ userRoutes.use("/users/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15577
+ userRoutes.use("/users", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15578
+ userRoutes.use("/invite-user", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15579
+ userRoutes.use("/resend-invitation/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15580
+ userRoutes.use("/cancel-invitation/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15581
+ userRoutes.use("/activity-logs", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15582
+ userRoutes.use("/activity-logs/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
15336
15583
  userRoutes.get("/", (c) => {
15337
15584
  return c.redirect("/admin/dashboard");
15338
15585
  });
@@ -15360,12 +15607,10 @@ var LANGUAGES = [
15360
15607
  { value: "ko", label: "Korean" },
15361
15608
  { value: "zh", label: "Chinese" }
15362
15609
  ];
15363
- var ROLES = [
15364
- { value: "admin", label: "Administrator" },
15365
- { value: "editor", label: "Editor" },
15366
- { value: "author", label: "Author" },
15367
- { value: "viewer", label: "Viewer" }
15368
- ];
15610
+ async function fetchRoleOptions(db) {
15611
+ const roles = await new chunkJCBDXEY2_cjs.RbacService(db).getRoles();
15612
+ return roles.map((r) => ({ value: r.id, label: r.display_name }));
15613
+ }
15369
15614
  userRoutes.get("/profile", async (c) => {
15370
15615
  const user = c.get("user");
15371
15616
  const db = c.env.DB;
@@ -15443,7 +15688,7 @@ userRoutes.put("/profile", async (c) => {
15443
15688
  const language = formData.get("language")?.toString() || "en";
15444
15689
  const emailNotifications = formData.get("email_notifications") === "1";
15445
15690
  if (!firstName || !lastName || !email) {
15446
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15691
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15447
15692
  type: "error",
15448
15693
  message: "First name, last name, and email are required.",
15449
15694
  dismissible: true
@@ -15451,7 +15696,7 @@ userRoutes.put("/profile", async (c) => {
15451
15696
  }
15452
15697
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
15453
15698
  if (!emailRegex.test(email)) {
15454
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15699
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15455
15700
  type: "error",
15456
15701
  message: "Please enter a valid email address.",
15457
15702
  dismissible: true
@@ -15463,7 +15708,7 @@ userRoutes.put("/profile", async (c) => {
15463
15708
  `);
15464
15709
  const existingUser = await checkStmt.bind(email, user.userId).first();
15465
15710
  if (existingUser) {
15466
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15711
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15467
15712
  type: "error",
15468
15713
  message: "Email is already taken by another user.",
15469
15714
  dismissible: true
@@ -15495,11 +15740,11 @@ userRoutes.put("/profile", async (c) => {
15495
15740
  const validation = validateCustomData(sanitized, profileConfig);
15496
15741
  if (!validation.valid) {
15497
15742
  const errorMessages = Object.values(validation.errors).join(", ");
15498
- return c.html(chunkJMJM7DMM_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
15743
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
15499
15744
  }
15500
15745
  await saveCustomData(db, user.userId, sanitized);
15501
15746
  }
15502
- await chunk37V3RET3_cjs.logActivity(
15747
+ await chunkE7E3NL3Y_cjs.logActivity(
15503
15748
  db,
15504
15749
  user.userId,
15505
15750
  "profile.update",
@@ -15509,14 +15754,14 @@ userRoutes.put("/profile", async (c) => {
15509
15754
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
15510
15755
  c.req.header("user-agent")
15511
15756
  );
15512
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15757
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15513
15758
  type: "success",
15514
15759
  message: "Profile updated successfully!",
15515
15760
  dismissible: true
15516
15761
  }));
15517
15762
  } catch (error) {
15518
15763
  console.error("Profile update error:", error);
15519
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15764
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15520
15765
  type: "error",
15521
15766
  message: "Failed to update profile. Please try again.",
15522
15767
  dismissible: true
@@ -15530,7 +15775,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15530
15775
  const formData = await c.req.formData();
15531
15776
  const avatarFile = formData.get("avatar");
15532
15777
  if (!avatarFile || typeof avatarFile === "string" || !avatarFile.name) {
15533
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15778
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15534
15779
  type: "error",
15535
15780
  message: "Please select an image file.",
15536
15781
  dismissible: true
@@ -15538,7 +15783,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15538
15783
  }
15539
15784
  const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
15540
15785
  if (!allowedTypes.includes(avatarFile.type)) {
15541
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15786
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15542
15787
  type: "error",
15543
15788
  message: "Please upload a valid image file (JPEG, PNG, GIF, or WebP).",
15544
15789
  dismissible: true
@@ -15546,7 +15791,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15546
15791
  }
15547
15792
  const maxSize = 5 * 1024 * 1024;
15548
15793
  if (avatarFile.size > maxSize) {
15549
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15794
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15550
15795
  type: "error",
15551
15796
  message: "Image file must be smaller than 5MB.",
15552
15797
  dismissible: true
@@ -15562,7 +15807,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15562
15807
  SELECT first_name, last_name FROM auth_user WHERE id = ?
15563
15808
  `);
15564
15809
  const userData = await userStmt.bind(user.userId).first();
15565
- await chunk37V3RET3_cjs.logActivity(
15810
+ await chunkE7E3NL3Y_cjs.logActivity(
15566
15811
  db,
15567
15812
  user.userId,
15568
15813
  "profile.avatar_update",
@@ -15572,7 +15817,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15572
15817
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
15573
15818
  c.req.header("user-agent")
15574
15819
  );
15575
- const alertHtml = chunkJMJM7DMM_cjs.renderAlert({
15820
+ const alertHtml = chunkTT3TQSCZ_cjs.renderAlert({
15576
15821
  type: "success",
15577
15822
  message: "Profile picture updated successfully!",
15578
15823
  dismissible: true
@@ -15586,7 +15831,7 @@ userRoutes.post("/profile/avatar", async (c) => {
15586
15831
  return c.html(alertHtml + avatarImageWithOob);
15587
15832
  } catch (error) {
15588
15833
  console.error("Avatar upload error:", error);
15589
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15834
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15590
15835
  type: "error",
15591
15836
  message: "Failed to upload profile picture. Please try again.",
15592
15837
  dismissible: true
@@ -15602,21 +15847,21 @@ userRoutes.post("/profile/password", async (c) => {
15602
15847
  const newPassword = formData.get("new_password")?.toString() || "";
15603
15848
  const confirmPassword = formData.get("confirm_password")?.toString() || "";
15604
15849
  if (!currentPassword || !newPassword || !confirmPassword) {
15605
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15850
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15606
15851
  type: "error",
15607
15852
  message: "All password fields are required.",
15608
15853
  dismissible: true
15609
15854
  }));
15610
15855
  }
15611
15856
  if (newPassword !== confirmPassword) {
15612
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15857
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15613
15858
  type: "error",
15614
15859
  message: "New passwords do not match.",
15615
15860
  dismissible: true
15616
15861
  }));
15617
15862
  }
15618
15863
  if (newPassword.length < 8) {
15619
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15864
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15620
15865
  type: "error",
15621
15866
  message: "New password must be at least 8 characters long.",
15622
15867
  dismissible: true
@@ -15627,21 +15872,21 @@ userRoutes.post("/profile/password", async (c) => {
15627
15872
  `);
15628
15873
  const userData = await userStmt.bind(user.userId).first();
15629
15874
  if (!userData) {
15630
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15875
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15631
15876
  type: "error",
15632
15877
  message: "User not found.",
15633
15878
  dismissible: true
15634
15879
  }));
15635
15880
  }
15636
- const validPassword = await chunk37V3RET3_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
15881
+ const validPassword = await chunkE7E3NL3Y_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
15637
15882
  if (!validPassword) {
15638
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15883
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15639
15884
  type: "error",
15640
15885
  message: "Current password is incorrect.",
15641
15886
  dismissible: true
15642
15887
  }));
15643
15888
  }
15644
- const newPasswordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(newPassword);
15889
+ const newPasswordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(newPassword);
15645
15890
  const historyStmt = db.prepare(`
15646
15891
  INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
15647
15892
  VALUES (?, ?, ?, ?)
@@ -15657,7 +15902,7 @@ userRoutes.post("/profile/password", async (c) => {
15657
15902
  WHERE id = ?
15658
15903
  `);
15659
15904
  await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
15660
- await chunk37V3RET3_cjs.logActivity(
15905
+ await chunkE7E3NL3Y_cjs.logActivity(
15661
15906
  db,
15662
15907
  user.userId,
15663
15908
  "profile.password_change",
@@ -15667,14 +15912,14 @@ userRoutes.post("/profile/password", async (c) => {
15667
15912
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
15668
15913
  c.req.header("user-agent")
15669
15914
  );
15670
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15915
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15671
15916
  type: "success",
15672
15917
  message: "Password updated successfully!",
15673
15918
  dismissible: true
15674
15919
  }));
15675
15920
  } catch (error) {
15676
15921
  console.error("Password change error:", error);
15677
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
15922
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15678
15923
  type: "error",
15679
15924
  message: "Failed to update password. Please try again.",
15680
15925
  dismissible: true
@@ -15724,7 +15969,7 @@ userRoutes.get("/users", async (c) => {
15724
15969
  `);
15725
15970
  const countResult = await countStmt.bind(...params).first();
15726
15971
  const totalUsers = countResult?.total || 0;
15727
- await chunk37V3RET3_cjs.logActivity(
15972
+ await chunkE7E3NL3Y_cjs.logActivity(
15728
15973
  db,
15729
15974
  user.userId,
15730
15975
  "users.list_view",
@@ -15795,7 +16040,7 @@ userRoutes.get("/users", async (c) => {
15795
16040
  if (isApiRequest) {
15796
16041
  return c.json({ error: "Failed to load users" }, 500);
15797
16042
  }
15798
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16043
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15799
16044
  type: "error",
15800
16045
  message: "Failed to load users. Please try again.",
15801
16046
  dismissible: true
@@ -15814,8 +16059,9 @@ userRoutes.get("/users/new", async (c) => {
15814
16059
  const regFieldNames = profileConfig?.registrationFields ?? [];
15815
16060
  const regFields = profileConfig && upRow ? regFieldNames.length > 0 ? profileConfig.fields.filter((f) => regFieldNames.includes(f.name)) : profileConfig.fields : [];
15816
16061
  const registrationFieldsHtml = regFields.length > 0 ? renderCustomProfileSection({ fields: regFields }, {}) : void 0;
16062
+ const roles = await fetchRoleOptions(db);
15817
16063
  const pageData = {
15818
- roles: ROLES,
16064
+ roles,
15819
16065
  registrationFieldsHtml,
15820
16066
  user: {
15821
16067
  name: user.email.split("@")[0] || user.email,
@@ -15826,7 +16072,7 @@ userRoutes.get("/users/new", async (c) => {
15826
16072
  return c.html(renderUserNewPage(pageData));
15827
16073
  } catch (error) {
15828
16074
  console.error("User new page error:", error);
15829
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16075
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15830
16076
  type: "error",
15831
16077
  message: "Failed to load user creation page. Please try again.",
15832
16078
  dismissible: true
@@ -15843,9 +16089,9 @@ userRoutes.post("/users/new", async (c) => {
15843
16089
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
15844
16090
  const phone = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
15845
16091
  const bio = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
15846
- const roleInput = formData.get("role")?.toString() || "viewer";
15847
- const validRoles = ["admin", "editor", "author", "viewer"];
15848
- const role = validRoles.includes(roleInput) ? roleInput : "viewer";
16092
+ const roleInput = formData.get("role")?.toString() || "";
16093
+ const validRoles = (await new chunkJCBDXEY2_cjs.RbacService(db).getRoles()).map((r) => r.id);
16094
+ const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
15849
16095
  const password = formData.get("password")?.toString() || "";
15850
16096
  const confirmPassword = formData.get("confirm_password")?.toString() || "";
15851
16097
  const isActive = formData.get("is_active") === "1";
@@ -15860,12 +16106,12 @@ userRoutes.post("/users/new", async (c) => {
15860
16106
  const validation = validateCustomData(sanitized, profileConfig);
15861
16107
  if (!validation.valid) {
15862
16108
  const errorMessages = Object.values(validation.errors).join(", ");
15863
- return c.html(chunkJMJM7DMM_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
16109
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
15864
16110
  }
15865
16111
  sanitizedRegistrationCustom = sanitized;
15866
16112
  }
15867
16113
  if (!firstName || !lastName || !email || !password) {
15868
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16114
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15869
16115
  type: "error",
15870
16116
  message: "First name, last name, email, and password are required.",
15871
16117
  dismissible: true
@@ -15873,21 +16119,21 @@ userRoutes.post("/users/new", async (c) => {
15873
16119
  }
15874
16120
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
15875
16121
  if (!emailRegex.test(email)) {
15876
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16122
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15877
16123
  type: "error",
15878
16124
  message: "Please enter a valid email address.",
15879
16125
  dismissible: true
15880
16126
  }));
15881
16127
  }
15882
16128
  if (password.length < 8) {
15883
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16129
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15884
16130
  type: "error",
15885
16131
  message: "Password must be at least 8 characters long.",
15886
16132
  dismissible: true
15887
16133
  }));
15888
16134
  }
15889
16135
  if (password !== confirmPassword) {
15890
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16136
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15891
16137
  type: "error",
15892
16138
  message: "Passwords do not match.",
15893
16139
  dismissible: true
@@ -15899,13 +16145,13 @@ userRoutes.post("/users/new", async (c) => {
15899
16145
  `);
15900
16146
  const existingUser = await checkStmt.bind(email).first();
15901
16147
  if (existingUser) {
15902
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16148
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15903
16149
  type: "error",
15904
16150
  message: "Email is already taken.",
15905
16151
  dismissible: true
15906
16152
  }));
15907
16153
  }
15908
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(password);
16154
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
15909
16155
  const userId = crypto.randomUUID();
15910
16156
  const createStmt = db.prepare(`
15911
16157
  INSERT INTO auth_user (
@@ -15930,7 +16176,7 @@ userRoutes.post("/users/new", async (c) => {
15930
16176
  if (sanitizedRegistrationCustom !== null && Object.keys(sanitizedRegistrationCustom).length > 0) {
15931
16177
  await writeProfileData(db, userId, { custom: sanitizedRegistrationCustom }, user.userId);
15932
16178
  }
15933
- await chunk37V3RET3_cjs.logActivity(
16179
+ await chunkE7E3NL3Y_cjs.logActivity(
15934
16180
  db,
15935
16181
  user.userId,
15936
16182
  "user!.create",
@@ -15944,7 +16190,7 @@ userRoutes.post("/users/new", async (c) => {
15944
16190
  return c.body(null, 200);
15945
16191
  } catch (error) {
15946
16192
  console.error("User creation error:", error);
15947
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16193
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
15948
16194
  type: "error",
15949
16195
  message: "Failed to create user!. Please try again.",
15950
16196
  dismissible: true
@@ -15969,7 +16215,7 @@ userRoutes.get("/users/:id", async (c) => {
15969
16215
  if (!userRecord) {
15970
16216
  return c.json({ error: "User not found" }, 404);
15971
16217
  }
15972
- await chunk37V3RET3_cjs.logActivity(
16218
+ await chunkE7E3NL3Y_cjs.logActivity(
15973
16219
  db,
15974
16220
  user.userId,
15975
16221
  "user!.view",
@@ -16014,7 +16260,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
16014
16260
  `);
16015
16261
  const userToEdit = await userStmt.bind(userId).first();
16016
16262
  if (!userToEdit) {
16017
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16263
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16018
16264
  type: "error",
16019
16265
  message: "User not found",
16020
16266
  dismissible: true
@@ -16067,9 +16313,10 @@ userRoutes.get("/users/:id/edit", async (c) => {
16067
16313
  }
16068
16314
  const queryMessage = c.req.query("message");
16069
16315
  const queryType = c.req.query("type") === "error" ? "error" : "success";
16316
+ const roles = await fetchRoleOptions(db);
16070
16317
  const pageData = {
16071
16318
  userToEdit: editData,
16072
- roles: ROLES,
16319
+ roles,
16073
16320
  hasProfilePlugin: profileConfig !== null && upRow !== null,
16074
16321
  customProfileFieldsHtml,
16075
16322
  tenantMemberships,
@@ -16084,7 +16331,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
16084
16331
  return c.html(renderUserEditPage(pageData));
16085
16332
  } catch (error) {
16086
16333
  console.error("User edit page error:", error);
16087
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16334
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16088
16335
  type: "error",
16089
16336
  message: "Failed to load user. Please try again.",
16090
16337
  dismissible: true
@@ -16101,9 +16348,9 @@ userRoutes.put("/users/:id", async (c) => {
16101
16348
  const lastName = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("last_name")?.toString());
16102
16349
  const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
16103
16350
  const phone = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
16104
- const roleInput = formData.get("role")?.toString() || "viewer";
16105
- const validRoles = ["admin", "editor", "author", "viewer"];
16106
- const role = validRoles.includes(roleInput) ? roleInput : "viewer";
16351
+ const roleInput = formData.get("role")?.toString() || "";
16352
+ const validRoles = (await new chunkJCBDXEY2_cjs.RbacService(db).getRoles()).map((r) => r.id);
16353
+ const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
16107
16354
  const isActive = formData.get("is_active") === "1";
16108
16355
  const emailVerified = formData.get("email_verified") === "1";
16109
16356
  const newPassword = formData.get("new_password")?.toString() || "";
@@ -16117,12 +16364,12 @@ userRoutes.put("/users/:id", async (c) => {
16117
16364
  const validation = validateCustomData(sanitized, profileConfig);
16118
16365
  if (!validation.valid) {
16119
16366
  const errorMessages = Object.values(validation.errors).join(", ");
16120
- return c.html(chunkJMJM7DMM_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
16367
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
16121
16368
  }
16122
16369
  sanitizedCustom = sanitized;
16123
16370
  }
16124
16371
  if (!email) {
16125
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16372
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16126
16373
  type: "error",
16127
16374
  message: "Email is required.",
16128
16375
  dismissible: true
@@ -16130,7 +16377,7 @@ userRoutes.put("/users/:id", async (c) => {
16130
16377
  }
16131
16378
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
16132
16379
  if (!emailRegex.test(email)) {
16133
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16380
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16134
16381
  type: "error",
16135
16382
  message: "Please enter a valid email address.",
16136
16383
  dismissible: true
@@ -16138,14 +16385,14 @@ userRoutes.put("/users/:id", async (c) => {
16138
16385
  }
16139
16386
  if (newPassword) {
16140
16387
  if (newPassword.length < 8) {
16141
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16388
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16142
16389
  type: "error",
16143
16390
  message: "Password must be at least 8 characters long.",
16144
16391
  dismissible: true
16145
16392
  }));
16146
16393
  }
16147
16394
  if (newPassword !== confirmPassword) {
16148
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16395
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16149
16396
  type: "error",
16150
16397
  message: "Passwords do not match.",
16151
16398
  dismissible: true
@@ -16158,7 +16405,7 @@ userRoutes.put("/users/:id", async (c) => {
16158
16405
  `);
16159
16406
  const existingUser = await checkStmt.bind(email, userId).first();
16160
16407
  if (existingUser) {
16161
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16408
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16162
16409
  type: "error",
16163
16410
  message: "Email is already taken by another user.",
16164
16411
  dismissible: true
@@ -16183,7 +16430,7 @@ userRoutes.put("/users/:id", async (c) => {
16183
16430
  userId
16184
16431
  ).run();
16185
16432
  if (newPassword) {
16186
- const passwordHash = await chunk37V3RET3_cjs.AuthManager.hashPassword(newPassword);
16433
+ const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(newPassword);
16187
16434
  const updatePasswordStmt = db.prepare(`
16188
16435
  UPDATE auth_user SET password_hash = ?, updated_at = ? WHERE id = ?
16189
16436
  `);
@@ -16196,7 +16443,7 @@ userRoutes.put("/users/:id", async (c) => {
16196
16443
  ...sanitizedCustom !== null ? { custom: sanitizedCustom } : {}
16197
16444
  }, user.userId);
16198
16445
  }
16199
- await chunk37V3RET3_cjs.logActivity(
16446
+ await chunkE7E3NL3Y_cjs.logActivity(
16200
16447
  db,
16201
16448
  user.userId,
16202
16449
  "user.update",
@@ -16206,7 +16453,7 @@ userRoutes.put("/users/:id", async (c) => {
16206
16453
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
16207
16454
  c.req.header("user-agent")
16208
16455
  );
16209
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16456
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16210
16457
  type: "success",
16211
16458
  message: "User updated successfully!",
16212
16459
  dismissible: true,
@@ -16214,7 +16461,7 @@ userRoutes.put("/users/:id", async (c) => {
16214
16461
  }));
16215
16462
  } catch (error) {
16216
16463
  console.error("User update error:", error);
16217
- return c.html(chunkJMJM7DMM_cjs.renderAlert({
16464
+ return c.html(chunkTT3TQSCZ_cjs.renderAlert({
16218
16465
  type: "error",
16219
16466
  message: "Failed to update user. Please try again.",
16220
16467
  dismissible: true
@@ -16242,7 +16489,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
16242
16489
  UPDATE auth_user SET is_active = ?, updated_at = ? WHERE id = ?
16243
16490
  `);
16244
16491
  await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
16245
- await chunk37V3RET3_cjs.logActivity(
16492
+ await chunkE7E3NL3Y_cjs.logActivity(
16246
16493
  db,
16247
16494
  user.userId,
16248
16495
  active ? "user.activate" : "user.deactivate",
@@ -16283,7 +16530,7 @@ userRoutes.delete("/users/:id", async (c) => {
16283
16530
  DELETE FROM auth_user WHERE id = ?
16284
16531
  `);
16285
16532
  await deleteStmt.bind(userId).run();
16286
- await chunk37V3RET3_cjs.logActivity(
16533
+ await chunkE7E3NL3Y_cjs.logActivity(
16287
16534
  db,
16288
16535
  user.userId,
16289
16536
  "user!.hard_delete",
@@ -16302,7 +16549,7 @@ userRoutes.delete("/users/:id", async (c) => {
16302
16549
  UPDATE auth_user SET is_active = 0, updated_at = ? WHERE id = ?
16303
16550
  `);
16304
16551
  await deleteStmt.bind(Date.now(), userId).run();
16305
- await chunk37V3RET3_cjs.logActivity(
16552
+ await chunkE7E3NL3Y_cjs.logActivity(
16306
16553
  db,
16307
16554
  user.userId,
16308
16555
  "user!.soft_delete",
@@ -16368,7 +16615,7 @@ userRoutes.post("/invite-user", async (c) => {
16368
16615
  Date.now(),
16369
16616
  Date.now()
16370
16617
  ).run();
16371
- await chunk37V3RET3_cjs.logActivity(
16618
+ await chunkE7E3NL3Y_cjs.logActivity(
16372
16619
  db,
16373
16620
  user.userId,
16374
16621
  "user!.invite_sent",
@@ -16425,7 +16672,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
16425
16672
  Date.now(),
16426
16673
  userId
16427
16674
  ).run();
16428
- await chunk37V3RET3_cjs.logActivity(
16675
+ await chunkE7E3NL3Y_cjs.logActivity(
16429
16676
  db,
16430
16677
  user.userId,
16431
16678
  "user!.invitation_resent",
@@ -16461,7 +16708,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
16461
16708
  }
16462
16709
  const deleteStmt = db.prepare(`DELETE FROM auth_user WHERE id = ?`);
16463
16710
  await deleteStmt.bind(userId).run();
16464
- await chunk37V3RET3_cjs.logActivity(
16711
+ await chunkE7E3NL3Y_cjs.logActivity(
16465
16712
  db,
16466
16713
  user.userId,
16467
16714
  "user!.invitation_cancelled",
@@ -16710,7 +16957,7 @@ function getFileIcon(mimeType) {
16710
16957
  }
16711
16958
 
16712
16959
  // src/templates/pages/admin-media-library.template.ts
16713
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
16960
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
16714
16961
  function renderMediaLibraryPage(data) {
16715
16962
  const pageContent = `
16716
16963
  <div>
@@ -17645,7 +17892,7 @@ function renderMediaLibraryPage(data) {
17645
17892
  version: data.version,
17646
17893
  content: pageContent
17647
17894
  };
17648
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
17895
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
17649
17896
  }
17650
17897
 
17651
17898
  // src/templates/components/media-file-details.template.ts
@@ -17842,7 +18089,7 @@ var fileValidationSchema2 = zod.z.object({
17842
18089
  // 50MB max
17843
18090
  });
17844
18091
  var adminMediaRoutes = new hono.Hono();
17845
- adminMediaRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
18092
+ adminMediaRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
17846
18093
  adminMediaRoutes.get("/", async (c) => {
17847
18094
  try {
17848
18095
  const user = c.get("user");
@@ -17884,7 +18131,7 @@ adminMediaRoutes.get("/selector", async (c) => {
17884
18131
  const { searchParams } = new URL(c.req.url);
17885
18132
  const search = searchParams.get("search") || "";
17886
18133
  const db = c.env.DB;
17887
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
18134
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
17888
18135
  const mediaPlugin = await pluginService.getPlugin("core-media");
17889
18136
  if (!mediaPlugin || mediaPlugin.status !== "active") {
17890
18137
  return c.html(html.html`
@@ -18260,7 +18507,7 @@ adminMediaRoutes.put("/:id", async (c) => {
18260
18507
  `);
18261
18508
  }
18262
18509
  });
18263
- adminMediaRoutes.delete("/cleanup", chunk37V3RET3_cjs.requireRole("admin"), async (c) => {
18510
+ adminMediaRoutes.delete("/cleanup", chunkE7E3NL3Y_cjs.requireRole("admin"), async (c) => {
18264
18511
  try {
18265
18512
  const db = c.env.DB;
18266
18513
  const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
@@ -18518,7 +18765,7 @@ function generateMediaItemHTML(file) {
18518
18765
  }
18519
18766
 
18520
18767
  // src/templates/pages/admin-plugins-list.template.ts
18521
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
18768
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
18522
18769
  function renderPluginsListPage(data) {
18523
18770
  const categories = [
18524
18771
  { value: "content", label: "Content Management" },
@@ -18690,15 +18937,6 @@ function renderPluginsListPage(data) {
18690
18937
  </div>
18691
18938
 
18692
18939
  <div class="flex items-center gap-3 w-full sm:w-auto">
18693
- <select id="sort-filter" onchange="filterAndSortPlugins()" class="block w-full sm:w-auto h-9 rounded-md border-0 py-1.5 pl-3 pr-8 text-zinc-900 ring-1 ring-inset ring-zinc-300 focus:ring-2 focus:ring-inset focus:ring-zinc-600 dark:bg-zinc-900 dark:text-white dark:ring-zinc-700 dark:focus:ring-zinc-500 sm:text-sm sm:leading-6">
18694
- <option value="name-asc">Name (A-Z)</option>
18695
- <option value="name-desc">Name (Z-A)</option>
18696
- <option value="newest">Newest Installed</option>
18697
- <option value="updated">Recently Updated</option>
18698
- <option value="popular">Popularity</option>
18699
- <option value="rating">Highest Rated</option>
18700
- </select>
18701
-
18702
18940
  <button
18703
18941
  onclick="location.reload()"
18704
18942
  class="inline-flex items-center gap-x-1.5 rounded-md bg-white dark:bg-zinc-900 px-3 py-1.5 h-9 text-sm font-semibold text-zinc-900 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-800"
@@ -18862,8 +19100,6 @@ function renderPluginsListPage(data) {
18862
19100
  .forEach(cb => params.append('status', cb.value));
18863
19101
  const search = document.getElementById('search-input').value;
18864
19102
  if (search) params.set('search', search);
18865
- const sort = document.getElementById('sort-filter').value;
18866
- if (sort && sort !== 'name-asc') params.set('sort', sort);
18867
19103
  const url = new URL(window.location.href);
18868
19104
  url.search = params.toString();
18869
19105
  history.replaceState(null, '', url.toString());
@@ -18881,8 +19117,6 @@ function renderPluginsListPage(data) {
18881
19117
  });
18882
19118
  const search = params.get('search');
18883
19119
  if (search) document.getElementById('search-input').value = search;
18884
- const sort = params.get('sort');
18885
- if (sort) document.getElementById('sort-filter').value = sort;
18886
19120
  if (params.toString()) filterAndSortPlugins();
18887
19121
  }
18888
19122
 
@@ -18898,7 +19132,6 @@ function renderPluginsListPage(data) {
18898
19132
  .map(cb => cb.value.toLowerCase());
18899
19133
 
18900
19134
  const searchInput = document.getElementById('search-input').value.toLowerCase();
18901
- const sortValue = document.getElementById('sort-filter').value;
18902
19135
 
18903
19136
  const pluginsGrid = document.getElementById('plugins-grid');
18904
19137
  const pluginCards = Array.from(pluginsGrid.querySelectorAll('.plugin-card'));
@@ -18922,30 +19155,6 @@ function renderPluginsListPage(data) {
18922
19155
  return true;
18923
19156
  });
18924
19157
 
18925
- // Sort
18926
- visibleCards.sort((a, b) => {
18927
- const aName = a.getAttribute('data-name') || '';
18928
- const bName = b.getAttribute('data-name') || '';
18929
- const aInstalled = parseInt(a.getAttribute('data-installed') || '0');
18930
- const bInstalled = parseInt(b.getAttribute('data-installed') || '0');
18931
- const aUpdated = parseInt(a.getAttribute('data-updated') || '0');
18932
- const bUpdated = parseInt(b.getAttribute('data-updated') || '0');
18933
- const aDownloads = parseInt(a.getAttribute('data-downloads') || '0');
18934
- const bDownloads = parseInt(b.getAttribute('data-downloads') || '0');
18935
- const aRating = parseFloat(a.getAttribute('data-rating') || '0');
18936
- const bRating = parseFloat(b.getAttribute('data-rating') || '0');
18937
-
18938
- switch (sortValue) {
18939
- case 'name-desc': return bName.localeCompare(aName);
18940
- case 'newest': return bInstalled - aInstalled;
18941
- case 'updated': return bUpdated - aUpdated;
18942
- case 'popular': return bDownloads - aDownloads;
18943
- case 'rating': return bRating - aRating;
18944
- case 'name-asc':
18945
- default: return aName.localeCompare(bName);
18946
- }
18947
- });
18948
-
18949
19158
  // Re-append
18950
19159
  pluginCards.forEach(card => card.style.display = 'none'); // Hide all first
18951
19160
 
@@ -19001,7 +19210,7 @@ function renderPluginsListPage(data) {
19001
19210
  version: data.version,
19002
19211
  content: pageContent
19003
19212
  };
19004
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
19213
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
19005
19214
  }
19006
19215
  function renderPluginCard(plugin) {
19007
19216
  const statusColors = {
@@ -19379,8 +19588,9 @@ function escapeHtmlAttr(value) {
19379
19588
  }
19380
19589
  function renderPluginSettingsPage(data) {
19381
19590
  const { plugin, activity = [], user, settingsTabData } = data;
19382
- const pluginDef = chunkBP52BFIV_cjs.getPluginDefinition(plugin.id || plugin.name);
19383
- const hasUserSettings = pluginDef?.settingsTabContent != null || Object.keys(plugin.settings || {}).some((k) => !k.startsWith("_"));
19591
+ const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(plugin.id || plugin.name);
19592
+ const pluginId = plugin.id || plugin.name;
19593
+ const hasUserSettings = pluginDef?.settingsTabContent != null || Object.keys(plugin.settings || {}).some((k) => !k.startsWith("_")) || hasCustomSettingsComponent(pluginId);
19384
19594
  const defaultTab = hasUserSettings ? "settings" : "info";
19385
19595
  const pageContent = `
19386
19596
  <div class="w-full px-4 sm:px-6 lg:px-8 py-6">
@@ -19545,9 +19755,28 @@ function renderPluginSettingsPage(data) {
19545
19755
  const form = document.getElementById('settings-form');
19546
19756
  const formData = new FormData(form);
19547
19757
  const isAuthPlugin = '${plugin.id}' === 'core-auth';
19758
+ const isOAuthPlugin = '${plugin.id}' === 'oauth-providers';
19548
19759
  let settings = {};
19549
19760
 
19550
- if (isAuthPlugin) {
19761
+ if (isOAuthPlugin) {
19762
+ // Build nested provider settings structure
19763
+ const getVal = id => (document.getElementById(id) || {}).value || '';
19764
+ const getChecked = id => !!(document.getElementById(id) || {}).checked;
19765
+ settings = {
19766
+ providers: {
19767
+ github: {
19768
+ clientId: getVal('oauth_github_clientId'),
19769
+ clientSecret: getVal('oauth_github_clientSecret'),
19770
+ enabled: getChecked('oauth_github_enabled'),
19771
+ },
19772
+ google: {
19773
+ clientId: getVal('oauth_google_clientId'),
19774
+ clientSecret: getVal('oauth_google_clientSecret'),
19775
+ enabled: getChecked('oauth_google_enabled'),
19776
+ },
19777
+ }
19778
+ };
19779
+ } else if (isAuthPlugin) {
19551
19780
  // Handle nested auth settings structure
19552
19781
  settings = {
19553
19782
  requiredFields: {},
@@ -19656,7 +19885,7 @@ function renderPluginSettingsPage(data) {
19656
19885
  user,
19657
19886
  content: pageContent
19658
19887
  };
19659
- return chunkE66UVONV_cjs.renderAdminLayout(layoutData);
19888
+ return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
19660
19889
  }
19661
19890
  function renderStatusBadge(status) {
19662
19891
  const statusColors = {
@@ -19685,7 +19914,7 @@ function renderSettingsTab(plugin, settingsTabData) {
19685
19914
  const settings = plugin.settings || {};
19686
19915
  const pluginId = plugin.id || plugin.name;
19687
19916
  const hasUserKeys = Object.keys(settings).some((k) => !k.startsWith("_"));
19688
- const pluginDef = chunkBP52BFIV_cjs.getPluginDefinition(pluginId);
19917
+ const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
19689
19918
  if (pluginDef?.settingsTabContent) {
19690
19919
  return pluginDef.settingsTabContent.render({ plugin, settings, data: settingsTabData });
19691
19920
  }
@@ -20035,7 +20264,8 @@ function formatTimestamp(timestamp) {
20035
20264
  }
20036
20265
  var pluginSettingsComponents = {
20037
20266
  "otp-login": renderOTPLoginSettingsContent,
20038
- "email": renderEmailSettingsContent
20267
+ "email": renderEmailSettingsContent,
20268
+ "oauth-providers": renderOAuthProvidersSettingsContent
20039
20269
  };
20040
20270
  function renderOTPLoginSettingsContent(plugin, settings) {
20041
20271
  const siteName = settings.siteName || "SonicJS";
@@ -20758,6 +20988,62 @@ defineUserProfile({
20758
20988
  </div>
20759
20989
  `;
20760
20990
  }
20991
+ function renderOAuthProvidersSettingsContent(plugin, settings) {
20992
+ const providers = settings.providers || {};
20993
+ const gh = providers.github || {};
20994
+ const gg = providers.google || {};
20995
+ const inputClass = "backdrop-blur-sm bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white placeholder-gray-300 focus:border-blue-400 focus:outline-none transition-colors w-full";
20996
+ return `
20997
+ <div class="space-y-6">
20998
+ <form id="settings-form">
20999
+ <div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6">
21000
+ <h3 class="text-lg font-semibold text-white">GitHub OAuth</h3>
21001
+ <div>
21002
+ <label for="oauth_github_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
21003
+ <input type="text" id="oauth_github_clientId" name="oauth_github_clientId"
21004
+ value="${escapeHtmlAttr(gh.clientId || "")}"
21005
+ placeholder="GitHub OAuth App Client ID" class="${inputClass}" />
21006
+ </div>
21007
+ <div>
21008
+ <label for="oauth_github_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
21009
+ <input type="password" id="oauth_github_clientSecret" name="oauth_github_clientSecret"
21010
+ value="${escapeHtmlAttr(gh.clientSecret || "")}"
21011
+ placeholder="GitHub OAuth App Client Secret" class="${inputClass}" />
21012
+ </div>
21013
+ <div class="flex items-center gap-3">
21014
+ <input type="checkbox" id="oauth_github_enabled" name="oauth_github_enabled"
21015
+ ${gh.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
21016
+ <label for="oauth_github_enabled" class="text-sm text-gray-300">Enable GitHub login</label>
21017
+ </div>
21018
+ </div>
21019
+
21020
+ <div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6 mt-6">
21021
+ <h3 class="text-lg font-semibold text-white">Google OAuth</h3>
21022
+ <div>
21023
+ <label for="oauth_google_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
21024
+ <input type="text" id="oauth_google_clientId" name="oauth_google_clientId"
21025
+ value="${escapeHtmlAttr(gg.clientId || "")}"
21026
+ placeholder="Google OAuth Client ID" class="${inputClass}" />
21027
+ </div>
21028
+ <div>
21029
+ <label for="oauth_google_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
21030
+ <input type="password" id="oauth_google_clientSecret" name="oauth_google_clientSecret"
21031
+ value="${escapeHtmlAttr(gg.clientSecret || "")}"
21032
+ placeholder="Google OAuth Client Secret" class="${inputClass}" />
21033
+ </div>
21034
+ <div class="flex items-center gap-3">
21035
+ <input type="checkbox" id="oauth_google_enabled" name="oauth_google_enabled"
21036
+ ${gg.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
21037
+ <label for="oauth_google_enabled" class="text-sm text-gray-300">Enable Google login</label>
21038
+ </div>
21039
+ </div>
21040
+ </form>
21041
+ </div>
21042
+ `;
21043
+ }
21044
+ function hasCustomSettingsComponent(pluginId) {
21045
+ return pluginId in pluginSettingsComponents;
21046
+ }
20761
21047
 
20762
21048
  // src/plugins/core-plugins/menu-plugin/services/menu-reconcile.ts
20763
21049
  async function upsertPluginRow(db, slug, entry, visible) {
@@ -20875,8 +21161,8 @@ async function fetchActivePluginIds(db) {
20875
21161
  }
20876
21162
  async function reconcileMenuFromPlugins(db) {
20877
21163
  try {
20878
- const singletonEntries = chunkBP52BFIV_cjs.getPluginMenu();
20879
- const manifestEntries = Object.values(chunkQCJHCSOK_cjs.PLUGIN_REGISTRY).filter(
21164
+ const singletonEntries = chunkD6FWEYQE_cjs.getPluginMenu();
21165
+ const manifestEntries = Object.values(chunkYAURVGUK_cjs.PLUGIN_REGISTRY).filter(
20880
21166
  (p) => p.adminMenu !== null
20881
21167
  );
20882
21168
  const byPluginId = /* @__PURE__ */ new Map();
@@ -20913,8 +21199,8 @@ async function reconcileMenuFromPlugins(db) {
20913
21199
 
20914
21200
  // src/routes/admin-plugins.ts
20915
21201
  var adminPluginRoutes = new hono.Hono();
20916
- adminPluginRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
20917
- var AVAILABLE_PLUGINS = Object.values(chunkQCJHCSOK_cjs.PLUGIN_REGISTRY).map((p) => ({
21202
+ adminPluginRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
21203
+ var AVAILABLE_PLUGINS = Object.values(chunkYAURVGUK_cjs.PLUGIN_REGISTRY).map((p) => ({
20918
21204
  id: p.id,
20919
21205
  name: p.codeName,
20920
21206
  display_name: p.displayName,
@@ -20934,7 +21220,7 @@ adminPluginRoutes.get("/", async (c) => {
20934
21220
  if (user?.role !== "admin") {
20935
21221
  return c.text("Access denied", 403);
20936
21222
  }
20937
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21223
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
20938
21224
  let installedPlugins = [];
20939
21225
  let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
20940
21226
  try {
@@ -21008,10 +21294,10 @@ adminPluginRoutes.get("/:id", async (c) => {
21008
21294
  if (user?.role !== "admin") {
21009
21295
  return c.redirect("/admin/plugins");
21010
21296
  }
21011
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21297
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21012
21298
  let plugin = await pluginService.getPlugin(pluginId);
21013
21299
  if (!plugin) {
21014
- const def = chunkBP52BFIV_cjs.getPluginDefinition(pluginId);
21300
+ const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
21015
21301
  if (!def) return c.text("Plugin not found", 404);
21016
21302
  plugin = await pluginService.ensurePlugin(pluginId, {
21017
21303
  displayName: def.displayName ?? pluginId,
@@ -21082,7 +21368,7 @@ adminPluginRoutes.get("/:id", async (c) => {
21082
21368
  timestamp: item.timestamp,
21083
21369
  user: item.userId || null
21084
21370
  }));
21085
- const pluginDef = chunkBP52BFIV_cjs.getPluginDefinition(pluginId);
21371
+ const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
21086
21372
  let settingsTabData = void 0;
21087
21373
  if (pluginDef?.settingsTabContent?.loadData) {
21088
21374
  try {
@@ -21112,14 +21398,14 @@ adminPluginRoutes.get("/:id/configure", async (c) => {
21112
21398
  const user = c.get("user");
21113
21399
  const pluginId = c.req.param("id");
21114
21400
  if (user?.role !== "admin") return c.redirect("/admin/plugins");
21115
- const def = chunkBP52BFIV_cjs.getPluginDefinition(pluginId);
21401
+ const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
21116
21402
  if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
21117
21403
  const db = c.env.DB;
21118
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21404
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21119
21405
  const plugin = await pluginService.getPlugin(pluginId);
21120
21406
  const stored = plugin?.settings ?? {};
21121
- const values = chunkBP52BFIV_cjs.applySchemaDefaults(def.configSchema, stored);
21122
- const fieldsHtml = chunkBP52BFIV_cjs.renderSchemaFields(def.configSchema, values);
21407
+ const values = chunkD6FWEYQE_cjs.applySchemaDefaults(def.configSchema, stored);
21408
+ const fieldsHtml = chunkD6FWEYQE_cjs.renderSchemaFields(def.configSchema, values);
21123
21409
  const displayName = plugin?.display_name ?? def.displayName ?? def.id;
21124
21410
  return c.html(`<!DOCTYPE html>
21125
21411
  <html lang="en"><head>
@@ -21146,12 +21432,12 @@ adminPluginRoutes.post("/:id/configure", async (c) => {
21146
21432
  const user = c.get("user");
21147
21433
  const pluginId = c.req.param("id");
21148
21434
  if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
21149
- const def = chunkBP52BFIV_cjs.getPluginDefinition(pluginId);
21435
+ const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
21150
21436
  if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
21151
21437
  const form = await c.req.formData();
21152
- const parsed = chunkBP52BFIV_cjs.parseFormDataToSettings(def.configSchema, form);
21438
+ const parsed = chunkD6FWEYQE_cjs.parseFormDataToSettings(def.configSchema, form);
21153
21439
  const db = c.env.DB;
21154
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21440
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21155
21441
  await pluginService.ensurePlugin(pluginId, {
21156
21442
  displayName: def.displayName ?? pluginId,
21157
21443
  version: def.version,
@@ -21175,7 +21461,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
21175
21461
  if (user?.role !== "admin") {
21176
21462
  return c.json({ error: "Access denied" }, 403);
21177
21463
  }
21178
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21464
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21179
21465
  await pluginService.activatePlugin(pluginId);
21180
21466
  await reconcileMenuFromPlugins(db);
21181
21467
  return c.json({ success: true });
@@ -21193,7 +21479,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
21193
21479
  if (user?.role !== "admin") {
21194
21480
  return c.json({ error: "Access denied" }, 403);
21195
21481
  }
21196
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21482
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21197
21483
  await pluginService.deactivatePlugin(pluginId);
21198
21484
  await reconcileMenuFromPlugins(db);
21199
21485
  return c.json({ success: true });
@@ -21211,8 +21497,8 @@ adminPluginRoutes.post("/install", async (c) => {
21211
21497
  return c.json({ error: "Access denied" }, 403);
21212
21498
  }
21213
21499
  const body = await c.req.json();
21214
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21215
- const registryEntry = chunkQCJHCSOK_cjs.findPluginByCodeName(body.name) || chunkQCJHCSOK_cjs.PLUGIN_REGISTRY[body.name] || chunkQCJHCSOK_cjs.PLUGIN_REGISTRY[body.id];
21500
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21501
+ const registryEntry = chunkYAURVGUK_cjs.findPluginByCodeName(body.name) || chunkYAURVGUK_cjs.PLUGIN_REGISTRY[body.name] || chunkYAURVGUK_cjs.PLUGIN_REGISTRY[body.id];
21216
21502
  if (!registryEntry) {
21217
21503
  return c.json({ error: "Plugin not found in registry" }, 404);
21218
21504
  }
@@ -21245,7 +21531,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
21245
21531
  if (user?.role !== "admin") {
21246
21532
  return c.json({ error: "Access denied" }, 403);
21247
21533
  }
21248
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21534
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21249
21535
  await pluginService.uninstallPlugin(pluginId);
21250
21536
  return c.json({ success: true });
21251
21537
  } catch (error) {
@@ -21263,7 +21549,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
21263
21549
  return c.json({ error: "Access denied" }, 403);
21264
21550
  }
21265
21551
  const settings = await c.req.json();
21266
- const pluginService = new chunkQCJHCSOK_cjs.PluginService(db);
21552
+ const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
21267
21553
  const existingPlugin = await pluginService.getPlugin(pluginId);
21268
21554
  const existingSettings = existingPlugin?.settings ?? {};
21269
21555
  await pluginService.updatePluginSettings(pluginId, { ...existingSettings, ...settings });
@@ -21298,7 +21584,7 @@ function formatLastUpdated(timestamp) {
21298
21584
  }
21299
21585
 
21300
21586
  // src/templates/pages/admin-logs-list.template.ts
21301
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
21587
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
21302
21588
  function renderLogsListPage(data) {
21303
21589
  const { logs, pagination, filters, user } = data;
21304
21590
  const content = `
@@ -21609,7 +21895,7 @@ function renderLogsListPage(data) {
21609
21895
  user,
21610
21896
  content
21611
21897
  };
21612
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
21898
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
21613
21899
  }
21614
21900
  function renderLogDetailsPage(data) {
21615
21901
  const { log, user } = data;
@@ -21821,7 +22107,7 @@ function renderLogDetailsPage(data) {
21821
22107
  </div>
21822
22108
  </div>
21823
22109
  `;
21824
- return chunkE66UVONV_cjs.adminLayoutV2({
22110
+ return chunkOUBUS74I_cjs.adminLayoutV2({
21825
22111
  title: `Log Details - ${log.id}`,
21826
22112
  user,
21827
22113
  content
@@ -22064,7 +22350,7 @@ function renderLogConfigPage(data) {
22064
22350
 
22065
22351
  <script src="https://unpkg.com/htmx.org@1.9.6"></script>
22066
22352
  `;
22067
- return chunkE66UVONV_cjs.adminLayoutV2({
22353
+ return chunkOUBUS74I_cjs.adminLayoutV2({
22068
22354
  title: "Log Configuration",
22069
22355
  user,
22070
22356
  content
@@ -22073,7 +22359,7 @@ function renderLogConfigPage(data) {
22073
22359
 
22074
22360
  // src/routes/admin-logs.ts
22075
22361
  var adminLogsRoutes = new hono.Hono();
22076
- adminLogsRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
22362
+ adminLogsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
22077
22363
  adminLogsRoutes.get("/", async (c) => {
22078
22364
  try {
22079
22365
  const user = c.get("user");
@@ -22445,7 +22731,7 @@ adminCheckboxRoutes.get("/", (c) => {
22445
22731
  role: user.role
22446
22732
  } : void 0
22447
22733
  };
22448
- return c.html(chunkE66UVONV_cjs.renderCheckboxPage(pageData));
22734
+ return c.html(chunkOUBUS74I_cjs.renderCheckboxPage(pageData));
22449
22735
  });
22450
22736
 
22451
22737
  // src/templates/pages/admin-dashboard.template.ts
@@ -22517,7 +22803,7 @@ function renderDashboardPage(data) {
22517
22803
  version: data.version,
22518
22804
  content: pageContent
22519
22805
  };
22520
- return chunkE66UVONV_cjs.renderAdminLayout(layoutData);
22806
+ return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
22521
22807
  }
22522
22808
  function renderStatsCards(stats) {
22523
22809
  const cards = [
@@ -23065,9 +23351,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
23065
23351
  }
23066
23352
 
23067
23353
  // src/routes/admin-dashboard.ts
23068
- var VERSION = chunkKKNEYIZJ_cjs.getCoreVersion();
23354
+ var VERSION = chunkBJ6NJL2E_cjs.getCoreVersion();
23069
23355
  var router = new hono.Hono();
23070
- router.use("*", chunk37V3RET3_cjs.requireAuth());
23356
+ router.use("*", chunkE7E3NL3Y_cjs.requireAuth());
23071
23357
  router.get("/", async (c) => {
23072
23358
  const user = c.get("user");
23073
23359
  try {
@@ -23257,7 +23543,7 @@ router.get("/system-status", async (c) => {
23257
23543
  });
23258
23544
 
23259
23545
  // src/templates/pages/admin-collections-list.template.ts
23260
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
23546
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
23261
23547
 
23262
23548
  // src/templates/components/table.template.ts
23263
23549
  function renderTable2(data) {
@@ -23739,11 +24025,11 @@ function renderCollectionsListPage(data) {
23739
24025
  version: data.version,
23740
24026
  content: pageContent
23741
24027
  };
23742
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
24028
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
23743
24029
  }
23744
24030
 
23745
24031
  // src/templates/pages/admin-collections-form.template.ts
23746
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
24032
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
23747
24033
  function getFieldTypeBadge(fieldType) {
23748
24034
  const typeLabels = {
23749
24035
  "text": "Text",
@@ -23916,8 +24202,8 @@ function renderCollectionFormPage(data) {
23916
24202
  <!-- Form Content -->
23917
24203
  <div class="px-6 py-6">
23918
24204
  <div id="form-messages"></div>
23919
- ${data.error ? chunkJMJM7DMM_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
23920
- ${data.success ? chunkJMJM7DMM_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
24205
+ ${data.error ? chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
24206
+ ${data.success ? chunkTT3TQSCZ_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
23921
24207
 
23922
24208
  <!-- Form Styling -->
23923
24209
  <style>
@@ -24028,7 +24314,7 @@ function renderCollectionFormPage(data) {
24028
24314
  }
24029
24315
  </style>
24030
24316
 
24031
- ${chunkE66UVONV_cjs.renderForm(formData)}
24317
+ ${chunkOUBUS74I_cjs.renderForm(formData)}
24032
24318
 
24033
24319
  ${isEdit && data.managed ? `
24034
24320
  <!-- Read-Only Fields Display for Managed Collections -->
@@ -25026,13 +25312,13 @@ function renderCollectionFormPage(data) {
25026
25312
  version: data.version,
25027
25313
  content: pageContent
25028
25314
  };
25029
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
25315
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
25030
25316
  }
25031
25317
 
25032
25318
  // src/routes/admin-collections.ts
25033
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
25319
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
25034
25320
  var adminCollectionsRoutes = new hono.Hono();
25035
- adminCollectionsRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
25321
+ adminCollectionsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
25036
25322
  adminCollectionsRoutes.get("/", async (c) => {
25037
25323
  try {
25038
25324
  const user = c.get("user");
@@ -25049,7 +25335,7 @@ adminCollectionsRoutes.get("/", async (c) => {
25049
25335
  results = queryResults.results ?? [];
25050
25336
  } catch (e) {
25051
25337
  }
25052
- const codeCollections = chunkQCJHCSOK_cjs.getCollectionRegistry().list();
25338
+ const codeCollections = chunkYAURVGUK_cjs.getCollectionRegistry().list();
25053
25339
  const codeCollectionsMap = new Map(
25054
25340
  codeCollections.map((cfg) => {
25055
25341
  const fieldCount = cfg.schema?.properties ? Object.keys(cfg.schema.properties).length : 0;
@@ -25063,7 +25349,7 @@ adminCollectionsRoutes.get("/", async (c) => {
25063
25349
  field_count: fieldCount,
25064
25350
  managed: cfg.managed !== false,
25065
25351
  source_type: "code",
25066
- internal: chunkQCJHCSOK_cjs.isCodeCollectionInternal(cfg),
25352
+ internal: chunkYAURVGUK_cjs.isCodeCollectionInternal(cfg),
25067
25353
  versioning: cfg.versioning === true
25068
25354
  }];
25069
25355
  })
@@ -25102,7 +25388,7 @@ adminCollectionsRoutes.get("/", async (c) => {
25102
25388
  field_count: fieldCount,
25103
25389
  managed: false,
25104
25390
  source_type: row.source === "code" || row.source === "system" || row.source === "plugin" ? "code" : "user",
25105
- internal: chunkQCJHCSOK_cjs.isDbDocTypeInternal(row.source),
25391
+ internal: chunkYAURVGUK_cjs.isDbDocTypeInternal(row.source),
25106
25392
  versioning: dbVersioning
25107
25393
  };
25108
25394
  });
@@ -25259,11 +25545,11 @@ export const myPlugin = definePlugin({
25259
25545
  `;
25260
25546
  const u = user;
25261
25547
  return c.html(
25262
- chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst({
25548
+ chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst({
25263
25549
  title: "Add a Collection",
25264
25550
  pageTitle: "Add a Collection",
25265
25551
  currentPath: "/admin/collections",
25266
- version: chunkKKNEYIZJ_cjs.getCoreVersion(),
25552
+ version: chunkBJ6NJL2E_cjs.getCoreVersion(),
25267
25553
  user: u ? { name: u.email ?? "Admin", email: u.email ?? "", role: u.role ?? "admin" } : void 0,
25268
25554
  content
25269
25555
  })
@@ -25280,7 +25566,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
25280
25566
  collection = await stmt.bind(id).first();
25281
25567
  } catch {
25282
25568
  }
25283
- const registryRecord = chunkQCJHCSOK_cjs.getCollectionRegistry().getById(id) ?? chunkQCJHCSOK_cjs.getCollectionRegistry().getByName(id);
25569
+ const registryRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getById(id) ?? chunkYAURVGUK_cjs.getCollectionRegistry().getByName(id);
25284
25570
  if (!collection && !registryRecord) {
25285
25571
  const formData2 = {
25286
25572
  isEdit: true,
@@ -25327,9 +25613,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
25327
25613
  isCodeDriven = true;
25328
25614
  }
25329
25615
  const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
25330
- chunk37V3RET3_cjs.isPluginActive(db, "tinymce-plugin"),
25331
- chunk37V3RET3_cjs.isPluginActive(db, "quill-editor"),
25332
- chunk37V3RET3_cjs.isPluginActive(db, "easy-mdx")
25616
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin"),
25617
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor"),
25618
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx")
25333
25619
  ]);
25334
25620
  const displayName = collection?.display_name ?? registryRecord?.displayName ?? id;
25335
25621
  const formData = {
@@ -25349,9 +25635,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
25349
25635
  console.error("Error fetching collection:", error);
25350
25636
  const user = c.get("user");
25351
25637
  const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
25352
- chunk37V3RET3_cjs.isPluginActive(db, "tinymce-plugin"),
25353
- chunk37V3RET3_cjs.isPluginActive(db, "quill-editor"),
25354
- chunk37V3RET3_cjs.isPluginActive(db, "easy-mdx")
25638
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin"),
25639
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor"),
25640
+ chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx")
25355
25641
  ]);
25356
25642
  const formData = {
25357
25643
  isEdit: true,
@@ -25365,7 +25651,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
25365
25651
  });
25366
25652
 
25367
25653
  // src/templates/pages/admin-settings.template.ts
25368
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
25654
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
25369
25655
  function renderSettingsPage(data) {
25370
25656
  const activeTab = data.activeTab || "general";
25371
25657
  const pageContent = `
@@ -25755,7 +26041,7 @@ function renderSettingsPage(data) {
25755
26041
  version: data.version,
25756
26042
  content: pageContent
25757
26043
  };
25758
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
26044
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
25759
26045
  }
25760
26046
  function renderTabButton(tabId, label, iconPath, activeTab) {
25761
26047
  const isActive = activeTab === tabId;
@@ -26300,7 +26586,7 @@ function renderDatabaseToolsSettings(settings) {
26300
26586
 
26301
26587
  // src/routes/admin-settings.ts
26302
26588
  var adminSettingsRoutes = new hono.Hono();
26303
- adminSettingsRoutes.use("*", chunk37V3RET3_cjs.requireAuth());
26589
+ adminSettingsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
26304
26590
  function getMockSettings(user) {
26305
26591
  return {
26306
26592
  general: {
@@ -26403,7 +26689,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
26403
26689
  adminSettingsRoutes.get("/api/migrations/status", async (c) => {
26404
26690
  try {
26405
26691
  const db = c.env.DB;
26406
- const migrationService = new chunkA2SN3RVL_cjs.MigrationService(db);
26692
+ const migrationService = new chunkMOGK3U4A_cjs.MigrationService(db);
26407
26693
  const status = await migrationService.getMigrationStatus();
26408
26694
  return c.json({
26409
26695
  success: true,
@@ -26443,7 +26729,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
26443
26729
  adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
26444
26730
  try {
26445
26731
  const db = c.env.DB;
26446
- const migrationService = new chunkA2SN3RVL_cjs.MigrationService(db);
26732
+ const migrationService = new chunkMOGK3U4A_cjs.MigrationService(db);
26447
26733
  const validation = await migrationService.validateSchema();
26448
26734
  return c.json({
26449
26735
  success: true,
@@ -26701,7 +26987,7 @@ adminSettingsRoutes.post("/", async (c) => {
26701
26987
  });
26702
26988
 
26703
26989
  // src/templates/pages/admin-api-reference.template.ts
26704
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
26990
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
26705
26991
  function renderAuthBadge(auth) {
26706
26992
  if (auth === true) {
26707
26993
  return `
@@ -27032,20 +27318,20 @@ function renderAPIReferencePage(data) {
27032
27318
  version: data.version,
27033
27319
  content: pageContent
27034
27320
  };
27035
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst(layoutData);
27321
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
27036
27322
  }
27037
27323
 
27038
27324
  // src/routes/admin-api-reference.ts
27039
- var VERSION2 = chunkKKNEYIZJ_cjs.getCoreVersion();
27325
+ var VERSION2 = chunkBJ6NJL2E_cjs.getCoreVersion();
27040
27326
  var router2 = new hono.Hono();
27041
- router2.use("*", chunk37V3RET3_cjs.requireAuth());
27327
+ router2.use("*", chunkE7E3NL3Y_cjs.requireAuth());
27042
27328
  router2.get("/", async (c) => {
27043
27329
  const user = c.get("user");
27044
27330
  try {
27045
27331
  const app2 = chunk36Z3AKX3_cjs.getAppInstance();
27046
27332
  const baseEndpoints = chunk36Z3AKX3_cjs.buildRouteList(app2);
27047
27333
  const collectionRoutes = [];
27048
- const collections = chunkQCJHCSOK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
27334
+ const collections = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
27049
27335
  const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
27050
27336
  for (const col of collections) {
27051
27337
  const displayName = col.displayName || col.name;
@@ -27166,5 +27452,5 @@ exports.test_cleanup_default = test_cleanup_default;
27166
27452
  exports.updateDocumentSchema = updateDocumentSchema;
27167
27453
  exports.userProfilesPlugin = userProfilesPlugin;
27168
27454
  exports.userRoutes = userRoutes;
27169
- //# sourceMappingURL=chunk-I767LVN7.cjs.map
27170
- //# sourceMappingURL=chunk-I767LVN7.cjs.map
27455
+ //# sourceMappingURL=chunk-6OA77UM7.cjs.map
27456
+ //# sourceMappingURL=chunk-6OA77UM7.cjs.map