@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.
- package/bin/db-reset.js +39 -22
- package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
- package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
- package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
- package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
- package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
- package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
- package/dist/{chunk-RJ2O5IIE.js → chunk-2D3A4X52.js} +2 -2
- package/dist/{chunk-RJ2O5IIE.js.map → chunk-2D3A4X52.js.map} +1 -1
- package/dist/{chunk-FHPEM77Y.js → chunk-2OXFMMA3.js} +11 -10
- package/dist/chunk-2OXFMMA3.js.map +1 -0
- package/dist/{chunk-SOZUG52O.js → chunk-3KGY4IBW.js} +3 -3
- package/dist/{chunk-SOZUG52O.js.map → chunk-3KGY4IBW.js.map} +1 -1
- package/dist/{chunk-I767LVN7.cjs → chunk-6OA77UM7.cjs} +757 -471
- package/dist/chunk-6OA77UM7.cjs.map +1 -0
- package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
- package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
- package/dist/{chunk-VC5XVPLM.js → chunk-7P5OCUPS.js} +424 -138
- package/dist/chunk-7P5OCUPS.js.map +1 -0
- package/dist/{chunk-3TMTYJAJ.js → chunk-BDQ55MWV.js} +18 -2
- package/dist/chunk-BDQ55MWV.js.map +1 -0
- package/dist/{chunk-KKNEYIZJ.cjs → chunk-BJ6NJL2E.cjs} +7 -12
- package/dist/chunk-BJ6NJL2E.cjs.map +1 -0
- package/dist/{chunk-VGEZNFWH.js → chunk-C54MH5UI.js} +5 -4
- package/dist/chunk-C54MH5UI.js.map +1 -0
- package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
- package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
- package/dist/{chunk-LNI3FYSI.js → chunk-CWIGQYRR.js} +7 -12
- package/dist/chunk-CWIGQYRR.js.map +1 -0
- package/dist/{chunk-BP52BFIV.cjs → chunk-D6FWEYQE.cjs} +6 -5
- package/dist/chunk-D6FWEYQE.cjs.map +1 -0
- package/dist/{chunk-UIHIXTIS.js → chunk-D7RLBBHE.js} +2 -2
- package/dist/{chunk-UIHIXTIS.js.map → chunk-D7RLBBHE.js.map} +1 -1
- package/dist/{chunk-IXUHXTHW.cjs → chunk-DLTT7QZU.cjs} +17 -6
- package/dist/chunk-DLTT7QZU.cjs.map +1 -0
- package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
- package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
- package/dist/{chunk-37V3RET3.cjs → chunk-E7E3NL3Y.cjs} +24 -23
- package/dist/chunk-E7E3NL3Y.cjs.map +1 -0
- package/dist/{chunk-VYQVDL2M.js → chunk-F26HP3B6.js} +36 -5
- package/dist/chunk-F26HP3B6.js.map +1 -0
- package/dist/{chunk-QZGABF2M.js → chunk-FVAK4C6L.js} +17 -6
- package/dist/chunk-FVAK4C6L.js.map +1 -0
- package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
- package/dist/chunk-HSDJDWLV.js.map +1 -0
- package/dist/{chunk-QJUJNTIU.cjs → chunk-I7MIRRFJ.cjs} +43 -12
- package/dist/chunk-I7MIRRFJ.cjs.map +1 -0
- package/dist/{chunk-LTZ5WYOK.cjs → chunk-JCBDXEY2.cjs} +18 -2
- package/dist/chunk-JCBDXEY2.cjs.map +1 -0
- package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
- package/dist/chunk-MI2YXCK4.cjs.map +1 -0
- package/dist/{chunk-A2SN3RVL.cjs → chunk-MOGK3U4A.cjs} +2 -2
- package/dist/{chunk-A2SN3RVL.cjs.map → chunk-MOGK3U4A.cjs.map} +1 -1
- package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
- package/dist/chunk-OUBUS74I.cjs.map +1 -0
- package/dist/{chunk-GMMCCIQO.cjs → chunk-RSBZITK3.cjs} +3 -3
- package/dist/{chunk-GMMCCIQO.cjs.map → chunk-RSBZITK3.cjs.map} +1 -1
- package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
- package/dist/chunk-SXC4HPK6.js.map +1 -0
- package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
- package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
- package/dist/{chunk-QCJHCSOK.cjs → chunk-YAURVGUK.cjs} +2 -2
- package/dist/{chunk-QCJHCSOK.cjs.map → chunk-YAURVGUK.cjs.map} +1 -1
- package/dist/config-4TIHSNW6.js +6 -0
- package/dist/{config-6FB2BXMP.js.map → config-4TIHSNW6.js.map} +1 -1
- package/dist/{config-OCH7S4WK.cjs → config-XN2ETAJ3.cjs} +5 -5
- package/dist/{config-OCH7S4WK.cjs.map → config-XN2ETAJ3.cjs.map} +1 -1
- package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
- package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
- package/dist/index.cjs +408 -370
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +67 -29
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +35 -35
- package/dist/middleware.d.cts +4 -1
- package/dist/middleware.d.ts +4 -1
- package/dist/middleware.js +6 -6
- package/dist/migrations-JAHMI5MK.js +4 -0
- package/dist/{migrations-Z6D27NAW.js.map → migrations-JAHMI5MK.js.map} +1 -1
- package/dist/migrations-KU4V6T73.cjs +13 -0
- package/dist/{migrations-FGXZPKDC.cjs.map → migrations-KU4V6T73.cjs.map} +1 -1
- package/dist/plugins.cjs +40 -40
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +3 -3
- package/dist/rbac-AORZ6O3N.cjs +14 -0
- package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-AORZ6O3N.cjs.map} +1 -1
- package/dist/rbac-P44772FP.js +5 -0
- package/dist/{rbac-Y43IEQOP.js.map → rbac-P44772FP.js.map} +1 -1
- package/dist/routes.cjs +31 -31
- package/dist/routes.js +11 -11
- package/dist/services.cjs +18 -18
- package/dist/services.d.cts +1 -1
- package/dist/services.d.ts +1 -1
- package/dist/services.js +2 -2
- package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
- package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
- package/dist/templates.cjs +17 -17
- package/dist/templates.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +12 -12
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -2
- package/package.json +5 -10
- package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
- package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
- package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
- package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
- package/dist/chunk-37V3RET3.cjs.map +0 -1
- package/dist/chunk-3TMTYJAJ.js.map +0 -1
- package/dist/chunk-BJROXF4N.js.map +0 -1
- package/dist/chunk-BP52BFIV.cjs.map +0 -1
- package/dist/chunk-E66UVONV.cjs.map +0 -1
- package/dist/chunk-FHPEM77Y.js.map +0 -1
- package/dist/chunk-I767LVN7.cjs.map +0 -1
- package/dist/chunk-IXUHXTHW.cjs.map +0 -1
- package/dist/chunk-KKNEYIZJ.cjs.map +0 -1
- package/dist/chunk-LNI3FYSI.js.map +0 -1
- package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
- package/dist/chunk-QJUJNTIU.cjs.map +0 -1
- package/dist/chunk-QZGABF2M.js.map +0 -1
- package/dist/chunk-THFZSDIU.js.map +0 -1
- package/dist/chunk-UYJQDDEE.cjs.map +0 -1
- package/dist/chunk-VC5XVPLM.js.map +0 -1
- package/dist/chunk-VGEZNFWH.js.map +0 -1
- package/dist/chunk-VYQVDL2M.js.map +0 -1
- package/dist/config-6FB2BXMP.js +0 -6
- package/dist/migrations-FGXZPKDC.cjs +0 -13
- package/dist/migrations-Z6D27NAW.js +0 -4
- package/dist/rbac-7QZ4JZ2E.cjs +0 -14
- 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
|
|
4
|
+
var chunkTT3TQSCZ_cjs = require('./chunk-TT3TQSCZ.cjs');
|
|
5
5
|
var chunk36Z3AKX3_cjs = require('./chunk-36Z3AKX3.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
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
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
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
|
|
15
|
+
var chunkDLTT7QZU_cjs = require('./chunk-DLTT7QZU.cjs');
|
|
16
16
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
17
|
-
var
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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("*",
|
|
487
|
-
adminDocumentsRoutes.use("*",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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",
|
|
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 =
|
|
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:
|
|
984
|
-
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("/",
|
|
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
|
|
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(
|
|
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:
|
|
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",
|
|
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
|
|
1106
|
-
const svc = new
|
|
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(
|
|
1128
|
-
const coll =
|
|
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:
|
|
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",
|
|
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(
|
|
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:
|
|
1263
|
-
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
|
|
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:
|
|
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 =
|
|
1729
|
-
const transformedResults = records.map(
|
|
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",
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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:
|
|
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",
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
1921
|
-
count:
|
|
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",
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
1992
|
-
count:
|
|
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",
|
|
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 =
|
|
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
|
|
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:
|
|
2032
|
-
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",
|
|
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
|
|
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(
|
|
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:
|
|
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",
|
|
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 =
|
|
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
|
|
2094
|
-
const svc = new
|
|
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(
|
|
2110
|
-
const coll =
|
|
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:
|
|
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",
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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("*",
|
|
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
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
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 =
|
|
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("*",
|
|
3124
|
-
adminApiRoutes.use("*",
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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-
|
|
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-
|
|
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">${
|
|
3610
|
-
${data.message ? `<div class="mb-6">${
|
|
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">${
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
7127
|
-
const cookieMaxAge = await
|
|
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
|
-
|
|
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
|
|
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
|
|
7256
|
-
const token = await
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
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
|
|
7321
|
-
const token = await
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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",
|
|
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
|
-
|
|
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
|
|
7412
|
-
const payload = await
|
|
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
|
|
7421
|
-
const newToken = await
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
7529
|
-
const token = await
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
7844
|
+
const rbac = new chunkJCBDXEY2_cjs.RbacService(db);
|
|
7635
7845
|
const results = [];
|
|
7636
7846
|
const upsertSeedUser = async (opts) => {
|
|
7637
|
-
const passwordHash = await
|
|
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
|
|
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
|
|
7880
|
-
const authToken = await
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
8912
|
-
${data.success ?
|
|
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
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
>
|
|
9120
|
-
<
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
|
10499
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
10279
10500
|
}
|
|
10280
10501
|
|
|
10281
10502
|
// src/templates/pages/admin-content-list.template.ts
|
|
10282
|
-
|
|
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
|
-
${
|
|
10717
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
|
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 =
|
|
11500
|
+
const blocksConfig = chunkDLTT7QZU_cjs.getBlocksFieldConfig(field.field_options);
|
|
11280
11501
|
if (blocksConfig) {
|
|
11281
|
-
const parsed =
|
|
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("*",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11785
|
+
const enabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, plugin);
|
|
11565
11786
|
flags[`${key}Enabled`] = enabled;
|
|
11566
11787
|
if (enabled) {
|
|
11567
|
-
const ps = new
|
|
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
|
|
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
|
|
11824
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11604
11825
|
const codeCollectionMap = new Map(codeCollections.map((c2) => [c2.name, c2]));
|
|
11605
|
-
const docTypeRegistry = new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11971
|
-
const tinymceEnabled = await
|
|
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
|
|
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
|
|
12199
|
+
const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
|
|
11979
12200
|
let quillSettings;
|
|
11980
12201
|
if (quillEnabled) {
|
|
11981
|
-
const pluginService = new
|
|
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
|
|
12206
|
+
const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
|
|
11986
12207
|
let mdxeditorSettings;
|
|
11987
12208
|
if (mdxeditorEnabled) {
|
|
11988
|
-
const pluginService = new
|
|
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
|
|
12213
|
+
const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
|
|
11993
12214
|
let lexicalSettings;
|
|
11994
12215
|
if (lexicalEnabled) {
|
|
11995
|
-
const pluginService = new
|
|
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
|
|
12132
|
-
const tinymceEnabled = await
|
|
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
|
|
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
|
|
12360
|
+
const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
|
|
12140
12361
|
let quillSettings;
|
|
12141
12362
|
if (quillEnabled) {
|
|
12142
|
-
const pluginService = new
|
|
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
|
|
12367
|
+
const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
|
|
12147
12368
|
let mdxeditorSettings;
|
|
12148
12369
|
if (mdxeditorEnabled) {
|
|
12149
|
-
const pluginService = new
|
|
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
|
|
12374
|
+
const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
|
|
12154
12375
|
let lexicalSettings;
|
|
12155
12376
|
if (lexicalEnabled) {
|
|
12156
|
-
const pluginService = new
|
|
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.
|
|
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",
|
|
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",
|
|
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
|
|
13195
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
12949
13196
|
const docType = await registry.findById(typeId);
|
|
12950
|
-
const svc = new
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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-
|
|
13109
|
-
const registry = new
|
|
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
|
-
|
|
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 ?
|
|
13150
|
-
${data.success ?
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ?
|
|
13954
|
-
${data.success ?
|
|
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
|
|
14523
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14277
14524
|
}
|
|
14278
14525
|
|
|
14279
14526
|
// src/templates/pages/admin-user-new.template.ts
|
|
14280
|
-
|
|
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 ?
|
|
14320
|
-
${data.success ?
|
|
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
|
|
14797
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14551
14798
|
}
|
|
14552
14799
|
|
|
14553
14800
|
// src/templates/pages/admin-users-list.template.ts
|
|
14554
|
-
|
|
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 ?
|
|
14711
|
-
${data.success ?
|
|
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
|
-
${
|
|
15135
|
+
${chunkOUBUS74I_cjs.renderTable(tableData)}
|
|
14889
15136
|
|
|
14890
15137
|
<!-- Pagination -->
|
|
14891
|
-
${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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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("*",
|
|
15329
|
-
userRoutes.use("/users/*",
|
|
15330
|
-
userRoutes.use("/users",
|
|
15331
|
-
userRoutes.use("/invite-user",
|
|
15332
|
-
userRoutes.use("/resend-invitation/*",
|
|
15333
|
-
userRoutes.use("/cancel-invitation/*",
|
|
15334
|
-
userRoutes.use("/activity-logs",
|
|
15335
|
-
userRoutes.use("/activity-logs/*",
|
|
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
|
-
|
|
15364
|
-
|
|
15365
|
-
{ value:
|
|
15366
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
15881
|
+
const validPassword = await chunkE7E3NL3Y_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
15637
15882
|
if (!validPassword) {
|
|
15638
|
-
return c.html(
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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() || "
|
|
15847
|
-
const validRoles =
|
|
15848
|
-
const role = validRoles.includes(roleInput) ? roleInput : "
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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() || "
|
|
16105
|
-
const validRoles =
|
|
16106
|
-
const role = validRoles.includes(roleInput) ? roleInput : "
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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("*",
|
|
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
|
|
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",
|
|
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
|
-
|
|
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
|
|
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 =
|
|
19383
|
-
const
|
|
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 (
|
|
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
|
|
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 =
|
|
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 =
|
|
20879
|
-
const manifestEntries = Object.values(
|
|
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("*",
|
|
20917
|
-
var AVAILABLE_PLUGINS = Object.values(
|
|
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
|
|
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
|
|
21297
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21012
21298
|
let plugin = await pluginService.getPlugin(pluginId);
|
|
21013
21299
|
if (!plugin) {
|
|
21014
|
-
const def =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
21122
|
-
const fieldsHtml =
|
|
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 =
|
|
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 =
|
|
21438
|
+
const parsed = chunkD6FWEYQE_cjs.parseFormDataToSettings(def.configSchema, form);
|
|
21153
21439
|
const db = c.env.DB;
|
|
21154
|
-
const pluginService = new
|
|
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
|
|
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
|
|
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
|
|
21215
|
-
const registryEntry =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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("*",
|
|
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(
|
|
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
|
|
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 =
|
|
23354
|
+
var VERSION = chunkBJ6NJL2E_cjs.getCoreVersion();
|
|
23069
23355
|
var router = new hono.Hono();
|
|
23070
|
-
router.use("*",
|
|
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
|
-
|
|
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
|
|
24028
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
23743
24029
|
}
|
|
23744
24030
|
|
|
23745
24031
|
// src/templates/pages/admin-collections-form.template.ts
|
|
23746
|
-
|
|
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 ?
|
|
23920
|
-
${data.success ?
|
|
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
|
-
${
|
|
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
|
|
25315
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
25030
25316
|
}
|
|
25031
25317
|
|
|
25032
25318
|
// src/routes/admin-collections.ts
|
|
25033
|
-
|
|
25319
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
25034
25320
|
var adminCollectionsRoutes = new hono.Hono();
|
|
25035
|
-
adminCollectionsRoutes.use("*",
|
|
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 =
|
|
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:
|
|
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:
|
|
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
|
-
|
|
25548
|
+
chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst({
|
|
25263
25549
|
title: "Add a Collection",
|
|
25264
25550
|
pageTitle: "Add a Collection",
|
|
25265
25551
|
currentPath: "/admin/collections",
|
|
25266
|
-
version:
|
|
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 =
|
|
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
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
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
|
-
|
|
25353
|
-
|
|
25354
|
-
|
|
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
|
-
|
|
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
|
|
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("*",
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
27321
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
27036
27322
|
}
|
|
27037
27323
|
|
|
27038
27324
|
// src/routes/admin-api-reference.ts
|
|
27039
|
-
var VERSION2 =
|
|
27325
|
+
var VERSION2 = chunkBJ6NJL2E_cjs.getCoreVersion();
|
|
27040
27326
|
var router2 = new hono.Hono();
|
|
27041
|
-
router2.use("*",
|
|
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 =
|
|
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-
|
|
27170
|
-
//# sourceMappingURL=chunk-
|
|
27455
|
+
//# sourceMappingURL=chunk-6OA77UM7.cjs.map
|
|
27456
|
+
//# sourceMappingURL=chunk-6OA77UM7.cjs.map
|